Progressive-disclosure MCP gateway that searches large remote catalogs through `mcp_search`, then invokes exact schemas through `mcp_call` with lazy connections and bounded caches.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:labmimors/dsh-mcp-lens
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time. Only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 简体中文
Shrink large MCP catalogs to a two-tool model surface.
MCP Lens lets DeepSeek Harness search and call 1,000 remote tools through two stable model-facing interfaces. Instead of sending every tool schema on every turn, it reveals exact schemas only for a small ranked set when a tool is actually needed.
Why users install it:
- Spend less on input-heavy turns: in the dated three-task pilot, estimated DeepSeek V4 Flash cost fell from
$0.0307204to$0.0034707. - Keep more room for the real task: the same pilot reduced
request/header.toolsJSON from674,249 Bto27,401 B. - Retrieve more relevant covered calls: on a frozen MCP-Atlas-derived convenience holdout, Recall@5 rose from
0.062610to0.246656across 304 untouched prompts. This is lexical retrieval evidence, not an official MCP-Atlas or end-to-end score. - Narrow the tool-choice surface: search reveals only a small ranked set of exact schemas, and the final
server/toolis still gated byallowToolsanddenyTools. - Preserve completion in the tested pilot: both arms completed
3/3tasks, while Lens used one extra search step.
Use MCP Lens if you have dozens to thousands of MCP tools, multiple servers, or long-tail tools that are expensive to advertise on every turn. Skip it if you have only a handful of tools that are used almost every request.
Install in 30 seconds
Prerequisites: DeepSeek Harness 0.1.0-rc.6, Node.js ^22.19.0 or >=24.0.0, and pnpm on PATH. The dsh plugin command delegates installation to pnpm.
Download and verify the prebuilt release, then install the local file into your Harness profile. Passing a redirected GitHub asset URL directly to pnpm can fail with ERR_PNPM_MISSING_TARBALL_INTEGRITY on some pnpm versions.
curl -fL --retry 3 -o dsh-mcp-lens-0.1.0-rc.8.tgz \
https://github.com/labmimors/dsh-mcp-lens/releases/download/v0.1.0-rc.8/dsh-mcp-lens-0.1.0-rc.8.tgz
printf '%s %s\n' \
'a930b5166ffe1cf1de4032d69289de935c444c94cf01b2a5ca5ad58949b91fa0' \
'dsh-mcp-lens-0.1.0-rc.8.tgz' | shasum -a 256 -c -
dsh plugin --profile web add ./dsh-mcp-lens-0.1.0-rc.8.tgz
On Windows, download the same asset from the rc.8 release, verify it with Get-FileHash -Algorithm SHA256, and pass its local path to dsh plugin add.
The three-command block downloads, verifies, and installs the plugin. To make it useful, continue with Connect your first MCP server; its copy-paste block adds both a server and the exact tools you want to allow. Then validate and start the profile:
dsh --profile web --dump-config
dsh --profile web
After that, prompt Harness normally. You do not need to mention mcp_search or mcp_call in your prompt.
Try the local-only catalog calculator to measure your current tool-schema bytes, then copy a schema-free share link or Markdown result. Shared results are always labeled self-reported local measurements and encode only bounded numeric fields—not tool names, descriptions, or schemas. The numeric check catches accidental edits; it is not a signature or proof that a measurement occurred. Prefer a repeatable CI guard? Use the schema budget Action to fail a workflow when tool count or schema bytes drift above your limit.
Need the same measurement in CI? This repository also ships a dependency-free GitHub Action that audits a checked-in tool payload and reports the model-facing tool count, canonical schema bytes, and byte reduction versus the fixed two-tool Lens surface.
- uses: labmimors/dsh-mcp-lens@v0.1.0-rc.7
with:
tools-file: fixtures/request-header-tools.json
For an immutable production reference, pin the reviewed rc.7 commit: f21169f921e7ed032a4db5062685afb6f948c2d1.
Why does the chart show 27 instead of 2? Both arms include the same 25 non-MCP Harness tools: the direct client exposes 25 + 1,000 = 1,025 total tools; Lens exposes 25 + 2 = 27. The MCP surface itself is 1,000 → 2.
What it solves
| Your problem | What MCP Lens changes |
|---|---|
| API input grows with every MCP tool | The MCP surface always starts with only mcp_search and mcp_call. In our live three-task pilot, estimated V4 Flash cost fell 88.702%. |
| Large tool lists consume standing context | With the same 1,000-tool server, complete Harness request-tool JSON fell from 674,249 B to 27,401 B. |
| You worry routing will reduce task completion | In the tested customer, Chinese-ticket, and GitHub tasks, Lens and the direct client both completed 3/3 with correct arguments and results. |
| Many similar tools widen the choice set | Search narrows what the model sees at once, returns exact inputSchema values, and calls an explicit server/tool identity. |
| Every server connects even when unused | Connections are lazy. Activation starts no MCP process and opens no MCP socket. |
| One server outage should not block the rest | Other servers keep working, and Lens keeps the previous usable catalog when a refresh fails. |
| Risky tools should be hidden by default | No remote tool appears until it matches allowTools; denyTools always wins in search and calls. |
In the live pilot, MCP Lens and the official direct client both completed 3/3 tasks. Lens used one extra search step and more output tokens, so it is designed for large, multi-server, or long-tail catalogs, not a handful of tools used on every turn. See the full pilot report.
The tarball is already built, so no dependency build permission is needed. The MCP documentation server used below requires no additional API key; Harness still needs your configured model provider.
dsh plugin --profile web add github:labmimors/dsh-mcp-lens#v0.1.0-rc.8
Git installs fetch source and run prepare. With pnpm 10+, add this exact package key to $DSH_HOME/profiles/web/pnpm-workspace.yaml (default ~/.dsh/profiles/web/pnpm-workspace.yaml), then rerun the command:
allowBuilds:
dsh-mcp-lens: true
Review the source and pin a tag or commit SHA before granting build permission.
Connect your first MCP server
The plugin ships with no servers and allows no remote tools until you opt in. Open:
$DSH_HOME/profiles/web/cordis.patch.yml
If DSH_HOME is unset, the default path is ~/.dsh/profiles/web/cordis.patch.yml. If the file contains only [], replace [] with the block below. If it already contains - id entries, append this as another top-level list item. It connects the public official MCP documentation server but exposes only its two read-only query tools:
- id: mcp-lens
config:
servers:
- name: mcp-docs
transport: streamable-http
url: https://modelcontextprotocol.io/mcp
cachePath: !!js dshHomePath('mcp-lens/catalog.json')
allowTools:
- mcp-docs/search_model_context_protocol
- mcp-docs/query_docs_filesystem_model_context_protocol
denyTools: ['mcp-docs/submit_feedback']
Verify the assembled profile, then start Harness:
dsh --profile web --dump-config
dsh --profile web
Now ask a normal question:
Use the official MCP documentation server to explain when an MCP client should use Streamable HTTP.
MCP Lens handles the two-step routing internally:
your request
→ mcp_search("search MCP documentation for Streamable HTTP")
→ exact mcp-docs/search_model_context_protocol input schema
→ mcp_call("mcp-docs", "search_model_context_protocol", arguments)
→ tool result
You do not have to mention mcp_search or mcp_call in normal prompts.
- id: mcp-lens
config:
servers:
- name: knowledge
transport: streamable-http
url: https://mcp.example.com/rpc
headers:
Authorization: !!js '`Bearer ${process.env.MCP_TOKEN}`'
cacheNamespace: knowledge-acme-readonly
cachePath: !!js dshHomePath('mcp-lens/catalog.json')
allowTools: ['knowledge/read_*', 'knowledge/search_*']
denyTools: ['*/delete_*', '*/destroy_*']
cacheNamespace is a non-secret identity for one tenant and permission scope. Rotate it when the account or scope changes. Never put the credential itself in this field. If a credentialed server omits it, Lens keeps that catalog memory-only and rediscovers it after restart.
Patterns match the exact server/tool identity, support literals plus *, and apply with deny winning. An empty allowTools list allows nothing. A later Cordis patch replaces this row's whole config, so include every non-default field you want to keep.
Is MCP Lens right for you?
| Choose | When it fits best |
|---|---|
Official @deepseek-ai/dsh-mcp-client |
You have a few stable tools that are used on most turns and want the simplest direct path. |
| MCP Lens | You have dozens to thousands of tools, several MCP servers, long-tail capabilities, or repeated context/cost pressure. |
Lens trades a search step on first use for a nearly constant standing MCP schema surface. The larger and less frequently used your catalog is, the stronger that trade becomes.
Speed: there is no universal latency win to claim. The first uncached use adds search and connection work; smaller requests may offset that cost on large catalogs, so measure your own workload.
Measured results
Frozen retrieval holdout
We evaluated the rc.8 ranker once on an MCP-Atlas-derived convenience holdout, not the official MCP-Atlas benchmark. It contains 15 real servers, 102 captured tool schemas, and 304 untouched prompts. The prompts exclude the earlier 15-query development set and 38-query holdout A; their exact-text overlap with this repository's 12-query regression fixture is zero.
| Metric | Released rc.7 ranker | rc.8 candidate v3 | Difference |
|---|---|---|---|
| Recall@5 | 0.062610 | 0.246656 | +0.184046 |
| MRR | 0.119999 | 0.258684 | +0.138685 |
| nDCG@5 | 0.051830 | 0.204307 | +0.152477 |
The rc.7 runtime ranker is byte-identical to the rc.6 runtime baseline used by the evaluator. The Recall@5 difference has a 100,000-replicate paired-bootstrap 95% CI of [0.144846, 0.224342]; prompt-level wins/ties/losses are 99/197/8. This result covers covered-call lexical retrieval only. It does not measure end-to-end task completion, tokens, cost, latency, semantic retrieval, or general product quality. See the method, boundaries, and artifact commitments.
Live DeepSeek V4 Flash pilot
Same DeepSeek Harness 0.1.0-rc.6, same 1,000-tool stdio server, and the same three customer/ticket/GitHub tasks:
| Metric across three tasks | Official direct client | MCP Lens | Difference |
|---|---|---|---|
| Completed tasks | 3 / 3 | 3 / 3 | Tie |
| Model-visible tools per request | 1,025 | 27 | 97.366% fewer |
request/header.tools JSON |
674,249 B | 27,401 B | 95.936% smaller |
| Uncached input tokens | 199,751 | 21,713 | 89.130% fewer |
| Cache-read input tokens | 934,912 | 74,496 | 92.032% fewer |
| Estimated API cost | $0.0307204 | $0.0034707 | 88.702% lower |
The cost estimate multiplies provider-reported usage by the official DeepSeek V4 Flash pricing retrieved on August 14, 2026. That pricing page also announces a new peak/off-peak schedule effective at 16:00 UTC on August 16, 2026, so later comparisons should recompute from the recorded usage. The three-task setup, observed calls, formula, and tradeoffs are recorded in docs/LIVE_DEEPSEEK_PILOT.md.
Keyless component benchmark
The checked-in benchmark uses a real Harness Context, SystemPrompt, and ToolRuntime, the official direct client as baseline, and the same local MCP fixture for both arms:
| Remote MCP tools | Direct-client schema JSON | Lens schema JSON | Reduction |
|---|---|---|---|
| 12 | 4,862 B | 1,114 B | 77.088% |
| 100 | 62,062 B | 1,114 B | 98.205% |
| 1,000 | 647,962 B | 1,114 B | 99.828% |
At 1,000 tools, the official client registers 1,000 remote schemas while Lens still registers two. On the frozen 12-query retrieval fixture, Lens measured Recall@1 / Recall@5 / MRR = 1.0 / 1.0 / 1.0. That fixture was authored for this repository, so treat it as a regression guard—not independent evidence of real-world retrieval quality.
Reproduce the component result without an API key:
npm ci
npm run verify
npm run bench -- --output benchmark.json
The exact metric, fixture, dependency versions, source digest, and measurement limits are in benchmark/README.md.
Keep schema drift out of CI
The dependency-free MCP Lens Schema Audit GitHub Action measures an exported model-facing tool payload inside the runner. It makes no network request, writes numeric metrics plus schema-free share-url / share-markdown outputs, and never copies tool names, descriptions, or schemas into the Step Summary. Optional budgets turn an unexpected schema expansion into a failing check.
Accepted JSON shapes are a tool array, { "tools": [...] }, { "schemas": [...] }, { "header": { "tools": [...] } }, or a recorded { "request": { "header": { "tools": [...] } } } payload.
name: MCP schema budget
on: [pull_request]
permissions:
contents: read
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
- uses: labmimors/dsh-mcp-lens@f21169f921e7ed032a4db5062685afb6f948c2d1
with:
tools-file: artifacts/request-header.json
max-tools: 100
max-schema-bytes: 65536
The action accepts files up to 64 MiB, resolves the input inside GITHUB_WORKSPACE, and rejects symlink escapes. The byte metric is canonical JSON.stringify(tools) UTF-8 size—not tokens, billing, latency, or task quality.
Reliability and resource controls
- Lazy by default: no MCP process or socket at plugin activation; idle connections close automatically.
- Failure isolation: catalog refreshes run per server; one failure does not hide healthy servers.
- Last-good behavior: failed or oversized discovery never replaces a usable catalog generation.
- Bounded input: deadlines and caps cover pagination, tool count, per-tool bytes, total catalog bytes, cursors, and streamed HTTP responses.
- Credential-aware cache: the owner-only
0600cache stores projected tool metadata, never explicit env/header values or URL credentials. - Exact policy: search and call share the same allow/deny decision at the final
server/toolidentity. - Clean shutdown: cancellation, HMR, and disposal close transports, children, timers, and in-flight work.
MCP Lens is not a sandbox: stdio servers execute on the host, and HTTP servers receive the headers you configure. The current release bridges MCP Tools; it does not implement OAuth, Resources, Prompts, Elicitation, or task-based tool execution.
Configuration reference
Most users only need servers, cachePath, allowTools, and denyTools. The remaining fields already have bounded defaults:
| Field | Default | Purpose |
|---|---|---|
catalogTtlMs |
86400000 |
Refresh a catalog after 24 hours |
idleDisconnectMs |
300000 |
Close an idle server after 5 minutes |
connectTimeoutMs |
30000 |
Connection deadline |
callTimeoutMs |
60000 |
Tool-call deadline |
discoveryTimeoutMs |
30000 |
Whole paginated discovery deadline |
maxDiscoveryPages |
1000 |
Maximum pages per discovery |
maxToolsPerServer |
10000 |
Maximum tools accepted from one server |
maxBytesPerTool |
1048576 |
Maximum projected metadata bytes per tool |
maxTotalCatalogBytes |
67108864 |
Maximum total catalog/cache bytes |
maxHttpResponseBytes |
16777216 |
Maximum streamed HTTP response bytes |
maxCursorBytes |
4096 |
Maximum UTF-8 pagination cursor bytes |
searchLimitDefault |
5 |
Default search results |
searchLimitMax |
10 |
Maximum search results |
See the shipped cordis.patch.yml for the canonical defaults.
Security, development, and community
- Useful on your catalog? Star the repository and join the catalog challenge; sanitized real workloads help the next user decide.
- Want a quick before/after number? Use the local-only catalog calculator to paste your current tool surface, compute exact UTF-8 bytes, and export a shareable card without uploading your schemas.
- End-user terms:
EULA.md. - Privacy and data handling:
PRIVACY.md. - Support and response targets:
SUPPORT.md. - Security reports: read
SECURITY.md; do not disclose an unpatched exploit in a public issue. - Contributions: read
CONTRIBUTING.md. - Search quality: submit a sanitized search miss and help turn it into a regression fixture.
- Release:
v0.1.0-rc.8.
DeepSeek Harness currently discovers community plugins through public GitHub repositories with the dsh-plugin topic and installs them from GitHub, tarballs, or npm packages. See the official plugin publishing guide.
MCP Lens is an independent MIT-licensed community plugin and is not affiliated with or endorsed by DeepSeek AI.
Links
More in this category
strukto-ai/mirage#dsh★ 3416
Swaps the filesystem and bash providers for a mirage virtual workspace: file tools and shell commands run over mounted resources (RAM, S3, Redis, Slack, Gmail, Notion, Postgres) instead of the host disk, with per-mount read/write/exec modes, per-command sandbox routing (monty, pyodide, quickjs in process; docker, e2b, daytona remote), and installed CLIs (git, gh, slack, linear, ntn, gws, or one you register) as head words in the virtual terminal.
hust-open-atom-club/oh-dsh★ 171
Community distribution: TUI, desktop, and Web UI as one bundle with layered installation.
Jayden-X-L/forkprobe★ 65
Compare multiple skills on the same task and pick the winner.
vlln/plugin-registry★ 37
Ecosystem infrastructure: a thin browser console for managing official repository plugins (zero patches) plus a make-dsh-plugin skill for guided plugin development.
forrestchang/dsh-multica-runtime★ 32
Run the dsh runtime on Multica.
DietCokewithSugar/dsh-user-experience★ 18
Finds potential UX issues in your project: automatically reviews React/TypeScript code, pinpoints each problem, and gives concrete suggestions.