deepseek-web-retrieval 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +187 -1
  2. package/README.md +13 -9
  3. package/dist/cli.js +4228 -178
  4. package/docs/adr/0001-refuse-drift-between-plan-and-apply.md +29 -0
  5. package/docs/agents/codex.md +193 -0
  6. package/docs/agents/domain.md +51 -0
  7. package/docs/agents/issue-tracker.md +45 -0
  8. package/docs/{opencode-v2.md → agents/opencode-v2.md} +30 -7
  9. package/docs/{pi.md → agents/pi.md} +35 -7
  10. package/docs/agents/triage-labels.md +15 -0
  11. package/docs/design/installer-design.md +184 -0
  12. package/docs/hosts.jsonc +59 -33
  13. package/docs/integration.md +45 -52
  14. package/docs/research/control-matrix.md +257 -0
  15. package/docs/{mcp-compatibility.md → research/mcp-compatibility.md} +39 -108
  16. package/package.json +5 -3
  17. package/src/core/auth.ts +1 -1
  18. package/src/core/client.ts +42 -249
  19. package/src/core/constants.ts +5 -0
  20. package/src/core/descriptions.ts +19 -0
  21. package/src/core/format.ts +31 -1
  22. package/src/core/jsonc.ts +16 -0
  23. package/src/core/options.ts +2 -3
  24. package/src/core/search.ts +5 -7
  25. package/src/core/transport.ts +253 -0
  26. package/src/core/types.ts +13 -11
  27. package/src/installer/apply.ts +176 -0
  28. package/src/installer/cli.ts +215 -0
  29. package/src/installer/detect.ts +85 -0
  30. package/src/installer/formats/index.ts +58 -0
  31. package/src/installer/formats/json.ts +151 -0
  32. package/src/installer/formats/rules.ts +62 -0
  33. package/src/installer/formats/toml.ts +163 -0
  34. package/src/installer/formats/value.ts +57 -0
  35. package/src/installer/hosts/codex.ts +128 -0
  36. package/src/installer/hosts/index.ts +134 -0
  37. package/src/installer/hosts/opencode.ts +118 -0
  38. package/src/installer/hosts/pi.ts +115 -0
  39. package/src/installer/hosts/shared.ts +31 -0
  40. package/src/installer/paths.ts +18 -0
  41. package/src/installer/render.ts +62 -0
  42. package/src/installer/revert.ts +61 -0
  43. package/src/installer/rulesContent.ts +32 -0
  44. package/src/installer/state.ts +63 -0
  45. package/src/installer/types.ts +126 -0
  46. package/src/installer/uninstall.ts +33 -0
  47. package/src/mcp/auth.ts +2 -1
  48. package/src/mcp/cli.ts +21 -5
  49. package/src/mcp/config.ts +70 -27
  50. package/src/mcp/server.ts +81 -65
  51. package/src/opencode/auth.ts +3 -2
  52. package/src/opencode/plugin.ts +93 -56
  53. package/src/mcp/format.ts +0 -31
