MCP — Model Context Protocol¶
Cortex ships three bundled MCP (Model Context Protocol) servers that give the agent access to remote machines, Cortex's own scheduling and cost systems, and Slack. This document explains what each server provides, how they are configured, and how to add third-party MCP servers.
What MCP is¶
MCP is an open protocol that lets LLM applications expose tools to agents through a standardized JSON-RPC interface over stdio or HTTP. Cortex uses MCP to bridge between the agent process (which has no direct access to agent-server internals) and the server's capabilities. MCP support varies by backend — see the feature matrix in backends.md.
Claude Code reads MCP server configurations from a JSON file and spawns each
server as a child process. The agent can then call MCP tools just like
built-in tools (Bash, Read, Edit, etc.), with the tool names prefixed by
mcp__<server-name>__.
Why Cortex ships its own MCP servers¶
Cortex's agent-server maintains state that the agent process cannot access directly: WebSocket connections to remote machines, the schedule database, cost records, the Slack API client, and execution registry. MCP servers serve as a controlled bridge — the agent calls an MCP tool, the MCP server talks to agent-server internals (via HTTP to the local webhook server on port 3001, or by reading shared files), and the result flows back to the agent.
The three bundled MCP servers¶
cortex-core¶
Exposes tools for interacting with remote machines. This is the only server loaded by thread/template sessions — thread agents get remote machine access but not Slack, cost, or schedule tools.
| Tool | Parameters | Description |
|---|---|---|
remote_bash |
device, command, timeout?, description?, run_in_background? |
Execute a shell command on a remote device via cortex-client |
remote_read |
device, file_path, offset?, limit? |
Read a file from a remote device (supports images and PDFs) |
remote_write |
device, file_path, content |
Write content to a file on a remote device |
remote_edit |
device, file_path, old_string, new_string, replace_all? |
Edit a file on a remote device by string replacement |
remote_glob |
device, pattern, path? |
Find files matching a glob pattern on a remote device |
remote_grep |
device, pattern, path?, glob?, type?, output_mode?, -A?, -B?, -C?, -i?, -n?, head_limit?, offset?, multiline? |
Search file contents on a remote device using ripgrep |
The server implementation is at
agent-server/src/domain/mcp/core-server.ts. Tools are implemented in
agent-server/src/domain/mcp/tools/task-ops.ts.
cortex-ext¶
Exposes Cortex management tools: scheduling, cost queries, execution tracking, Slack file upload, and context resolution. This server is only loaded by direct/user-initiated sessions — thread agents do not get these tools.
| Tool | Parameters | Description |
|---|---|---|
cortex_schedule_add |
type, message, interval?, time?, dayOfWeek?, delay?, target?, fallback?, profile?, preCheck?, channel? |
Create a scheduled task (interval, daily, weekly, or once) |
cortex_schedule_list |
limit? |
List all scheduled tasks with their status |
cortex_schedule_get |
id |
Look up a scheduled task by its 8-char hex ID |
cortex_schedule_remove |
id |
Delete a scheduled task (idempotent) |
cortex_schedule_pause |
id |
Pause a recurring scheduled task |
cortex_schedule_resume |
id |
Resume a paused scheduled task |
cost_query |
(none) | Query current cost: today/month spending, budget limits, remaining budget, API/plan split, source breakdown, token usage |
query_executions |
execution_id?, task_id?, status?, project?, limit? |
Query execution records — filter by status, project, or look up by ID |
cortex_context |
(none) | Return the current execution context: channel, sessionId, sessionName, threadId, profile, project, backend |
slack_send_file |
file_path, file_name?, title?, comment? |
Upload a local file to Slack |
The server implementation is at agent-server/src/domain/mcp/server.ts.
Individual tools are in agent-server/src/domain/mcp/tools/:
slack.js, cost.js, executions.js, context.js, schedule.js.
cortex-tui-bridge¶
Only loaded in TUI (terminal UI) mode. Replaces Claude Code's native
EnterPlanMode, ExitPlanMode, and AskUserQuestion tools with MCP
equivalents that route through Slack instead of the terminal.
| Tool | Description |
|---|---|
cortex_plan_enter |
Emits a reminder that the agent is in plan mode |
cortex_plan_exit |
Reads the plan file, sends to Slack for human approval, blocks until resolved |
cortex_ask_user |
Asks 1–4 questions via Slack modal, blocks until answered |
The server implementation is at agent-server/src/domain/mcp/tui-server.ts.
Tools are in agent-server/src/domain/mcp/tools/tui-plan.js and tui-ask.js.
MCP configuration files¶
Cortex auto-generates three MCP config files at startup (via
agent-server/src/core/config-generator.ts and the ensureMcpConfig() call
in agent-server/src/entry/startup-helpers.ts):
| File | Loaded by | Servers |
|---|---|---|
~/.cortex/config/mcp-config.json |
Direct/user-initiated sessions | cortex-core + cortex-ext |
~/.cortex/config/mcp-config-core.json |
Thread/template sessions | cortex-core only |
~/.cortex/config/mcp-config-tui.json |
TUI mode sessions | cortex-tui-bridge only |
Each file follows Claude Code's standard MCP config format:
{
"mcpServers": {
"cortex-core": {
"command": "node",
"args": ["/path/to/core-server.js"],
"cwd": "/path/to/cwd"
},
"cortex-ext": {
"command": "node",
"args": ["/path/to/server.js"],
"cwd": "/path/to/cwd"
}
}
}
The config files are regenerated on every agent-server startup. Manual edits
to them will be overwritten. To customize MCP configuration, modify the
generator in core/config-generator.ts or the profile/budget/schedule settings
that the tools read.
How the right config gets selected¶
In agent-adapter/claude/spawn-args.ts, the MCP config path is selected based
on session context:
- TUI mode: loads
mcp-config-tui.json - Print mode, user-initiated sessions: loads
mcp-config.json - Thread/template sessions: loads
mcp-config-core.json
The thread session override happens in the Claude adapter
(adapter.ts), which checks session.cortexContext.useCoreMcp. This field is
set by the thread executor to ensure thread agents only get remote machine
tools, not Slack, cost, or scheduling tools.
How MCP tools communicate with agent-server¶
MCP servers run as separate child processes. They cannot directly access agent-server in-process state (WebSocket connections, the schedule repo, the execution registry). Instead, they communicate through two paths:
-
HTTP loopback — remote machine tools (
remote_bash,remote_read, etc.) send HTTP POST tohttp://127.0.0.1:3001/webhook/remote-command. The webhook handler inagent-server/src/orchestration/routing/webhook.tsforwards the request toclient-manager.sendCommand(), which sends it over WebSocket to the remote device. -
Shared file access — schedule, cost, and execution tools read and write the shared data files in
~/.cortex/data/(schedules.json, costs.jsonl, executions.json) directly, using the same repository layer as the main server process.
Adding a third-party MCP server¶
To add a third-party MCP server (e.g., a database connector, a web search
tool, or a custom research tool), add it to ~/.cortex/config/mcp-config.json
(and mcp-config-core.json if thread agents should also have it):
{
"mcpServers": {
"cortex-core": { "command": "node", "args": ["..."], "cwd": "..." },
"cortex-ext": { "command": "node", "args": ["..."], "cwd": "..." },
"my-custom-server": {
"command": "python",
"args": ["/home/user/my-mcp-server/server.py"],
"env": { "API_KEY": "${MY_API_KEY}" }
}
}
}
Important: the config files are regenerated on every server restart. To
persist custom MCP server entries, you must modify the generator in
agent-server/src/core/config-generator.ts (the buildFullConfig() and/or
buildCoreConfig() functions) rather than editing the JSON files directly.
The type system already supports third-party MCP servers through the
AgentSpawnConfig.mcpServers field (per-backend McpServerConfig array), but
this field is not yet consumed by the adapters as of the current codebase. All
MCP configuration still flows through the --mcp-config CLI flag.
Permission model¶
MCP tools cross the trust boundary from the agent process into agent-server internals and remote machines. Cortex applies the following controls:
-
Tool availability — the agent's tool list (controlled per profile and per thread template) determines which MCP tools appear to the agent. Thread agents load only
cortex-core(no Slack, no cost, no scheduling). -
Claude Code's third-party MCP is disabled — the setting
ENABLE_CLAUDEAI_MCP_SERVERS: "false"in~/.cortex/.claude/settings.jsonprevents Claude from auto-discovering MCP servers from its own directory. Cortex exclusively manages MCP servers through its own config files. -
Bypass permissions — Claude Code is spawned with
--dangerously-skip-permissions --permission-mode bypassPermissions, meaning it won't prompt for each MCP tool call. Access control happens at the MCP tool implementation level and through the PreToolUse hook system. -
PreToolUse guards — the
tasks-yaml-guard.mjshook intercepts Edit/Write operations onTASKS.yamlfiles (including remote edits) and checks project locks. Thesensitive-file-edit.mjshook handles.claude/path protection. -
Network boundary — MCP tools that talk to remote machines go through the client-manager's WebSocket layer. The
machines.jsonregistry controls which devices are known. Only devices with an active WebSocket connection can receive commands.
Environment variables passed to MCP servers¶
The MCP server processes receive a subset of the agent server's environment:
| Variable | Source | Used by |
|---|---|---|
SLACK_CHANNEL |
Channel parameter at spawn time | cortex-ext (slack_send_file), tui-server |
SLACK_BOT_TOKEN |
process.env | cortex-ext |
CORTEX_SESSION_ID |
Session context | tui-server, context tools |
CORTEX_SESSION_NAME |
Session context | context tools |
CORTEX_THREAD_ID |
Thread context | context tools |
CORTEX_PROFILE |
Session context | context tools |
CORTEX_PROJECT |
Session context | context tools |
CORTEX_EXECUTION_ID |
Execution context | task lock hooks |
CORTEX_TUI_MODE |
Set to '1' in TUI mode |
tui-server |
CORTEX_CALLBACK_SOURCE |
Optional callback metadata | cortex-ext |
CORTEX_SCHEDULE_TASK_ID |
Optional schedule task ID | cortex-ext |
CORTEX_ROUTE_CONTEXT_FILE |
Per-turn context file path | cortex-ext (Codex routing) |
ANTHROPIC_BASE_URL |
Optional API base URL override | Model routing |
Security considerations¶
MCP tools give the agent the ability to execute shell commands on remote machines, read and write files, upload to Slack, and modify schedules. The security posture assumes:
- The
cortex-clientWebSocket port (3002) is not exposed to the public internet. Use Tailscale, a VPN, or localhost-only binding (see cross-machine.md for network topology options). - The webhook HTTP port (3001) is bound to
127.0.0.1only — MCP servers talk to it via loopback, not over the network. - The agent operates within the same blast-radius safety boundaries documented in safety-and-approvals.md. MCP tools cannot bypass the need-approval gating for high-privilege operations.