You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Codex parity — the missing two halves of our MCP story.
Today we have half of what codex mcp ships:
deepseek mcp-server (in crates/tui/src/mcp_server.rs) exposes a curated set of individual tools (file_read, file_write, search, apply_patch, shell) over stdio. Useful, but it's not an agent. A caller can't say "drive a full DeepSeek turn for me" — they have to hand-orchestrate every step.
Client-side, there is no deepseek mcp add / list / get / remove. Users hand-edit ~/.deepseek/mcp.json. Adding a new MCP server takes a doc lookup and a JSON file open every time.
codex_tool_runner.rs::run_codex_tool_session — spawns a Tokio task that starts a thread via ThreadManager, drives the agent loop to completion, and streams every Event back as MCP notifications/message (with OutgoingNotificationMeta { request_id, thread_id } so the client can correlate). On completion it returns a CallToolResult whose structuredContent = { threadId, content } so the LLM can continue the conversation.
message_processor.rs registers two tools: codex (start a session) and codex-reply (continue an existing thread by thread_id). Approval requests (exec / patch) round-trip through exec_approval.rs / patch_approval.rs as MCP elicitations.
add supports both transports: stdio (positional command + --env KEY=VALUE) and streamable-HTTP (--url + --bearer-token-env-var).
Persists into ~/.codex/config.toml via ConfigEditsBuilder — we already have a config layer (crates/config) that can host the same edit surface.
Scope: split into phases
Phase A — agent-style server tool (mirror codex / codex-reply)
Define DeepseekToolCallParam in crates/tui/src/mcp_server.rs (or a new agent_tool.rs): prompt, model, profile, cwd, approval_mode, mode (Plan/Agent/YOLO — our analogue of Codex's sandbox enum), base_instructions, developer_instructions, optional config overrides. Mirror Codex field names where they map cleanly so existing MCP clients can swap with minimal change.
Register two tools in the stdio server's tools/list:
deepseek — start a new session, return a thread_id in structuredContent.
deepseek-reply — continue by thread_id + prompt.
Wire tools/call to spawn a Tokio task that drives core/engine.rs to turn-completion, streaming each Event to the caller as notifications/message with { request_id, thread_id } meta. Reuse runtime_threads.rs for the durable thread store so reply works across server restarts.
Approval requests round-trip as MCP elicitations (mirror exec_approval.rs / patch_approval.rs). Default approval mode is suggest; respect approval_mode: never for fully unattended use.
Cancellation: when the MCP request is cancelled, propagate via CancellationToken into the engine.
Tests: stdio fixture that lists tools, calls deepseek with a no-op prompt, asserts a thread_id comes back and notifications stream.
Phase B — deepseek mcp add/list/get/remove client surface
New Mcp(McpArgs) variant on the top-level Commands enum in crates/cli/src/lib.rs (separate from the existing McpServer server-mode variant — keep that for stdio).
Subcommands mirroring codex mcp:
deepseek mcp list [--json]
deepseek mcp get <name> [--json]
deepseek mcp add <name> (--url <URL> | -- <COMMAND>...) with --env KEY=VALUE (stdio) and --bearer-token-env-var <ENV> (HTTP)
deepseek mcp remove <name>
Persist into ~/.deepseek/mcp.json (existing format) via the config layer. Do not silently rewrite unrelated fields — preserve user formatting where feasible.
On add, validate the server starts (best-effort: spawn, list-tools, kill) so users get an immediate error instead of a silent broken entry. --no-validate to skip.
Surface in deepseek doctor already exists for individual MCP servers (doctor_check_mcp_server); ensure new entries flow through it.
Tests in crates/cli/tests/: round-trip add → list → get → remove against a tempdir ~/.deepseek.
Phase C — DX polish
deepseek mcp (no subcommand) prints the table of configured servers, like codex mcp does.
Document in docs/MCP.md how the agent tool lets another LLM (Claude Code, Cursor, etc.) drive a DeepSeek session — the headline use case.
Phase D — DeepSeek-unique extensions (optional, post-parity)
Expose mode (Plan / Agent / YOLO) as a first-class field in the agent tool — Codex collapses this into approval+sandbox, but our mode axis is more legible.
Per-call cycle_budget and provider overrides so a calling agent can say "reply with V4-Flash, single cycle" for cheap tool-use turns vs. "V4-Pro, no budget" for hard reasoning.
Acceptance (Phase A + B = the milestone bar)
deepseek mcp-server registers deepseek and deepseek-reply tools; an external MCP client (Claude Code) can drive a full DeepSeek session over stdio and receive streamed events.
deepseek mcp add github -- npx -y @modelcontextprotocol/server-github writes a valid entry to ~/.deepseek/mcp.json and deepseek mcp list shows it.
deepseek mcp remove github removes it cleanly.
Existing mcp-server tool surface (file_read/write/search/apply_patch/shell) keeps working — additive change.
Standard verification gates pass (cargo fmt, clippy -D warnings, cargo test --workspace --all-features --locked, parity gates).
Open questions
Naming: keep the server tool as deepseek / deepseek-reply for codex-mirror clarity, or deepseek_agent / deepseek_agent_reply to match our internal agent_* tool family? Lean toward the former — outside-facing name should match the brand.
Should mcp add accept a JSON blob (--json '{...}') for power users / scripting? Codex doesn't, but it'd be cheap to add.
Login/logout for OAuth MCP servers — Codex has a full flow (codex mcp login, scopes discovery, RMCP). Worth deferring to a follow-up issue unless someone needs Linear/Notion-style auth in 0.8.6.
References
crates/tui/src/mcp_server.rs — current stdio MCP server (tool-only, no agent).
crates/tui/src/runtime_threads.rs — durable thread store we'd reuse for deepseek-reply.
crates/cli/src/lib.rs:138 — Commands::McpServer (stdio mode); the new Commands::Mcp(McpArgs) lands next to it.
Pitch
Codex parity — the missing two halves of our MCP story.
Today we have half of what
codex mcpships:deepseek mcp-server(incrates/tui/src/mcp_server.rs) exposes a curated set of individual tools (file_read,file_write,search,apply_patch,shell) over stdio. Useful, but it's not an agent. A caller can't say "drive a full DeepSeek turn for me" — they have to hand-orchestrate every step.deepseek mcp add/list/get/remove. Users hand-edit~/.deepseek/mcp.json. Adding a new MCP server takes a doc lookup and a JSON file open every time.Codex nails both. We should mirror both.
Reference design (codex-main)
Server side —
codex-rs/mcp-server/src/:codex_tool_config.rs— definesCodexToolCallParam(prompt, model, profile, cwd, approval-policy, sandbox, base_instructions, developer_instructions, compact_prompt, config overrides) and thecodextool's JSON schema.codex_tool_runner.rs::run_codex_tool_session— spawns a Tokio task that starts a thread viaThreadManager, drives the agent loop to completion, and streams everyEventback as MCPnotifications/message(withOutgoingNotificationMeta { request_id, thread_id }so the client can correlate). On completion it returns aCallToolResultwhosestructuredContent = { threadId, content }so the LLM can continue the conversation.message_processor.rsregisters two tools:codex(start a session) andcodex-reply(continue an existing thread bythread_id). Approval requests (exec / patch) round-trip throughexec_approval.rs/patch_approval.rsas MCP elicitations.Client side —
codex-rs/cli/src/mcp_cmd.rs:list(with--json),get <name>(with--json),add <name> (--url <URL> | -- <COMMAND>...),remove <name>,login <name> [--scopes …],logout <name>.addsupports both transports: stdio (positional command +--env KEY=VALUE) and streamable-HTTP (--url+--bearer-token-env-var).~/.codex/config.tomlviaConfigEditsBuilder— we already have a config layer (crates/config) that can host the same edit surface.Scope: split into phases
Phase A — agent-style server tool (mirror
codex/codex-reply)DeepseekToolCallParamincrates/tui/src/mcp_server.rs(or a newagent_tool.rs):prompt,model,profile,cwd,approval_mode,mode(Plan/Agent/YOLO — our analogue of Codex's sandbox enum),base_instructions,developer_instructions, optionalconfigoverrides. Mirror Codex field names where they map cleanly so existing MCP clients can swap with minimal change.tools/list:deepseek— start a new session, return athread_idinstructuredContent.deepseek-reply— continue bythread_id+prompt.tools/callto spawn a Tokio task that drivescore/engine.rsto turn-completion, streaming eachEventto the caller asnotifications/messagewith{ request_id, thread_id }meta. Reuseruntime_threads.rsfor the durable thread store so reply works across server restarts.exec_approval.rs/patch_approval.rs). Default approval mode issuggest; respectapproval_mode: neverfor fully unattended use.CancellationTokeninto the engine.deepseekwith a no-op prompt, asserts athread_idcomes back and notifications stream.Phase B —
deepseek mcp add/list/get/removeclient surfaceMcp(McpArgs)variant on the top-levelCommandsenum incrates/cli/src/lib.rs(separate from the existingMcpServerserver-mode variant — keep that for stdio).codex mcp:deepseek mcp list [--json]deepseek mcp get <name> [--json]deepseek mcp add <name> (--url <URL> | -- <COMMAND>...)with--env KEY=VALUE(stdio) and--bearer-token-env-var <ENV>(HTTP)deepseek mcp remove <name>~/.deepseek/mcp.json(existing format) via the config layer. Do not silently rewrite unrelated fields — preserve user formatting where feasible.add, validate the server starts (best-effort: spawn, list-tools, kill) so users get an immediate error instead of a silent broken entry.--no-validateto skip.deepseek doctoralready exists for individual MCP servers (doctor_check_mcp_server); ensure new entries flow through it.crates/cli/tests/: round-trip add → list → get → remove against a tempdir~/.deepseek.Phase C — DX polish
deepseek mcp(no subcommand) prints the table of configured servers, likecodex mcpdoes.--helpexamples that copy/paste cleanly:docs/MCP.mdhow the agent tool lets another LLM (Claude Code, Cursor, etc.) drive a DeepSeek session — the headline use case.Phase D — DeepSeek-unique extensions (optional, post-parity)
cycle_budgetandprovideroverrides so a calling agent can say "reply with V4-Flash, single cycle" for cheap tool-use turns vs. "V4-Pro, no budget" for hard reasoning.Acceptance (Phase A + B = the milestone bar)
deepseek mcp-serverregistersdeepseekanddeepseek-replytools; an external MCP client (Claude Code) can drive a full DeepSeek session over stdio and receive streamed events.deepseek mcp add github -- npx -y @modelcontextprotocol/server-githubwrites a valid entry to~/.deepseek/mcp.jsonanddeepseek mcp listshows it.deepseek mcp remove githubremoves it cleanly.mcp-servertool surface (file_read/write/search/apply_patch/shell) keeps working — additive change.cargo fmt,clippy -D warnings,cargo test --workspace --all-features --locked, parity gates).Open questions
deepseek/deepseek-replyfor codex-mirror clarity, ordeepseek_agent/deepseek_agent_replyto match our internalagent_*tool family? Lean toward the former — outside-facing name should match the brand.mcp addaccept a JSON blob (--json '{...}') for power users / scripting? Codex doesn't, but it'd be cheap to add.codex mcp login, scopes discovery, RMCP). Worth deferring to a follow-up issue unless someone needs Linear/Notion-style auth in 0.8.6.References
crates/tui/src/mcp_server.rs— current stdio MCP server (tool-only, no agent).crates/tui/src/runtime_threads.rs— durable thread store we'd reuse fordeepseek-reply.crates/cli/src/lib.rs:138—Commands::McpServer(stdio mode); the newCommands::Mcp(McpArgs)lands next to it.codex-rs/mcp-server/src/{codex_tool_config,codex_tool_runner,message_processor}.rs,codex-rs/cli/src/mcp_cmd.rs.