MCP (Model Context Protocol)
Read this when you connect external tool servers. Writing extensions → extensions.md.
Quick setup
Ink consumes tools from MCP servers over stdio (command) or
Streamable HTTP (url), so existing setups work unchanged:
// ~/.config/mcp/mcp.json (or ~/.agents/mcp.json, or <project>/.mcp.json)
{
"mcpServers": {
"zai-vision": {
"command": "npx",
"args": ["-y", "@z_ai/mcp-server"],
"env": { "Z_AI_API_KEY": "…" }
},
"tushare": {
// token in the URL — the env placeholder keeps it out of the file
"url": "https://api.tushare.pro/mcp/token=${TUSHARE_MCP_TOKEN}"
},
"github": {
"url": "https://api.githubcopilot.com/mcp/",
"headers": { "Authorization": "Bearer ${GITHUB_PAT}" }
}
}
}
Config discovery
Later files override earlier ones per server (whole entry):
~/.config/mcp/mcp.json~/.agents/mcp.json~/.agents/mcp/mcp.json<project>/.mcp.json<project>/mcp.json
The two project files are executable resources behind the trust gate —
an untrusted directory skips them with a note (ink --trust to enable).
Value expansion: ${VAR}, $env:VAR, and {env:VAR} placeholders work in
command/args/env and in url/headers. "disabled": true skips a
server (visible in /mcp).
Rules and limits
- Server keys must be lowercase: the composite tool name has to match
^[a-z][a-z0-9_-]{0,63}$. A mismatched key (tushareMcp) registers zero tools while/mcpstill says connected — rename it (tushare). - Every server tool registers flat as
<server>_<tool>(e.g.zai-vision_analyze_image) and is callable by the model like a built-in tool. urlmust be https (plain http only for loopback hosts); redirects are never followed — a token may ride the URL, and following one could leak it.- Connections start asynchronously at startup (npx cold starts can take a while); tools that connect while a run is in flight join at the next run boundary. A server that dies mid-session reconnects transparently on the next tool call; an expired HTTP session is re-initialized and the call retried once.
/mcpshows per-server status.INK_MCP=0or"mcp": {"enabled": false}in settings disables the module entirely. No config found = zero cost, nothing spawns, no requests are made.
Scope (deliberate)
Tools only. No OAuth (authenticate with a PAT or a URL token), no sampling
or elicitation, no resources/prompts surfaces, no per-call approval gates,
no cross-vendor config import (cursor/claude/windsurf), no mcp proxy tool
(flat registration until a server with ≥10 tools shows up). Each deferral
has a recorded trigger in the design archive.