@@ -0,0 +1,257 @@
1
+ # Control levels across hosts
2
+
3
+ This note answers one question: for each host in the [support matrix](../integration.md), how
4
+ strongly can a user steer when the DeepSeek tools are called — optionally available,
5
+ preferentially used, or forcibly routed — independently for search and fetch? It is also
6
+ the per-host reference for setup facts: MCP registration, rules files, built-in web
7
+ competitors, and their kill switches. [integration.md](../integration.md) keeps the mechanism
8
+ taxonomy and host-support matrix; [mcp-compatibility.md](mcp-compatibility.md) keeps the
9
+ protocol research and its evidence.
10
+
11
+ **Research baseline:** 2026-10-20, using the same version locks as
12
+ [hosts.jsonc](../hosts.jsonc), the single source of truth for host facts. Open-source rows are
13
+ verified at exact git tags, npm tarballs, or binary analysis; proprietary rows from official
14
+ docs and changelogs at the locked versions. Version mentions inside the per-host sections
15
+ and the generated `key` strings are research-provenance anchors verified at the lock, not
16
+ restatements of it; they are re-verified on a baseline bump (see the drift list at the end).
17
+ The matrix below is generated — edit
18
+ hosts.jsonc, then run `bun run docs:matrix`.
19
+
20
+ ## Tiers
21
+
22
+ | Tier | Meaning | Determinism |
23
+ | --- | --- | --- |
24
+ | Optional | Tools are declared to the model with no preference guidance; the model picks freely among available tools. | None |
25
+ | Preferred | Prompt-level rules (instruction files, system-prompt additions) steer the model toward the tools. | Probabilistic |
26
+ | Forced | Routing is deterministic **relative to the built-in competitor**; other web-capable MCP servers or a higher configuration layer can still break it (reading notes below). Three flavors: **replacement** (the built-in tool's implementation is swapped), **exclusion** (the built-in competitor is denied or disabled so the DeepSeek path is the only one), **de-facto** (the host ships no built-in web tool). | Deterministic (conditional) |
27
+
28
+ ## Matrix
29
+
30
+ <!-- generated: control-matrix — edit docs/hosts.jsonc, then run `bun run docs:matrix` -->
31
+
32
+ | Host | Capability | Optional | Preferred | Forced | Mechanism |
33
+ | --- | --- | --- | --- | --- | --- |
34
+ | Cline | Search | Yes | Yes | Yes | De-facto — no built-in web-search tool at 0.0.13 (binary-verified) |
35
+ | Cline | Fetch | Yes | Yes | Yes | Exclusion — `disabledTools` in `~/.cline/data/settings/global-settings.json` |
36
+ | Codex | Search | Yes | Yes | Yes | Exclusion — `web_search = "disabled"` (top-level config.toml) |
37
+ | Codex | Fetch | Yes | Yes | Yes | De-facto — no built-in fetch tool at 0.163.0 |
38
+ | OpenCode | Search | n/a | n/a | Yes | Replacement — `websearch.provider: "deepseek"` or plugin `setDefaultWebsearch` |
39
+ | OpenCode | Fetch | Yes | Yes | Yes | Replacement — `fetchOverrideWebfetch: true` |
40
+ | Pi | Search | Yes | Yes | Yes | De-facto — no built-in web tool at 1.3.0 (source-verified) |
41
+ | Pi | Fetch | Yes | Yes | Yes | De-facto — no built-in web tool at 1.3.0 (source-verified) |
42
+ | Claude Code | Search | Yes | Yes | Yes | Exclusion — `permissions.deny: ["WebSearch"]` removes the tool from context |
43
+ | Claude Code | Fetch | Yes | Yes | Yes | Exclusion — `permissions.deny: ["WebFetch"]`, or `CLAUDE_CODE_DISABLE_WEB_FETCH=1` |
44
+ | Cursor | Search | Yes | Yes | No | — |
45
+ | Cursor | Fetch | Yes | Yes | Yes | Exclusion — `permissions.deny: ["WebFetch(*)"]` |
46
+ | Devin | Search | Yes | Yes | Yes | Exclusion — `disabled_tools` / `permissions.deny` in config.json |
47
+ | Devin | Fetch | Yes | Yes | Yes | Exclusion — `disabled_tools` / `permissions.deny` in config.json |
48
+ | GitHub Copilot | Search | Yes | Yes | Yes | Exclusion — `githubMcpTools` settings (competitor ships via the bundled GitHub MCP server) |
49
+ | GitHub Copilot | Fetch | Yes | Yes | Yes | Exclusion — `--deny-tool web_fetch` / `--excluded-tools` (session flags) |
50
+
51
+ <!-- /generated: control-matrix -->
52
+
53
+ Reading notes:
54
+
55
+ - `n/a` marks a structurally unreachable tier, not missing research: OpenCode's search
56
+ provider is host-level config, not a model-selectable tool, so the model never chooses
57
+ between engines — the only choice is replacement on or off.
58
+ - A `De-facto` Forced flavor needs no config: the host ships no built-in competitor, so the
59
+ registered tools are the only web path.
60
+ - Cursor's search row is the one Forced-tier gap in the matrix: no documented deny token
61
+ exists for its built-in web search.
62
+ - An `Exclusion` flavor forces routing **relative to the built-in competitor only**. If
63
+ other web-capable MCP servers are already registered, they stay on the field and
64
+ routing is not forced until they are excluded too; higher configuration layers
65
+ (managed, enterprise, system) can also outrank the kill switch. Install-time handling
66
+ of both conditions is specified in the
67
+ [installer design](../design/installer-design.md).
68
+
69
+ ## Per-host reference
70
+
71
+ One section per host, in hosts.jsonc order. Each carries what an install needs beyond the
72
+ matrix: the built-in competitors, their kill switches, how the MCP server is registered,
73
+ and which rules files steer preference. The `init` CLI implements these tiers for
74
+ OpenCode, Pi, and Codex (see [installer design](../design/installer-design.md)). Config
75
+ paths imply the available scopes; keys locked to a single scope are enumerated in the
76
+ [installer design](../design/installer-design.md#scope).
77
+
78
+ ### Cline
79
+
80
+ - **Positioning** — VSCode-extension agent with an experimental lightweight CLI (`clite`,
81
+ built on the Cline SDKs). Apache-2.0. MCP plus CLI/SDK custom tools; neither replaces the
82
+ built-in `fetch_web_content`. Current docs.cline.bot describes the newer 3.x `cline`
83
+ binary — the lock is 0.0.13 `clite`, and everything here is verified against that binary.
84
+ - **Built-in web tools** — `fetch_web_content` (fetch a URL and analyze it with a prompt);
85
+ no built-in web search (the binary's `web_search` strings are Bedrock provider tool
86
+ versions). Kill switch: `"disabledTools": ["fetch_web_content"]` in
87
+ `~/.cline/data/settings/global-settings.json` (path overridable via
88
+ `CLINE_GLOBAL_SETTINGS_PATH`); a disabled tool is dropped from the available set.
89
+ `--yolo` mode also deactivates web fetch.
90
+ - **MCP registration** — `~/.cline/settings/cline_mcp_settings.json`
91
+ (`CLINE_MCP_SETTINGS_PATH`), written by the `clite mcp` wizard in a nested form:
92
+ `mcpServers.<name>.transport` with `type` (`stdio` | `sse` | `streamableHttp`) plus
93
+ `command`/`args`/`env`, `disabled`, and `autoApprove`. Negotiates `2024-11-05` — the
94
+ protocol floor of the matrix; treat it as text-content-blocks-only.
95
+ - **Rules** — `.clinerules` (file or directory) and `.cline/rules/` plus `AGENTS.md` at
96
+ project scope; `~/.cline/rules` and `~/Documents/Cline/Rules` at user scope — all
97
+ verified inside the 0.0.13 binary.
98
+
99
+ ### Codex
100
+
101
+ - **Positioning** — OpenAI's official Rust CLI. Apache-2.0. MCP is the only integration
102
+ path.
103
+ - **Built-in web tools** — a native Responses `web_search` tool. The default mode is
104
+ `cached` (an OpenAI-maintained index, no external web access — the competitor exists
105
+ silently by default); `live` requires opt-in (`--search`, `web_search = "live"`, or a
106
+ full-access sandbox). No built-in fetch tool. Kill switch: top-level
107
+ `web_search = "disabled"` in `~/.codex/config.toml`. Trap: the `[tools] web_search =
108
+ <bool>` form parses but discards the value at 0.163.0 — a silent no-op
109
+ ([config source at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/config_toml.rs)).
110
+ - **MCP registration** — `~/.codex/config.toml` `[mcp_servers.<name>]`: stdio
111
+ `command`/`args`/`env`/`env_vars`; `startup_timeout_sec` (10 s), `tool_timeout_sec`
112
+ (60 s); `enabled_tools`/`disabled_tools`, per-tool approval modes, and output limits.
113
+ stdio children do not inherit the parent environment (only `HOME`, `PATH`, and explicit
114
+ `env`), so `DEEPSEEK_API_KEY` must be passed explicitly. When a tool result has
115
+ `structuredContent`, Codex replaces the content blocks with the serialized JSON. No SSE.
116
+ - **Rules** — `~/.codex/AGENTS.md` (with `AGENTS.override.md` preferred) at user scope;
117
+ every `AGENTS.md` from the project root down to the cwd, concatenated root→cwd.
118
+ Extensible via `project_doc_fallback_filenames` and `developer_instructions`
119
+ ([agents_md.rs at rust-v0.163.0](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/core/src/agents_md.rs)).
120
+
121
+ ### OpenCode
122
+
123
+ - **Positioning** — the only host with both a native websearch provider and a native fetch
124
+ override; the shipped adapter uses them, not MCP. See [OpenCode v2](../agents/opencode-v2.md).
125
+ - **Built-in web tools** — `websearch` (bundled providers: exa, firecrawl, parallel,
126
+ tavily, tinyfish, or `"random"`) and `webfetch`. `"websearch": false` removes the search
127
+ tool from model requests entirely; `webfetch` has no disable config key at 2.0.32 — the
128
+ deterministic paths are a permissions deny (`action: "webfetch"`) or a plugin
129
+ tool-transform removal, the latter being what `fetchOverrideWebfetch` does.
130
+ - **MCP registration** — out of scope for this host: the shipped path is the plugin
131
+ adapter, and OpenCode's MCP support is not part of it.
132
+ - **Rules** — `AGENTS.md` only (no CLAUDE.md fallback in v2): global
133
+ `~/.config/opencode/AGENTS.md`, then project files from the workspace toward home,
134
+ nested files injected when the agent reads into that subtree. The `instructions` config
135
+ key adds files, globs, or URLs ([docs](https://opencode.ai/v2/docs/instructions)).
136
+
137
+ ### Pi
138
+
139
+ - **Positioning** — minimal, fully customizable agent (earendil-works). MIT. MCP server
140
+ plus a TypeScript extension API. See [Pi](../agents/pi.md).
141
+ - **Built-in web tools** — none at 1.3.0. The built-in set is exactly `bash, edit, find,
142
+ grep, ls, powershell, read, write` (default-active: `read, bash, edit, write`); web
143
+ search/fetch arrive via MCP or extensions
144
+ ([tools index at v1.3.0](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/src/core/tools/index.ts)).
145
+ - **MCP registration** — `~/.pi/agent/mcp.json` or `.pi/mcp.json`: stdio
146
+ `command`/`args`/`env`/`cwd`, HTTP `url`/`headers`, plus `timeout`, `enabled`,
147
+ `exposure`. MCP tools are hidden from the model by default
148
+ (`exposure: "codemode"`); `"exposure": "direct"` declares them like built-ins — the
149
+ prerequisite for every tier. SSE is rejected. Text results over 20 KB are
150
+ middle-truncated with the full text saved to a file, and the per-request default
151
+ timeout is 60 s. Pi is content-first for the model, with a `structuredContent`
152
+ fallback used only when a result has no content blocks — the one open-source host that
153
+ touches `structuredContent` at all — and a re-declared (not validated) tool
154
+ `outputSchema`.
155
+ - **Rules** — `AGENTS.md`/`CLAUDE.md` context files from the agent dir, the working
156
+ directory, and its parents; `SYSTEM.md` replaces the system prompt and `APPEND_SYSTEM.md`
157
+ adds to it; extensions can replace the whole prompt via `before_agent_start`
158
+ ([configuration.md at v1.3.0](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/docs/configuration.md)).
159
+
160
+ ### Claude Code
161
+
162
+ - **Positioning** — Anthropic's official CLI. Proprietary. MCP adds tools; built-ins are
163
+ not replaceable.
164
+ - **Built-in web tools** — `WebSearch` and `WebFetch`. Kill switch: bare deny rules —
165
+ `"permissions": {"deny": ["WebSearch", "WebFetch"]}` — remove the tools from the model's
166
+ context entirely; deny outranks allow at every settings level and cannot be carved out.
167
+ `--disallowedTools` is the flag form. `CLAUDE_CODE_DISABLE_WEB_FETCH=1` (2.1.285+) kills
168
+ WebFetch only; there is no env equivalent for WebSearch
169
+ ([tools](https://code.claude.com/docs/en/tools),
170
+ [permissions](https://code.claude.com/docs/en/permissions)).
171
+ - **MCP registration** — `.mcp.json` (`mcpServers` with `command`/`args`/`env`, or
172
+ `type: "http"` + `url`); `${VAR}` expansion in `command`/`args`/`env`/`url`/`headers`.
173
+ Tool permission rules use `mcp__<server>__<tool>`. Tool descriptions are capped at 4,096
174
+ chars (2.1.296+) and tool output at 25k tokens by default (`MAX_MCP_OUTPUT_TOKENS`),
175
+ with oversized text saved to a file; 16 MiB message cap on HTTP transports.
176
+ - **Rules** — `CLAUDE.md` hierarchy (managed → user `~/.claude/CLAUDE.md` → project →
177
+ `CLAUDE.local.md`) with `@import`; `AGENTS.md` is read instead only when no CLAUDE.md
178
+ exists anywhere above the cwd (since 2.1.277)
179
+ ([memory](https://code.claude.com/docs/en/memory)).
180
+
181
+ ### Cursor
182
+
183
+ - **Positioning** — AI-first editor plus a same-family CLI. Proprietary. MCP is the CLI
184
+ path.
185
+ - **Built-in web tools** — web search and `WebFetch`. Fetch kill switch:
186
+ `"permissions.deny": ["WebFetch(*)"]` in `~/.cursor/cli-config.json` (global) or
187
+ `.cursor/cli.json` (project — only `permissions` is project-configurable); deny wins
188
+ over allow. Web search has no documented deny token; the only control is
189
+ `autoAcceptWebSearch` (a per-call approval prompt, not a hard deny). This is the
190
+ matrix's one Forced-tier gap
191
+ ([CLI permissions](https://cursor.com/docs/cli/reference/permissions),
192
+ [changelog](https://cursor.com/docs/cli/changelog)).
193
+ - **MCP registration** — the same `mcp.json` servers as the editor (`.cursor/mcp.json` or
194
+ `~/.cursor/mcp.json`): `command`/`args`/`env` for stdio, `url`/`headers` for remote;
195
+ `${env:NAME}` interpolation. MCP tools prompt for approval; `--approve-mcps` bypasses,
196
+ and global-scope servers have been auto-approved since April 2026.
197
+ - **Rules** — `.cursor/rules/*.mdc` (with `description`/`globs`/`alwaysApply` frontmatter —
198
+ a plain `.md` file there is ignored), `AGENTS.md` at the root and in subdirectories, and
199
+ `CLAUDE.md`; "The CLI agent supports the same rules system as the editor"
200
+ ([CLI using](https://cursor.com/docs/cli/using)).
201
+
202
+ ### Devin
203
+
204
+ - **Positioning** — Cognition's autonomous-agent CLI. Proprietary. Plugins bundle skills,
205
+ rules, hooks, and MCP servers — not arbitrary custom tools — so MCP is the tool path.
206
+ - **Built-in web tools** — `web_search` (v2026.5.6-1) and `webfetch` (v2026.5.26-0). Kill
207
+ switch: `"disabled_tools": ["webfetch", "web_search"]` in user `config.json`, and
208
+ `web_search` is accepted as a tool name in `permissions.deny`/`ask`/`allow` (both
209
+ changelog-documented at v3000.10.21, not yet on the reference pages); PreToolUse hooks
210
+ block calls by exiting with code 2; an enterprise "Enable Web Search" team setting
211
+ exists ([changelog](https://docs.devin.ai/cli/changelog)).
212
+ - **MCP registration** — `.devin/mcp_config.local.json` (default),
213
+ `.devin/mcp_config.json`, or `~/.config/devin/mcp_config.json`, all with the same
214
+ `mcpServers` shape; `devin mcp add <name> -- <cmd>` / `<URL>`. MCP tools prompt for
215
+ approval by default; `mcp__server__tool` allow/deny patterns in `permissions`.
216
+ - **Rules** — `AGENTS.md` (root, nested, and global `~/.config/devin/AGENTS.md`),
217
+ `AGENTS.local.md`, `.devin/rules/*.md` with `trigger` frontmatter,
218
+ `.devin/global_rules.md`, and plugin-shipped rules; imports other tools' rules via
219
+ `read_config_from` ([rules](https://docs.devin.ai/cli/extensibility/rules)).
220
+
221
+ ### GitHub Copilot
222
+
223
+ - **Positioning** — GitHub's official CLI. Proprietary. MCP servers, optionally bundled in
224
+ plugins.
225
+ - **Built-in web tools** — `web_fetch` (since 0.0.374) and `web_search` via the bundled
226
+ GitHub MCP server (which exposes only that tool since 1.0.57). Kill switch, session
227
+ scoped: `--deny-tool web_fetch,web_search` or `--excluded-tools` — the docs' own example
228
+ for avoiding web search entirely; deny wins even under `--allow-all`. Persistent:
229
+ `web_search` via `githubMcpToolsets`/`githubMcpTools` settings, and
230
+ `network.allowOutbound: false` blocks fetch egress at the network layer; a persistent
231
+ key for the built-in `web_fetch` itself is unconfirmed at 1.0.98
232
+ ([allowing tools](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools),
233
+ [changelog](https://github.com/github/copilot-cli/blob/main/changelog.md)).
234
+ - **MCP registration** — `~/.copilot/mcp-config.json` or project `.mcp.json`; stdio
235
+ entries use `"type": "local"` plus `command`/`args`/`env`; a per-server `tools` list
236
+ gates which tools are exposed — per-tool control at registration time.
237
+ - **Rules** — `~/.copilot/copilot-instructions.md` (user),
238
+ `.github/copilot-instructions.md` (repo) and `.github/instructions/**/*.instructions.md`
239
+ (path-scoped via `applyTo` globs); `AGENTS.md`/`CLAUDE.md` discovery (changelog-dated
240
+ ≤1.0.86; `GEMINI.md` could not be dated to the lock);
241
+ `COPILOT_CUSTOM_INSTRUCTIONS_DIRS` adds directories
242
+ ([custom instructions](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-custom-instructions)).
243
+
244
+ ## Cross-cutting observations
245
+
246
+ - **AGENTS.md is the de-facto rules standard.** Seven of the eight hosts read it
247
+ natively (Codex, Cline, Cursor, Devin, Copilot, Pi, OpenCode); Claude Code reads it as
248
+ a fallback. One rules file works nearly everywhere; the exception: OpenCode v2 has no
249
+ CLAUDE.md fallback.
250
+ - **Replacement is exclusive to native extension points** — only OpenCode. Exclusion is
251
+ the general forced path on MCP hosts. The two structural limits: OpenCode search has no
252
+ middle tier, and Cursor search cannot be forced at all.
253
+ - **Version drift to re-verify on the next baseline pass:** Cline's docs describe the 3.x
254
+ `cline` binary while the lock is 0.0.13 `clite`; Codex's config docs have moved and
255
+ describe a newer release; Copilot's `GEMINI.md` support could not be changelog-dated to
256
+ ≤1.0.98. Protocol-revision evidence for every host lives in
257
+ [mcp-compatibility.md](mcp-compatibility.md).
@@ -1,18 +1,18 @@
1
1
  # MCP compatibility across hosts
2
2
 
3
- This note answers one question for the planned MCP server: do the hosts in the
4
- [support matrix](integration.md) speak the same MCP protocol standard? Short answer: they all
3
+ This note answers one question for the shipped MCP server: do the hosts in the
4
+ [support matrix](../integration.md) speak the same MCP protocol standard? Short answer: they all
5
5
  speak MCP, but not the same revision. MCP has split into two eras, hosts negotiate different
6
6
  revisions, and one dual-era server covers them all.
7
7
 
8
- The nine MCP-capable hosts in the matrix span **four different negotiated revisions**:
9
- `2024-11-05` (Cline), `2025-06-18` (Codex, Gemini), `2025-11-25` (Continue, Pi), and
8
+ The seven MCP-capable hosts in the matrix span **four different negotiated revisions**:
9
+ `2024-11-05` (Cline), `2025-06-18` (Codex), `2025-11-25` (Pi), and
10
10
  `2026-07-28` (Claude Code, Devin, GitHub Copilot) — plus Cursor, whose revision no primary
11
11
  source pins. OpenCode is out of scope here: its shipped integration is the
12
- [native plugin adapter](opencode-v2.md), not MCP.
12
+ [native plugin adapter](../agents/opencode-v2.md), not MCP.
13
13
 
14
14
  **Research baseline:** 2026-10-19, using the same version locks as the host support matrix in
15
- [integration.md](integration.md). Claims are cited to primary sources: the MCP specification,
15
+ [integration.md](../integration.md). Claims are cited to primary sources: the MCP specification,
16
16
  official host docs and changelogs, npm registry manifests, and host source code at the locked
17
17
  versions.
18
18
 
@@ -74,87 +74,28 @@ Two release lines of the official TypeScript SDK ([docs](https://github.com/mode
74
74
 
75
75
  ## What each host supports
76
76
 
77
- | Host | Version | Negotiated revision | Transports | Evidence |
78
- | --- | --- | --- | --- | --- |
79
- | Cline | 0.0.13 | `2024-11-05` | stdio, Streamable HTTP, SSE | Custom client (no official SDK); `protocolVersion "2024-11-05"` extracted from the 0.0.13 platform binary; source repo not public |
80
- | Codex | 0.163.0 | `2025-06-18`; `mcp_2026_07_28` feature flag opts into `2026-07-28` | stdio, Streamable HTTP (no SSE) | Git tag `rust-v0.163.0`: rmcp 3.5.1 pinned; initialize sends `V_2025_06_18` |
81
- | Continue | 1.5.47 | `2025-11-25` | stdio, Streamable HTTP, SSE | 1.5.47 npm tarball: bundled TS SDK ≥ 1.24.1 (contains `2025-11-25` constants); no git tag exists |
82
- | Gemini | 0.64.0 | `2025-06-18` | stdio, Streamable HTTP, SSE | Git tag `v0.64.0`: `@modelcontextprotocol/sdk` 1.23.0 pinned in package.json |
83
- | Pi | 1.3.0 | `2025-11-25` | stdio, Streamable HTTP (SSE rejected) | Git tag `v1.3.0`: own `@earendil-works/pi-mcp` client, `LATEST_PROTOCOL_VERSION "2025-11-25"` |
84
- | Claude Code | 2.1.303 | `2026-07-28` by default (`MCP_PROTOCOL_NEGOTIATION=legacy` opt-out) | stdio, Streamable HTTP, SSE, ws | Changelog 2.1.296+: "negotiate MCP protocol version 2026-07-28 by default"; docs: TS SDK 2.0 runtime |
85
- | Cursor | 2026.10.08 | Unpinnable from primary sources (docs show ≥ `2025-06-18` features) | stdio, Streamable HTTP, SSE | Docs feature set only; no revision stated in docs or changelog |
86
- | Devin | 3000.11.92 | `2026-07-28` | stdio, Streamable HTTP (SSE fallback), SSE | Changelog for 3000.11.92 itself: "Support for MCP protocol revision 2026-07-28" |
87
- | GitHub Copilot | 1.0.98 | `2026-07-28` | stdio (`type: "local"`), Streamable HTTP, SSE | Changelog 1.0.81: "Ship MCP 2026-07-28 support to CLI, SDK, IDE, and in-memory clients" |
88
-
89
- Open-source rows are verified at the exact locked versions (git tag, npm tarball, or binary
90
- analysis); proprietary rows are verified from official docs and changelogs at the locked
91
- versions. All nine support stdio and Streamable HTTP; legacy SSE is never required (and Codex
92
- and Pi reject it).
93
-
94
- ### Open-source hosts
95
-
96
- - **Cline** — Custom MCP client, no official SDK. Config at 0.0.13:
97
- `~/.cline/settings/cline_mcp_settings.json` (override with `CLINE_MCP_SETTINGS_PATH`),
98
- written by the `clite mcp` wizard in a nested form: `mcpServers.<name>.transport` with
99
- `type` (`stdio` | `sse` | `streamableHttp`), `command`/`args`/`env` or `url`/`headers`, plus
100
- `disabled` and `autoApprove`. Current docs describe a newer, flatter layout than the locked
101
- binary. The client declares no capabilities and requests `2024-11-05` — the protocol floor
102
- of the whole matrix; treat it as text-content-blocks-only.
103
- - **Codex** — Rust client on the official rmcp crate. Config: `~/.codex/config.toml`
104
- `[mcp_servers.<name>]` — stdio `command`/`args`/`env`/`env_vars`; HTTP `url`,
105
- `bearer_token_env_var`, `http_headers`; `startup_timeout_sec` (10s), `tool_timeout_sec`
106
- (60s), `enabled_tools`/`disabled_tools`, per-tool approval modes and output limits.
107
- **stdio children do not inherit the parent environment** — only `HOME`, `PATH`, and a few
108
- system vars plus explicitly configured `env`, so `DEEPSEEK_API_KEY` must be passed
109
- explicitly. When a tool result has `structuredContent`, Codex replaces the content blocks
110
- with the serialized JSON. No SSE support.
111
- - **Continue** — Config: `~/.continue/config.yaml` `mcpServers` list — `name`, `type`
112
- (`stdio` | `sse` | `streamable-http`), `command`/`args`/`env`/`cwd` or `url`/`apiKey`/
113
- `requestOptions`; `${{ secrets.NAME }}` interpolation; headless mode fails if any MCP
114
- server fails to connect. **Tool names are exposed raw, without a server prefix**, and
115
- matching is first-found across servers — avoid generic names like `search`.
116
- `structuredContent` is never read; content blocks are JSON-stringified for the model.
117
- - **Gemini** — Config: `mcpServers` in `~/.gemini/settings.json` or `.gemini/settings.json` —
118
- `command`/`args`/`env`/`cwd`, or `url` with `type: "http" | "sse"` (at 0.64.0 a bare `url`
119
- defaults to Streamable HTTP), `headers`, `timeout`, `includeTools`/`excludeTools`; `env`
120
- values expand `$VAR`/`${VAR}`. Tools get an `mcp_{server}_{tool}` name truncated at 63
121
- chars, and underscores in the server name break its FQN parsing — keep the server name
122
- short and underscore-free. Reads only `content` blocks; `structuredContent` is ignored.
123
- - **Pi** — Config: `~/.pi/agent/mcp.json` or `.pi/mcp.json` — stdio `command`/`args`/`env`/
124
- `cwd`, HTTP `url`/`headers`, plus `timeout`, `enabled`, `exposure`. **MCP tools are hidden
125
- from the model by default (`exposure: "codemode"`) — set `exposure: "direct"`** so the
126
- search/fetch tools are declared. SSE is explicitly rejected. Text results over 20 KB are
127
- middle-truncated with the full text saved to a file. Pi is the one open-source host that
128
- uses `structuredContent` and tool `outputSchema`.
129
-
130
- ### Proprietary hosts
131
-
132
- All four locked versions happen to be the latest stable releases at the research date, so
133
- current docs and changelogs apply to them directly. Notes relevant to a two-tool DeepSeek
134
- search/fetch server:
135
-
136
- - **Claude Code** — [MCP docs](https://code.claude.com/docs/en/mcp),
137
- [changelog](https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md).
138
- Config: `.mcp.json` (`mcpServers` with `command`/`args`/`env`, or `type: "http"` + `url`).
139
- Env expansion `${VAR}` works in `command`/`args`/`env`/`url`/`headers`. Tool permission
140
- rules `mcp__<server>__<tool>`; tool descriptions capped at 4,096 chars (2.1.296+); tool
141
- output capped at 25k tokens by default (`MAX_MCP_OUTPUT_TOKENS`), oversized text saved to a
142
- file; 16 MiB message cap on HTTP transports.
143
- - **Cursor** — [MCP docs](https://cursor.com/docs/mcp),
144
- [CLI MCP](https://cursor.com/docs/cli/mcp). Config: `.cursor/mcp.json` or
145
- `~/.cursor/mcp.json`; `command`/`args`/`env` for stdio (docs mark `type` as required),
146
- `url`/`headers` for remote; `${env:NAME}` interpolation. MCP tools need approval; the CLI
147
- has `--approve-mcps`, global-scope servers have been auto-approved since April 2026.
148
- - **Devin** — [MCP config](https://docs.devin.ai/cli/extensibility/mcp/configuration),
149
- [changelog](https://docs.devin.ai/cli/changelog). Config: `.devin/mcp_config.local.json`
150
- (default), `.devin/mcp_config.json`, or `~/.config/devin/mcp_config.json`; same
151
- `mcpServers` shape; `devin mcp add <name> -- <cmd>` / `<URL>`. MCP tools prompt for
152
- approval by default, with `mcp__server__tool` allow/deny patterns in `permissions`.
153
- - **GitHub Copilot** — [MCP docs](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers),
154
- [repo](https://github.com/github/copilot-cli). Config: `~/.copilot/mcp-config.json` or
155
- project `.mcp.json`; stdio entries use `"type": "local"` plus `command`/`args`/`env`; a
156
- per-server `tools` list gates which tools are exposed; runtime flags
157
- `--allow-tool`/`--deny-tool` accept `MCP_SERVER_NAME(tool)`.
77
+ Host versions are locked in [`docs/hosts.jsonc`](../hosts.jsonc), the single source of truth for
78
+ host facts; each row below was verified against that lock on the research baseline.
79
+
80
+ | Host | Negotiated revision | Transports | Evidence |
81
+ | --- | --- | --- | --- |
82
+ | Cline | `2024-11-05` | stdio, Streamable HTTP, SSE | Custom client (no official SDK); `protocolVersion "2024-11-05"` extracted from the platform binary; source repo not public |
83
+ | Codex | `2025-06-18`; `mcp_2026_07_28` feature flag opts into `2026-07-28` | stdio, Streamable HTTP (no SSE) | Git tag `rust-v0.163.0`: rmcp 3.5.1 pinned; initialize sends `V_2025_06_18` |
84
+ | Pi | `2025-11-25` | stdio, Streamable HTTP (SSE rejected) | Git tag: own `@earendil-works/pi-mcp` client, `LATEST_PROTOCOL_VERSION "2025-11-25"` |
85
+ | Claude Code | `2026-07-28` by default (`MCP_PROTOCOL_NEGOTIATION=legacy` opt-out) | stdio, Streamable HTTP, SSE, ws | Changelog 2.1.296+: "negotiate MCP protocol version 2026-07-28 by default"; docs: TS SDK 2.0 runtime |
86
+ | Cursor | Unpinnable from primary sources (docs show ≥ `2025-06-18` features) | stdio, Streamable HTTP, SSE | Docs feature set only; no revision stated in docs or changelog |
87
+ | Devin | `2026-07-28` | stdio, Streamable HTTP (SSE fallback), SSE | Changelog for the locked release itself: "Support for MCP protocol revision 2026-07-28" |
88
+ | GitHub Copilot | `2026-07-28` | stdio (`type: "local"`), Streamable HTTP, SSE | Changelog 1.0.81: "Ship MCP 2026-07-28 support to CLI, SDK, IDE, and in-memory clients" |
89
+
90
+ All seven support stdio and Streamable HTTP; legacy SSE is never required (and Codex
91
+ and Pi reject it). Verification methodology and provenance follow the
92
+ [per-host reference](control-matrix.md#per-host-reference); the Evidence column cites per-row
93
+ sources and Sources lists the file-level links.
94
+
95
+ Registration paths, config shapes, approval surfaces, and per-host quirks live in the
96
+ [per-host reference](control-matrix.md#per-host-reference) of the control-matrix note; they
97
+ are setup facts, not protocol facts. The table above carries the protocol evidence, and
98
+ source-level links follow in Sources.
158
99
 
159
100
  ## One server for all hosts
160
101
 
@@ -164,12 +105,14 @@ differences:
164
105
 
165
106
  1. **Tools only, text-first results.** Expose the retrieval as two tools via the `tools`
166
107
  capability; do not rely on resources, prompts, sampling, elicitation, or roots — the
167
- hosts' client capabilities are inconsistent (Codex has elicitation only; Gemini and Pi
168
- serve roots; Continue exposes nothing beyond tools and prompts). Always return readable
108
+ hosts' client capabilities are inconsistent (Codex has elicitation only; Pi serves
109
+ roots). Always return readable
169
110
  text in `content` blocks, and mirror the same data in `structuredContent` for
170
111
  `2025-06-18`+ clients — the spec's own backwards-compat SHOULD. This split matters in
171
- practice: Codex *replaces* content with `structuredContent` when present, Gemini and
172
- Continue *ignore* `structuredContent`, Pi and Cline read content only.
112
+ practice: Codex *replaces* content with `structuredContent` when present; Cline reads
113
+ text content only; Pi is
114
+ content-first, falling back to `structuredContent` only when a result has no content
115
+ blocks (verified in `tools.ts` at v1.3.0).
173
116
  2. **stdio is the universal transport.** Every host in the matrix launches stdio servers
174
117
  with the same conceptual JSON (`mcpServers` → `command`/`args`/`env`), differing only in
175
118
  file location and cosmetic field names. stdio needs no OAuth and no URL config, and the
@@ -185,15 +128,11 @@ differences:
185
128
  different `type` strings: `http`, `streamable-http`, `streamableHttp`), and OAuth 2.1
186
129
  resource-server behavior (RFC 9728 metadata) then applies; prefer pre-registered clients
187
130
  over the now-deprecated Dynamic Client Registration.
188
- 5. **Host quirks to design around.** Name tools distinctly (`deepseek_web_search`,
189
- `deepseek_fetch`): Continue exposes raw names with cross-server collisions, and Gemini
190
- truncates the `mcp_{server}_{tool}` name at 63 chars. Pass the API key explicitly in
191
- config — Codex's stdio children do not inherit the parent environment, while other hosts
192
- expand `${VAR}`-style references. Keep tool descriptions under Claude Code's 4,096-char
193
- cap and fetch output bounded (Claude Code caps tool output at 25k tokens by default; Pi
194
- truncates text over 20 KB). Document per-host approval: `mcp__deepseek__*` rules (Claude
195
- Code, Devin), `tools` lists and `--allow-tool` (Copilot), `--approve-mcps` (Cursor),
196
- `autoApprove` (Cline), `exposure: "direct"` (Pi).
131
+ 5. **Host quirks to design around.** Tool naming (`deepseek_web_search`,
132
+ `deepseek_fetch`) already reflects the quirk catalog in the
133
+ [per-host reference](control-matrix.md#per-host-reference) — name collisions and
134
+ truncation, environment passing, output caps, and per-host approval surfaces; consult
135
+ it per host rather than this summary.
197
136
 
198
137
  ## Sources
199
138
 
@@ -215,20 +154,12 @@ differences:
215
154
 
216
155
  ### Hosts
217
156
 
218
- - Gemini CLI: [v0.64.0 tag](https://github.com/google-gemini/gemini-cli/tree/v0.64.0) —
219
- [package.json (SDK 1.23.0 pin)](https://github.com/google-gemini/gemini-cli/blob/v0.64.0/packages/core/package.json),
220
- [mcp-client.ts](https://github.com/google-gemini/gemini-cli/blob/v0.64.0/packages/core/src/tools/mcp-client.ts),
221
- [mcp-tool.ts (name handling, result rendering)](https://github.com/google-gemini/gemini-cli/blob/v0.64.0/packages/core/src/tools/mcp-tool.ts),
222
- [npm 0.64.0](https://registry.npmjs.org/@google/gemini-cli)
223
157
  - Codex: [rust-v0.163.0 tag](https://github.com/openai/codex/tree/rust-v0.163.0) —
224
158
  [Cargo.toml (rmcp pin)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/Cargo.toml),
225
159
  [rmcp_client.rs (initialize params)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/codex-mcp/src/rmcp_client.rs),
226
160
  [mcp_types.rs (config keys)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/config/src/mcp_types.rs),
227
161
  [utils.rs (stdio env allowlist)](https://github.com/openai/codex/blob/rust-v0.163.0/codex-rs/rmcp-client/src/utils.rs),
228
162
  [rust-sdk protocol constants at the pinned rev](https://github.com/modelcontextprotocol/rust-sdk/blob/4048ac40e958fb1a7d614617a2ae8d26666ee2fa/crates/rmcp/src/model.rs)
229
- - Continue: [1.5.47 npm tarball](https://registry.npmjs.org/@continuedev/cli/-/cli-1.5.47.tgz)
230
- (MCPService.ts, mcpTransports.ts, bundled SDK protocol constants; no git tag exists),
231
- [current docs](https://docs.continue.dev/customize/deep-dives/mcp)
232
163
  - Pi: [v1.3.0 tag](https://github.com/earendil-works/pi/tree/v1.3.0) —
233
164
  [pi-mcp protocol types](https://github.com/earendil-works/pi/blob/v1.3.0/packages/mcp/src/protocol/types.ts),
234
165
  [MCP docs at the tag](https://github.com/earendil-works/pi/blob/v1.3.0/packages/coding-agent/docs/mcp.md),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "deepseek-web-retrieval",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "description": "Token-efficient DeepSeek Search and Fetch for coding agents, starting with OpenCode v2.",
6
6
  "type": "module",
7
7
  "license": "MIT",
@@ -26,7 +26,7 @@
26
26
  "./mcp": "./src/mcp/server.ts"
27
27
  },
28
28
  "bin": {
29
- "deepseek-web-retrieval": "./dist/cli.js"
29
+ "deepseek-web-retrieval": "dist/cli.js"
30
30
  },
31
31
  "files": [
32
32
  "index.ts",
@@ -46,7 +46,7 @@
46
46
  "test:e2e": "bun run test/e2e/run.ts",
47
47
  "docs:matrix": "bun run scripts/render-matrix.ts",
48
48
  "test:coverage": "bun test --coverage",
49
- "check": "bun run typecheck && bun run build && bun test"
49
+ "check": "bun run typecheck && bun run docs:matrix --check && bun run build && bun test"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "@opencode/plugin": "^2.0.32"
@@ -64,6 +64,8 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@modelcontextprotocol/server": "^2.3.1",
67
+ "jsonc-parser": "^3.3.1",
68
+ "smol-toml": "^1.9.1",
67
69
  "zod": "^4"
68
70
  }
69
71
  }
package/src/core/auth.ts CHANGED
@@ -1,4 +1,4 @@
1
- export const API_KEY_ENV = "DEEPSEEK_API_KEY"
1
+ import { API_KEY_ENV } from "./constants"
2
2
 
3
3
  export function apiKeyFromEnv(
4
4
  env: Readonly<Record<string, string | undefined>> = process.env,