Agenten stärken
Der eigene Befehl des Herausgebers. Kein PlugMCP-Endpunkt.
Host a copy with our keys and logs.
npx -y [email protected]Claude Code hat keinen Installationslink für einen lokalen Befehl. Kopieren Sie den Befehl unten und führen Sie ihn in einem Terminal aus.
claude mcp add dsh-mcp-apps -- npx -y dsh-mcp-apps@0.2.6In einem Terminal ausführen.
{ "mcpServers": { "dsh-mcp-apps": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}claude_desktop_config.json
Remote-URL oder ein Befehl auf Ihrem Rechner? Worin sich die beiden Installationen unterscheiden
Auf PlugMCP ausführen
A new server you create. It is not this listing's official endpoint. Use the publisher install when you want their URL and their credentials.
StartenRenders MCP Apps as sandboxed interactive iframes in DeepSeek Harness (DSH) web chat.
MCP servers can return more than text: the MCP Apps extension (SEP-1865) lets a tool result carry a ui:// resource — a small, self-contained web app such as a dashboard, a map, or a form. By default, DSH doesn't know what to do with these and just shows the raw tool result. dsh-mcp-apps is a Cordis 4 plugin for DSH that recognizes these ui:// resources and renders them as live, interactive apps directly inside the chat turn, in a sandboxed iframe. The app can also call back into the host to run more tools (e.g. a "Refresh" button), gated behind an explicit, per-server approval policy.
ui:// resources) as interactive dashboards, charts, maps, and forms right inside DSH chat.allow-same-origin, no ambient access to the host page.deny / approve / allow).Interactive App badge and resist DSH's auto-collapse behavior, so they don't fold away when the model finishes streaming.${VAR} expansion for env vars and headers blocks DSH-internal and secret-shaped variable names unless you explicitly allow them.inject list (tools, connection) has no hard webServer requirement, so tool calls still work even where there's no browser to render into.>= 0.1.7-rc.2 with Cordis ~4.0.4dsh.client.platform is web (see package.json), so its UI does not render in other profiles (e.g. tui, headless) even if the plugin is installed there — but the plugin's host-side tools still register on those profiles (see Features).The packed plugin has been installed and exercised in a clean DSH 0.1.7-rc.2 web profile, including iframe rendering and delivery of the fixture tool input/result. Other DSH/Cordis combinations remain unverified; see the compatibility record.
DSH checks a plugin's @deepseek-ai/dsh-* peer ranges against its own runtime version (evaluatePluginCompatibility) and refuses to load an incompatible plugin. Match your DSH version to a plugin release:
See docs/dsh-compatibility.md for how the check works and why an exact-pinned peer (no range operator) fails against a later prerelease.
Open DSH Harness and click Plugins in the sidebar.

Click + Add plugin, then enter one of the following and click Install:
https://github.com/katticot/dsh-mcp-appsdsh-mcp-apps (Official npm registry)
pnpm dlx @deepseek-ai/[email protected] plugin --profile web add dsh-mcp-apps
This forwards to pnpm inside your DSH profile directory ($DSH_HOME/profiles/web), not your current project — it adds dsh-mcp-apps to that profile's own package.json. Don't run a plain pnpm add dsh-mcp-apps in an unrelated project and expect it to do anything for DSH.
dsh-mcp-apps ships as a DSH bundle (package.json#dsh.bundle): installing it also activates it, whether you install it through the UI or the CLI above. The package's own dsh/cordis.patch.yml inserts a single id: mcp-apps row with an empty server map, so the plugin is loaded (with no servers configured yet) as soon as it's installed — you don't hand-write that insert: yourself, and you shouldn't (see Configure below).
The plugin is already loaded with an empty servers: {} by the bundle patch above. To add servers, patch that same row from your own profile's patch file (e.g. ~/.dsh/profiles/web/cordis.patch.yml) — a top-level entry (no insert:) that targets the existing id: mcp-apps:
- id: mcp-apps
config:
# Required for any `oauth`-enabled server below: this DSH host's own
# externally reachable base URL, used to build the OAuth redirect_uri.
# It is never derived from an inbound request (a request's Host header
# is caller-controlled and cannot be trusted for a value baked into
# dynamic client registration) — set it explicitly to match however this
# host is actually reached (localhost, a LAN address, a reverse proxy...).
externalUrl: 'http://localhost:PORT'
servers:
# A remote server speaking Streamable HTTP or SSE
my-server:
transport: streamable-http
url: 'https://your-mcp-server.example.com/mcp'
# An OAuth-protected remote server, proxied through mcp-remote
my-oauth-server:
transport: stdio
command: npx
args: [-y, [email protected], 'https://your-mcp-server.example.com/mcp']
# An OAuth-protected remote server, handled natively (no mcp-remote)
my-native-oauth-server:
transport: streamable-http
url: 'https://your-mcp-server.example.com/mcp'
oauth: true
oauth: true enables native OAuth for sse/streamable-http servers: dynamic client registration (RFC 7591) plus the authorization-code + PKCE flow, with the "Connect Account" button in the plugin's status UI kicking off the browser-facing part. It's remote-transport only — stdio servers keep using the mcp-remote proxy above. oauth requires the top-level externalUrl to be set, and also accepts an object to configure a statically registered client instead of DCR:
my-static-oauth-server:
transport: streamable-http
url: 'https://your-mcp-server.example.com/mcp'
oauth:
clientId: 'my-client-id'
clientSecret: '${OAUTH_CLIENT_SECRET}'
scopes: [read, write]
Tokens (and any dynamically registered client) are stored per server in ~/.dsh/mcp-apps/oauth/<server-name>.json (plaintext, 0600/0700 permissions — the same access-controlled-not-encrypted trust model this plugin already applies to headers/env secrets).
A patch replaces the targeted row's whole config — it doesn't merge — so restate every key you want (including defaultTimeoutMs and every server, not just the one you're adding or changing).
Do not wrap this in insert:. insert: creates a new row; since the bundle already inserted one id: mcp-apps row for you, inserting a second one gives you two plugin instances both registering the same /api/mcp-apps/* RPC routes, which throws (connection: exact Fetch route "..." is already registered) — see Migrating from 0.2.x if you have an older insert:-based entry lying around.
A fuller example, showing environment expansion, headers, and reverse tool-calls:
- id: mcp-apps
config:
defaultTimeoutMs: 30000
servers:
# Local stdio subprocess (env values support ${VAR} / ${VAR:-default} expansion)
local-tool:
transport: stdio
command: go
args: ['run', 'main.go']
cwd: '/path/to/mcp-server'
env:
DATABASE_URL: '${DATABASE_URL}'
toolCallTimeoutMs: 45000
allowAppToolCalls: approve
# Remote SSE server with an auth header
remote-analytics:
transport: sse
url: 'https://mcp.example.com/sse'
headers:
Authorization: 'Bearer ${MCP_TOKEN}'
allowedVars: [MCP_TOKEN] # secret-shaped vars are blocked unless listed
reconnectOptions:
maxRetries: 10
Before 0.2.3, this package wasn't a bundle — you activated it yourself with an - insert: - id: <anything> \n name: dsh-mcp-apps entry in your profile's cordis.patch.yml. Since installing now activates the plugin automatically (via the package's own bundle patch), that old insert: entry is a second, duplicate instance and must be removed:
- insert: block that named dsh-mcp-apps (whatever id you gave it) from your profile's cordis.patch.yml.id: mcp-apps (no insert:), restating your servers config as shown above.npx @deepseek-ai/dsh --profile web --dump-config and confirm exactly one row with name: dsh-mcp-apps appears. Two rows means duplicate servers and a crash on load (see above) — remove whichever insert: you added.After saving cordis.patch.yml, restart the web profile so the loader applies the plugin entry:
pnpm dlx @deepseek-ai/[email protected] web
Call a tool on a configured server that returns a ui:// resource. Its tool input and result render in a sandboxed iframe with an Interactive App badge. App callbacks follow that server's allowAppToolCalls policy.
Rendered apps can call back into host tools (e.g. a "Refresh Data" button). That path is locked down by default:
tools/call request from an app must carry a valid AppSessionStore session token, scoped to the tool names and server it was issued for. A missing, expired, or mismatched-server token is rejected before the tool ever runs (src/index.ts).allowAppToolCalls (per server, default false/'deny'): a 'deny' | 'approve' | 'allow' setting (a plain boolean is also accepted as legacy shorthand for false/'allow').
'deny' (default): no tools are exposed for reverse calls from that server's apps.'allow' / true: reverse calls are permitted without approval.'approve': each reverse call is routed through ctx.approval (@deepseek-ai/dsh-user-approval) and requires the originating agent to have an open turn (agent.status === 'running'); outside of that window, or if the approval/agent services aren't available, the call fails with unavailable rather than silently allowing or hanging.isToolVisibilityAppOnly) are never registered with the LLM's tool list, and tools marked model-only (isToolVisibilityModelOnly) are excluded from the set an app is allowed to call back into — each direction is a one-way gate.${VAR} / ${VAR:-default} expansion only applies to env and headers values — not to url, args, or cwd. $$ is an escaped literal $. A default value cannot itself contain a nested ${...} expansion (e.g. ${MISSING:-${PORT}} is taken literally, not expanded recursively).
@deepseek-ai/dsh-mcp-client against the same MCP server alongside this plugin registers that server's tools through both plugins, duplicating them. Use one or the other for a given server.${VAR} isn't expanding: DSH_*-prefixed and secret-shaped (KEY/PASSWORD/SECRET/TOKEN) variable names, plus SSH_AUTH_SOCK/GPG_AGENT_INFO, are blocked by default — add the name to that server's allowedVars.allowAppToolCalls defaults to deny. Set it to approve or allow. Under approve, the call also needs an open, running agent turn to prompt for approval — it fails with unavailable outside of that window.http:// is only allowed to a loopback host (localhost, 127.0.0.1, ::1); anything else must be https://.dsh.client.platform: "web"). It won't render in tui, headless, or other profiles.dsh-mcp-apps rows: the plugin activates itself on install (it's a bundle) with an id: mcp-apps row — your own profile patch should target that same id with a bare top-level entry (no insert:, see Configure). An insert: there creates a second row, which crashes on load (duplicate /api/mcp-apps/* RPC route registration); see Migrating from 0.2.x. Run npx @deepseek-ai/dsh --profile web --patch <file> --dump-config to print the composed config and confirm exactly one name: dsh-mcp-apps row appears.Plugin [email protected] is incompatible with dsh <version>: peerDependencies {...}: your DSH runtime version doesn't satisfy this plugin's @deepseek-ai/dsh-* peer ranges. Check the compatibility table — [email protected]+ requires DSH >= 0.1.7-rc.2; upgrade DSH, or install an older plugin version matched to your DSH release.externalUrl is set (oauth/authorize fails immediately with a clear error if it isn't) and that it matches an address the browser can actually reach back to for the callback. Click Connect Account again — a stale authorize attempt's PKCE verifier expires after 10 minutes. Make sure the popup isn't blocked by the browser and that it's able to reach both the authorization server and externalUrl. If the authorization server rejects the callback with a redirect_uri mismatch, externalUrl changed since the client was registered — clear ~/.dsh/mcp-apps/oauth/<server-name>.json to force fresh dynamic client registration and try again.The plugin bridges a sandboxed iframe and the DSH host over postMessage-based JSON-RPC, manages a pool of MCP server connections, and normalizes tool names/visibility for the LLM. For the full internals — CSP synthesis, the postMessage handshake, tool fingerprinting, the anti-collapse behavior, and the resize circuit breaker — see docs/how-it-works.md.
# Install dependencies
pnpm install
# Type-check
pnpm typecheck
# Build host and client bundles (tsdown)
pnpm build
# Run Vitest test suite
pnpm test
./client (the browser-side bundle loaded by DSH's window.__ModuleLoader__) is loader-only: it has no types entry in package.json#exports and cannot be imported directly from Node or a bundler — only the . (host) entry ships type declarations.
See CONTRIBUTING.md for the release process.
MIT © katticot
Universal MCP Apps Host & UI Plugin for DeepSeek Harness (DSH)
{ "mcpServers": { "dsh-mcp-apps": { "command": "npx", "args": [ "-y", "[email protected]" ] } }}Tools
Noch keine Tool-Liste. Remote-Server erhalten eine nach dem ersten Health-Check.
FAQ
Kopieren Sie auf dieser Seite die stdio-Konfiguration für Cursor, Claude Desktop, Claude Code oder VS Code. Sie nutzt die Installation des Herausgebers, keinen PlugMCP-Proxy.
In diesem Eintrag ist keine erforderliche Umgebungsvariable aufgeführt.
Dsh MCP Apps läuft lokal über stdio.
Zuletzt geprüft: 2026-11-13. Universal MCP Apps Host & UI Plugin for DeepSeek Harness (DSH)