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 @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file. The format

- [#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.

### Changed

Expand Down
73 changes: 8 additions & 65 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,84 +23,26 @@ Miftah runs locally by default. It has no cloud dependency or telemetry.
Generate a safe template:

```bash
miftah init github --preset github --output ~/.config/miftah/github.json
miftah init github --preset github --output ~/.config/miftah/github.json --client claude-desktop
```

Edit the profile environment to reference shell variables, then validate it:
Set the generated profile environment references in the environment that launches your client, then validate the configuration:

```bash
export GITHUB_WORK_TOKEN='...'
miftah validate --config ~/.config/miftah/github.json
```

Run a wrapped server directly:
`init --client` prints a host-specific JSON snippet with absolute launcher paths. Copy that JSON to the appropriate client configuration; Miftah does not write a client file. See the [preset and client compatibility matrix](docs/presets-and-clients.md) for the catalog pin, client location, and security boundaries.

Run a wrapped server directly when testing local STDIO:

```bash
miftah --config ~/.config/miftah/github.json
```

The same process can be configured in Claude Desktop:

```json
{
"mcpServers": {
"github": {
"command": "miftah",
"args": ["--config", "/Users/me/.config/miftah/github.json"]
}
}
}
```

## Profiles

Profiles are named credential environments. Keep secret values outside JSON whenever possible:

```json
{
"version": "1",
"name": "github",
"defaultProfile": "work",
"upstream": {
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server:v1.5.0"]
},
"profiles": {
"work": {
"description": "Work GitHub",
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_WORK_TOKEN}"
},
"policy": "safe-write"
},
"personal": {
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_TOKEN}"
},
"policy": "readonly"
}
},
"policies": {
"readonly": {
"allowRisk": ["read"],
"denyRisk": ["write", "destructive"]
},
"safe-write": {
"allowRisk": ["read", "write"],
"denyRisk": ["destructive"],
"requireConfirmation": ["write"]
}
},
"security": {
"allowPlaintextSecrets": false,
"allowProfileSwitchingFromMcp": true,
"requireExplicitProfileForDestructive": true
}
}
```

The GitHub preset pins `ghcr.io/github/github-mcp-server:v1.5.0`. To upgrade safely, read the release notes first, update the tag in your config, run `miftah validate`, then smoke-test both profiles before rollout.
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_profile_info`, `miftah_health`, `miftah_validate_config`, `miftah_list_upstream_tools`, `miftah_restart_profile`, 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.

Expand Down Expand Up @@ -182,7 +124,7 @@ Use `miftah --help` for the generated command list and `miftah <command> --help`
| `miftah --config <file>` / `miftah serve --config <file>` | Run the STDIO MCP wrapper. |
| `miftah validate --config <file>` | Parse and validate JSON config; writes JSON. |
| `miftah doctor --config <file> [--json]` | Report redacted configuration and upstream readiness. |
| `miftah init [name] [--name <name>] [--preset <name>] [--output <file>]` | Generate a generic, GitHub, or Sentry template. |
| `miftah init [name] [--name <name>] [--preset <name>] [--output <file>] [--interactive] [--client <client>] [--credential-env <name>] [--npm-package <package>] [--docker-image <image>] [--url <url>] [--header-name <name>] [--header-prefix <prefix>]` | Generate a strict catalog template and optionally print client JSON. |
| `miftah schema` | Print the JSON Schema. |
| `miftah list-tools --config <file> [--profile <name>]` | Discover upstream tools as JSON. |
| `miftah test-profile --config <file> [--profile <name>]` | Start and initialize one profile; writes JSON. |
Expand All @@ -200,6 +142,7 @@ Structured success output is written to stdout with stderr empty. Stable nonzero
- [CLI](docs/cli.md)
- [Library API](docs/library-api.md)
- [Claude Desktop](docs/claude-desktop.md)
- [Preset and client compatibility](docs/presets-and-clients.md)
- [GitHub example](docs/examples/github.md)
- [Sentry example](docs/examples/sentry.md)
- [Changelog and release policy](CHANGELOG.md)
Expand Down
31 changes: 16 additions & 15 deletions docs/claude-desktop.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
# Claude Desktop

Install Miftah globally, create a wrapper config, and add one server entry:

```json
{
"mcpServers": {
"github": {
"command": "miftah",
"args": [
"--config",
"/Users/me/.config/miftah/github.json"
]
}
}
}
Generate a strict configuration and a Claude Desktop snippet:

```sh
miftah init github --preset github --output ~/.config/miftah/github.json --client claude-desktop
```

Miftah writes only `~/.config/miftah/github.json` in this example. It prints JSON for you to copy and does not create or overwrite a Claude Desktop configuration file.

Claude Desktop uses an `mcpServers` object and is officially available on macOS and Windows. Its normal locations are:

- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

Use the installed app’s **Developer → Edit Config** flow as the source of truth for the actual location and schema. Merge the generated top-level `mcpServers` property into the host config. If the host config already has an `mcpServers` object, merge the generated server entry into that object instead of nesting another `mcpServers` property. Do not convert its absolute command and argument paths into a shell command. The launcher uses absolute Node and compiled Miftah CLI paths because desktop GUI processes often have a different `PATH` than a terminal.

Regenerate the snippet after moving or upgrading Miftah, or changing the Miftah config path. Keep credentials outside both JSON files; set only the generated `${ENV_NAME}` references in the environment that launches Claude Desktop.

Claude Desktop generally provides one STDIO session per configured server. Profile state is therefore session-local in the default mode. Miftah cannot infer every detail of a conversation; use `miftah_use_profile` for explicit switching and configure routing rules for stable tool arguments such as repositories, organizations, or projects.

Do not configure every account as a separate Claude server. Give each wrapper one entry and keep account-specific credentials in profiles.
Do not configure every account as a separate Claude server. Give each wrapper one entry and keep account-specific credentials in profiles. For catalog pins, safety boundaries, and all client destinations, see [preset and client compatibility](presets-and-clients.md).
8 changes: 6 additions & 2 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The root command list is `serve`, `validate`, `doctor`, `schema`, `init`, `list-
| `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. |
| `miftah init [name]` | none | `--name <name>`, `--preset <name>`, `--output <file>` | Writes a starter configuration with exclusive creation. The positional `name` and `--name` are alternatives; the default name is `miftah-wrapper`. |
| `miftah init [name]` | none | `--name <name>`, `--preset <name>`, `--output <file>`, `--interactive`, `--client <claude-desktop\|claude-code\|cursor\|vscode\|all>`, `--credential-env <name>`, `--npm-package <package>`, `--docker-image <image>`, `--url <url>`, `--header-name <name>`, `--header-prefix <prefix>` | Writes a strict catalog configuration with exclusive creation and can print client JSON snippets. The positional `name` and `--name` are alternatives; the default name is `miftah-wrapper`. |
| `miftah list-tools --config <file>` | `--config` | `--config <file>`, `--profile <name>` | Starts the selected profile, discovers its upstream tools, writes a JSON array, then closes the manager. `--profile` defaults to the configured default profile. |
| `miftah test-profile --config <file>` | `--config` | `--config <file>`, `--profile <name>` | Starts and initializes one profile, writes `{"ok":true,"profile":"…"}`, then closes the manager. `--profile` defaults to the configured default profile. |
| `miftah logs --config <file>` | `--config` | `--config <file>`, `--follow` | Reads the configured audit JSONL as normalized, redacted JSONL. `--follow` continues watching it. This command does not construct an upstream manager. |
Expand All @@ -30,13 +30,17 @@ Every command also accepts `--help` and `-h`; those generated per-command help s

### `init` presets and paths

`--preset` defaults to `generic`. The named templates are `generic`, `github`, and `sentry`; an unrecognized preset name falls back to the generic template. `--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:
`--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:

```sh
miftah init "work wrapper" --preset github --output "$HOME/Miftah configs/work wrapper.json"
miftah validate --config "$HOME/Miftah configs/work wrapper.json"
```

`generic-npx` requires `--npm-package` with exact package SemVer; `generic-docker` requires a canonical digest in `--docker-image`; and `streamable-http` requires `--url` plus optional credential environment/header metadata. `--credential-env` is optional where supported. See [preset and client compatibility](presets-and-clients.md) for exact inputs, pins, provenance, and client snippets.

`--interactive` uses a wizard only when both input and output are TTYs. EOF or Ctrl-C cancels without writing a config. It asks for variable names and safe metadata, never secret values. In noninteractive use, `init` creates only the config unless `--client` is supplied. `--client` prints JSON with absolute Node and compiled Miftah paths; it does not write a host config. Regenerate the snippet after moving or upgrading Miftah or changing the config path.

### `doctor`

`doctor` checks configuration, secret references, redaction, permissions, configured audit storage, executable availability, upstream startup, discovery, and clean shutdown where applicable. Its checks have stable `code`, `status`, `target`, `explanation`, and `remediation` fields.
Expand Down
2 changes: 2 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ miftah schema > miftah.schema.json

Miftah accepts config version `"1"` only and does not silently migrate config files. A future migration must be explicit and documented; an unsupported version returns `UNSUPPORTED_CONFIG_VERSION` with remediation.

For strict starter configurations, use the versioned `init` catalog rather than treating generic command examples as trusted upstream recommendations. The [preset and client compatibility matrix](presets-and-clients.md) records exact pins, required inputs, upstream provenance, and the validation boundary for every catalog entry.

The generated JSON Schema enforces static structure, including exactly one of `upstream` or `upstreams`. References to names declared in dynamic maps cannot be represented by JSON Schema alone; run `miftah validate` in addition to editor validation to verify profile, policy, routing, lock, and per-profile upstream references.

With `upstreams`, each profile may override `env`, `headers`, `args`, or `cwd` under a named upstream. Miftah namespaces discovered tools as `<upstream>__<tool>` so one wrapper can safely expose several providers. Tool discovery uses the active profile. Clients receive `notifications/tools/list_changed` after a profile change, restart, or upstream recovery that changes the public tool surface and must re-run `tools/list` before relying on cached tools or schemas. If a routing rule selects another profile, Miftah forwards only tools with an identical client-visible schema in both profiles; otherwise it returns `TOOL_SCHEMA_MISMATCH` instead of forwarding a call whose schema the client did not see.
Expand Down
46 changes: 7 additions & 39 deletions docs/examples/github.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,13 @@
# GitHub

Use the generic wrapper to run GitHub MCP with separate work and personal tokens:
The strict GitHub catalog output is [`examples/github.miftah.json`](../../examples/github.miftah.json). Generate an equivalent configuration with:

```json
{
"version": "1",
"name": "github",
"defaultProfile": "work",
"upstream": {
"transport": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server:v1.5.0"]
},
"profiles": {
"work": {
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_WORK_TOKEN}"
},
"policy": "safe-write"
},
"personal": {
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_TOKEN}"
},
"policy": "readonly"
}
},
"policies": {
"readonly": {
"allowRisk": ["read"],
"denyRisk": ["write", "destructive"]
},
"safe-write": {
"allowRisk": ["read", "write"],
"denyRisk": ["destructive"],
"requireConfirmation": ["write"]
}
}
}
```sh
miftah init github --preset github --output github.miftah.json
```

This config contains references only. Set the variables in the shell that launches Claude Desktop.
It runs Docker STDIO with the exact `ghcr.io/github/github-mcp-server:v1.5.0` tag, `--read-only`, and `--toolsets=repos,issues,pull_requests`. The example contains only `${GITHUB_WORK_TOKEN}` and `${GITHUB_PERSONAL_TOKEN}` references; provide least-privilege GitHub provider tokens outside the JSON.

When upgrading the pinned image tag, review upstream release notes first, then run `miftah validate --config <file>` and test both profiles before adopting the new tag.
The tag is intentionally not presented as a digest. Before reproducible production deployment, use an authenticated promotion process and record the resolved image digest in deployment records; do not invent one. Miftah’s local policy cannot make a write-capable provider token read-only.

See the [preset and client compatibility matrix](../presets-and-clients.md) for upstream links, digest guidance, validation boundaries, and client snippets.
42 changes: 9 additions & 33 deletions docs/examples/sentry.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,13 @@
# Sentry

Sentry MCP can use the same wrapper pattern:
The strict Sentry catalog output is [`examples/sentry.miftah.json`](../../examples/sentry.miftah.json). Generate an equivalent configuration with:

```json
{
"version": "1",
"name": "sentry",
"defaultProfile": "work",
"upstream": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@sentry/mcp-server"]
},
"profiles": {
"work": {
"env": {
"SENTRY_AUTH_TOKEN": "${SENTRY_WORK_TOKEN}",
"SENTRY_ORG": "work-org"
}
},
"client-a": {
"env": {
"SENTRY_AUTH_TOKEN": "${SENTRY_CLIENT_A_TOKEN}",
"SENTRY_ORG": "client-a"
},
"policy": "readonly"
}
},
"policies": {
"readonly": {
"allowRisk": ["read"],
"denyRisk": ["write", "destructive"]
}
}
}
```sh
miftah init sentry --preset sentry --output sentry.miftah.json
```

It runs `@sentry/mcp-server@0.36.0` with `--skills=inspect` and contains only the `${SENTRY_ACCESS_TOKEN}` reference. The upstream requires Node.js `>=20`, independently of Miftah’s own Node.js requirement.

`--skills=inspect` filters Sentry MCP CLI skills. It does not authorize a token, and it is not a read-only flag or preset. Use least-privilege Sentry token scopes; Miftah local policy cannot reduce provider-side token permissions.

See the [preset and client compatibility matrix](../presets-and-clients.md) for upstream sources, validation boundaries, and client snippets.
Loading
Loading