odek has two-way Model Context Protocol support:
- odek as MCP server (
odek mcp) — other agents (Claude Code, Cursor) use odek's tools - odek as MCP client (config) — odek connects to external MCP servers and uses their tools
Start odek as an MCP server over stdio. This lets Claude Code, Cursor, and other MCP-compatible clients use odek's built-in tools.
odek mcpAdd to ~/.claude/claude_dotfiles/claude.json or your project's .claude/settings.json:
{
"mcpServers": {
"odek": {
"command": "odek",
"args": ["mcp"]
}
}
}For Cursor, add the same entry in Cursor Settings → MCP Servers.
| Tool | Description |
|---|---|
shell |
Run shell commands (with security classification) |
read_file |
Read files with line numbers and pagination |
write_file |
Write content to files (creates directories) |
search_files |
Search file contents or find files by name |
patch |
Find-and-replace edits with fuzzy matching |
browser |
Navigate web pages, take snapshots, click elements |
The delegate_tasks and memory tools are not exposed via MCP — they are
specific to odek's own agent loop.
odek mcp --sandboxAll shell commands run inside a Docker container with --cap-drop ALL,
--security-opt no-new-privileges, resource limits, and noexec tmpfs.
Same DangerousConfig as odek run. No TTY in MCP mode → non_interactive
fallback applies (default: allow). Configure per-class overrides in odek.json:
{
"dangerous": {
"non_interactive": "deny",
"classes": {
"network_egress": "deny",
"code_execution": "prompt"
}
}
}Stdio transport with JSON-RPC 2.0:
initialize— protocol handshake (protocolVersion: "2025-03-26")tools/list— returns all available tools with schemastools/call— invokes a tool with the given argumentsping— health check (returns empty object)initialized— notification
Logging goes to stderr; stdin/stdout are reserved for the MCP protocol.
odek can connect to external MCP servers and expose their tools to the agent
during odek run, odek repl, odek serve, and odek mcp.
Add mcp_servers to ~/.odek/config.json (global, operator-trusted) or odek.json
(project-level):
{
"mcp_servers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp"]
},
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
},
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"],
"env": {
"LOG_LEVEL": "debug"
}
}
}
}Each server is defined by:
command— the executable to runargs— optional command-line argumentsenv— optional environment variable overrides (empty string removes the variable)
Environment sanitisation. MCP server children receive only a minimal allowlist of safe variables (e.g.
PATH,HOME,LANG) plus the overrides fromenv. Keys matching secret patterns (*_API_KEY,*_TOKEN,*_SECRET,*_PASSWORD, etc.) are stripped even when listed inenv, so a compromised server cannot exfiltrate parent secrets. Pass authentication material via server-specific config files or command-line arguments instead of environment variables.
The format matches Claude Code's mcpServers config — any MCP server you use
with Claude Code can be added to odek's config.
Because mcp_servers in ./odek.json can execute arbitrary commands, odek
requires explicit approval for any server introduced by a project config
before it spawns the subprocess. Global servers from ~/.odek/config.json are
operator-trusted and do not require approval.
Approval methods:
- Interactive prompt — when running on a TTY, odek asks for each project
server:
Approve? [y/N]. ODEK_APPROVE_MCP=1— approve all project MCP servers for a single invocation. Useful in CI, scheduled jobs, or non-interactive use:ODEK_APPROVE_MCP=1 odek run "task"- Persisted approvals — approvals are stored in
~/.odek/mcp_approvals.json(0600) keyed by project directory + server name- command + args. If the config changes, you are prompted again.
If approval is required and cannot be obtained, odek aborts before spawning any MCP server.
After a project-level server is approved, each individual tool it advertises via
tools/list must also be approved before the agent can call it. This prevents a
server from quietly registering a high-risk or spoofed tool after its server
config was reviewed.
Tool approval uses the same methods as server approval:
- Interactive prompt — on a TTY, odek lists the discovered tools and asks which to approve.
ODEK_APPROVE_MCP=1— approves every tool from every project-level server for the invocation.- Persisted approvals — approved tools are stored in
~/.odek/mcp_tool_approvals.json(0600), keyed by project directory + server name + tool name. If a tool is renamed or a new tool appears, it must be approved again.
Tools from global servers (~/.odek/config.json) are operator-trusted and do
not require per-tool approval.
On startup, odek:
- Spawns each configured MCP server as a subprocess
- Performs the MCP handshake (
initialize) - Discovers all tools via
tools/list - Registers each tool as
<server_name>__<tool_name>(e.g.,playwright__navigate) - Forwards
tools/callrequests to the appropriate server - Cleans up all server processes on exit
Tools are prefixed with the server name to avoid collisions between servers:
playwright__navigate— from theplaywrightserverfetch__fetch— from thefetchservergithub__search_issues— from thegithubserver
Tool names must be ASCII letters, digits, underscores, or hyphens and no longer than 64 characters. Names that do not match this pattern, or that collide with odek's built-in tool names (even before prefixing), are rejected at startup with a warning.
Any server that implements the MCP stdio transport with tools/list and
tools/call. Common examples:
- Playwright MCP (
npx @playwright/mcp) — browser automation - Fetch MCP (
uvx mcp-server-fetch) — HTTP requests - GitHub MCP — repository management
- SQLite MCP — database queries
- Filesystem MCP — file operations
- Docker MCP — container management
MCP server processes are spawned when odek starts and killed when odek exits
(via defer). Each process gets its own stdin/stdout pipes — stderr from
MCP servers is shown in the odek console.
odek logs MCP server connections to stderr:
odek: connected MCP server "playwright" (5 tools)
odek: connected MCP server "fetch" (1 tool)
Errors during discovery are reported at startup — the server is skipped and odek continues with the remaining servers.
{
"mcp_servers": {
"my-server": {
"command": "command",
"args": ["arg1", "arg2"],
"env": {
"API_KEY": "${MY_API_KEY}",
"REMOVE_ME": ""
}
}
}
}