diff --git a/AGENTS.md b/AGENTS.md
index 5db5664..89b889e 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -6,15 +6,18 @@ Shared guardrails distilled from the various `~/Projects/*/AGENTS.md` files (sta
Usage: In repo copies, the shared content lives inside `…` and the tool list inside `…`. Keep those tagged blocks identical across repos; anything outside them is repo-local and can be customized freely.
## Codex Global Instructions
+
- Keep the system-wide Codex guidance at `~/.codex/AGENTS.md` (the Codex home; override via `CODEX_HOME` if needed) so every task inherits these rules by default.
## General Guardrails
### Intake & Scoping
+
- Open the local agent instructions plus any `docs:list` summaries at the start of every session. Re-run those helpers whenever you suspect the docs may have changed.
- Review any referenced tmux panes, CI logs, or failing command transcripts so you understand the most recent context before writing code.
### Tooling & Command Wrappers
+
- Use the command wrappers provided by the workspace (`./runner …`, `scripts/committer`, `pnpm mcp:*`, etc.). Skip them only for trivial read-only shell commands if that’s explicitly allowed.
- Stick to the package manager and runtime mandated by the repo (pnpm-only, bun-only, swift-only, go-only, etc.). Never swap in alternatives without approval.
- When editing shared guardrail scripts (runners, committer helpers, browser tools, etc.), mirror the same change back into the `agent-scripts` folder so the canonical copy stays current.
@@ -23,29 +26,34 @@ Usage: In repo copies, the shared content lives inside `…` an
- Keep the project’s `AGENTS.md` `` block in sync with the full tool list from `TOOLS.md` so downstream repos get the latest tool descriptions.
### tmux & Long Tasks
+
- Run any command that could hang (tests, servers, log streams, browser automation) inside tmux using the repository’s preferred entry point.
- Do not wrap tmux commands in infinite polling loops. Run the job, sleep briefly (≤30 s), capture output, and surface status at least once per minute.
- Document which sessions you create and clean them up when they are no longer needed unless the workflow explicitly calls for persistent watchers.
### Build, Test & Verification
+
- Before handing off work, run the full “green gate” for that repo (lint, type-check, tests, doc scripts, etc.). Follow the same command set humans run—no ad-hoc shortcuts.
- Leave existing watchers running unless the owner tells you to stop them; keep their tmux panes healthy if you started them.
- Treat every bug fix as a chance to add or extend automated tests that prove the behavior.
- When someone asks to “fix CI,” use the GitHub CLI (`gh`) to inspect, rerun, and unblock failing workflows on GitHub until they are green.
### Code Quality & Naming
+
- Refactor in place. Never create duplicate files with suffixes such as “V2”, “New”, or “Fixed”; update the canonical file and remove obsolete paths entirely.
- Favor strict typing: avoid `any`, untyped dictionaries, or generic type erasure unless absolutely required. Prefer concrete structs/enums and mark public concurrency surfaces appropriately.
- Keep files at a manageable size. When a file grows unwieldy, extract helpers or new modules instead of letting it bloat.
- Match the repo’s established style (commit conventions, formatting tools, component patterns, etc.) by studying existing code before introducing new patterns.
### Git, Commits & Releases
+
- Invoke git through the provided wrappers, especially for status, diffs, and commits. Only commit or push when the user asks you to do so.
- To resolve a rebase, `git add`/`git commit` is allowed.
- Follow the documented release or deployment checklists instead of inventing new steps.
- Do not delete or rename unfamiliar files without double-checking with the user or the repo instructions.
### Documentation & Knowledge Capture
+
- Update existing docs whenever your change affects them, including front-matter metadata if the repo’s `docs:list` tooling depends on it.
- Whenever doing a large refactor, track work in `docs/refactor/
.md`, update it as you go, and delete it when the work is finished.
- Only create new documentation when the user or local instructions explicitly request it; otherwise, edit the canonical file in place.
@@ -53,16 +61,19 @@ Usage: In repo copies, the shared content lives inside `…` an
- Routine test additions don’t require changelog entries; reserve changelog lines for user-visible behavior changes.
### Troubleshooting & Observability
+
- Design workflows so they are observable without constant babysitting: use tmux panes, CI logs, log-tail scripts, MCP/browser helpers, and similar tooling to surface progress.
- If you get stuck, consult external references (web search, official docs, Stack Overflow, etc.) before escalating, and record any insights you find for the next agent.
- Keep any polling or progress loops bounded to protect hang detectors and make it obvious when something stalls.
### Stack-Specific Reminders
+
- Start background builders or watchers using the automation provided by the repo (daemon scripts, tmux-based dev servers, etc.) instead of running binaries directly.
- Use the official CLI wrappers for browser automation, screenshotting, or MCP interactions rather than crafting new ad-hoc scripts.
- Respect each workspace’s testing cadence (e.g., always running the main `check` script after edits, never launching forbidden dev servers, keeping replies concise when requested).
## Swift Projects
+
- Kick off the workspace’s build daemon or helper before running any Swift CLI or app; rely on the provided wrapper to rebuild targets automatically instead of launching stale binaries.
- Validate changes with `swift build` and the relevant filtered test suites, documenting any compiler crashes and rewriting problematic constructs immediately so the suite can keep running.
- Keep concurrency annotations (`Sendable`, actors, structured tasks) accurate and prefer static imports over dynamic runtime lookups that break ahead-of-time compilation.
@@ -70,6 +81,7 @@ Usage: In repo copies, the shared content lives inside `…` an
- When encountering toolchain instability, capture the repro steps in the designated troubleshooting doc and note any required cache cleans (DerivedData, SwiftPM caches) you perform.
## TypeScript Projects
+
- Use the package manager declared by the workspace (often `pnpm` or `bun`) and run every command through the same wrapper humans use; do not substitute `npm`/`yarn` or bypass the runner.
- Start each session by running the repo’s doc-index script (commonly a `docs:list` helper), then keep required watchers (`lint:watch`, `test:watch`, dev servers) running inside tmux unless told otherwise.
- Treat `lint`, `typecheck`, and `test` commands (e.g., `pnpm run check`, `bun run typecheck`) as mandatory gates before handing off work; surface any failures with their exact command output.
@@ -101,7 +113,7 @@ Edit guidance: keep the actual tool list inside this `` block so
- `firecrawl`: MCP-powered site fetcher to Markdown; run `npx mcporter firecrawl`.
- `XcodeBuildMCP`: MCP wrapper around Xcode tooling; run `npx mcporter XcodeBuildMCP`.
- `gh`: GitHub CLI for PRs, CI logs, releases, repo queries; run `gh help`.
-
+
# Repo Notes
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e06fd6..4869ff9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,22 +3,27 @@
## [0.8.2] - Unreleased
### CLI
+
- Respect schema-declared string parameters when coercing numeric-looking `mcporter call` key=value arguments, so Slack timestamps like `thread_ts` stay strings. (PR #141, thanks @Hamzaa6296)
## [0.8.1] - 2026-03-29
### CLI
+
- Bun-compiled/Homebrew binaries now embed the package version before boot, so `mcporter --version` reports the real release (for example `0.8.1`) instead of falling back to `0.0.0-dev`.
### Tests
+
- Added regression coverage for the Bun compile wrapper so future release builds keep the embedded runtime version intact.
### Tooling / Dependencies
+
- npm publishes now use an explicit package allowlist, so local release tarballs/checksum files do not get bundled into the published package.
## [0.8.0] - 2026-03-29
### CLI
+
- Preserve OAuth flow vs post-auth transport failures so invalid OAuth/provider errors surface directly, while real legacy 404/405 transport mismatches still fall back to SSE correctly. (PR #97, thanks @mavam)
- Ignore static `Authorization` headers once OAuth is active so imported editor configs cannot override fresh OAuth tokens. (PR #123, thanks @ahonn)
- Keep `mcporter call --output json` parseable by emitting valid JSON even when the command falls back to raw output. (PR #128, thanks @armanddp)
@@ -39,31 +44,39 @@
- Added generated `mcporter.schema.json` plus `pnpm generate:schema` for IDE autocomplete/validation, including `$schema` and `oauthScope`/`oauth_scope` coverage. (PR #43, thanks @aryasaatvik)
### Tooling / Dependencies
+
- Updated dependencies to latest releases (including MCP SDK, Rolldown RC, Zod, Biome, Oxlint, Vitest, Bun types).
- Synced `biome.json` schema URL to Biome `2.4.5`.
## [0.7.3] - 2025-12-29
### CLI
+
- Fixed generated CLIs to read Commander.js option values via camelCased properties so snake_case tool schemas map correctly. (Thanks @rawwerks, PR #28)
- Coerce generated CLI array arguments based on JSON Schema item types (including integer arrays). (Thanks @rawwerks, PR #27)
- `mcporter generate-cli` supports `--include-tools` / `--exclude-tools` to generate CLIs for a subset of server tools. (Thanks @zackleman, PR #24)
### Tests
+
- Added regression coverage for typed array parsing in generated CLIs.
- - Added regression coverage for snake_case, camelCase, and numeric option names in generated CLIs.
- - Increased the Bun bundler integration-test timeout to reduce flakes on slower runners.
+- Added regression coverage for snake_case, camelCase, and numeric option names in generated CLIs.
+- Increased the Bun bundler integration-test timeout to reduce flakes on slower runners.
### Tooling / Dependencies
+
- Updated dependency set (SDK, Rolldown, Zod, Biome, Oxlint, Bun types).
- Synced the Biome schema URL to the current CLI version.
## [0.7.1] - 2025-12-08
+
### Daemon
+
- Track config file mtimes for every loaded layer (home + project or explicit) in daemon metadata and auto-restart when any layer changes, so newly added keep-alive servers are picked up without manual restarts. Includes regression tests for stale-daemon detection.
## [0.7.0] - 2025-12-06
+
### CLI
+
- Centralized OAuth credentials in a shared vault (`~/.mcporter/credentials.json`) while still honoring per-server `tokenCacheDir` when present; legacy per-server caches are migrated automatically.
- `mcporter auth --reset` now clears the vault and legacy caches without crashing on corrupted credential files, making re-auth reliable for servers like Gmail.
- StdIO servers that expose a separate auth subcommand (e.g., Gmail MCP) can now declare `oauthCommand.args`; `mcporter auth ` will spawn that helper and wait for browser completion, so Gmail auth now works without running npx manually.
@@ -71,68 +84,89 @@
- Added regression coverage to ensure future raw output changes cannot reintroduce truncation.
## [0.6.6] - 2025-11-28
+
### CLI
+
- Prevented ENOENT crashes when no config file exists anywhere by only passing an explicit `--config`/`MCPORTER_CONFIG` path to the runtime; implicit defaults now fall back cleanly across list/config/daemon flows.
## [0.6.5] - 2025-11-26
+
### CLI
+
- `mcporter call|auth|list help/--help` now print the command-specific usage text instead of attempting to run a server, matching the footer’s “mcporter --help” hint.
- Added a hidden `list-tools` alias for `mcporter list` to preserve older muscle memory and avoid “Unknown MCP server” errors when copied from legacy docs.
- Ad-hoc HTTP flows now accept `--insecure` as a hidden synonym for `--allow-http`, making plain-HTTP testing flags match common intuition. `--sse` also aliases `--http-url` to keep older examples working.
+
### Security / Dependencies
+
- Override transitive `body-parser` to 2.2.1 (CVE-2025-13466) via pnpm overrides.
## [0.6.4] - 2025-11-25
+
### CLI
+
- `mcporter list` now uses cached OAuth access tokens (if present) for the all-servers view without opening browser windows, so previously authorized servers no longer show spurious “auth required” in non-interactive listings.
- `pnpm test --filter ` now works by translating to a Vitest file pattern, avoiding the prior “Unknown option --filter” error.
## [0.6.3] - 2025-11-22
+
### Runtime & CLI
+
- Updated to `@modelcontextprotocol/sdk` 1.22.0; inline stdio test server now uses Zod schemas to remain compatible with the SDK’s JSON Schema conversion path.
### Runtime
+
- `listTools` now follows SDK pagination, looping through `nextCursor` so long catalogs return complete tool lists.
### Configuration
+
- Claude imports now preserve root-fallback parsing for legacy `.claude.json` and `.claude/mcp.json` files while treating `.claude/settings*.json` as container-only configs, preventing metadata fields like `statusLine` from being misdetected as MCP servers.
- Added regression coverage for Claude settings and mcp.json imports to guard the root-fallback behavior.
## [0.6.2] - 2025-11-18
### Runtime
+
- Propagate `--timeout` / `MCPORTER_CALL_TIMEOUT` into MCP tool calls (SDK `timeout`, `resetTimeoutOnProgress`, `maxTotalTimeout`) so long-running requests are no longer capped by the SDK’s 60s default.
### CLI
+
- `mcporter generate-cli` once again treats single-token `--command` values (e.g., `./scripts/server.ts`) as STDIO transports instead of trying to coerce them into HTTP URLs, restoring the pre-0.6.1 behavior for ad-hoc scripts.
- Global flag parsing moved into `cli-factory` for consistent log-level/oauth-timeout handling across commands.
- `daemon` host/client hardened and covered with new tests; idle eviction and restart paths verified.
### Configuration
+
- Reintroduced support for `OPENCODE_CONFIG_DIR` so OpenCode imports continue to honor the documented directory override alongside `OPENCODE_CONFIG`.
- Platform-aware defaults for Cursor/Claude/Windsurf/VS Code/OpenCode configs now dedupe paths and include Windows-specific locations.
### Platform resilience (Windows/WSL)
+
- Added `fs-helpers` that treat chmod/copy failures on NTFS/DrvFs as best-effort so CLI generation keeps working on WSL mounts.
- Documented Windows/WSL workflows: install/test from ext4 copies, remount guidance for /mnt/c, and syncing tips.
### StdIO MCP coverage
+
- Added stdio e2e tests using in-repo filesystem & memory MCP fixtures to ensure list/call works via execPath.
### Content extraction
+
- `createCallResult` now reads nested `raw.content`/`raw.structuredContent` so tools that wrap responses render text/markdown/json correctly; new unit tests cover text joining, markdown, and JSON.
## [0.6.1] - 2025-11-17
### CLI
+
- `mcporter list --verbose` now surfaces every config path that registers the target server (primary first, then duplicates) in both text and JSON output, making it easier to trace where a name is coming from.
- JSON list payloads include a new `sources` array when `--verbose` is set, mirroring the on-screen path list for programmatic consumers.
- Verbose source listings now tag the import kind (cursor/vscode/codex, etc.) and explicitly label the primary entry vs. shadowed duplicates.
### Runtime
+
## [0.6.0] - 2025-11-16
### Configuration
+
- Default config resolution now layers the system config (`~/.mcporter/mcporter.json[c]`) before the project config (`config/mcporter.json`), so globally installed MCP servers remain available inside repos while allowing per-project overrides.
- `--config` and `MCPORTER_CONFIG` continue to select a single file without merging for explicit workflows.
- `mcporter config add --scope home|project` lets you choose the write target explicitly (project remains the default; `--persist ` still wins when provided).
@@ -140,16 +174,19 @@
## [0.5.11] - 2025-11-16
### Code generation & metadata
+
- Quick start examples in generated CLIs now derive from actual embedded tools (up to three), showing real command names/flags instead of generic placeholders.
## [0.5.10] - 2025-11-16
### Code generation & metadata
+
- Generated CLIs now present the canonical kebab-cased tool names in help while accepting underscore aliases at runtime, eliminating the “unknown command” errors when copying names directly from server tool lists.
## [0.5.9] - 2025-11-15
### CLI
+
- `mcporter list` suppresses raw STDIO stderr dumps when enumerating all configured servers, keeping the summary output readable while still surfacing per-server health statuses.
- `mcporter config --help` (and `mcporter config help `) now display detailed usage, flags, and examples for every config subcommand instead of returning a placeholder message. Inline `--help` tokens are intercepted before executing the command, so flows like `mcporter config add --help` no longer throw usage errors.
- `mcporter config doctor` prints the project and system config paths before reporting diagnostics, making it obvious which files were inspected when tracking down configuration issues.
@@ -157,17 +194,20 @@
## [0.5.8] - 2025-11-15
### CLI & runtime
+
- STDIO transports now interpolate `${VAR}`/`$env:VAR` tokens in the configured command and arguments before spawning child processes, so chrome-devtools inherits the live `CHROME_DEVTOOLS_URL` value instead of receiving the literal placeholder.
- Keep-alive detection skips any STDIO server whose command/args reference `CHROME_DEVTOOLS_URL`, ensuring daemon mode relaunches chrome-devtools for each Oracle browser session instead of pinning a stale port.
- Command arguments that escape placeholders as `\${VAR}` (common when using `String.raw` in TypeScript config helpers) now trim the backslash after interpolation so downstream servers receive clean URLs.
### CLI
+
- Ad-hoc STDIO invocations that start with `npx -y ` now infer the npm package name (stripping versions and ignoring arguments after `--`) instead of producing slugs like `npx-y`, so repeated `mcporter list|call` runs automatically reuse a readable server key without passing `--name`.
- Quoted inline commands such as `mcporter list "npx -y xcodebuildmcp"` now auto-detect the ad-hoc STDIO transport, so you can skip `--stdio` entirely when probing MCP packages via `npx`.
## [0.5.7] - 2025-11-14
### CLI
+
- Added `mcporter daemon restart`, a stop+start convenience that reuses logging flags so agents can bounce the keep-alive daemon with a single command.
- Added `list_tools` as a hidden shortcut for `mcporter list `, so `chrome-devtools.list_tools` (and similar selectors) print the tool catalog instantly without requiring a real MCP tool.
- Warn when colon-style arguments omit a value (e.g., `command:`) and suggest quoting/`--args` JSON so agents don’t accidentally send `undefined` to STDIO servers.
@@ -175,53 +215,63 @@
## [0.5.6] - 2025-11-11
### CLI & runtime
+
- Reset cached keep-alive connections whenever STDIO transports hit fatal errors (timeouts, closed pipes, daemon restarts, etc.), so chrome-devtools automatically recovers after you close Chrome instead of requiring `mcporter daemon stop`.
- Daemon-routed calls now log a restart notice and automatically retry once after closing the stale transport, providing self-healing behavior when Chrome or other keep-alive servers crash mid-call.
## [0.5.5] - 2025-11-11
### CLI & runtime
+
- Added hidden agent shortcuts: `mcporter describe ` now aliases `mcporter list`, and calling `.help` automatically falls back to the list output when a server lacks a `help` tool (also wired into the legacy `pnpm mcp call` path) so agents always get a readable summary.
## [0.5.4] - 2025-11-10
### CLI & runtime
+
- Propagate the CLI’s per-call timeout (defaults to 60s or `--timeout`) through the keep-alive daemon, so chrome-devtools and other persistent STDIO servers stop as soon as the caller times out.
- `Runtime.callTool` now honors `timeoutMs` directly, ensuring TanStack MCP clients and the CLI share a single source of truth for cancellation even outside the daemon.
- Ad-hoc STDIO servers launched via `mcporter call "npx …"` (or `--stdio`) inherit the same keep-alive heuristics and canonical names as config-defined entries, so `MCPORTER_DISABLE_KEEPALIVE=chrome-devtools` and similar overrides work without passing `--name`.
### Tests
+
- Added regression coverage (`tests/daemon-client-timeout.test.ts`, `tests/runtime-call-timeout.test.ts`, and updated keep-alive suites) to guard timeout propagation and canonical keep-alive detection.
## [0.5.3] - 2025-11-10
### CLI & runtime
+
- Fixed Claude imports so `mcporter list` merges project-scoped servers from `.claude.json` (matching the current workspace) and ignores metadata-only keys like `tipsHistory`/`cachedStatsigGates`, resolving GitHub issues #6 and #7.
- OpenCode imports now read only the documented `mcp` container (no root-level fallback), matching the current OpenCode schema and preventing stray metadata from being misinterpreted as servers.
## [0.5.2] - 2025-11-10
### CLI & runtime
+
- `mcporter call "" ...` now auto-detects ad-hoc STDIO servers, so you can skip `--stdio/--stdio-arg` entirely and just quote the command you want to run.
- When a server exposes exactly one tool, `mcporter call` infers it automatically (and prints a dim log), letting one-tool servers like Vercel Domains run with only their arguments.
- STDIO transports now inherit your current shell environment by default, so ad-hoc commands see the same variables as your terminal; keep `--env KEY=value` for explicit overrides.
### Fixes
+
- `mcporter config list` and `mcporter config doctor` no longer crash when the project config is missing or contains malformed JSON; we log a single warning and keep going, matching the behavior of the top-level `mcporter list`.
## [0.5.1] - 2025-11-10
### CLI & runtime
+
- Added a per-login daemon that auto-starts when keep-alive MCP servers (e.g., Chrome DevTools, Mobile MCP, Playwright) are invoked. The daemon keeps STDIO transports alive across agents, exposes `mcporter daemon `, and supports idle shutdown plus manual restarts.
- Keep-alive detection now honors the `lifecycle` config flag/env overrides and also inspects STDIO command signatures, so renaming `chrome-devtools` (or other stateful servers) no longer disables the daemon accidentally.
- Introduced daemon logging controls (`mcporter daemon start --log|--log-file`, `--log-servers`, `MCPORTER_DAEMON_LOG*` env vars, and per-server `logging.daemon.enabled`). `mcporter daemon status` reports the active log path, and a new `tests/daemon.integration.test.ts` suite keeps the end-to-end flow covered.
### Fixes
+
- `mcporter list` (and every CLI entry point) once again treats missing project configs as empty instead of throwing ENOENT, matching the 0.4.x behavior when you run the CLI outside a repo.
## [0.5.0] - 2025-11-10
### CLI & runtime
+
- **Daemonized keep-alive servers.** A new per-login daemon automatically spins up whenever keep-alive MCP servers (Chrome DevTools, Mobile MCP, Playwright, etc.) are invoked. It keeps STDIO transports warm across agents, exposes `mcporter daemon `, supports idle shutdowns/manual restarts, and respects the `lifecycle` config flag plus STDIO command metadata so renamed servers stay eligible.
- Fixed `createKeepAliveRuntime` so the daemon wrapper’s `listTools` implementation matches the base `Runtime` signature; `pnpm build` (and any command that shells out to `pnpm build`) succeeds again.
- Cursor imports now cover both workspace and user `.cursor/mcp.json` files plus the platform-specific `Cursor/User/mcp.json` directories, and the VS Code/Windsurf walkers dedupe paths so editor-managed MCP servers are auto-discovered consistently across macOS, Linux, and Windows.
@@ -230,63 +280,76 @@
## [0.4.5] - 2025-11-10
### CLI & runtime
+
- Fixed the npm `bin` entry so it points to `dist/cli.js` without a leading `./`, keeping the executable in the published tarball and restoring `npx mcporter` functionality. Also bumped the embedded runtime version to 0.4.4 so the CLI reports the correct release.
- Added `MCPORTER_CONFIG` plus a home-directory fallback (`~/.mcporter/mcporter.json[c]`) so the CLI automatically finds your system-wide config when a project file is missing.
### Docs
+
- Consolidated the external MCP import matrix into `docs/import.md`, removing the short-lived `docs/mcp-import.md` duplication, and clarified the release checklist to stop immediately on failing tests or lint warnings.
## [0.4.3] - 2025-11-10
### CLI & runtime
+
- Added OpenCode imports (project `opencode.json[c]`, `OPENCODE_CONFIG_DIR`, user config, and the `OPENCODE_CONFIG` override) plus JSONC parsing so `mcporter list/config` can auto-discover servers defined in OpenCode.
- Claude Code imports now honor `.claude/settings.local.json` and `.claude/settings.json` ahead of the legacy `mcp.json`, and we skip entries that lack a URL/command (e.g., permissions blocks) so malformed settings no longer break the merge.
### Docs
+
- Documented the full import matrix (including OpenCode + Claude settings hierarchy) directly in `docs/import.md` and `docs/config.md`.
## [0.4.2] - 2025-11-09
### CLI & runtime
+
- `mcporter list` (and other commands that load imports) now skip empty or malformed Claude Desktop / Cursor / Codex config files instead of throwing, so a blank `claude_desktop_config.json` no longer blocks the rest of the imports.
- Bundled sample config adds the Mobile Next MCP definition, making it available out of the box when you run `mcporter list` before customizing your own config.
## [0.4.1] - 2025-11-08
### CLI & runtime
+
- Fixed the fallback when `config/mcporter.json` is missing so `mcporter list` continues to import Cursor/Claude/Codex/etc. configs even when you run the CLI outside a repo that defines its own config, matching the 0.3.x behavior.
- Added regression coverage that exercises the “no config file” path to ensure future changes keep importing user-level MCP servers.
## [0.4.0] - 2025-11-08
### CLI & runtime
+
- `mcporter config list` now displays only local entries by default, appends a color-aware summary of every imported config (path, counts, sample names), and still lets you pass `--source import`/`--json` for the merged view.
- `mcporter config get`, `remove`, and `logout` now use the same fuzzy matching/suggestion logic as `mcporter list`/`call`, auto-correcting near-miss names and emitting “Did you mean …?” hints when ambiguity remains.
## [0.3.6] - 2025-11-08
### CLI & runtime
+
- `mcporter list` now prints copy/pasteable examples for ad-hoc servers by repeating the HTTP URL (with quoting) so the commands shown under `Examples:` actually work before you persist the definition.
### Code generation
+
- Staged the actual dependency directories (`commander`, `mcporter`) directly into the Bun bundler workspace so `npx mcporter generate-cli "npx -y chrome-devtools-mcp" --compile` succeeds even when npm hoists dependencies outside the package (fixes the regression some users still saw with 0.3.5).
## [0.3.5] - 2025-11-08
### Code generation
+
- Ensure the Bun bundler resolves `commander`/`mcporter` even when `npx mcporter generate-cli … --compile` runs inside an empty temp directory by symlinking mcporter’s own `node_modules` into the staging workspace before invoking `bun build`. This keeps the “one weird trick” workflow working post-0.3.4 without requiring extra installs.
## [0.3.4] - 2025-11-08
### CLI & runtime
+
- Added a global `--oauth-timeout ` flag (and the matching `MCPORTER_OAUTH_TIMEOUT_MS` override) so long-running OAuth handshakes can be shortened during debugging; the runtime now logs a clear warning and tears down the flow once the limit is reached, ensuring `mcporter list/call/auth` always exit.
### Docs
+
- Documented the new OAuth timeout flag/env var across the README and tmux/hang-debug guides so release checklists and manual repro steps call out the faster escape hatch.
## [0.3.3] - 2025-11-07
### Code generation
+
- When a server definition omits `description`, `mcporter generate-cli` now asks the MCP server for its own `instructions`/`serverInfo.title` during tool discovery and embeds that value, so generated CLIs introduce themselves with the real server description instead of the generic “Standalone CLI…” fallback.
- Embedded tool listings inside generated CLIs now show each command’s flag signature (no `usage:` prefix) separated by blank lines, and per-command `--help` output inherits the same colorized usage/option styling as the main `mcporter` binary for readability on rich TTYs.
- Added a `--bundler rolldown|bun` flag to `mcporter generate-cli`, defaulting to Rolldown but allowing Bun’s bundler (when paired with `--runtime bun`) for teams that want to stay entirely inside the Bun toolchain. The generator now records the chosen bundler in artifact metadata and enforces the Bun-only constraint so reproduction via `--from` stays deterministic.
@@ -296,50 +359,58 @@
## [0.3.2] - 2025-11-07
### CLI
+
- Embedded the CLI version so Homebrew/Bun builds respond to `mcporter --version` even when `package.json` is unavailable.
- Revamped `mcporter --help` to mirror the richer list/call formatting (name + summary rows, grouped sections, quick-start examples, and ANSI colors when TTYs are detected).
- Fixed `mcporter list` so it no longer errors when `config/mcporter.json` is absent—fresh installs now run without creating config files, and a regression test guards the optional-config flow.
- Generated standalone CLIs now print the full help menu (same grouped layout as the main CLI) when invoked without arguments, matching the behavior of `mcporter` itself.
### Code generation
+
- Generated binaries now default to the current working directory (using the inferred server name) when `--compile` is provided without a path, and automatically append a numeric suffix when the target already exists.
- Standalone CLIs inherit the improved help layout (color-aware title, grouped command summaries, embedded tool listings, and quick-start snippets) so generated artifacts read the same way as the main CLI.
- Swapped the bundler from esbuild to Rolldown for both JS and Bun targets, removing the fragile per-architecture esbuild binaries while keeping aliasing for local dependencies and honoring `--minify` via Rolldown’s native minifier.
- Improved `generate-cli` so inline stdio commands (e.g., `"npx chrome-devtools-mcp"`) parse correctly even when invoked from empty directories.
### Code generation
+
- `readPackageMetadata()` now tolerates missing `package.json` files; when invoked from a directory without a manifest it falls back to mcporter’s own version string, so `generate-cli` works even when you call it via `npx` in an empty folder.
## [0.3.1] - 2025-11-07
### CLI & runtime
+
- Short-circuited global `--help` / `--version` handling so these flags no longer fall through command inference and always print immediately, regardless of which command the user typed first.
- Added regression coverage for the new shortcuts and kept the existing `runCli` helper exported so tests (and downstream tools) can exercise argument parsing without forking the entire process.
### Code generation & metadata
+
- Fixed `mcporter generate-cli --bundle/--compile` in empty directories by aliasing `commander`/`mcporter` imports to the CLI’s own installation so esbuild always resolves dependencies. Verified with a new fixture that bundles from temp dirs without `node_modules` (fixes #1).
- Added an end-to-end integration test that runs `node dist/cli.js generate-cli` twice—once for bundling and once for `--compile`—as well as a GitHub Actions step that installs Bun so CI exercises the compiled binary path on every PR.
-
## [0.3.0] - 2025-11-06
### CLI & runtime
+
- Added configurable log levels (`--log-level` / `MCPORTER_LOG_LEVEL`) that default to `warn`, promoting noisy transport fallbacks to warnings so critical issues still surface.
- Forced the CLI to exit cleanly after shutdown (opt out with `MCPORTER_NO_FORCE_EXIT`) and patched `StdioClientTransport` so stdio MCP servers no longer leave Node handles hanging; stderr from stdio servers is buffered and replayed via `MCPORTER_STDIO_LOGS=1` or whenever a server exits with a non-zero status.
### Discovery, calling, and ad-hoc workflows
+
- Rebuilt `mcporter list`: spinner updates stream live, summaries print only after discovery completes, and single-server views now render TypeScript-style doc blocks, inline examples, inferred return hints, and compact `// optional (N): …` summaries. The CLI guarantees at least five parameters before truncating, introduced a single `--all-parameters` switch (replacing the `--required-only` / `--include-optional` pair), and shares its formatter with `mcporter generate-cli` so signatures are consistent everywhere.
- Verb inference and parser upgrades let bare server names dispatch to `list`, dotted invocations jump straight to `call`, colon-delimited flags (`key:value` / `key: value`) sit alongside `key=value`, and the JavaScript-like call syntax now supports unlabeled positional arguments plus typo correction heuristics when tool names are close but not exact.
- Ad-hoc workflows are significantly safer: `--http-url` / `--stdio` definitions (with `--env`, `--cwd`, `--name`, `--persist`) work across `list`, `call`, and `auth`, mcporter reuses existing config entries when a URL matches (preserving OAuth tokens / redirect URIs), and `mcporter auth ` piggybacks on the same resolver to persist entries or retry when a server flips modes mid-flight.
- Hardened OAuth detection automatically promotes ad-hoc HTTP servers that return 401/403 to `auth: "oauth"`, broadens the unauthorized heuristic for Supabase/Vercel/GitHub-style responses, and performs a one-time retry whenever a server switches into OAuth mode while you are connecting.
### Code generation & metadata
+
- Generated CLIs now embed their metadata (generator version, resolved server definition, invocation flags) behind a hidden `__mcporter_inspect` command. `mcporter inspect-cli` / `mcporter generate-cli --from ` read directly from the artifact, while legacy `.metadata.json` sidecars remain as a fallback for older binaries.
- Shared the TypeScript signature formatter between `mcporter list` and `mcporter generate-cli`, ensuring command summaries, CLI hints, and generator help stay pixel-perfect and are backed by new snapshot/unit tests.
- Introduced `mcporter emit-ts`, a codegen command that emits `.d.ts` tool interfaces or ready-to-run client wrappers (`--mode types|client`, `--include-optional`) using the same doc/comment data that powers the CLI, so agents/tests can consume MCP servers with strong TypeScript types.
- `mcporter generate-cli` now accepts inline stdio commands via `--command "npx -y package@latest"` or by quoting the command as the first positional argument, automatically splits the command/args, infers a friendly name from scripts or package scopes, and documents the chrome-devtools one-liner in the README; additional unit tests cover HTTP, stdio, scoped package, and positional shorthand flows.
### Documentation & references
+
- Added `docs/tool-calling.md`, `docs/call-syntax.md`, and `docs/call-heuristic.md` to capture every invocation style (flags, function expressions, inferred verbs) plus the typo-correction rules.
- Expanded the ad-hoc/OAuth story across `README.md`, `docs/adhoc.md`, `docs/local.md`, `docs/known-issues.md`, and `docs/supabase-auth-issue.md`, detailing when servers auto-promote to OAuth, how retries behave, and how to persist generated definitions safely.
- Updated the README, CLI reference, and generator docs to cover the new `--all-parameters` flag, list formatter, metadata embedding, the `mcporter emit-ts` workflow, and refreshed branding so the CLI and docs consistently introduce the project as **MCPorter**.
@@ -365,22 +436,28 @@
## [0.1.0]
- Initial release.
+
## [0.6.2] - 2025-11-18
### Platform resilience (Windows/WSL)
+
- Added `fs-helpers` that treat chmod/copy failures on NTFS/DrvFs as best-effort so CLI generation keeps working on WSL mounts.
- Documented Windows/WSL workflows: install/test from ext4 copies, remount guidance for /mnt/c, and syncing tips.
### CLI/runtime
+
- Global flag parsing moved into `cli-factory` for consistent log-level/oauth-timeout handling across commands.
- `daemon` host/client hardened and covered with new tests; idle eviction and restart paths verified.
- Imports now include platform-aware defaults for Cursor/Claude/Windsurf/VS Code/OpenCode configs with path dedupe.
### StdIO MCP coverage
+
- Added stdio e2e tests using in-repo filesystem & memory MCP fixtures to ensure list/call works via execPath.
### Content extraction
+
- `createCallResult` now reads nested `raw.content`/`raw.structuredContent` so tools that wrap responses render text/markdown/json correctly; new unit tests cover text joining, markdown, and JSON.
### Docs
+
- New `docs/windows.md` with WSL/NTFS tips; added to docs index.
diff --git a/config/mcporter.json b/config/mcporter.json
index 7272fc3..77971a6 100644
--- a/config/mcporter.json
+++ b/config/mcporter.json
@@ -3,10 +3,7 @@
"chrome-devtools": {
"description": "Chrome DevTools protocol bridge for driving local tabs during debugging or automation.",
"command": "npx",
- "args": [
- "-y",
- "chrome-devtools-mcp@latest"
- ],
+ "args": ["-y", "chrome-devtools-mcp@latest"],
"env": {
"npm_config_loglevel": "error"
}
@@ -14,10 +11,7 @@
"mobile-mcp": {
"description": "Mobile Next MCP server for automating iOS/Android simulators and devices.",
"command": "npx",
- "args": [
- "-y",
- "@mobilenext/mobile-mcp@latest"
- ],
+ "args": ["-y", "@mobilenext/mobile-mcp@latest"],
"env": {
"npm_config_loglevel": "error"
}
@@ -47,10 +41,7 @@
"obsidian": {
"description": "Local Obsidian vault access via obsidian-mcp-server.",
"command": "npx",
- "args": [
- "-y",
- "obsidian-mcp-server@latest"
- ],
+ "args": ["-y", "obsidian-mcp-server@latest"],
"env": {
"OBSIDIAN_API_KEY": "${OBSIDIAN_API_KEY}",
"OBSIDIAN_BASE_URL": "${OBSIDIAN_BASE_URL:-https://127.0.0.1:27124}",
@@ -84,10 +75,7 @@
"signoz": {
"description": "SigNoz Query MCP server (logs, traces, metrics).",
"command": "npx",
- "args": [
- "-y",
- "signoz-mcp-server@latest"
- ],
+ "args": ["-y", "signoz-mcp-server@latest"],
"env": {
"SIGNOZ_URL": "${SIGNOZ_URL:-http://localhost:3301}",
"SIGNOZ_TOKEN": "${SIGNOZ_TOKEN:-}",
@@ -102,13 +90,7 @@
"iterm": {
"description": "iTerm2 terminal bridge via local iterm-mcp",
"command": "pnpm",
- "args": [
- "--dir",
- "/Users/steipete/Projects/iterm-mcp",
- "exec",
- "node",
- "build/index.js"
- ],
+ "args": ["--dir", "/Users/steipete/Projects/iterm-mcp", "exec", "node", "build/index.js"],
"env": {
"npm_config_loglevel": "error"
}
@@ -116,19 +98,11 @@
"XcodeBuildMCP": {
"description": "XcodeBuild MCP server for building, testing, and inspecting Xcode projects and simulators.",
"command": "npx",
- "args": [
- "-y",
- "xcodebuildmcp@latest"
- ],
+ "args": ["-y", "xcodebuildmcp@latest"],
"env": {
"npm_config_loglevel": "error"
}
}
},
- "imports": [
- "cursor",
- "claude-code",
- "claude-desktop",
- "codex"
- ]
+ "imports": ["cursor", "claude-code", "claude-desktop", "codex"]
}
diff --git a/docs/adhoc.md b/docs/adhoc.md
index c04d0f9..e1050f0 100644
--- a/docs/adhoc.md
+++ b/docs/adhoc.md
@@ -16,6 +16,7 @@ Two new flag sets let you describe a server on the command line:
- `mcporter call --stdio "bun run ./server.ts" --name local-tools`
You can also pass a bare URL as the selector (`mcporter list https://mcp.linear.app/mcp`) or embed the URL in a `call` expression (`mcporter call 'https://mcp.example.com/tools.generate({ topic: "release" })'`).
+
- Add `--json` to `mcporter list …` when you need a machine-readable summary of status counts and per-server failures, use `--output json`/`--output raw` with `mcporter call` to receive structured `{ server, tool, issue }` envelopes whenever a transport error occurs, and run `mcporter auth … --json` to capture the same envelope if OAuth or transport setup fails.
### Example: HTTP ad-hoc workflow
diff --git a/docs/call-heuristic.md b/docs/call-heuristic.md
index 759a42d..98b3286 100644
--- a/docs/call-heuristic.md
+++ b/docs/call-heuristic.md
@@ -6,19 +6,22 @@ read_when:
# Call Command Auto-Correction
-`mcporter call` aims to help when a tool name is *almost* correct without hiding real mistakes.
+`mcporter call` aims to help when a tool name is _almost_ correct without hiding real mistakes.
## Confident Matches → Auto-Correct
+
- We normalise tool names (strip punctuation, lowercase) and compute a Levenshtein distance.
- If the distance is ≤ `max(2, floor(length × 0.3))`, or the names only differ by case/punctuation, we retry automatically.
- A dim informational line explains the correction: `[mcporter] Auto-corrected tool call to linear.list_issues (input: linear.listIssues).`
## Low-Confidence Matches → Suggest
+
- When the best candidate falls outside the threshold we keep the original failure.
- We still print a hint so the user learns the canonical name: `[mcporter] Did you mean linear.list_issue_statuses?`
- No second call is attempted in this case.
## Edge Cases
+
- We only inspect the tool catalog if the server explicitly replied with “Tool … not found”. Other MCP errors surface untouched.
- If listing tools itself fails (auth, offline, etc.) we skip both auto-correct and hints.
- Behaviour is covered by `tests/cli-call.test.ts`.
diff --git a/docs/call-syntax.md b/docs/call-syntax.md
index 6e3dfee..734f21d 100644
--- a/docs/call-syntax.md
+++ b/docs/call-syntax.md
@@ -8,11 +8,11 @@ read_when:
`mcporter call` now understands two complementary styles:
-| Style | Example | Notes |
-|-------|---------|-------|
-| Flag-based (compatible) | `mcporter call linear.create_comment --issue-id LNR-123 --body "Hi"` | Use `key=value`, `key:value`, or `key: value` pairs—ideal for shell scripts. |
-| Function-call (expressive) | `mcporter call 'linear.create_comment(issueId: "LNR-123", body: "Hi")'` | Mirrors the pseudo-TypeScript signature shown by `mcporter list`; unlabeled values map to schema order. |
-| Structured output | `mcporter call 'linear.create_comment(...)' --output json` | Successful calls emit JSON bodies; failures emit `{ server, tool, issue }` envelopes so automation can react to auth/offline/http errors. |
+| Style | Example | Notes |
+| -------------------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
+| Flag-based (compatible) | `mcporter call linear.create_comment --issue-id LNR-123 --body "Hi"` | Use `key=value`, `key:value`, or `key: value` pairs—ideal for shell scripts. |
+| Function-call (expressive) | `mcporter call 'linear.create_comment(issueId: "LNR-123", body: "Hi")'` | Mirrors the pseudo-TypeScript signature shown by `mcporter list`; unlabeled values map to schema order. |
+| Structured output | `mcporter call 'linear.create_comment(...)' --output json` | Successful calls emit JSON bodies; failures emit `{ server, tool, issue }` envelopes so automation can react to auth/offline/http errors. |
Both forms share the same validation pipeline, so required parameters, enums, and formats behave identically.
diff --git a/docs/cli-generator.md b/docs/cli-generator.md
index e0db864..ad963d8 100644
--- a/docs/cli-generator.md
+++ b/docs/cli-generator.md
@@ -9,9 +9,11 @@ read_when:
Default behavior: generating `.ts` in the working directory if no output path is provided. Bundling is opt-in via `--bundle` and produces a single JS file with shebang; otherwise we emit TypeScript targeting Node.js. Rolldown handles bundling by default unless the runtime resolves to Bun—in that case Bun’s native bundler is selected automatically (still requires `--runtime bun` or Bun auto-detection); `--bundler` lets you override either choice.
## Goal
+
Create an `mcporter generate-cli` command that produces a standalone CLI for a single MCP server. The generated CLI should feel like a Unix tool: subcommands map to MCP tools, arguments translate to schema fields, and output can be piped/redirected easily.
## High-Level Requirements
+
- **Input**: Identify the target server either by shorthand name or by providing an explicit MCP server definition.
- **Output**: Emit a TypeScript file (ESM) targeting Node.js by default (`.ts` unless `--output` overrides). Bundling to a standalone JS file happens only when `--bundle` is passed.
- **Runtime Selection**: Prefer Bun when it is available (`bun --version` succeeds); otherwise fall back to Node.js. Callers can force either runtime via `--runtime bun|node`.
@@ -21,6 +23,7 @@ Create an `mcporter generate-cli` command that produces a standalone CLI for a s
- **Documentation**: Update README (or similar) to show how to generate and use the CLI.
## Steps
+
1. **Command Scaffolding**
- Add `generate-cli` subcommand to the existing CLI.
- Parse flags: `--server`, `--name`, `--command`, optional `--description`, plus `--output`, `--runtime=node|bun`, `--bundle`, `--bundler=rolldown|bun`, `--minify`, `--compile`, `--include-tools`, `--exclude-tools`, etc. Runtime auto-detects Bun when available, and the bundler inherits that choice unless overridden.
@@ -53,6 +56,7 @@ Create an `mcporter generate-cli` command that produces a standalone CLI for a s
- Provide an example generated CLI under `examples/generated/.ts` (if we keep an examples directory).
## Notes
+
- Generated CLI depends on the latest `commander` for argument parsing.
- Default timeout for tool calls is 30 seconds, overridable via `--timeout`.
- Runtime flag remains (`--runtime bun`) to tailor shebang/usage instructions, but Node.js is the default.
@@ -94,8 +98,6 @@ npx mcporter generate-cli --command "npx -y chrome-devtools-mcp@latest"
`npx mcporter generate-cli linear --exclude-tools debug_tool,admin_reset`.
```
-
-
## Artifact Metadata & Regeneration
- Every generated artifact embeds its metadata (generator version, resolved server definition, invocation flags). A hidden `__mcporter_inspect` subcommand prints the payload without contacting the MCP server, so binaries remain self-describing even after being copied to another machine.
@@ -103,14 +105,14 @@ npx mcporter generate-cli --command "npx -y chrome-devtools-mcp@latest"
- `mcporter generate-cli --from ` replays the stored invocation against the latest mcporter build. `--server`, `--runtime`, `--timeout`, `--minify/--no-minify`, `--bundle`, `--compile`, `--output`, and `--dry-run` let you override specific pieces of the stored metadata when necessary.
- Because the metadata lives inside the artifact, any template, bundle, or compiled binary can be refreshed after a generator upgrade without juggling sidecar files.
-
-
## Status
+
- ✅ `generate-cli` subcommand implemented with schema-aware proxy generation.
- ✅ Inline JSON / file / shorthand server resolution wired up.
- ✅ Bundling via Rolldown by default (or Bun automatically when the runtime is Bun, with `--bundler` available for overrides) plus optional minification and Bun bytecode compilation.
- ✅ Integration tests cover bundling, minification, compiled binaries, and metadata/regeneration flows against the mock MCP server.
Next steps:
+
1. Add optional shell completion scaffolding if demand arises.
2. Explore templated TypeScript definitions for generated CLIs to improve editor tooling.
diff --git a/docs/cli-reference.md b/docs/cli-reference.md
index 3384ec4..ff8cbc3 100644
--- a/docs/cli-reference.md
+++ b/docs/cli-reference.md
@@ -10,6 +10,7 @@ A quick reference for the primary `mcporter` subcommands. Each command inherits
`--config ` and `--root ` to override where servers are loaded from.
## `mcporter list [server]`
+
- Without arguments, lists every configured server (with live discovery + brief
status).
- With a server name, prints TypeScript-style signatures for each tool, doc
@@ -22,6 +23,7 @@ A quick reference for the primary `mcporter` subcommands. Each command inherits
- `--timeout ` – per-server timeout when enumerating all servers.
## `mcporter call `
+
- Invokes a tool once and prints the response; supports positional arguments via
pseudo-TS syntax and `--arg` flags.
- Useful flags:
@@ -35,6 +37,7 @@ A quick reference for the primary `mcporter` subcommands. Each command inherits
- `--tail-log` – stream tail output when the tool returns log handles.
## `mcporter generate-cli`
+
- Produces a standalone CLI for a single MCP server (optionally bundling or
compiling with Bun).
- Key flags:
@@ -58,6 +61,7 @@ A quick reference for the primary `mcporter` subcommands. Each command inherits
treats the URL as an ad-hoc server definition.
## `mcporter emit-ts `
+
- Emits TypeScript definitions (and optionally a ready-to-use client) describing
a server’s tools. This reuses the same formatter as `mcporter list` so doc
comments, signatures, and examples stay in sync.
diff --git a/docs/config.md b/docs/config.md
index ddc22a6..faf354d 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -5,6 +5,7 @@ read_when:
---
# CLI Help Menu Snapshot
+
```
mcporter config
Usage: mcporter config [options]
@@ -35,9 +36,11 @@ See https://github.com/sweetistics/mcporter/blob/main/docs/config.md for config
# Configuration Guide
## Overview
+
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.
## Quick Start
+
1. Create `config/mcporter.json` at the repo root:
```jsonc
{
@@ -46,10 +49,10 @@ mcporter keeps three configuration buckets in sync: repository-scoped JSON (`con
"linear": {
"description": "Linear issues",
"baseUrl": "https://mcp.linear.app/mcp",
- "headers": { "Authorization": "Bearer ${LINEAR_API_KEY}" }
- }
+ "headers": { "Authorization": "Bearer ${LINEAR_API_KEY}" },
+ },
},
- "imports": ["cursor", "claude-code", "claude-desktop", "codex", "windsurf", "opencode", "vscode"]
+ "imports": ["cursor", "claude-code", "claude-desktop", "codex", "windsurf", "opencode", "vscode"],
}
```
The `$schema` property enables IDE autocomplete and validation. Use the raw GitHub URL for the latest schema, or copy `mcporter.schema.json` locally.
@@ -66,41 +69,47 @@ mcporter now merges home and project config files by default so global servers s
3. Otherwise, mcporter loads both of these layers (when present):
- `~/.mcporter/mcporter.json` or `~/.mcporter/mcporter.jsonc`
- `/config/mcporter.json`
- Entries from the project file override entries with the same name from the home file. Each layer still pulls in its own imports before merging.
+ Entries 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 (`/config/mcporter.json`). To edit the home file explicitly, run commands like `mcporter config --config ~/.mcporter/mcporter.json add …` or set `MCPORTER_CONFIG` in your shell profile.
## Discovery & Precedence
+
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 `/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. |
+| 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 `/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 ` can show you the path before you edit or remove the local copy with `mcporter config remove `.
- Imports remain read-only until you explicitly copy an entry via `mcporter config import --copy` or run `mcporter config add --copy-from claude-code:linear` (feature planned alongside the CLI work).
## CLI Workflows
+
`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 ` still takes precedence when you need a custom file.
### `mcporter config list [filter]`
+
- Shows **local** entries by default. Pass `--source import` to list imported editor configs, or `--json` for machine output.
- Always appends a summary of other config files (paths, counts, sample names) so you know where imported entries live.
- `filter` accepts a name, glob fragment, or `source:cursor` selector.
- Adds informational notes when we auto-correct names (same machinery as `mcporter list`).
### `mcporter config get `
+
- 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.
### `mcporter config add [target]`
+
- 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`
- `--url` or `--command`/`--stdio`
@@ -109,9 +118,11 @@ Use `--scope home|project` with `mcporter config add` to pick the write target e
- `--dry-run` shows the JSON diff without writing, while `--persist ` overrides the destination file.
### `mcporter config remove `
+
- Removes the local definition. Names sourced exclusively from imports remain untouched until you copy them locally.
### `mcporter config import `
+
- Displays (and optionally copies) entries from editor-specific configs:
- `cursor`: `.cursor/mcp.json` in the repo, falling back to `~/.config/Cursor/User/mcp.json` (or `%APPDATA%/Cursor/User` on Windows).
- `claude-code`: `/.claude/settings.local.json`, `/.claude/settings.json`, `/.claude/mcp.json`, then `~/.claude/settings.json`, `~/.claude/mcp.json`, `~/.claude.json`. `settings.local.json` is meant for untracked per-developer overrides, while `settings.json` is the shared project config.
@@ -123,14 +134,17 @@ Use `--scope home|project` with `mcporter config add` to pick the write target e
- `--copy` writes selected entries into your local config; `--filter ` narrows the import list; `--path ` lets you point at bespoke locations.
### `mcporter config login ` / `logout`
+
- Mirrors `mcporter auth`. `login` completes 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 in `docs/adhoc.md`.
- `--browser none` suppresses automatic browser launch (useful for copying the URL into a remote browser).
- `logout` wipes token caches under `~/.mcporter//` (or the custom `tokenCacheDir`). Pass `--all` to clear everything.
### `mcporter config doctor`
+
- 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.
## Ad-hoc & Persistence
+
- `--http-url` and `--stdio` flags live on `mcporter list|call|auth`, keeping `mcporter config` focused on persistent config files.
- Names default to slugified hostnames or executable/script combos. Supply `--name` to improve reuse; mcporter uses that slug for OAuth caches even before persistence.
- `--allow-http` is mandatory for cleartext endpoints so we never downgrade transport silently.
@@ -138,6 +152,7 @@ Use `--scope home|project` with `mcporter config add` to pick the write target e
- `--env KEY=VAL` entries merge with existing `env` dictionaries if you later persist the same server; nothing is lost when you alternate between CLI flags and JSON edits.
## JSON Schema for IDE Support
+
mcporter provides a JSON Schema for config file validation and autocompletion. Add the `$schema` property to your config file:
```jsonc
@@ -148,6 +163,7 @@ mcporter provides a JSON Schema for config file validation and autocompletion. A
```
For local development, you can reference the schema from the repo root:
+
```jsonc
{
"$schema": "../mcporter.schema.json",
@@ -158,48 +174,53 @@ For local development, you can reference the schema from the repo root:
The schema is auto-generated from the Zod validation schemas using `pnpm generate:schema`.
## Schema Reference
+
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. |
+| 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. |
-| `oauthScope` | Optional explicit OAuth scope string. If omitted, mcporter lets the MCP SDK derive scope from server/auth metadata. Use this as an escape hatch for providers that require explicit scopes but don’t publish `scopes_supported`. |
-| `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 `, so you don’t need to call `npx ... auth` manually. |
+| 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. |
+| `oauthScope` | Optional explicit OAuth scope string. If omitted, mcporter lets the MCP SDK derive scope from server/auth metadata. Use this as an escape hatch for providers that require explicit scopes but don’t publish `scopes_supported`. |
+| `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 `, 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.
## Imports & Conflict Resolution
+
- `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 --copy --filter name` or use `mcporter 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 (`servers` vs `mcpServers`).
## Project vs. Machine Layers
+
- Keep `config/mcporter.json` under 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`; point `mcporter 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//`, `dist/`).
## Validation & Troubleshooting
+
- `mcporter list --http-url ...` refuses to auto-run OAuth to keep listing commands quick; use `mcporter config login ...` or `mcporter 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 --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 the `imports` array to move Cursor later or set it to `[]` to disable imports entirely.
- `docs/adhoc.md` covers deeper debugging, including tmux workflows and OAuth promotion logs.
## Outstanding Coverage Items
+
- Describe how `--persist` writes through the same import merge pipeline (especially once `mcporter config add --copy-from` ships) so users know exactly which file changes.
- Call out that `--allow-http` remains required for cleartext URLs even in config mutations, and reiterate that `--env KEY=VAL` merges 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 login` help output.
diff --git a/docs/emit-ts.md b/docs/emit-ts.md
index d1ee1d8..fc13a4e 100644
--- a/docs/emit-ts.md
+++ b/docs/emit-ts.md
@@ -19,14 +19,14 @@ mcporter emit-ts --out linear-client.ts \
```
- `--mode types` (default) emits a `.d.ts` interface (`LinearTools`) with
-docblocks + promisified signatures. Missing output schemas fall back to
-`CallResult`.
+ docblocks + promisified signatures. Missing output schemas fall back to
+ `CallResult`.
- `--mode client` emits both the interface (auto-derived `.d.ts`) **and** an
-executable `.ts` helper that wraps `createServerProxy`. Each method returns a
-`CallResult`, and the factory exposes a `close()` helper for runtimes the client
-creates.
+ executable `.ts` helper that wraps `createServerProxy`. Each method returns a
+ `CallResult`, and the factory exposes a `close()` helper for runtimes the client
+ creates.
- `--include-optional` mirrors `mcporter list --all-parameters`, ensuring every
-parameter is shown even when optional.
+ parameter is shown even when optional.
Outputs overwrite existing files automatically so you can regenerate artifacts
whenever the server schema changes.
@@ -81,13 +81,13 @@ returned object’s `close()` becomes a no-op.
## Flags
-| Flag | Description |
-| --- | --- |
-| `--out ` | Required. `.d.ts` target for `types`, `.ts` target for `client`. |
-| `--mode types|client` | Output kind (defaults to `types`). |
+| Flag | Description |
+| -------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------- |
+| `--out ` | Required. `.d.ts` target for `types`, `.ts` target for `client`. |
+| `--mode types | client` | Output kind (defaults to `types`). |
| `--types-out ` | Optional override for the `.d.ts` file when `--mode client`. Default: derive from `--out`. |
-| `--include-optional` | Include every parameter (not just the minimum 5 + required). |
-| `--json` | Emit a JSON summary describing the emitted file(s) instead of plain-text logs. |
+| `--include-optional` | Include every parameter (not just the minimum 5 + required). |
+| `--json` | Emit a JSON summary describing the emitted file(s) instead of plain-text logs. |
## Testing
diff --git a/docs/hang-debug.md b/docs/hang-debug.md
index 76a2c46..cb14fc3 100644
--- a/docs/hang-debug.md
+++ b/docs/hang-debug.md
@@ -21,7 +21,7 @@ culprit is a child MCP server process that keeps the stdio transport alive.
child remains, mcporter will now unref and force-kill it, but the debug list
tells you exactly what was keeping the event loop alive.
4. **Capture the pane output** – run `tmux capture-pane -p -t -S
- -200` to save the diagnostic log for later review.
+-200` to save the diagnostic log for later review.
5. **Retry with `--timeout`** – if the tool itself hangs, use
`--timeout ` or `MCPORTER_CALL_TIMEOUT` to fail fast while still
gathering diagnostics.
@@ -65,7 +65,7 @@ child process, which mcporter will now terminate during shutdown.
- Killing residual children is best-effort; if you see repeated `kill-failed`
messages, manually terminate the PID listed in the log.
- Always keep tmux sessions tidy after debugging: `tmux kill-session -t
- `.
+`.
- The CLI now forces `process.exit(0)` after cleanup by default so Node never
lingers on leaked handles. Export `MCPORTER_NO_FORCE_EXIT=1` if you’re
debugging and need the process to stay alive.
diff --git a/docs/import.md b/docs/import.md
index d514822..6a367c1 100644
--- a/docs/import.md
+++ b/docs/import.md
@@ -28,15 +28,15 @@ Set `"imports": []` when you want to disable auto-merging entirely, or supply a
## Import Support Matrix
-| Kind | Typical owner | Format | Project paths | User paths | Notes |
-| --- | --- | --- | --- | --- | --- |
-| `cursor` | Cursor IDE | JSON (`mcpServers`) | `.cursor/mcp.json` | macOS/Linux: `${XDG_CONFIG_HOME:-~/.config}/Cursor/User/mcp.json`
Windows: `%APPDATA%/Cursor/User/mcp.json` | Mirrors Cursor’s “MCP Servers” panel. Per-workspace files override the global file when both exist. |
-| `claude-code` | Claude Code (browser) | JSON (`mcpServers`) | `.claude/settings.local.json`, `.claude/settings.json`, `.claude/mcp.json` | `~/.claude/settings.json`, `~/.claude/mcp.json`, `~/.claude.json` | `settings.local.json` (ignored by git) overrides `settings.json`, which is the shared project config; both beat the legacy `mcp.json`. |
-| `claude-desktop` | Claude Desktop | JSON (`mcpServers`) | — | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
Windows: `%APPDATA%/Claude/claude_desktop_config.json`
Linux: `~/.config/Claude/claude_desktop_config.json` | Desktop Claude stores all servers per-machine, so there’s no project-relative file. |
-| `codex` | Sweetistics Codex | TOML (`[mcp_servers.*]`) | `.codex/config.toml` | `~/.codex/config.toml` | Only `config.toml` is recognized; the deprecated `mcp.toml` filename is ignored. |
-| `windsurf` | Codeium Windsurf | JSON (`mcpServers`) | — | Windows: `%APPDATA%/Codeium/windsurf/mcp_config.json`
macOS/Linux: `~/.codeium/windsurf/mcp_config.json` | Global-only config managed by Codeium. |
-| `opencode` | OpenCode | JSON/JSONC (`mcp`, `mcpServers`, or root map) | `opencode.json`, `opencode.jsonc` | `OPENCODE_CONFIG` override
`OPENCODE_CONFIG_DIR/opencode.json(c)`
macOS/Linux: `${XDG_CONFIG_HOME:-~/.config}/opencode/opencode.json(c)`
Windows: `%APPDATA%/opencode/opencode.json(c)` | Accepts comment-friendly `.jsonc` files and honors OpenCode’s precedence env vars. |
-| `vscode` | VS Code MCP extension | JSON (`mcpServers` or `servers`) | — | macOS: `~/Library/Application Support/Code(/Code - Insiders)/User/mcp.json`
Windows: `%APPDATA%/Code(/Code - Insiders)/User/mcp.json`
Linux: `~/.config/Code(/Code - Insiders)/User/mcp.json` | We probe both Stable and Insiders directories; the first readable file wins. |
+| Kind | Typical owner | Format | Project paths | User paths | Notes |
+| ---------------- | --------------------- | --------------------------------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
+| `cursor` | Cursor IDE | JSON (`mcpServers`) | `.cursor/mcp.json` | macOS/Linux: `${XDG_CONFIG_HOME:-~/.config}/Cursor/User/mcp.json`
Windows: `%APPDATA%/Cursor/User/mcp.json` | Mirrors Cursor’s “MCP Servers” panel. Per-workspace files override the global file when both exist. |
+| `claude-code` | Claude Code (browser) | JSON (`mcpServers`) | `.claude/settings.local.json`, `.claude/settings.json`, `.claude/mcp.json` | `~/.claude/settings.json`, `~/.claude/mcp.json`, `~/.claude.json` | `settings.local.json` (ignored by git) overrides `settings.json`, which is the shared project config; both beat the legacy `mcp.json`. |
+| `claude-desktop` | Claude Desktop | JSON (`mcpServers`) | — | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
Windows: `%APPDATA%/Claude/claude_desktop_config.json`
Linux: `~/.config/Claude/claude_desktop_config.json` | Desktop Claude stores all servers per-machine, so there’s no project-relative file. |
+| `codex` | Sweetistics Codex | TOML (`[mcp_servers.*]`) | `.codex/config.toml` | `~/.codex/config.toml` | Only `config.toml` is recognized; the deprecated `mcp.toml` filename is ignored. |
+| `windsurf` | Codeium Windsurf | JSON (`mcpServers`) | — | Windows: `%APPDATA%/Codeium/windsurf/mcp_config.json`
macOS/Linux: `~/.codeium/windsurf/mcp_config.json` | Global-only config managed by Codeium. |
+| `opencode` | OpenCode | JSON/JSONC (`mcp`, `mcpServers`, or root map) | `opencode.json`, `opencode.jsonc` | `OPENCODE_CONFIG` override
`OPENCODE_CONFIG_DIR/opencode.json(c)`
macOS/Linux: `${XDG_CONFIG_HOME:-~/.config}/opencode/opencode.json(c)`
Windows: `%APPDATA%/opencode/opencode.json(c)` | Accepts comment-friendly `.jsonc` files and honors OpenCode’s precedence env vars. |
+| `vscode` | VS Code MCP extension | JSON (`mcpServers` or `servers`) | — | macOS: `~/Library/Application Support/Code(/Code - Insiders)/User/mcp.json`
Windows: `%APPDATA%/Code(/Code - Insiders)/User/mcp.json`
Linux: `~/.config/Code(/Code - Insiders)/User/mcp.json` | We probe both Stable and Insiders directories; the first readable file wins. |
> Tip: mcporter resolves `~` and `$XDG_CONFIG_HOME` inside these paths automatically, so you can rely on the same `imports` list across platforms.
>
diff --git a/docs/known-issues.md b/docs/known-issues.md
index 83a1a6e..50feb59 100644
--- a/docs/known-issues.md
+++ b/docs/known-issues.md
@@ -9,6 +9,7 @@ read_when:
This file tracks limitations that users regularly run into. Most of these require upstream cooperation or larger refactors—feel free to reference this when triaging bugs.
## Hosted OAuth servers (Supabase, GitHub MCP, etc.)
+
- Supabase’s hosted MCP server rejects the standard `mcp:tools` scope and only accepts Supabase-specific scopes (`projects:read`, `database:write`, ...). Because they do not expose OAuth discovery metadata or scope negotiation, mcporter cannot auto-register or complete the flow. Workarounds:
- Use Supabase’s supported clients (Cursor, Windsurf).
- Self-host their MCP server and configure PAT headers / custom OAuth.
@@ -16,16 +17,19 @@ This file tracks limitations that users regularly run into. Most of these requir
- GitHub’s MCP endpoint (`https://api.githubcopilot.com/mcp/`) returns “does not support dynamic client registration” when mcporter attempts to connect. Copilot’s backend expects pre-registered client credentials. Until GitHub publishes a dynamic-registration API (or client secrets), mcporter cannot interact with their hosted server.
## Output schemas missing/buggy on many servers
+
- The MCP spec allows servers to omit `outputSchema`. In practice, many hosted MCPs return empty or inconsistent schemas, so features that rely on return types (TypeScript signatures, generated CLIs, `createServerProxy` return helpers) may degrade to `unknown`.
- Workarounds: inspect the server’s README / manual docs for output details, or wrap the tool via `createServerProxy` and handle the raw envelope manually.
- Potential improvement: allow user-provided schema overrides (e.g., `mcporter config patch`, CLI flag to load schema JSON) so we can fill gaps on a per-tool basis.
## MCP SDK 1.22.0 inline-stdio regression
+
- Upgrading `@modelcontextprotocol/sdk` to 1.22.0 causes `mcporter generate-cli --compile` (and direct runtime `listTools`) to fail against inline STDIO servers with `MCP error -32603: Cannot read properties of undefined (reading 'typeName')`.
- Repro: `pnpm mcporter generate-cli "node mock-stdio.mjs" --compile /tmp/inline-cli --runtime bun` using the inline stdio harness in `tests/cli-generate-cli.integration.test.ts`.
- Status: reproduced locally; pinned the SDK to `~1.21.2` until upstream ships a fix.
## Next Steps
+
- Implement true scope negotiation (read discovery metadata, allow `--oauth-scope`).
- Keep lobbying providers for spec-compliant OAuth behavior.
- Consider adding schema override hooks or auto-caching schema snapshots per tool.
diff --git a/docs/livetests.md b/docs/livetests.md
index c6763e8..dc68f81 100644
--- a/docs/livetests.md
+++ b/docs/livetests.md
@@ -9,10 +9,12 @@ read_when:
These tests hit real hosted MCP servers and require outbound HTTP. They are **off by default** to keep CI and local runs deterministic.
## When to run
+
- Before releases when you want end-to-end validation against hosted servers.
- When debugging regressions that only repro against real servers (e.g., DeepWiki).
## How to run
+
```bash
MCP_LIVE_TESTS=1 pnpm test:live
```
@@ -20,6 +22,7 @@ MCP_LIVE_TESTS=1 pnpm test:live
This runs the Vitest suite under `tests/live`, in-band, with longer timeouts.
## Current coverage
+
- **DeepWiki**:
- Streamable HTTP success path: `https://mcp.deepwiki.com/mcp`
- Deprecated SSE endpoint classification: `https://mcp.deepwiki.com/sse`
@@ -28,6 +31,7 @@ This runs the Vitest suite under `tests/live`, in-band, with longer timeouts.
- assert the legacy SSE endpoint currently returns a structured HTTP `410` issue envelope
## Notes
+
- Tests are skipped entirely unless `MCP_LIVE_TESTS=1` is set.
- Ensure network egress is allowed. No secrets are required for the current DeepWiki checks.
- As of 2026-03-29, DeepWiki's hosted `/sse` endpoint responds with HTTP `410`, so the live suite treats that as a compatibility/error-classification smoke rather than a success-path transport check.
diff --git a/docs/manual-testing.md b/docs/manual-testing.md
index d716bc7..a753570 100644
--- a/docs/manual-testing.md
+++ b/docs/manual-testing.md
@@ -40,6 +40,7 @@ cat /tmp/list-SERVER.log
```
Verify:
+
- Header shows the right name/transport and the new metadata line (`tools · duration · transport`).
- Timeouts produce the footer block: `Tools: ` and `Reason: ...`.
@@ -53,6 +54,7 @@ cat /tmp/call-SERVER.log
```
Checks:
+
- Successful calls print the payload; failures reuse the shared hinting (`SSE error ...`, auto-correct messages, etc.).
- For HTTP selectors (`https://.../mcp.tool` or `https://.../mcp.tool(args)`), ensure no OAuth prompt appears and the request hits the configured server.
@@ -68,6 +70,7 @@ cat /tmp/auth-SERVER.log
```
Expectations:
+
- If a token cache exists, log should mention the cleared directory.
- Failed auths emit the unified message (`Failed to authorize 'SERVER': ...`).
diff --git a/docs/migration.md b/docs/migration.md
index 41dc737..b4b3928 100644
--- a/docs/migration.md
+++ b/docs/migration.md
@@ -33,11 +33,11 @@ npm install mcporter
## 4. Programmatic Usage
```ts
-import { createRuntime } from "mcporter";
+import { createRuntime } from 'mcporter';
-const runtime = await createRuntime({ configPath: "./config/mcporter.json" });
-const tools = await runtime.listTools("chrome-devtools");
-await runtime.callTool("chrome-devtools", "take_screenshot", { args: { url: "https://x.com" } });
+const runtime = await createRuntime({ configPath: './config/mcporter.json' });
+const tools = await runtime.listTools('chrome-devtools');
+await runtime.callTool('chrome-devtools', 'take_screenshot', { args: { url: 'https://x.com' } });
await runtime.close();
```
@@ -46,12 +46,12 @@ Prefer `createRuntime` for long-lived agents so connections and OAuth tokens can
## 5. Single Call Helper
```ts
-import { callOnce } from "mcporter";
+import { callOnce } from 'mcporter';
await callOnce({
- server: "firecrawl",
- toolName: "crawl",
- args: { url: "https://anthropic.com" },
+ server: 'firecrawl',
+ toolName: 'crawl',
+ args: { url: 'https://anthropic.com' },
});
```
@@ -65,12 +65,12 @@ Use `callOnce` for fire-and-forget invocations.
## 7. Troubleshooting
-| Symptom | Fix |
-| --- | --- |
-| Browser did not open | Copy the printed OAuth URL manually into a browser. |
-| Authorization hangs | Ensure the callback URL can bind to `127.0.0.1`; firewalls may block it. |
-| Tokens are stale | Delete `~/.mcporter//tokens.json` and retry. |
-| Stdio command fails | Pass `--root` to point at the repo root so relative paths resolve. |
+| Symptom | Fix |
+| -------------------- | ------------------------------------------------------------------------ |
+| Browser did not open | Copy the printed OAuth URL manually into a browser. |
+| Authorization hangs | Ensure the callback URL can bind to `127.0.0.1`; firewalls may block it. |
+| Tokens are stale | Delete `~/.mcporter//tokens.json` and retry. |
+| Stdio command fails | Pass `--root` to point at the repo root so relative paths resolve. |
---
diff --git a/docs/refactor.md b/docs/refactor.md
index 3da69b0..330acd9 100644
--- a/docs/refactor.md
+++ b/docs/refactor.md
@@ -9,7 +9,8 @@ read_when:
This doc tracks remaining reuse/refactor work now that the original plan is done.
Each section lists the goal, why it matters, and the concrete steps/tests needed.
-## 1. Shared Tool Schema Cache *(Completed)*
+## 1. Shared Tool Schema Cache _(Completed)_
+
- **Problem**: `generate-cli` and `emit-ts` both fetch & serialize tool schemas
independently (and `mcporter list` re-parses them too).
- **What we did**:
@@ -18,7 +19,8 @@ Each section lists the goal, why it matters, and the concrete steps/tests needed
3. Added `tests/tool-cache.test.ts` + updated emit-ts tests to ensure the helper is covered.
- **Next**: Consider integrating the cache into `generate-cli` if we ever reuse runtime instances there.
-## 2. Unified Flag Parsing for Generator-style Commands *(Completed)*
+## 2. Unified Flag Parsing for Generator-style Commands _(Completed)_
+
- **Problem**: `generate-cli`, the (now legacy) `regenerate-cli` wrapper, and `emit-ts` each
reimplemented `--runtime`, `--timeout`, and `--include-optional` handling.
- **What we did**:
@@ -29,7 +31,8 @@ Each section lists the goal, why it matters, and the concrete steps/tests needed
3. Added `tests/generator-flag-parser.test.ts` to cover runtime/timeout and
optional flags.
-## 3. Test Fixture Reuse *(Completed)*
+## 3. Test Fixture Reuse _(Completed)_
+
- **Problem**: Emit-ts/tool-cache/unit tests each defined their own tool/definition
fixtures, leading to divergence.
- **What we did**:
@@ -39,7 +42,8 @@ Each section lists the goal, why it matters, and the concrete steps/tests needed
3. Ensured the fixture covers required+optional parameters so both suites hit
the same edge cases.
-## 4. CallResult Helper Extraction *(Completed)*
+## 4. CallResult Helper Extraction _(Completed)_
+
- **Problem**: `call-command.ts` and the emit-ts client template both wrapped
results with `createCallResult`, but there was no shared helper.
- **What we did**:
@@ -49,7 +53,8 @@ Each section lists the goal, why it matters, and the concrete steps/tests needed
they stay in sync.
3. Adjusted emit-ts tests to assert the helper is referenced.
-## 5. CLI Docs Consolidation *(Completed)*
+## 5. CLI Docs Consolidation _(Completed)_
+
- **Problem**: CLI usage guidance was scattered across README, `docs/spec.md`,
and various feature docs.
- **What we did**:
@@ -60,7 +65,8 @@ Each section lists the goal, why it matters, and the concrete steps/tests needed
- **Next**: Once the other doc changes land, update README/spec to link to the
reference and drop redundant sections.
-## 6. Runtime Module Split *(Completed)*
+## 6. Runtime Module Split _(Completed)_
+
- **Problem**: `src/runtime.ts` had grown bulky (600+ lines) mixing transport setup, OAuth flow control, and small helpers, making tests and reuse harder.
- **What we did**:
1. Extracted transport construction/retry logic to `src/runtime/transport.ts`.
@@ -72,5 +78,6 @@ Each section lists the goal, why it matters, and the concrete steps/tests needed
- **Next**: Keep new helpers in sync as runtime evolves; prefer adding surface to these modules over growing `runtime.ts` again.
---
+
Tracking the above here keeps future agents aligned. Update this checklist as
items ship (mark sections “Completed” when done, or delete the doc once empty).
diff --git a/docs/spec.md b/docs/spec.md
index 1e367f8..705dcd1 100644
--- a/docs/spec.md
+++ b/docs/spec.md
@@ -7,11 +7,13 @@ summary: 'Plan for the mcporter package replacing the Sweetistics pnpm MCP helpe
> Inspired in part by Anthropic’s guidance on MCP code execution agents: https://www.anthropic.com/engineering/code-execution-with-mcp
## Goals
+
- Provide a TypeScript runtime + CLI that exposes all MCP servers defined in `~/Projects/sweetistics/config/mcporter.json`.
- Preserve current one-shot `pnpm mcporter:call` ergonomics while enabling reusable connections for Bun/Node agents.
- Keep feature parity with the Python helper (env interpolation, stdio wrapping, OAuth caching) and extend test coverage.
## Deliverables
+
- `packages/mcporter` (standalone npm package) exporting:
- `createRuntime()` for shared connections (list/call tools, resolve resources).
- `callOnce()` convenience matching today’s single-call flow.
@@ -23,6 +25,7 @@ summary: 'Plan for the mcporter package replacing the Sweetistics pnpm MCP helpe
- Documentation: README, usage examples, migration guide for replacing `pnpm mcp:*`.
## Architecture Notes
+
- Load MCP definitions from JSON (support relative paths + HTTPS).
- Reuse `@modelcontextprotocol/sdk` transports; invoke stdio servers directly (e.g., call `npx` with env overrides) without an extra wrapper script.
- Automatically detect OAuth requirements for ad-hoc HTTP servers by retrying failed handshakes and promoting the definition to `auth: "oauth"` when a 401/403 is encountered, then launching the browser flow immediately.
@@ -35,6 +38,7 @@ summary: 'Plan for the mcporter package replacing the Sweetistics pnpm MCP helpe
- Document Cursor-compatible `config/mcporter.json` structure; support env-sourced headers and stdio commands while keeping inline overrides available for scripts.
## Schema-Aware Proxy Strategy
+
- Cache tool schemas on first access, persist them under `~/.mcporter//schema.json` for reuse across processes, and tolerate failures by falling back to raw `callTool`.
- Allow direct method-style invocations such as `context7.getLibraryDocs("react")` by:
- Mapping camelCase properties to kebab-case tool names.
@@ -47,6 +51,7 @@ summary: 'Plan for the mcporter package replacing the Sweetistics pnpm MCP helpe
- Back the proxy with targeted unit tests that cover primitive-only calls, positional tuples + option bags, and error fallbacks when schemas are missing.
## Standalone CLI Generation
+
- `generate-cli` should accept inline JSON, file paths, inline stdio commands (either via `--command` or as the first positional argument), or existing config names and produce a ready-to-run CLI that maps tools to Commander subcommands.
- Embed schemas (via `listTools { includeSchema: true }`) directly in the generated source so repeat executions avoid additional metadata calls.
- Support optional bundling through esbuild, producing Node-friendly `.cjs` files or Bun-ready `.js` binaries with executable shebangs.
@@ -54,24 +59,28 @@ summary: 'Plan for the mcporter package replacing the Sweetistics pnpm MCP helpe
- Add integration tests asserting the generated CLI can list tools, execute with positional/flag arguments, and hydrate cache files without additional list calls.
## Configuration
+
- Single file `config/mcporter.json` mirrors Cursor/Claude schema: `mcpServers` map with entries containing `baseUrl` or `command`+`args`, optional `headers`, `env`, `description`, `auth`, `tokenCacheDir`, and convenience `bearerToken`/`bearerTokenEnv` fields.
- Optional `imports` array (defaulting to ['cursor', 'claude-code', 'claude-desktop', 'codex', 'windsurf', 'vscode']) controls auto-merging of editor configs; entries earlier in the list win conflicts while local definitions can still override.
- Provide `configPath` override for scripts/tests; keep inline overrides in examples for completeness but default to file-based configuration.
- Add fixtures validating HTTP vs. stdio normalization, header/env behavior, and editor config imports (Cursor, Claude Code/Desktop, Codex, Windsurf, VS Code) to ensure priority ordering matches defaults.
## Work Phases
+
1. **Scaffold Package**
- Init pnpm workspace config, tsconfig, lint/test scaffolding, build script.
2. **Core Runtime**
- Port config parsing + env/header logic.
- Implement connection cache, tool invocation, resource helpers.
3. **CLI Surface**
+
- Implement `list` (with optional schema) and `call` commands.
- Render tool metadata as pseudo-TypeScript declarations: blue `function` signatures, grey doc comments using `@param` lines, inferred return names, and compact optional summaries that collapse longer lists until users pass `--all-parameters`. The default view must still surface at least five parameters (even if they’re optional) before summarising the remainder.
- Ensure output parity with existing helper.
- `call` has to parse both `server.tool` tokens and HTTP selectors like `https://host/path.tool(args)`; in the HTTP case we need to peel off the `.tool` suffix, infer/auto-register the ad-hoc server (respecting `--allow-http`), and hydrate arguments from parentheses or trailing `key=value` pairs.
- Add `generate-cli` for standalone/bundled CLIs with embedded schema caching.
- Ensure `generate-cli`, `inspect-cli`, and `emit-ts` share the same server-resolution logic as `list/call`, including HTTP URL matching and scheme-less selectors with `.tool` suffixes.
+
4. **Testing & Fixtures**
- Mock representative MCP servers (stdio + HTTP + OAuth) for integration tests.
- Snapshot output for `list` vs. `call`.
@@ -80,6 +89,7 @@ summary: 'Plan for the mcporter package replacing the Sweetistics pnpm MCP helpe
- Update Sweetistics docs to point to the new package.
## Open Questions
+
- How aggressively should we parallelize list calls? Current helper serializes to avoid load.
- Should we bundle a minimal REPL for ad-hoc debugging, or keep CLI focused on list/call?
- Do we expose streaming/async iterator interfaces for tools returning logs?
diff --git a/docs/subagent.md b/docs/subagent.md
index 0773221..d00eb2b 100644
--- a/docs/subagent.md
+++ b/docs/subagent.md
@@ -5,6 +5,7 @@ summary: 'Multi-agent system directives and coordination rules. Master reference
# Claude Subagent Quickstart
## CLI Basics
+
- Never invoke subagents through `./runner`—launch them inside tmux directly so the session can persist and bypass the runner timeouts. Example:
```bash
@@ -13,6 +14,7 @@ summary: 'Multi-agent system directives and coordination rules. Master reference
```
Once inside the session, run `/model` to confirm the active alias (`haiku` maps to Claude 3.5 Haiku) and switch models if needed.
+
- Need to queue instructions without attaching? Use `bun scripts/agent-send.ts --session -- "your command"` to inject text into a running agent session (single Enter is sent by default).
- Run Claude through the repo wrapper when you just need help (`./runner claude --help`), but for actual delegation launch Claude inside tmux so the work keeps running after you disconnect.
- Two modes:
@@ -23,16 +25,19 @@ summary: 'Multi-agent system directives and coordination rules. Master reference
- Ralph’s supervisor loop launches Claude the same way (`claude --dangerously-skip-permissions ""`) to keep the tmux automation flowing.
## One-Shot Prompts
+
- The CLI accepts the prompt as a trailing argument in one-shot mode. Multi-line prompts can be piped: `echo "..." | ./runner claude --print`.
- Add `--output-format json` when you need structured fields (e.g., summary + bullets) for post-processing.
- Keep prompts explicit about reading full files: “Read docs/example.md in full and produce a 2–3 sentence summary covering all sections.”
## Bulk Markdown Conversion
+
- Produce the markdown inventory first (`pnpm run docs:list`) and feed batches of filenames to your Claude session.
- For each batch, issue a single instruction like “Rewrite these files with YAML front matter summaries, keep all other content verbatim.” Haiku can loop over multi-file edits when you provide the explicit list.
- After Claude reports success, diff each file locally (`./runner git diff docs/.md`) before moving to the next batch.
## Ralph Integration Notes
+
- Ralph (see `scripts/ralph.ts`) spins up tmux sessions, auto-wakes the worker, and calls Claude as the supervisor via `claude --dangerously-skip-permissions`.
- Supervisor responses must end with either `CONTINUE`, `SEND: `, or `RESTART`; Ralph parses these tokens to decide the next action.
- To start Ralph manually: `bun scripts/ralph.ts start --goal "…" [--markdown path]`. Progress is tracked in `.ralph/progress.md` by default.
diff --git a/docs/supabase-auth-issue.md b/docs/supabase-auth-issue.md
index d67fd1b..3098274 100644
--- a/docs/supabase-auth-issue.md
+++ b/docs/supabase-auth-issue.md
@@ -7,6 +7,7 @@ read_when:
# OAuth Notes & Hosted MCP Compatibility
## MCP Spec Expectations
+
- The June 18 2025 MCP “Authorization” spec (and the linked OAuth flow document) requires OAuth 2.1 dynamic client registration plus RFC 7235 `WWW-Authenticate` challenges for scope negotiation.
- Servers SHOULD expose discovery metadata via `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource`. Those documents list supported scopes and additional OAuth endpoints.
- Clients are expected to start with a baseline scope (the spec uses `mcp:tools`) and then re-authenticate with any server-supplied scope hints.
@@ -14,6 +15,7 @@ read_when:
We currently hard-code `mcp:tools` because it is the only scope guaranteed to exist in the MCP reference implementation. We need richer negotiation to support providers that enforce product-specific scopes.
## Hosted Supabase MCP (~Oct 2025)
+
Supabase’s hosted MCP server (`https://mcp.supabase.com/mcp`) validates the requested scopes against their management API permissions (`organizations:read`, `projects:read`, `database:write`, `storage:read`, etc.). When mcporter asks for `mcp:tools`, their authorization server rejects the request with HTTP 400 and a body similar to:
```
@@ -21,11 +23,13 @@ Supabase’s hosted MCP server (`https://mcp.supabase.com/mcp`) validates the re
```
Key takeaways from Supabase’s docs:
+
1. Hosted installs rely on dynamic client registration and are currently integrated with Cursor/Windsurf (which embed the Supabase scope list).
2. Manual authentication is offered for self-hosted/CI workflows (PAT headers or custom OAuth app), but their hosted server still expects Supabase-specific scopes.
3. There is no public metadata endpoint describing those scopes, so third-party MCP clients cannot opt in automatically.
## mcporter’s Current Behavior
+
- We auto-promote ad-hoc HTTP servers to OAuth and retry once when we see 401/403 errors.
- We surface any server-supplied OAuth error payload so it’s obvious whether the problem is scope-related, a missing token, etc.
- After the second failure we stop retrying to avoid infinite loops.
@@ -33,6 +37,7 @@ Key takeaways from Supabase’s docs:
This works for providers that use standard MCP scopes (e.g., the MCP example server, Vercel’s MCP), but it fails for Supabase because they reject `mcp:tools` outright.
## Roadmap / Proposed Improvements
+
1. **Scope discovery & negotiation**
- Fetch `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server` when a server advertises OAuth. If `scopes_supported` is present, intersect it with user overrides and use that list instead of `mcp:tools`.
- Parse `WWW-Authenticate` challenges on 401/403 responses and restart the authorization flow with the scopes the server demands.
@@ -46,6 +51,7 @@ This works for providers that use standard MCP scopes (e.g., the MCP example ser
- File upstream issues (e.g., Supabase) requesting support for standard MCP scopes or publication of `scopes_supported` metadata, so we can integrate without custom code.
## Workarounds Today
+
- Use a supported GUI client (Cursor, Claude Desktop, Windsurf) for Supabase’s hosted MCP—they already ship the necessary scopes.
- Self-host Supabase MCP and configure PAT headers or your own OAuth client; you can then relax scope validation to include `mcp:tools`.
- For other providers, consult their docs for discovery metadata. If they list scopes, set them via a future `--oauth-scope` flag once we implement it (tracked in #TODO).
diff --git a/docs/tmux.md b/docs/tmux.md
index 3b984f5..4831a8e 100644
--- a/docs/tmux.md
+++ b/docs/tmux.md
@@ -13,11 +13,14 @@ Use `tmux` to verify whether a CLI command actually exits or is stalled on open
tmux new-session -ds mcporter-check "pnpm exec tsx src/cli.ts list"
```
2. Wait a few seconds, then ask tmux if the session is still running:
+
```bash
tmux has-session -t mcporter-check
```
+
- Exit status **1** (`can't find session`) means the process exited normally.
- Exit status **0** means the command is still running (or hung) inside the session.
+
3. Capture the output without attaching:
```bash
tmux capture-pane -pt mcporter-check | tail -n 40
diff --git a/docs/tool-calling.md b/docs/tool-calling.md
index b3571a1..a476275 100644
--- a/docs/tool-calling.md
+++ b/docs/tool-calling.md
@@ -69,6 +69,7 @@ mcporter call --http-url https://mcp.example.com/mcp fetch_docs repoName=value
---
**Tips**
+
- Use `mcporter list ` to see parameter names, return types, and example invocations.
- Optional fields hide by default; add `--all-parameters` when listing a server to reveal everything.
- `mcporter auth ` accepts the same ad-hoc flags, so you can authenticate immediately after a 401 without editing config.
diff --git a/docs/windows.md b/docs/windows.md
index be164a9..ff17f20 100755
--- a/docs/windows.md
+++ b/docs/windows.md
@@ -5,21 +5,21 @@ summary: What to do when pnpm/test flows fail on NTFS-backed worktrees.
## Installing dependencies
-* `pnpm install` fails on `/mnt/c` because NTFS/DrvFs blocks `futime`. Clone/sync the repo to `$HOME` (ext4 inside WSL) and run `./runner pnpm install` there instead. Example: `rsync -a --delete --exclude node_modules /mnt/c/Projects/mcporter/ ~/mcporter-wsl/`.
-* Keep `$HOME/.bun/bin` and `$HOME/.local/share/pnpm` on your PATH before invoking `./runner`. Without Bun and pnpm the runner prints the guardrail error and exits.
-* If you *must* work from `/mnt/c`, remount with `metadata` support (`sudo mount -t drvfs C: /mnt/c -o metadata,uid=$(id -u),gid=$(id -g),umask=22,fmask=111`). Otherwise installs, chmods, and copyfile calls will continue to fail.
+- `pnpm install` fails on `/mnt/c` because NTFS/DrvFs blocks `futime`. Clone/sync the repo to `$HOME` (ext4 inside WSL) and run `./runner pnpm install` there instead. Example: `rsync -a --delete --exclude node_modules /mnt/c/Projects/mcporter/ ~/mcporter-wsl/`.
+- Keep `$HOME/.bun/bin` and `$HOME/.local/share/pnpm` on your PATH before invoking `./runner`. Without Bun and pnpm the runner prints the guardrail error and exits.
+- If you _must_ work from `/mnt/c`, remount with `metadata` support (`sudo mount -t drvfs C: /mnt/c -o metadata,uid=$(id -u),gid=$(id -g),umask=22,fmask=111`). Otherwise installs, chmods, and copyfile calls will continue to fail.
## Running tests
-* Use the ext4 copy (`~/mcporter-wsl`) for `pnpm lint`, `pnpm typecheck`, and the Vitest suites. All tests pass there (71 files / 280 tests, 1 file and 2 tests skipped).
-* Whole-repo `pnpm test` on `/mnt/c` repeatedly times out because Vitest cannot start workers when the node_modules tree belongs to root or sits on NTFS. Copy the repo to ext4 or fix ownership before retrying.
-* When working cross-filesystem, remember to sync the edited source files back to the canonical `/mnt/c/Projects/mcporter` tree (e.g., `rsync -a ~/mcporter-wsl/src/cli/generate/{template,artifacts,fs-helpers}.ts /mnt/c/Projects/mcporter/src/cli/generate/`).
-* The stdio integration suite now vendors two tiny fixtures under `tests/fixtures/stdio-*.mjs` that spin up filesystem/memory MCP servers via `node`. The tests shell out to `process.execPath`, so make sure your PATH resolves `node` correctly (fnm/nvs setups sometimes expose only `node.exe` on Windows). If you need to debug them manually, run `./runner pnpm exec vitest run tests/stdio-servers.integration.test.ts` so the guardrails apply.
+- Use the ext4 copy (`~/mcporter-wsl`) for `pnpm lint`, `pnpm typecheck`, and the Vitest suites. All tests pass there (71 files / 280 tests, 1 file and 2 tests skipped).
+- Whole-repo `pnpm test` on `/mnt/c` repeatedly times out because Vitest cannot start workers when the node_modules tree belongs to root or sits on NTFS. Copy the repo to ext4 or fix ownership before retrying.
+- When working cross-filesystem, remember to sync the edited source files back to the canonical `/mnt/c/Projects/mcporter` tree (e.g., `rsync -a ~/mcporter-wsl/src/cli/generate/{template,artifacts,fs-helpers}.ts /mnt/c/Projects/mcporter/src/cli/generate/`).
+- The stdio integration suite now vendors two tiny fixtures under `tests/fixtures/stdio-*.mjs` that spin up filesystem/memory MCP servers via `node`. The tests shell out to `process.execPath`, so make sure your PATH resolves `node` correctly (fnm/nvs setups sometimes expose only `node.exe` on Windows). If you need to debug them manually, run `./runner pnpm exec vitest run tests/stdio-servers.integration.test.ts` so the guardrails apply.
## Windows-specific fixes in the repo
-* CLI generation now uses `src/cli/generate/fs-helpers.ts`: `markExecutable` ignores `EPERM/EINVAL/ENOSYS/EACCES` so NTFS builds no longer fail when setting executable bits.
-* `safeCopyFile` falls back to a manual read/write when DrvFs blocks `copyFile`, keeping Bun bundling stable on Windows.
-* These helpers only affect Windows/WSL behavior—Linux/macOS paths still perform real `chmod`/`copyFile`.
-* Regenerated CLIs (for example `node dist/cli.js generate-cli context7 --config config/mcporter.json --bundle /mnt/c/Temp/context7-cli.js --runtime node`) now complete successfully even when the bundle lives on `/mnt/c`, and the resulting executable runs with `node /mnt/c/Temp/context7-cli.js --help`.
-* When running `mcporter generate-cli` with `--command ./relative-script.ts`, the CLI no longer tries to normalize the path into an HTTP URL—relative/bare commands are always treated as STDIO transports now, matching the PowerShell/WSL behavior you expect.
+- CLI generation now uses `src/cli/generate/fs-helpers.ts`: `markExecutable` ignores `EPERM/EINVAL/ENOSYS/EACCES` so NTFS builds no longer fail when setting executable bits.
+- `safeCopyFile` falls back to a manual read/write when DrvFs blocks `copyFile`, keeping Bun bundling stable on Windows.
+- These helpers only affect Windows/WSL behavior—Linux/macOS paths still perform real `chmod`/`copyFile`.
+- Regenerated CLIs (for example `node dist/cli.js generate-cli context7 --config config/mcporter.json --bundle /mnt/c/Temp/context7-cli.js --runtime node`) now complete successfully even when the bundle lives on `/mnt/c`, and the resulting executable runs with `node /mnt/c/Temp/context7-cli.js --help`.
+- When running `mcporter generate-cli` with `--command ./relative-script.ts`, the CLI no longer tries to normalize the path into an HTTP URL—relative/bare commands are always treated as STDIO transports now, matching the PowerShell/WSL behavior you expect.
diff --git a/mcporter.schema.json b/mcporter.schema.json
index 2b02d78..0d350ba 100644
--- a/mcporter.schema.json
+++ b/mcporter.schema.json
@@ -127,9 +127,7 @@
"description": "Arguments for the OAuth command"
}
},
- "required": [
- "args"
- ],
+ "required": ["args"],
"additionalProperties": false
},
"oauth_command": {
@@ -144,9 +142,7 @@
"description": "Arguments for the OAuth command"
}
},
- "required": [
- "args"
- ],
+ "required": ["args"],
"additionalProperties": false
},
"bearerToken": {
@@ -200,9 +196,7 @@
"maximum": 9007199254740991
}
},
- "required": [
- "mode"
- ],
+ "required": ["mode"],
"additionalProperties": false
}
],
@@ -237,15 +231,7 @@
"type": "array",
"items": {
"type": "string",
- "enum": [
- "cursor",
- "claude-code",
- "claude-desktop",
- "codex",
- "windsurf",
- "opencode",
- "vscode"
- ],
+ "enum": ["cursor", "claude-code", "claude-desktop", "codex", "windsurf", "opencode", "vscode"],
"description": "Supported editor/client configurations to import MCP servers from"
}
},
@@ -254,9 +240,7 @@
"description": "JSON Schema URL for IDE validation and autocomplete"
}
},
- "required": [
- "mcpServers"
- ],
+ "required": ["mcpServers"],
"additionalProperties": false,
"description": "mcporter configuration file schema",
"$id": "https://raw.githubusercontent.com/steipete/mcporter/main/mcporter.schema.json"
diff --git a/tests/fixtures/imports/.config/opencode/opencode.jsonc b/tests/fixtures/imports/.config/opencode/opencode.jsonc
index b0d8ea2..2c9942b 100644
--- a/tests/fixtures/imports/.config/opencode/opencode.jsonc
+++ b/tests/fixtures/imports/.config/opencode/opencode.jsonc
@@ -4,7 +4,7 @@
"opencode-user-only": {
"description": "User-level OpenCode server",
"command": "opencode-user-cli",
- "args": ["--json"]
- }
- }
+ "args": ["--json"],
+ },
+ },
}
diff --git a/tests/fixtures/imports/opencode.jsonc b/tests/fixtures/imports/opencode.jsonc
index ac6121f..ea2ebf0 100644
--- a/tests/fixtures/imports/opencode.jsonc
+++ b/tests/fixtures/imports/opencode.jsonc
@@ -5,7 +5,7 @@
"description": "Project-level OpenCode server",
"type": "stdio",
"command": "opencode-cli",
- "args": ["serve"]
- }
- }
+ "args": ["serve"],
+ },
+ },
}