Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file. The format
- [#81](https://github.com/mohanagy/miftah/issues/81) Added configuration format v3 and a strict, non-secret OAuth connection core: opaque profile/upstream/resource/issuer bindings, canonical HTTPS Streamable HTTP validation, static-Authorization collision refusal, OS-vault credential isolation, crash-released binding-scoped transaction coordination, redacted lifecycle primitives, and v1/v2-to-v3 migration with no credential synthesis.
- [#82](https://github.com/mohanagy/miftah/issues/82) Enabled standards-compatible OAuth for exact v3 HTTPS Streamable HTTP connections: protected-resource plus authorization-server/OpenID discovery, explicit pre-registered, Client ID Metadata, or Dynamic Client Registration, system-browser PKCE authorization through a single-use literal-loopback callback, RFC 9207 issuer validation, profile-bound OS-vault credentials, refresh and reconnect, typed redacted failures, and unchanged non-OAuth transport behavior. Provider-specific/local OAuth, revocation, and operator lifecycle commands remain outside this release surface.
- [#83](https://github.com/mohanagy/miftah/issues/83) Added durable bounded profile/account identity bindings, visible per-profile binding states and evidence, exact OAuth connection identity-state updates, and opt-in explicit or confirmed current-session selection for protected multi-profile operations. Persisted evidence never replaces live verification, and external state changes never silently override an active client's in-memory profile.
- [#84](https://github.com/mohanagy/miftah/issues/84) Added dry-run-first OAuth connection setup, redacted connection list/status/test reports, safe connect and reauthentication, exact local disconnect, client snippets, and headless diagnostics through shared typed application services.
- [#85](https://github.com/mohanagy/miftah/issues/85) Added the explicitly launched, literal-loopback Console control API with a separate `/api/v1` listener, one-use terminal bootstrap, bounded HttpOnly browser sessions, strict Host/Origin and CSRF enforcement, metadata-only configuration/profile/connection health, atomic audited connection changes, redacted Console audit queries, credential rotation, and clean shutdown. The browser UI remains a separate roadmap layer.

## [0.3.3] - 2026-07-22

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ For credential-file workflows, see [profile credential isolation](docs/config.md

When an operator enables profile locking, `miftah_lock_profile` and `miftah_unlock_profile` expose that control to the MCP client. For the complete security scope and future work, read the linked designs below.

The optional local Console control API is started explicitly with `miftah console --config <file>`. It binds only to loopback, uses a one-time terminal bootstrap plus browser session/CSRF protection, and exposes redacted metadata and audited connection operations under `/api/v1`. It is not a daemon and cannot change an already-running MCP client's in-memory session. The browser UI is a separate roadmap layer; see the [Console API contract](docs/console-api.md).

## Is Miftah right for you?

Miftah is a good fit when account context matters: you work across clients, organizations, environments, or credentials; you want a deliberate boundary before write/destructive actions; or you want one local place to inspect safe, redacted connection activity.
Expand All @@ -115,6 +117,7 @@ If you use one account with one direct MCP server and do not need profile, routi
- [Configuration reference](docs/config.md)
- [Security boundary](docs/security.md), [Threat model](docs/threat-model.md), and [OAuth and Console security design](docs/oauth-console-threat-model.md)
- [OAuth support](docs/oauth-support.md)
- [Local Console control API](docs/console-api.md)
- [CLI reference](docs/cli.md)
- [Architecture](docs/architecture.md)
- [Changelog and release policy](CHANGELOG.md)
Expand Down
4 changes: 3 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Architecture

The [threat model](threat-model.md) maps these components and their boundaries to public security controls and residual risks. The [OAuth and Console security design delta](oauth-console-threat-model.md) describes the control-plane and credential-lifecycle gates. Version 3 adds a standards-compatible remote OAuth runtime and in-process operator lifecycle services for exact HTTPS Streamable HTTP connections; provider adapters, provider-side revocation, and the local Console remain separate milestones.
The [threat model](threat-model.md) maps these components and their boundaries to public security controls and residual risks. The [OAuth and Console security design delta](oauth-console-threat-model.md) describes the control-plane and credential-lifecycle gates. Version 3 adds a standards-compatible remote OAuth runtime, in-process operator lifecycle services, and a separately launched local Console control API for exact HTTPS Streamable HTTP connections; provider adapters, provider-side revocation, and the browser UI remain separate milestones.

Miftah is an MCP-aware proxy, not a byte-level reverse proxy:

Expand All @@ -16,6 +16,8 @@ MCP client
-> upstream STDIO server
```

The Console control plane is a sibling process boundary, not another MCP transport. `miftah console` binds literal loopback only and routes `/api/v1` browser requests through one-use bootstrap, a bounded HttpOnly session, exact Host/Origin checks, CSRF validation, typed application services, and a separate fail-closed mutation journal. It has no `/mcp` route and cannot mutate another process's active STDIO session.

The STDIO public server is built with the official `@modelcontextprotocol/sdk` `Server` and `StdioServerTransport`. Each profile/upstream pair gets an SDK `Client` and its configured transport on first use: local processes use `StdioClientTransport`; remote upstreams use Streamable HTTP by default (the historical `"http"` alias is accepted only by version 1) or the deprecated legacy SSE client. Resolved profile headers override upstream headers case-insensitively before either remote transport is constructed. An exact version-3 OAuth binding gives only that Streamable HTTP session a profile-bound SDK OAuth provider; static Authorization headers on the same target are rejected. The provider validates protected-resource and authorization-server discovery, drives PKCE/browser/callback exchange, and loads or refreshes credentials through the exact OS-vault binding before reconnecting with bearer authorization. Streamable HTTP session shutdown sends DELETE while its session ID is still available, then closes the local client transport and any pending OAuth handoff; legacy SSE has no corresponding server-session teardown request. Request cancellation and requested progress notifications retain their MCP request context across both STDIO and Streamable HTTP upstreams. Startup HTTP failures and operation HTTP/MCP/OAuth failures are normalized before crossing the proxy boundary, retaining only stable category/code metadata rather than server response text. See [OAuth support](oauth-support.md) for the supported native OAuth boundary.

The optional HTTP host owns the listener and no shared Miftah session state. It validates the exact `/mcp` target, Host, Origin, bearer authentication, a bounded JSON initialize request, and capacity before creating a `StreamableHTTPServerTransport`. That transport and a new `MiftahServer`, `ProfileManager`, and upstream manager belong to one HTTP session only. The host forces the session runtime to in-memory `session` profile state, even if normal STDIO configuration uses workspace/global persistence. Its session registry owns only opaque MCP session IDs, idle timers, and cleanup tasks; DELETE, expiry, connection shutdown, and wrapper shutdown detach the record before asynchronous runtime cleanup so no client can reuse a closing runtime, while retaining that capacity reservation until cleanup succeeds. A rejected cleanup is recorded, retains capacity, and makes graceful shutdown fail rather than silently admitting unlimited replacement runtimes. A reconnect is routed to the existing transport by its session ID, while the SDK permits only one active standalone SSE stream for that session.
Expand Down
13 changes: 10 additions & 3 deletions docs/cli.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# CLI reference

`miftah` is an MCP wrapper with STDIO as its default transport and an opt-in local Streamable HTTP server. Run `miftah --help` for the generated command list, or `miftah <command> --help` for the options accepted by one command. The help text is the authoritative grammar for the installed version.
`miftah` is an MCP wrapper with STDIO as its default transport, an opt-in local Streamable HTTP server, and a separately launched local Console control API. Run `miftah --help` for the generated command list, or `miftah <command> --help` for the options accepted by one command. The help text is the authoritative grammar for the installed version.

## Help

```text
Usage: miftah [command] [options]
```

The root command list includes `serve`, `validate`, `doctor`, `schema`, `init`, `migrate-config`, `connection add|list|status|test`, `auth connect|reauth|disconnect`, `list-tools`, `test-profile`, `logs`, `audit-export`, `audit-verify`, and `version`. With no command, Miftah runs `serve`.
The root command list includes `serve`, `console`, `validate`, `doctor`, `schema`, `init`, `migrate-config`, `connection add|list|status|test`, `auth connect|reauth|disconnect`, `list-tools`, `test-profile`, `logs`, `audit-export`, `audit-verify`, and `version`. With no command, Miftah runs `serve`.

Documented command names, options, JSON success forms, and exit categories are compatibility contracts. An incompatible CLI removal, rename, required-option change, or semantic output change requires the pre-1.0 deprecation/removal process in the [public compatibility policy](library-api.md#compatibility-policy).

Expand All @@ -19,6 +19,7 @@ Documented command names, options, JSON success forms, and exit categories are c
| Command | Required input | Options | Output and behavior |
| --- | --- | --- | --- |
| `miftah serve --config <file>` | `--config` | `--config <file>`, `--transport <stdio\|http>` | Runs the STDIO MCP wrapper by default, or the configured local Streamable HTTP endpoint with `--transport http`. `miftah --config <file>` is the equivalent default-command STDIO form. |
| `miftah console --config <file>` | `--config` | `--config <file>`, `--port <number>` | Explicitly starts the separate literal-loopback Console control API. It prints the URL and a one-use terminal bootstrap code; no daemon or MCP session is started. |
| `miftah validate --config <file>` | `--config` | `--config <file>` | Validates the JSON configuration without starting an upstream. Writes a JSON object with `ok`, `name`, and `profiles`. |
| `miftah doctor --config <file>` | `--config` | `--config <file>`, `--json` | Validates configuration and checks upstream readiness. Default output is a human-readable report; `--json` writes only the JSON report. A healthy or degraded report exits `0`; a failed report exits `1`. |
| `miftah schema` | none | none | Writes the Miftah JSON Schema as pretty-printed JSON. |
Expand Down Expand Up @@ -46,6 +47,12 @@ Every command also accepts `--help` and `-h`; those generated per-command help s

HTTP bearer authentication is configured only through `server.http.authToken` as a secret reference. The CLI never accepts a bearer token option and never writes one to its listener or error output. See [HTTP server transport](config.md#http-server-transport) for loopback, non-loopback, Host, Origin, session, and request-limit requirements.

### Local Console control API

`miftah console --config <file>` binds only literal `127.0.0.1`, uses an ephemeral port unless `--port` is supplied, and prints an invocation-bound one-use bootstrap code to the launching terminal. The code is not an OAuth token or MCP bearer. Enter it only in the local Console bootstrap screen; never paste it into a URL, client configuration, log, or support ticket. Stopping the process closes the listener and invalidates every browser session. Restarting produces a fresh bootstrap credential.

The Console API is versioned under `/api/v1` and uses exact Host/Origin checks, a short-lived HttpOnly same-site session, CSRF proof for every mutation, bounded JSON, fail-closed mutation audit, and metadata-only responses. It modifies durable configuration and exact local OAuth credentials for future client connections; it cannot take over or silently change another process's active Claude Desktop session. See the [local Console control API](console-api.md) for the full endpoint and bootstrap contract.

### `init` presets and paths

`--preset` defaults to `generic`. The strict catalog accepts `generic`, `github`, `sentry`, `generic-npx`, `generic-docker`, and `streamable-http`; an unrecognized preset is a usage error. `--output` defaults to `<name>.miftah.json`. Miftah resolves the output path from the current working directory, creates missing parent directories, and refuses to overwrite an existing file. Quote shell paths and names containing spaces:
Expand Down Expand Up @@ -92,7 +99,7 @@ When identity verification is unconfigured, doctor records `DOCTOR_IDENTITY` as

`miftah_verify_identity` is an MCP management tool, not a shell subcommand. It accepts optional `profile` and `upstream` strings. `profile` defaults to the active profile. Supplying a named `upstream` verifies only that target; `upstream: "default"` is an alias only for a single unnamed upstream. With `upstream` omitted, Miftah verifies every configured target in deterministic upstream order. The response always contains safe structured identity results, including nonverified states, and its audit event contains only safe evidence and a failure outcome when verification did not succeed.

`miftah_list_profiles` and `miftah_profile_info` show each profile's configured and persisted binding evidence; `miftah_current_profile`, `miftah_health`, and `miftah_route_preview` expose the same configured, persisted, or cached identity status. None starts an upstream or runs a probe. A newly started client reloads persisted evidence and durable profile selection, but another process or future Console action cannot silently replace an already active client's in-memory selection; restart that client when applying an external configuration or durable-selection change.
`miftah_list_profiles` and `miftah_profile_info` show each profile's configured and persisted binding evidence; `miftah_current_profile`, `miftah_health`, and `miftah_route_preview` expose the same configured, persisted, or cached identity status. None starts an upstream or runs a probe. A newly started client reloads persisted evidence and durable profile selection, but another process or Console action cannot silently replace an already active client's in-memory selection; restart that client when applying an external configuration or durable-selection change.

### MCP profile management

Expand Down
Loading