Skip to content

Skip stdio config entries by default in bulk connect, add --stdio flag#201

Merged
jancurn merged 2 commits intomainfrom
claude/isolate-stdio-confirmation-naxrh
Apr 24, 2026
Merged

Skip stdio config entries by default in bulk connect, add --stdio flag#201
jancurn merged 2 commits intomainfrom
claude/isolate-stdio-confirmation-naxrh

Conversation

@jancurn
Copy link
Copy Markdown
Member

@jancurn jancurn commented Apr 24, 2026

Summary

Isolated from #165 to make review and testing easier. This PR only contains the --stdio safety gate for bulk mcpc connect <config-file> operations. The auto-discovery feature (mcpc connect with no args) remains in #165 and can be merged separately.

Motivation

Stdio entries in MCP config files execute arbitrary local commands via child_process.spawn(). When connecting all servers from a config file at once, this is a supply-chain risk — a malicious or compromised config could silently execute code on connect, even if the MCP handshake later fails.

This PR defaults bulk connects to HTTP-only entries and requires an explicit --stdio opt-in to execute stdio entries.

Behavior

  • mcpc connect <config-file> — stdio entries are skipped by default with a chalk.dim message listing what was skipped and how to include them. Pass --stdio to include stdio entries.
  • mcpc connect file:entry — single-entry connects are not affected (explicit opt-in per entry).
  • All-stdio config — if every entry in the config is stdio and --stdio is not passed, a clear error with remediation is shown.
  • JSON output — skipped entries appear under skipped with reason: "stdio".

Changes

src/lib/config.ts

  • Adds isStdioEntry(config, entryName) helper that returns true when the entry has a command field.

src/cli/commands/sessions.ts

  • connectAllFromConfig() partitions server names into "to connect" and "stdio skipped" unless options.stdio is true, prints a dim skip summary in human mode, emits a skipped array with reason: "stdio" in JSON mode, and throws a clear error (with --stdio remediation) when every entry is stdio.

src/cli/index.ts

  • Adds --stdio option to connect.
  • Extends the Stdio servers help section to document the new default-skip behavior and the --stdio opt-in.
  • Forwards opts.stdio to connectAllFromConfig().

test/unit/lib/config.test.ts

  • Unit tests for isStdioEntry() covering command-only, url-only, missing, and mixed configs.

Test plan

  • npm run lint passes
  • npm run build passes
  • npm run test:unit passes (559/559)
  • Manual check: mcpc connect <config-with-mixed-entries> skips stdio by default
  • Manual check: mcpc connect <config-with-mixed-entries> --stdio connects all
  • Manual check: mcpc connect <stdio-only-config> errors with remediation
  • Manual check: mcpc connect file:entry still works for stdio entries (no --stdio needed)
  • Manual check: --json output includes skipped entries with reason: "stdio"

https://claude.ai/code/session_0138fCGaEqxPbT7y2hWFAAC1


Generated by Claude Code

claude added 2 commits April 24, 2026 21:29
Stdio entries in MCP config files execute arbitrary local commands via
child_process.spawn(). To prevent supply-chain attacks through malicious
config files, `mcpc connect <config-file>` (bulk connect) now skips stdio
entries by default. Pass --stdio to opt in. Single-entry connects
(`mcpc connect file:entry`) are unaffected.

Isolated from #165 to make review and testing easier.

https://claude.ai/code/session_0138fCGaEqxPbT7y2hWFAAC1
@jancurn jancurn merged commit af680e5 into main Apr 24, 2026
6 checks passed
@jancurn jancurn deleted the claude/isolate-stdio-confirmation-naxrh branch April 24, 2026 21:50
jancurn pushed a commit that referenced this pull request Apr 24, 2026
…g-file connect

The --stdio gating from #201 only covered connectAllFromConfig. This extends
it to connectAllFromStandardConfigs / aggregateDiscoveredEntries so bare
`mcpc connect` also skips stdio entries by default.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd
jancurn added a commit that referenced this pull request Apr 28, 2026
)

* Auto-discover standard MCP config files on bare `mcpc connect`

Running `mcpc connect` with no arguments now scans the current directory
and the user's home dir for standard MCP config file locations (inspired
by https://www.withone.ai/docs/cli#mcp-server-installation) and connects
every server defined across them:

- Project scope (CWD): .mcp.json, .cursor/mcp.json, .vscode/mcp.json,
  .kiro/settings/mcp.json
- Global (home):       ~/.claude.json, ~/.cursor/mcp.json,
  ~/.vscode/mcp.json, ~/.codeium/windsurf/mcp_config.json,
  ~/.kiro/settings/mcp.json, plus Claude Desktop's platform-specific path

Entries with the same auto-generated session name across files are
deduplicated (project scope wins over global). Re-running the command
reuses existing sessions. Missing files and files without `mcpServers`
are silently skipped; invalid JSON is logged and skipped.

The existing parallel bulk-connect logic was extracted into a shared
helper (`bulkConnectEntries`) used by both `mcpc connect <config-file>`
and the new no-arg discovery path.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Add stdio filtering to auto-discovery path for consistency with config-file connect

The --stdio gating from #201 only covered connectAllFromConfig. This extends
it to connectAllFromStandardConfigs / aggregateDiscoveredEntries so bare
`mcpc connect` also skips stdio entries by default.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Add mcp.json (without dot prefix) to auto-discovery paths

Some projects use `mcp.json` rather than `.mcp.json` in the project root.
Include it in the standard discovery list right after `.mcp.json`.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Add mcp_config.json to project-level auto-discovery paths

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Auto-connect to mcp.apify.com when APIFY_API_TOKEN is set

When `mcpc connect` (auto-discovery) runs and the APIFY_API_TOKEN
environment variable is present, automatically connect to
https://mcp.apify.com as @apify with the token as a Bearer header.
Existing live @apify sessions are reused without restart.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Add VS Code app config path and support for "servers" key

VS Code stores MCP config at ~/Library/Application Support/Code/User/mcp.json
(macOS), %APPDATA%/Code/User/mcp.json (Windows), and ~/.config/Code/User/mcp.json
(Linux), using a "servers" key instead of "mcpServers". Discovery now checks
these paths and normalizes "servers" to "mcpServers" when parsing.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Update CHANGELOG for auto-discovery, APIFY_API_TOKEN, and VS Code servers key

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Redesign discovery output, fix loadConfig for VS Code "servers" key, remove labels

- loadConfig() now normalizes VS Code's "servers" key to "mcpServers",
  fixing "missing mcpServers field" errors for VS Code app configs
- Discovery output groups entries under their config file path, showing
  each entry with session name, target URL/command, and skip status
- Summary line shows "Connecting N servers. Skipped M stdio servers..."
- Removed redundant label field from ConfigCandidate, DiscoveredConfig,
  and all JSON output — the file path is sufficient

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

* Fix E2E test assertion for new discovery output format

The collision test checked for "skipping" but the new grouped output
uses "skipped (duplicate)" instead.

https://claude.ai/code/session_01LuMKCJPYJSU8GyqsrLveXd

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants