DSHarness Systems Dissection Pinned baseline 47f943859b · 36 verified / 0 in progress / 36 chapters
中文
Execution Environment·Chapter 22

Web, LSP, MCP, and Skills

Stable tool names, replaceable providers, and progressive capability disclosure

VerifiedUpstream 47f943859bScope: Analyze web-provider registries, LSP normalization, MCP client mounting, skill catalog/load, and prompt exposure.

Conclusion: Four Extension Surfaces, Four Different Contracts

DeepSeek Harness does not flatten every external capability into one generic plugin API. Web keeps stable product-owned tool names over replaceable providers; LSP keeps one closed operation vocabulary over extension-routed language servers; MCP imports provider-owned names and schemas dynamically; Skills publish a compact routing catalog and reveal trusted instruction bodies only on demand. The common philosophy is not “everything is a tool,” but “put a stable, typed seam at the narrowest layer that can own the semantics.”

This separation is unusually useful for analysis because each surface answers a different question: who owns the public name, who selects the provider, how much data enters every model request, and where untrusted or privileged content crosses into execution. Treating the four as equivalent would hide their most important safety and cache properties.

1. Capability Topology: Stability Moves to a Different Layer in Each Surface

SurfaceStable model-facing unitReplaceable/dynamic unitSelection pointDefault exposure
Webweb_search / web_fetchSearch and fetch providersExecution-time configured ID or exactly one usable providerSearch only
LSPOne lsp tool with four operationsExtension-to-language-server routesFinal file extensionOptional examples, not the shipped base
MCPmcp__server__raw per discovered toolThe entire remote tool generationServer discovery and re-syncDefault-off examples
SkillOne skill loader plus a summary catalogWinning provider candidate and loaded bodyScope layer, then rank within the layerShipped in coding presets
Design reading

The architecture spends stability where it buys the most. Web and LSP can define a portable product vocabulary, so their schemas stay fixed. MCP exists precisely to accept an external server's vocabulary, so it stabilizes identity and generation swaps instead. Skills stabilize discovery metadata while postponing the expensive and authoritative body.

2. Web: Provider Choice Is Deterministic and Re-evaluated at Every Call

web_search(query)
  → ctx.web.search(request)
      ├─ configured id exists + available → use it
      ├─ configured id missing/unavailable → typed failure
      ├─ no configured id + one usable    → auto-select
      ├─ no configured id + many usable   → ambiguous failure
      └─ no usable provider               → unavailable failure
  → cap sources to maxResults
No registration-order lottery

Search and fetch have separate registries, duplicate IDs fail, and provider availability is checked at execution time. Environment overrides feed the same two configuration fields rather than forming a hidden priority chain. If more than one unconfigured provider is usable, execution fails and asks for an explicit choice. CAP-WEB-SELECTION

The result vocabulary is intentionally small: search returns optional answer text plus citeable sources; fetch returns final URL, status, a closed HTML/text body union, and truncation. A non-2xx response is resource state rather than a transport exception. CAP-WEB-TYPES

3. Stable Tool Visibility Is Decoupled from Provider Health

dsh-tool-web owns schemas, prompt guidance, result caps, and presentation. Its search/fetch booleans decide whether the tools register; concrete providers do not. Consequently, an enabled tool remains in the model catalog even if its configured provider is temporarily absent or unusable, and fails with structured metadata only when called. CAP-WEB-TOOL

Tradeoff

This protects tool-schema and KV-prefix stability across credential outages and provider HMR. It also means “the model can see this tool” is not a readiness signal. Operations need a separate provider-health view; otherwise the first user-visible probe is a failed tool call.

4. Shipped Web Is Search-Only Because Fetch Has an Explicit SSRF Hole

Actual base composition

The base composition mounts ctx.web, pins search to deepseek-official, mounts the DeepSeek provider, exposes web_search with a 60-second tool budget, and sets fetch:false. It mounts no fetch provider. The configuration comment names the reason: the local fetcher defers SSRF/private-network protection while the model chooses the target. CAP-WEB-SHIPPED

The optional HTTP fetcher still enforces useful transport hygiene: HTTP(S) only, no embedded credentials, bounded URL size, same-origin redirects, supported text content types, declared charset decoding, one timeout, byte and character caps, and no browser cookies or ambient credentials. It explicitly warns that private-network blocking is absent. CAP-WEB-FETCH-POLICYCAP-WEB-FETCH-TRANSPORTCAP-WEB-FETCH-CAPS

5. DeepSeek Search Is an Auxiliary Model Call, Not Reuse of the Main LLM Adapter

web_search query
  → resolve one settings + credential snapshot
  → append secret-free web/deepseek-search-llm-request
  → POST Anthropic-compatible /messages
       model: deepseek-v4-flash
       tool: web_search_20250305
  → require web_search_tool_result blocks
  → join cited_text by URL, deduplicate, normalize
Private wire, public seam

The provider uses its own native fetch client and Anthropic-compatible request, not ctx.llm. It snapshots endpoint, key source, model, token cap, and search-use cap once per operation; records the exact secret-free auxiliary request before dispatch; rejects redirects; and sends both supported API-key header shapes. CAP-WEB-DEEPSEEK-WIRECAP-WEB-DEEPSEEK-REQUESTCAP-WEB-DEEPSEEK-SETTINGS

No prose fallback

A response without native search-result blocks is an error. Result items are deduplicated by URL, while snippets come from separate citation text blocks. Final maxResults truncation remains owned by the Web seam, not this adapter. CAP-WEB-DEEPSEEK-MAP

Cost consequence

One visible web_search is an additional metered model request with its own failure and latency path. It is observable in the initiating Session, but it is not routed through the main adapter's retry, model selection, or streaming implementation.

6. LSP Deliberately Refuses to Become Generic JSON-RPC

The LSP service exports exactly goToDefinition, findReferences, goToImplementation, and hover. A provider atomically reserves one ID and an exclusive set of normalized file extensions. The registry validates the whole mapping before mutation; conflicts publish nothing, and disposal releases every route together. Query selection uses the file's final lowercase extension—foo.d.ts routes as .ts—and exposes no raw JSON-RPC escape hatch. CAP-LSP-REGISTRY

Why the closed set matters

The seam can normalize positions, results, caps, errors, cancellation, and read-only retry because it understands every operation. Arbitrary JSON-RPC would maximize protocol coverage but move compatibility and safety back into prompts and provider-specific behavior.

7. The lsp Tool Is a Precision Aid, Not a General Code Browser

Model contract

One read-only tool accepts a closed operation enum, file path, and one-based UTF-16 line/character. It requires the calling Session's workspace with no fallback, converts into the normalized seam, caps location count and rendered characters, and carries a 60-second timeout. Its prompt explicitly recommends ordinary search/read first and LSP only when textual navigation is ambiguous or a change needs precise symbol relationships. CAP-LSP-TOOL

This is an important restraint: LSP does not replace source reads. It answers semantic navigation questions over the current file text, then returns bounded locations or hover content that the model can verify by reading.

8. The Stdio LSP Backend Shares the Filesystem and Process Execution World

query(file, workspace)
  → ctx.fs canonicalizes workspace and proves containment
  → ctx.fs streams one complete byte-bounded source
  → per-canonical-workspace queue
      → lazy one-server process via ctx.subprocess
      → didOpen → query → didClose
      → on transport failure: replace once and replay read-only query
Transactional activation

The plugin validates every server config and resolves every executable before registering any provider. Registry conflicts roll back earlier registrations. Processes start lazily on the first matching query, routes are removed before teardown, and sibling process disposals settle before errors propagate. CAP-LSP-STDIO-LOAD

Workspace serialization

Each canonical workspace owns one pooled server and one queue spanning source read, document open, query, and close. Source bytes come through ctx.fs; servers launch through ctx.subprocess. A transport failure may replace the selected process and retry once because the operation set is read-only. CAP-LSP-STDIO-POOLCAP-LSP-HOST-FS

9. LSP Is Implemented and Demonstrated as an Optional Capability

The repository demonstrates LSP in an optional Headless/E2B composition, where the operator supplies a concrete server command and extension map. The example pins typescript-language-server and exposes the tool only beside the service and stdio provider. CAP-LSP-OPTIONAL

Deployment consequence

Package existence is not product availability. A useful UI or capability inventory must distinguish “code exists,” “provider is configured,” “tool is visible to this Agent,” and “the provider is currently ready.”

10. MCP Imports a Server-Owned Tool Generation into the Native Registry

One MCP client instance owns one stdio or Streamable HTTP server. A stable local serverName reserves a namespace, and each discovered raw name becomes mcp__<serverName>__<rawName>. Invalid characters or overlength names receive a deterministic identity-derived hash suffix, so reconnection order never renames a tool and normalization collisions become extremely unlikely. CAP-MCP-CONFIGCAP-MCP-NAMING

Startup semantics

Activation waits for the first connection and complete tool discovery. failOnStartupError:true rejects and rolls back the plugin; otherwise activation may complete with no tools while the supervisor retries. Duplicate live server namespaces fail before the connection begins. CAP-MCP-STARTUP

11. Tool Re-sync Is Transactional in Fetch, but a Registration Conflict Drops the Old Generation

1

Fetch all pages

Build the entire next definition map without touching the registry.

2

Preserve on fetch failure

A network, schema, or duplicate-list failure leaves the previous generation live.

3

Swap

Dispose the previous generation, then register every next definition.

4

Fail closed on collision

If a foreign tool squats on the namespace, roll back the partial new generation to zero.

Precise atomicity boundary

The fetch phase is last-known-good, while the registration phase is all-new-or-none—not rollback-to-old. Every initial, notification, and reconnect sync is serialized across client generations so swaps cannot interleave. CAP-MCP-SYNCCAP-MCP-RECONNECT

12. MCP Recovery Retains the Last Good Catalog Until the Attempt Budget Is Exhausted

A transport close starts bounded exponential backoff. During the outage the last good registrations remain visible, but calls fail against the unavailable generation. A sufficiently stable connection resets the outage budget; a crash loop eventually unregisters every tool and stops until reload/restart. A generation that cannot prove closure within the bounded barrier stops reconnection rather than overlapping two stdio server processes. Disposal cancels timers, closes the current client, drains the connection attempt and sync chain, then unregisters the final generation. CAP-MCP-RECONNECTCAP-MCP-GENERATION

Same visibility/readiness split

Like Web, an MCP schema can remain visible while execution is temporarily impossible. Unlike Web's stable schemas, MCP recovery may replace the entire model-facing catalog when the server changes its tool list.

13. Canonical MCP Results Are Rich; Native Model History Is Deliberately Lossy

DataExecution-local canonical valueNative model rendering
Text blocksFull JSON blocksText joined with newlines
Image/audio/resourceFull JSON blocksShort “content discarded” placeholders
structuredContentPreserved; advertised supported schema enforcedNot separately rendered into rich content
isError:trueConverted to a thrown execution failureToolRuntime's normalized error result
Task-required toolRejectedUnsupported execution error
Trust-boundary normalization

The bridge validates network values defensively, preserves complete JSON for programmatic/Code Mode callers, and falls back to unconstrained JSON when an advertised output schema uses unsupported vocabulary. Native context intentionally discards non-text payloads. CAP-MCP-RESULT

14. MCP Stdio Does Not Share the Harness Subprocess/Sandbox Spawn Path

The stdio transport reuses the subprocess package's environment-scrubbing definition, then merges explicit config environment. But the MCP SDK owns the actual child spawn; it does not call ctx.subprocess. Therefore it does not automatically inherit the configured execution world, sandbox runner, remote process provider, process-tree contract, or output collector used by Shell and LSP. Streamable HTTP similarly delegates transport to the SDK and accepts configured headers. CAP-MCP-TRANSPORT

Security finding

This is the most important cross-surface inconsistency in the chapter. LSP deliberately co-locates file reads and server processes behind shared seams; MCP stdio only shares credential-name scrubbing. A deployment that assumes “all child processes are sandboxed” is wrong unless it independently confines the Host or MCP command.

15. MCP Is Broadly Interoperable but Narrower Than the Protocol

The bridge consumes Tools only; MCP Resources, Prompts, and server instructions have no consumer. Connection/discovery timeout is inherited from the SDK rather than exposed as plugin configuration. Streamable HTTP request failures do not necessarily trigger the stdio-style supervisor path. Native non-text projection is lossy, task-required execution is unsupported, and unsupported output-schema vocabulary loses validation. CAP-MCP-LIMITS

