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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. The format

### Added

- [#32](https://github.com/mohanagy/miftah/issues/32) Delivered MCP protocol conformance for resource templates, subscriptions, upstream list/update notifications, aggregate pagination, explicit capability/unsupported behavior, and request cancellation/progress forwarding across STDIO and Streamable HTTP upstreams.
- [#18](https://github.com/mohanagy/miftah/issues/18) The packed-package contract now exercises the installed CLI through shell and Windows command quoting, paths with spaces, generated help, stable category exits, JSON automation output, and normalized/redacted audit-log output.
- [#18](https://github.com/mohanagy/miftah/issues/18) The CLI reference now documents generated help, every command and option, version compatibility output, exit statuses, JSON streams, and audit snapshot/follow safety boundaries.
- [#19](https://github.com/mohanagy/miftah/issues/19) The versioned strict preset catalog, first-run onboarding wizard, generated absolute client snippets, compatibility matrix, and exact generated examples are documented and contract-tested. Tests validate generated configuration without constructing or starting external providers.
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ miftah --config ~/.config/miftah/github.json

Profiles are named credential environments. Keep secret values outside JSON and use the exact generated references in the checked-in [GitHub](examples/github.miftah.json), [Sentry](examples/sentry.miftah.json), or [generic reference](examples/generic.miftah.json) example. The strict catalog pins GitHub to `ghcr.io/github/github-mcp-server:v1.5.0` with its documented read-only tool configuration; it does not claim a digest. The [compatibility matrix](docs/presets-and-clients.md) describes safe promotion and deployment recording for that tag.

Claude can call `miftah_list_profiles`, `miftah_current_profile`, `miftah_use_profile`, `miftah_reset_profile`, `miftah_lock_profile`, `miftah_unlock_profile`, `miftah_profile_info`, `miftah_health`, `miftah_validate_config`, `miftah_list_upstream_tools`, `miftah_restart_profile`, `miftah_verify_identity`, and `miftah_route_preview`. Upstream tools are exposed unchanged unless they collide with a reserved management name. After a profile change, restart, upstream failure, or recovery that changes a public capability surface, MCP clients receive list-change notifications and should re-list the affected tools, resources, or prompts before relying on cached capabilities.
Claude can call `miftah_list_profiles`, `miftah_current_profile`, `miftah_use_profile`, `miftah_reset_profile`, `miftah_lock_profile`, `miftah_unlock_profile`, `miftah_profile_info`, `miftah_health`, `miftah_validate_config`, `miftah_list_upstream_tools`, `miftah_restart_profile`, `miftah_verify_identity`, and `miftah_route_preview`. Upstream tools are exposed unchanged unless they collide with a reserved management name. After a profile change, restart, upstream failure, recovery, or upstream list-change notification that changes a public capability surface, MCP clients receive list-change notifications and should re-list the affected tools, resources, resource templates, or prompts before relying on cached capabilities.

Active profile state is in-memory by default. `state.scope: "session"` resets on a new MCP transport; opt-in `workspace` or config-identity-namespaced `global` scope persists only safe selection metadata (the profile and timestamp) using atomic owner-restricted storage. Clients cannot choose a scope or state path. Optional runtime locks and risk leases are connection-bound and never enter that durable state. See [active profile state](docs/config.md#active-profile-state) for lock precedence, fallback diagnostics, and platform paths.

For credential-file workflows, opt in to [profile credential isolation](docs/config.md#profile-credential-isolation). It gives each POSIX profile/upstream target a Miftah-managed HOME/XDG tree, can copy approved configuration-relative files into it, and can generate fixed Docker/Podman bind-mount arguments. It is deliberately not a sandbox for a hostile native process running as the same OS user.

For account bundles, define `upstreams` instead of `upstream`. Tools, resource names, and prompt names are exposed as `<upstream>__<name>` (for example `github__search_issues` and `github__account_prompt`), and each profile can provide per-upstream environment or header overrides. A multi-upstream resource URI is a Miftah-owned route such as `miftah://resource/github?uri=account%3A%2F%2Fcurrent`; its encoded value is redacted before exposure, while Miftah retains the exact original URI only in its per-profile route map. Before exposing multi-upstream resource or prompt URI metadata, Miftah strips URI userinfo and fragments and redacts every query value. Reads and prompt gets are routed only through the exact route map, never by guessing from a client identifier.
For account bundles, define `upstreams` instead of `upstream`. Tools, resource names, resource-template names, and prompt names are exposed as `<upstream>__<name>` (for example `github__search_issues` and `github__account_prompt`), and each profile can provide per-upstream environment or header overrides. A multi-upstream resource URI is a Miftah-owned route such as `miftah://resource/github?uri=account%3A%2F%2Fcurrent`; resource templates use opaque Miftah-owned template bases. Their encoded values are redacted before exposure, while Miftah retains the exact original upstream URI or URI template only in its per-profile route map. Before exposing multi-upstream resource or prompt URI metadata, Miftah strips URI userinfo and fragments and redacts every query value. Reads and prompt gets are routed only through the exact route map, never by guessing from a client identifier.

For repeatable account selection, opt in to [provider routing matchers](docs/config.md#provider-routing-matchers) on a profile. Miftah's fixed built-in GitHub, Sentry, Jira, Linear, and PostHog matchers use only typed canonical identifiers and safe context, including an allowlisted canonical HTTPS provider URI on a standard resource read; a matcher never loads code from configuration. Explicit hints and routing rules remain stronger, a matcher never authorizes a destructive operation by itself, and competing profile matches fail closed.

Multi-upstream resource and prompt lists use opaque, bounded in-memory Miftah cursors so individual upstream cursors are not exposed. Re-list after a profile change or restart instead of retaining an old cursor. A standard `upstream` or a one-entry `upstreams` map preserves credential-free raw resource URIs, prompt names, and native upstream cursors for compatibility; URI and icon fields with userinfo, query values, or fragments are structurally redacted before they cross the boundary. A zero-entry bundle still omits resource and prompt capabilities.
Multi-upstream resource, resource-template, and prompt lists use opaque, bounded in-memory Miftah cursors so individual upstream cursors are not exposed. Re-list after a profile change, restart, or upstream list-change notification instead of retaining an old cursor. When every selectable profile and upstream supports subscriptions, Miftah advertises `resources.subscribe`, proxies subscribe/unsubscribe calls through the same resource-read routing and policy boundary, and forwards only matching Miftah-namespaced resource-update URIs. Miftah probes those finite upstream capability handshakes sequentially, closes each probe session before accepting the client connection, and therefore does not guess an immutable MCP capability or hold profile capacity for the probe. Subscription transitions for one URI are serialized; a profile change clears every connection-bound subscription and bounds upstream cleanup by `process.shutdownTimeoutMs`. A standard `upstream` or a one-entry `upstreams` map preserves credential-free raw resource URIs, prompt names, and native upstream cursors for compatibility; URI and icon fields with userinfo, query values, or fragments are structurally redacted before they cross the boundary. A zero-entry bundle still omits resource and prompt capabilities.

`tooling.toolDiscoveryMode` defaults to `"permissive"`. In that mode, a bundled list returns only healthy upstream contributions, removes routes for failed upstreams, and retries incomplete tool discovery on later tool requests. If every upstream fails a capability list, Miftah returns `UPSTREAM_DISCOVERY_FAILED` instead of advertising an empty upstream surface. Set it to `"strict"` to reject any unavailable upstream; strict tool discovery additionally checks every configured profile for an identical client-visible tool contract. `miftah_health` reports the profile, upstream name, overall and process state, transition time, automatic restart count, redacted error, intentional stop reason, pending recovery time, and per-capability discovery state for each started upstream. See `examples/multi-upstream.miftah.json`.

Expand Down Expand Up @@ -83,7 +83,7 @@ Use `"streamable-http"` for a remote MCP server:

Header names are case-insensitive, and a profile header always replaces the upstream header of the same name. Miftah requires HTTPS for non-loopback remote URLs; HTTP is accepted only for local development endpoints on `localhost`, `127.0.0.0/8`, or `::1`. The `"http"` transport is a compatibility alias for `"streamable-http"`. `"sse"` remains available for legacy MCP servers but is deprecated; prefer Streamable HTTP for new deployments.

An intentional Streamable HTTP restart or wrapper shutdown sends the MCP session DELETE request before closing the local client transport. A server may decline DELETE with HTTP 405, in which case Miftah still closes its local session but the remote server controls any remaining server-side state. If DELETE does not settle before the configured shutdown deadline, Miftah aborts the local transport rather than leaving a live credential session behind. HTTP status failures are returned as `UPSTREAM_HTTP_ERROR` and MCP JSON-RPC failures as `UPSTREAM_PROTOCOL_ERROR`; response bodies and remote error messages are not exposed to callers.
An intentional Streamable HTTP restart or wrapper shutdown sends the MCP session DELETE request before closing the local client transport. A server may decline DELETE with HTTP 405, in which case Miftah still closes its local session but the remote server controls any remaining server-side state. If DELETE does not settle before the configured shutdown deadline, Miftah aborts the local transport rather than leaving a live credential session behind. Requested cancellation and requested progress notifications are forwarded across both local STDIO and Streamable HTTP upstreams. HTTP status failures are returned as `UPSTREAM_HTTP_ERROR` and MCP JSON-RPC failures as `UPSTREAM_PROTOCOL_ERROR`; response bodies and remote error messages are not exposed to callers.

Miftah uses the SDK's existing 60-second MCP request timeout and does not add a second request-timeout setting. Startup and shutdown retain the configured 30-second and 5-second defaults. The SDK performs its bounded Streamable HTTP SSE reconnection behavior; if the transport ultimately closes, Miftah's opt-in `process.restartOnCrash` policy and bounded `maxRestarts` budget control profile recovery.

Expand All @@ -107,7 +107,7 @@ Routing can use the active profile or rules matching tool arguments:
}
```

When several profiles match, Miftah refuses to guess. Use explicit profile switching for write and destructive actions. The same routing, policy, redaction, and audit pipeline applies to upstream tool calls, resource reads, and prompt retrieval. Policy patterns use each upstream tool's original name for tools, `resources/read` for reads, and `prompts/get` for prompt retrieval. A deny, blocked, or ambiguous decision is returned before Miftah forwards the request. A confirmation-required operation pauses for a connection-bound, one-time approval: form-capable MCP clients receive a generic boolean elicitation, while other clients receive a short-lived fallback bearer for `miftah_approve` or `miftah_deny`. Provider token scopes still matter: local policy cannot make a write-capable provider token read-only. Profiles that set a policy name must reference an existing entry in `policies`, while profiles with no `policy` field keep the default allow behavior.
When several profiles match, Miftah refuses to guess. Use explicit profile switching for write and destructive actions. The same routing, policy, redaction, and audit pipeline applies to upstream tool calls, resource reads and subscriptions, and prompt retrieval. Policy patterns use each upstream tool's original name for tools, `resources/read` for reads and subscriptions, and `prompts/get` for prompt retrieval. A deny, blocked, or ambiguous decision is returned before Miftah forwards the request. A confirmation-required operation pauses for a connection-bound, one-time approval: form-capable MCP clients receive a generic boolean elicitation, while other clients receive a short-lived fallback bearer for `miftah_approve` or `miftah_deny`. Provider token scopes still matter: local policy cannot make a write-capable provider token read-only. Profiles that set a policy name must reference an existing entry in `policies`, while profiles with no `policy` field keep the default allow behavior.

Miftah can also match bounded workspace metadata without treating a project file as configuration. It resolves a valid environment hint, then the nearest valid project-marker hint, then matching rules over tool arguments and collected context, then the configured fallback. Rules that select different profiles return `ROUTING_AMBIGUOUS`, and a context hint never authorizes a destructive operation that requires an explicit rule. `miftah_route_preview` and eligible audit records expose only sanitized routing evidence plus risk-classification source/confidence, not raw project environment values, upstream metadata, or project file contents. See [routing context](docs/config.md#routing-context) for the marker schema, root behavior, and evidence boundary.

Expand Down
Loading