Skip stdio config entries by default in bulk connect, add --stdio flag#201
Merged
Skip stdio config entries by default in bulk connect, add --stdio flag#201
--stdio flag#201Conversation
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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Isolated from #165 to make review and testing easier. This PR only contains the
--stdiosafety gate for bulkmcpc connect <config-file>operations. The auto-discovery feature (mcpc connectwith 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
--stdioopt-in to execute stdio entries.Behavior
mcpc connect <config-file>— stdio entries are skipped by default with achalk.dimmessage listing what was skipped and how to include them. Pass--stdioto include stdio entries.mcpc connect file:entry— single-entry connects are not affected (explicit opt-in per entry).--stdiois not passed, a clear error with remediation is shown.skippedwithreason: "stdio".Changes
src/lib/config.tsisStdioEntry(config, entryName)helper that returns true when the entry has acommandfield.src/cli/commands/sessions.tsconnectAllFromConfig()partitions server names into "to connect" and "stdio skipped" unlessoptions.stdiois true, prints a dim skip summary in human mode, emits askippedarray withreason: "stdio"in JSON mode, and throws a clear error (with--stdioremediation) when every entry is stdio.src/cli/index.ts--stdiooption toconnect.Stdio servershelp section to document the new default-skip behavior and the--stdioopt-in.opts.stdiotoconnectAllFromConfig().test/unit/lib/config.test.tsisStdioEntry()covering command-only, url-only, missing, and mixed configs.Test plan
npm run lintpassesnpm run buildpassesnpm run test:unitpasses (559/559)mcpc connect <config-with-mixed-entries>skips stdio by defaultmcpc connect <config-with-mixed-entries> --stdioconnects allmcpc connect <stdio-only-config>errors with remediationmcpc connect file:entrystill works for stdio entries (no--stdioneeded)--jsonoutput includesskippedentries withreason: "stdio"https://claude.ai/code/session_0138fCGaEqxPbT7y2hWFAAC1
Generated by Claude Code