No MCP server ships in the default composition. The repository's memory integrations are explicitly default-off reference overlays; the operator installs and configures the third-party server and owns its storage, identity, model, embedding, and licensing behavior. CAP-MCP-DEFAULT-OFF

16. Skills Are a Two-Stage Prompt Capability: Route Cheaply, Load Authority Deliberately

provider list() → SkillCandidate summaries
  → layered merge and cache
  → durable <available_skills> names + descriptions
  → model calls skill(name) OR user explicitly invokes /name
  → provider get(winning candidate)
  → canonical <skill_content> body + resource base

A summary separates routing data from the full definition and carries two independent permissions: modelInvocable and userInvocable. Resource bases may be directories, URLs, or opaque provider instructions. Full bodies are asynchronous provider loads, not stored in every catalog entry. CAP-SKILL-TYPES

Trusted body contract

The wrapper escapes framing metadata but embeds the instruction body verbatim because Skills are defined as trusted local content. The resource hint tells the model to load referenced assets only when needed. CAP-SKILL-RENDER

17. Scope Beats Rank; Rank Only Breaks Ties Inside One Layer

Filesystem sourceRankMeaning within one layer
Project .dsh/skills100Highest local priority
Project .agents/skills200Below project-native skills
Runtime registration250Between project and custom/user roots
Custom roots300Operator-supplied roots
User .dsh/skills400User-native fallback
User .agents/skills500Shared-agent fallback
Bundled600Lowest filesystem priority
Layer merge

The registry merges global, ancestor, then exact-Agent layers; a nearer layer replaces a same-name entry outright. Only candidates inside one layer are sorted by rank and registration order. Complete observations are cached by cwd, scope chain, and revision; incomplete discovery is never cached, and one revision race receives a bounded retry. CAP-SKILL-LAYERSCAP-SKILL-COLLECT

18. The Filesystem Provider Uses the Execution-World FS for Reads, but Host Watchers for Change Detection

Workspace-sensitive discovery builds project, custom, user, and bundled roots with the ranks above. When ctx.fs exists, ordinary roots are listed and read through it; a trusted bundled host root may use Node filesystem access directly. Model-facing write/edit observations synchronously invalidate matching roots. Host-local watchers are bounded by a maximum retained project count and coalesce invalidations. CAP-SKILL-FS-ROOTSCAP-SKILL-FS-TRUST

Split-world consequence

Discovery content can follow a remote/sandbox filesystem while watcher mechanics remain Host-local. The provider explicitly represents watcher failure as an incomplete observation, allowing the model catalog to retain its last good version and retry later instead of publishing a transient empty list.

19. Model Invocation and User Invocation Take Different, Revalidated Paths

PathDiscovery gateLoad gateDurable/model-visible result
Model calls skill(name)Summary must still exist and be model-invocableLoaded definition is recheckedOrdinary tool call/result containing the body
User message invokes /nameOnly direct source.kind=user text is scannedLoaded definition must be user-invocableInstructions-form user context appended last
Unknown/user-disabled gestureNo recognized authorityNo injectionRemains ordinary prose
No stale-catalog trust

The model tool lists, then loads, and checks modelInvocable at both boundaries. The explicit-user path loads directly and checks userInvocable, making it the only route to a model-disabled/user-enabled Skill. The same canonical renderer is used on both paths. CAP-SKILL-TOOL-LOADCAP-SKILL-USER-INVOKE

20. The Skill Catalog Is Durable Replacement State, Not a Rebuilt System-Prompt Blob

At every eligible pre-step, the plugin publishes only sorted model-invocable names and bounded descriptions—and only when its exact skill registration is visible. The durable source stores those entries directly. A digest change appends a complete replacement catalog; an empty replacement explicitly retires older names; incomplete discovery publishes nothing; compaction hiding the visible catalog causes a later complete observation to re-establish it. CAP-SKILL-CATALOG

Cache-aware disclosure

Adding a Skill does not inject every body into every request. Catalog changes are append-only suffix facts, while a body appears only in the chosen tool result or explicit invocation. The price is historical duplication: whole-list replacements cost tokens, body-only edits do not change the summary digest, and an older loaded body remains a historical Session fact.

The base owns the layered Skill registry, while coding presets mount filesystem discovery and the loader into their Agent scope. This allows global repository contributions and preset-local shadowing to coexist. CAP-SKILL-BASECAP-SKILL-SHIPPED

