| summary | How mcporter discovers, merges, and mutates configuration files (project + home + imports), including OAuth and persistence. | |
|---|---|---|
| read_when |
|
mcporter config
Usage: mcporter config [options] <command>
Manage configured MCP servers, imports, and ad-hoc discoveries.
Commands:
list [options] [filter] Show merged servers (local + imports + ad-hoc cache)
get <name> Inspect a single server with resolved source info
add [options] <name> [target] Persist a server definition (URL or stdio command)
remove [options] <name> Delete a local entry or copy from an import
import <kind> [options] Copy entries from cursor/claude/codex/etc. into config
login <name|url> Complete OAuth/auth flows for a server
logout <name> Clear cached credentials for a server
doctor [options] Validate config files and report common mistakes
help [command] Show CLI or subcommand help
Global Options:
--config <path> Use an explicit config file (default: config/mcporter.json)
--root <dir> Set project root for import discovery (default: cwd)
--json Emit machine-readable output when supported
-h, --help Display help for mcporter config
Run `mcporter config help add` to see transport flags, ad-hoc persistence tips, and schema docs.
See https://github.com/sweetistics/mcporter/blob/main/docs/config.md for config anatomy, import precedence, and troubleshooting guidance.
mcporter keeps three configuration buckets in sync: repository-scoped JSON (config/mcporter.json), imported editor configs (Cursor, Claude, Codex, Windsurf, OpenCode, VS Code), and ad-hoc definitions supplied on the CLI. This guide explains how those sources merge, how to mutate them with mcporter config ..., and the safety rails around OAuth, env interpolation, and persistence.
- Create
config/mcporter.jsonat the repo root: - Run
mcporter list linear(ormcporter config list linear) to make sure the runtime can reach it. - Use
mcporter config add shadcn https://www.shadcn.io/api/mcpto persist another server without editing JSON. - Authenticate any OAuth-backed server with either
mcporter auth <name>ormcporter config login <name>; tokens land under~/.mcporter/<name>/unless you overridetokenCacheDir.
mcporter now merges home and project config files by default so global servers stay available inside repos. The order depends on how you invoke the CLI:
- If you pass
--config <file>(or set--configprogrammatically), only that file is used—no merging. - If
MCPORTER_CONFIGis set, only that file is used—no merging. - Otherwise, mcporter loads both of these layers (when present):
~/.mcporter/mcporter.jsonor~/.mcporter/mcporter.jsonc<root>/config/mcporter.jsonEntries from the project file override entries with the same name from the home file. Each layer still pulls in its own imports before merging.
All mcporter config … mutations still write back to a single file: the explicit path when provided; otherwise the project config path (<root>/config/mcporter.json). To edit the home file explicitly, run commands like mcporter config --config ~/.mcporter/mcporter.json add <name> … or set MCPORTER_CONFIG in your shell profile.
mcporter builds a merged view of all known servers before executing any command. The sources load in this order:
| Priority | Source | Notes |
|---|---|---|
| 1 | Explicit --http-url, --stdio, or bare URL passed to commands |
Highest priority, never cached unless --persist is supplied. Requires --allow-http for plain HTTP URLs. |
| 2 | config/mcporter.json (or the file passed via --config) |
Default path is <root>/config/mcporter.json; missing file returns an empty config so commands continue to work. |
| 3 | Imports listed in "imports" |
When you omit imports, mcporter loads ['cursor','claude-code','claude-desktop','codex','windsurf','opencode','vscode']. When you specify a non-empty array, mcporter appends any omitted defaults after your list so shared presets remain available. |
Rules:
- Later sources never override earlier ones. Local config always wins over imports; ad-hoc descriptors override both for the duration of a command.
- Each merged server tracks its origin (local path vs. import path), so
mcporter config get <name>can show you the path before you edit or remove the local copy withmcporter config remove <name>. - Imports remain read-only until you explicitly copy an entry via
mcporter config import <kind> --copyor runmcporter config add --copy-from claude-code:linear(feature planned alongside the CLI work).
mcporter config is the entry point for reading and writing configuration files. Use the existing ad-hoc flags on mcporter list|call|auth when you want ephemeral definitions; once you’re ready to persist them, switch back to mcporter config add.
Use --scope home|project with mcporter config add to pick the write target explicitly. project is always the default (creating config/mcporter.json if needed); home writes to ~/.mcporter/mcporter.json even when a project config is present. --persist <path> still takes precedence when you need a custom file.
- Shows local entries by default. Pass
--source importto list imported editor configs, or--jsonfor machine output. - Always appends a summary of other config files (paths, counts, sample names) so you know where imported entries live.
filteraccepts a name, glob fragment, orsource:cursorselector.- Adds informational notes when we auto-correct names (same machinery as
mcporter list).
- Prints the resolved definition for a single server, including the on-disk path, inherited headers/env, and transport details.
- Near-miss names are auto-corrected with the same heuristics as
mcporter list/call, and you’ll see suggestions whenever ambiguity remains. - Supports ad-hoc descriptors so you can inspect a URL before persisting it.
- Persists a server into the writable config file. Accepts both positional shortcuts (
mcporter config add sentry https://mcp.sentry.dev/mcp) and flag-driven definitions:--transport http|sse|stdio--urlor--command/--stdio--env,--header,--token-cache-dir,--description,--tag,--client-name,--oauth-redirect-url--copy-from importKind:nameto clone settings from an imported entry before editing.
--dry-runshows the JSON diff without writing, while--persist <path>overrides the destination file.
- Removes the local definition. Names sourced exclusively from imports remain untouched until you copy them locally.
- Displays (and optionally copies) entries from editor-specific configs:
cursor:.cursor/mcp.jsonin the repo, falling back to~/.config/Cursor/User/mcp.json(or%APPDATA%/Cursor/Useron Windows).claude-code:<root>/.claude/settings.local.json,<root>/.claude/settings.json,<root>/.claude/mcp.json, then~/.claude/settings.json,~/.claude/mcp.json,~/.claude.json.settings.local.jsonis meant for untracked per-developer overrides, whilesettings.jsonis the shared project config.claude-desktop: platform-specificClaude/claude_desktop_config.jsonpaths.codex:<root>/.codex/config.toml, then~/.codex/config.toml.windsurf: Codeium’s Windsurf config under%APPDATA%/Codeium/windsurf/mcp_config.jsonor~/.codeium/windsurf/mcp_config.json.opencode: HonorsOPENCODE_CONFIGwhen set, then<root>/opencode.json(c),OPENCODE_CONFIG_DIR/opencode.json(c), and finally${XDG_CONFIG_HOME:-~/.config}/opencode/opencode.json(c)(or%APPDATA%/opencode/opencode.json(c)on Windows). Both.jsonand.jsoncextensions are supported.vscode:Code/User/mcp.json(stable + Insiders) inside the OS-appropriate config directory.
--copywrites selected entries into your local config;--filter <glob>narrows the import list;--path <file>lets you point at bespoke locations.
- Mirrors
mcporter auth.logincompletes OAuth (or token provisioning) for either a named server or an ad-hoc URL. When a hosted MCP returns 401/403, mcporter automatically promotes that target to OAuth and re-runs the flow, matching the behavior documented indocs/adhoc.md. --browser nonesuppresses automatic browser launch (useful for copying the URL into a remote browser).logoutwipes token caches under~/.mcporter/<name>/(or the customtokenCacheDir). Pass--allto clear everything.
- Early validator that checks for simple issues (e.g., OAuth entries missing cache paths). Future iterations will add fixes for Accept headers, duplicate imports, and more.
--http-urland--stdioflags live onmcporter list|call|auth, keepingmcporter configfocused on persistent config files.- Names default to slugified hostnames or executable/script combos. Supply
--nameto improve reuse; mcporter uses that slug for OAuth caches even before persistence. --allow-httpis mandatory for cleartext endpoints so we never downgrade transport silently.- Add
--persist <path>(defaulting toconfig/mcporter.jsonwhen omitted) to copy the ad-hoc definition into config. We reuse the same serializer as the import pipeline, so copying from Cursor → local config produces identical structure and preserves custom env/header fields. --env KEY=VALentries merge with existingenvdictionaries if you later persist the same server; nothing is lost when you alternate between CLI flags and JSON edits.
Top-level structure:
| Key | Type | Description |
|---|---|---|
mcpServers |
object | Map of server names → definitions. Required even if empty. |
imports |
string[] | Optional list of import kinds. Empty array disables imports entirely; omitting the key falls back to the default list. |
Server definition fields (subset of what RawEntrySchema accepts):
| Field | Description |
|---|---|
description |
Free-form summary printed by mcporter list/config list. |
baseUrl / url / serverUrl |
HTTPS or HTTP endpoint. http:// requires --allow-http in ad-hoc mode but works in config if you explicitly set it. |
command / args |
Stdio executable definition (string or array). Arrays are preferred because they avoid shell quoting issues. |
env |
Key/value pairs applied when launching stdio commands. Supports ${VAR} interpolation and ${VAR:-fallback} defaults. Existing process env values win over fallbacks. |
headers |
Request headers for HTTP/SSE transports. Values can reference $env:VAR or ${VAR} placeholders, which must be set at runtime or mcporter aborts with a helpful error. |
auth |
Currently only oauth is recognized. Any other string is ignored (treated as undefined) to avoid stale state from other clients. |
tokenCacheDir |
Directory for OAuth tokens; still honored, but mcporter now keeps a centralized vault in ~/.mcporter/credentials.json (legacy per-server caches are auto-migrated). Supports ~ expansion. |
clientName |
Optional identifier some servers use for telemetry/audience segmentation. |
oauthRedirectUrl |
Override the default localhost callback. Useful when tunneling OAuth through Codespaces or remote dev boxes. |
oauthCommand.args |
For STDIO servers that ship a custom auth subcommand (e.g., Gmail MCP). mcporter will spawn the stdio command with these args when you run mcporter auth <name>, so you don’t need to call npx ... auth manually. |
mcporter normalizes headers to include Accept: application/json, text/event-stream automatically, matching the runtime’s streaming expectations.
pathsForImport(kind, rootDir)determines every candidate path. mcporter searches the repo first, then user-level directories, and stops at the first file that parses.- Entries pulled from imports are treated as read-only snapshots. The merge process keeps the first definition for each name; later sources with the same name are skipped until you override locally.
- To copy an imported entry, either run
mcporter config import <kind> --copy --filter nameor usemcporter config add name --copy-from kind:name. The copy operation writes through the same JSON normalization stack, so the resulting file matches our schema even if the source format was TOML (Codex) or legacy JSON shapes (serversvsmcpServers).
- Keep
config/mcporter.jsonunder version control. Encourage contributors to add sensitive data via env vars (${LINEAR_API_KEY}) rather than inline secrets. - Machine-specific additions can live in
~/.mcporter/local.json; pointmcporter config --config ~/.mcporter/local.json add ...there when you prefer not to touch the repo. Since the runtime only watches one config at a time, CI jobs should always pass--config config/mcporter.json(or run from the repo root) for deterministic behavior. - OAuth tokens, cached server metadata, and generated CLIs should remain outside the repo (
~/.mcporter/<name>/,dist/).
mcporter list --http-url ...refuses to auto-run OAuth to keep listing commands quick; usemcporter config login ...ormcporter auth ...to finish credential setup.- When env placeholders are missing, commands fail fast with the exact variable name. Add the variable or wrap it in
${VAR:-fallback}to provide defaults. - Use
mcporter config get <name> --show-source(planned flag) to confirm whether a server came from an import. If a teammate’s Cursor config keeps overriding your local entry, reorder theimportsarray to move Cursor later or set it to[]to disable imports entirely. docs/adhoc.mdcovers deeper debugging, including tmux workflows and OAuth promotion logs.
- Describe how
--persistwrites through the same import merge pipeline (especially oncemcporter config add --copy-fromships) so users know exactly which file changes. - Call out that
--allow-httpremains required for cleartext URLs even in config mutations, and reiterate that--env KEY=VALmerges with on-disk env blocks rather than replacing them entirely. - Clarify and illustrate the automatic OAuth promotion path for ad-hoc HTTP entries in both this doc and future
mcporter config loginhelp output. - Flesh out
mcporter config doctoronce the validator is implemented so we can show real output samples and suggested fixes.
{ "mcpServers": { "linear": { "description": "Linear issues", "baseUrl": "https://mcp.linear.app/mcp", "headers": { "Authorization": "Bearer ${LINEAR_API_KEY}" } } }, "imports": ["cursor", "claude-code", "claude-desktop", "codex", "windsurf", "opencode", "vscode"] }