Field notes
2026-05-11 — external MCP via mcp.json
- Client-supplied MCP servers shipped. New
$SLAUDE_HOME/mcp.json(override path viaSLAUDE_MCP_CONFIGenv) declares external stdio/sse/http MCP servers in the same shape Claude Code's mcp.json uses. Loader issrc/config/mcp.ts:loadExternalMcp()— read once at boot insrc/gateway/slack/adapter.tsand spread into the resolver alongside the in-processslaude_slack+slaude_skillsservers. Restart slaude after editing the file; there is no hot-reload (deliberate — server lifetimes are tied to SDK Query lifetimes). - Shape:
{ "mcpServers": { "<name>": { command, args?, env? } | { type: "http" | "sse", url, headers? } } }. Stdio is implicit whencommandis present (matches Claude Code's mcp.json — notype: "stdio"required). HTTP/SSE require explicittype. ${VAR}substitution applied tocommand, every entry ofargs[], every value ofenv,url, every value ofheaders. Missing vars expand to empty string (POSIX shell semantics) so a malformed env doesn't crash the boot — typo-detection is the operator's job, not the loader's.- Reserved-name defence:
slaude_slackandslaude_skillsare dropped at load time with a warning so user config cannot shadow the in-process Slack output server (would deadlock the agent — only path to user-visible output). - Permission posture:
mcp__<external>__*tools are NOT auto-allowed byPermissionGate(onlymcp__slaude_slack__*plus read-onlymcp__slaude_skills__{list,read}_skill). External tool calls fall through to the standard Block Kit approve/deny prompt. "Always allow" still grants session-scoped auto-approval on first click. - Env propagation: stdio child processes inherit
process.env(Bun default). Loader does not whitelist — operators who care about secret isolation should set explicitenv: {…}on the server config. - Test file:
tests/config-mcp.test.tscovers missing file →{}, malformed JSON, missingmcpServersroot, stdio (implicit type + env+arg expansion), http (header expansion), sse, missing${VAR}→ empty, stdio without command, http without url, non-object entry, non-array args, reserved-name drop (both names),SLAUDE_MCP_CONFIGoverride. 14 tests; full suite 189 pass. New module at 100% func / 100% line.