21. Trust Matrix: “External” Does Not Mean the Same Thing Across These Surfaces

BoundaryData authorityExecution authorityPrimary hazard
Web search resultRemote, untrusted contentNo local process by itselfPrompt injection and citation quality
Web fetch URLModel-chosen remote targetHost network reachabilitySSRF/private-network access
LSP serverLocal source plus server responseProcess in shared execution worldOperator-chosen executable and workspace content
MCP serverRemote schemas and result blocksExternal actions or an SDK-spawned childDynamic capability, auth, and spawn confinement
Skill bodyTrusted instructions by designIndirect authority over later tool choicesWritable skill roots become prompt-authority roots
Security synthesis

The strongest reusable lesson is to name prompt authority explicitly. Escaping XML-like framing cannot make a Skill body untrusted because following the body is its purpose. Conversely, a Web page must never acquire that authority merely because it arrived through a first-party search tool. Path policy, provider authentication, and prompt provenance solve different problems.

22. Focused Codex Comparison: Similar Progressive Disclosure, Broader Documented MCP Policy

This comparison uses only OpenAI's public Web search, Model Context Protocol, and Customization documentation, retrieved on 2026-08-13. DeepSeek Harness is analyzed at pinned source; Codex is described only at the public-documentation level. No claim is made about private services or undocumented implementation.

DimensionDeepSeek Harness pinned sourceCodex public documentation
WebProvider registry; shipped DeepSeek auxiliary search; fetch disabled for missing SSRF defenseFirst-party search; cached by default locally, live/disabled modes; results explicitly treated as untrusted input
MCP transportsStdio and Streamable HTTP; Tools onlyStdio and Streamable HTTP; documented server instructions and richer auth
MCP controlsPer-server startup strictness, call timeout, reconnect; no tool allow/deny or per-tool approval in this bridgeDocumented startup/tool timeouts, required server, tool allow/deny, server/per-tool approval modes, OAuth and bearer options
SkillsSummary catalog, on-demand body, separate model/user invocation, durable replacement factsMetadata first, SKILL.md on selection, references/scripts as needed; implicit or explicit $ invocation
LSPClosed four-operation seam with optional stdio backendThe retrieved official manual documents no standalone LSP tool surface; no parity claim is made
What each makes especially legible

DeepSeek Harness's source makes provider selection, catalog durability, result projection, and process seams exceptionally auditable. Codex's public MCP surface documents a more complete operator policy plane—authentication, filtering, required startup, server guidance, and per-tool approval. Both publicly describe progressive Skill disclosure; the DeepSeek source additionally exposes exactly how replacement catalogs become Session facts.

23. Transferable Design Rules

1

Stabilize the narrowest honest vocabulary

Use fixed tools for product semantics; import dynamic schemas only where interoperability requires it.

2

Separate visibility from readiness

Stable catalogs help caching, but provider health must be observable independently.

3

Make generation swaps explicit

Define separately what happens on discovery failure, registration conflict, transport loss, and exhausted recovery.

4

Treat instruction stores as authority stores

A writable Skill root is not merely documentation storage; it can steer subsequent privileged calls.

Final assessment

The chapter's deepest pattern is progressive capability disclosure with typed ownership. Web hides provider diversity behind stable product semantics; LSP narrows a huge protocol into four reliable questions; MCP accepts dynamism but wraps it in deterministic identity and lifecycle generations; Skills keep routing cheap and instruction authority explicit. The remaining debt appears exactly where a surface crosses a seam it does not own: fetch without network policy, MCP spawn outside the subprocess world, and trusted Skill bodies rooted in mutable files.

Verification scope

All DeepSeek claims above are tied to the pinned baseline's production source, shipped configuration, examples, and package documentation. This delivery also ran 16 focused Vitest files across Web, LSP, MCP, and Skills under an isolated temporary root: all 454 tests passed. The Codex comparison is separately bounded to the three linked official pages and their retrieval date. Runtime validation does not turn an optional composition into a shipped default, and passing package tests does not prove real-network safety or third-party server correctness.

My Learning Notes

Autosaved only in this browser. Nothing is uploaded or committed. Export Markdown whenever you want to keep a copy.