@auggieteo/dsh-mcp-adapter 0.1.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.
package/CONTEXT.md ADDED
@@ -0,0 +1,37 @@
1
+ # DSH MCP Adapter
2
+
3
+ A Deepseek Harness (DSH) plugin that connects the DSH agent to MCP servers, mirroring the major features of pi-mcp-adapter. Configuration lives in the DSH web UI under Settings > MCP.
4
+
5
+ ## Language
6
+
7
+ **Adapter**:
8
+ The DSH plugin this repo builds. It owns MCP client connections and exposes their tools to the DSH agent.
9
+ _Avoid_: extension, bridge, wrapper
10
+
11
+ **Server**:
12
+ One configured MCP server entry, identified by its name. A server has one transport and produces zero or more tools.
13
+ _Avoid_: endpoint, backend, service
14
+
15
+ **Transport**:
16
+ How the adapter talks to a server: stdio subprocess, or remote streamable HTTP with SSE fallback.
17
+ _Avoid_: channel, protocol, connection type
18
+
19
+ **Proxy Tool**:
20
+ The single DSH tool named `mcp` that the model uses to search, describe, and call any server's tools. It is the token-efficient default surface, mirroring pi-mcp-adapter.
21
+ _Avoid_: bridge tool, gateway tool, dispatcher
22
+
23
+ **Promotion**:
24
+ Turning one MCP tool into a native DSH tool registered in the DSH tool registry, with its own tool card and approval behavior. Controlled per tool in Settings > MCP. Mirrored from pi-mcp-adapter's `directTools`.
25
+ _Avoid_: direct tool, native tool, registration
26
+
27
+ **Auto-allow**:
28
+ A per-server toggle that lets that server's tool calls run without asking the user. All other calls ask per call through the DSH approval system.
29
+ _Avoid_: trust, bypass, whitelist
30
+
31
+ **Config**:
32
+ The standard `mcpServers`-shaped JSON stored in the adapter's DSH settings namespace, editable in Settings > MCP. Global: one list for every DSH session.
33
+ _Avoid_: manifest, registry file
34
+
35
+ **Lazy Lifecycle**:
36
+ The connection policy: a server connects on first use and disconnects after an idle timeout. Opposite of eager connect at startup.
37
+ _Avoid_: on-demand boot, cold start
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 The dsh-mcp-adapter authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # dsh-mcp-adapter
2
+
3
+ A [Deepseek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) plugin that connects the DSH agent to MCP servers. It mirrors the major features of [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter): one token-efficient `mcp` proxy tool over every configured server, optional per-tool promotion to native DSH tools, and lazy server lifecycles. Servers are added and configured in the DSH web UI under **Settings > MCP**; configuration persists in the DSH settings document (`$DSH_HOME/settings.yaml`, namespace `mcp`).
4
+
5
+ Vocabulary lives in [CONTEXT.md](./CONTEXT.md). Design decisions live in [docs/adr/](./docs/adr/). Work is tracked as [GitHub issues](https://github.com/auggie246/dsh-mcp-adapter/issues).
6
+
7
+ ## Status
8
+
9
+ The v1 implementation is complete through issues #1–#7. See the [v1 end-to-end verification](./docs/verification/v1-e2e.md). Issues #8–#14 track deferred follow-ups.
10
+
11
+ ## Config
12
+
13
+ The Host registers one live DSH settings namespace, `mcp`. Its user layer lives under `mcp:` in `$DSH_HOME/settings.yaml`; the Settings > MCP page owns normal edits.
14
+
15
+ ```yaml
16
+ mcp:
17
+ mcpServers:
18
+ filesystem:
19
+ command: npx
20
+ args: [-y, "@modelcontextprotocol/server-filesystem", /workspace]
21
+ autoAllow: false
22
+ hosted:
23
+ url: https://mcp.example.com/api
24
+ headers:
25
+ Authorization: Bearer example-token
26
+ ```
27
+
28
+ Each Server configures exactly one Transport: `command` for stdio, or `url` for streamable HTTP with SSE fallback. Adapter extension fields are `disabled`, `autoAllow`, `lifecycle` (`lazy` only in v1), `idleTimeoutMinutes` (default `10`), and `promotedTools`.
29
+
30
+ The schema rejects unknown fields and invalid transport combinations before they reach `$DSH_HOME/settings.yaml`. Each `env` and `headers` value has the DSH `secret` schema role. Wire views retain each key and redact its value.
31
+
32
+ ## Settings page
33
+
34
+ Open **Settings > MCP** to add, import, edit, reconnect, disable, or delete a Server. The Server list shows live connection state and cached tool counts. The detail panel manages Transport fields, secret values, Auto-allow, the idle timeout, and Promotions.
35
+
36
+ JSON import accepts the standard `{ "mcpServers": { ... } }` shape. Import replaces matching Server entries and preserves Servers absent from the import.
37
+
38
+ Every page write carries the latest namespace revision. Field edits use path mutations. Existing secret values remain saved when their value inputs stay blank.
39
+
40
+ ## Server lifecycle
41
+
42
+ The Host creates no unpromoted Server connection at startup. The first tool-list or tool-call request connects the Server and fills an in-memory metadata cache. A persisted Promotion can connect once to rebuild its native input schema. MCP `tools/list_changed` notifications refresh the cache. The default idle timeout closes the connection after 10 minutes without a request; the next request reconnects it.
43
+
44
+ Changing, disabling, or removing a Server closes its connection and clears its cache. Re-enabling a Server restores the lazy behavior. A Connection RPC channel, `/mcp-adapter`, exposes detached `status`, `catalog`, and combined `overview` snapshots. Its `reconnect` endpoint restarts one named Server. These endpoints never expose Config secrets or SDK objects.
45
+
46
+ ## Proxy Tool
47
+
48
+ The Host registers one global `mcp` tool with three actions:
49
+
50
+ ```text
51
+ mcp({ action: "search", query: "screenshot" })
52
+ mcp({ action: "describe", server: "browser", tool: "take_screenshot" })
53
+ mcp({ action: "call", server: "browser", tool: "take_screenshot", args: {} })
54
+ ```
55
+
56
+ Search results use `<server>__<tool>` names to avoid collisions. The first search fills empty metadata caches; later search and describe operations use the cache. Call requests ask for DSH approval unless that Server has `autoAllow: true`.
57
+
58
+ Call, search, and describe output is limited to 50 KiB and 2,000 lines. Larger text uses `spillStore` for a full-result reference. Raw structured details larger than 16 KiB become a compact summary with their own spill reference.
59
+
60
+ ## Promotion
61
+
62
+ Add a raw MCP tool name to a Server's `promotedTools` list to register `<server>__<tool>` as a native DSH tool. The native tool uses the MCP input schema and the same approval, call, and output-guard path as `mcp({ action: "call" })`.
63
+
64
+ Promotion changes apply through `settings/updated`. They do not restart a connected Server. Removing a Promotion unregisters its native tool. Non-promoted tools remain available only through the `mcp` Proxy Tool.
65
+
66
+ DSH native tool names must match `[A-Za-z0-9_-]` and contain at most 64 characters. The Adapter logs a warning and skips an invalid or colliding Promotion name.
67
+
68
+ ## Install
69
+
70
+ Requires the `dsh` CLI and a web profile (the browser GUI you run DSH with).
71
+
72
+ ```sh
73
+ dsh plugin --profile web add @auggieteo/dsh-mcp-adapter
74
+ ```
75
+
76
+ Then restart DSH. The Settings panel (`⌘,` / sidebar foot) gains an **MCP** section.
77
+
78
+ ### Local development
79
+
80
+ ```sh
81
+ pnpm install
82
+ pnpm build # produces lib/client.js (required before install)
83
+ dsh plugin --profile web add /absolute/path/to/dsh-mcp-adapter
84
+ ```
85
+
86
+ During client development, run `pnpm dev` alongside DSH. `dsh-client-hmr` reloads each rebuilt client bundle without a manual refresh.
87
+
88
+ Host changes need a DSH restart. The web profile disables host HMR for plugin rows.
89
+
90
+ ## Uninstall
91
+
92
+ ```sh
93
+ dsh plugin --profile web remove @auggieteo/dsh-mcp-adapter
94
+ ```
95
+
96
+ ## Release
97
+
98
+ The package uses Semantic Versioning. Update `package.json` before each release.
99
+
100
+ ```sh
101
+ pnpm version patch --no-git-tag-version # or minor, major, or an explicit version
102
+ pnpm test
103
+ ```
104
+
105
+ Merge the version change. Then publish a GitHub Release whose tag is exactly `v<package version>`.
106
+
107
+ The `Publish to npm` workflow rejects any different tag. It tests and builds the package before publishing with npm provenance.
108
+
109
+ A prerelease GitHub Release publishes with the npm `next` tag. A regular GitHub Release publishes with the npm `latest` tag.
110
+
111
+ The first publish creates the npm package. Add a short-lived granular npm token as the GitHub `NPM_TOKEN` secret for this publish.
112
+
113
+ Then configure npm trusted publishing for `auggie246/dsh-mcp-adapter` and `publish.yml`. Allow `npm publish`, then delete `NPM_TOKEN`.
114
+
115
+ Later releases use GitHub OIDC and need no long-lived npm token. npm requires the package to exist before trusted publishing configuration.
116
+
117
+ ## Layout
118
+
119
+ ```
120
+ cordis.patch.yml bundle patch: inserts the host composition row on install
121
+ src/host/ host half: plain ESM, no build step
122
+ src/client/ client half: JSX, bundled to lib/client.js
123
+ build.mjs esbuild wrapper producing the loader-compatible bundle
124
+ lib/client.js build artifact (gitignored), required at runtime
125
+ docs/adr/ architecture decisions
126
+ CONTEXT.md project vocabulary
127
+ ```
@@ -0,0 +1,8 @@
1
+ # Bundle patch for dsh-mcp-adapter: inserts the Adapter's host row into the
2
+ # profile tree. `dsh plugin --profile web add <this repo>` appends this bundle
3
+ # to dsh.profile.bundles automatically. The client roster entry is discovered
4
+ # from package.json's dsh.client block by the clientModules scan — no row here.
5
+
6
+ - insert:
7
+ - id: mcp-adapter
8
+ name: "@auggieteo/dsh-mcp-adapter"
@@ -0,0 +1,7 @@
1
+ # Proxy-first tool surface
2
+
3
+ The Adapter exposes every Server's tools to the DSH agent through one Proxy Tool named `mcp` (search / describe / call) instead of registering every MCP tool natively, mirroring pi-mcp-adapter's headline design. The reason is token economy: registering every MCP tool natively would put hundreds of tool schemas into every model step of every session, whether or not they are used. Native registration stays available through Promotion, a per-tool toggle in Settings > MCP, for tools whose DSH-native card and approval UX justify the context cost.
4
+
5
+ Considered options: native registration for every server (best per-tool UX, unbounded context cost, rejected); proxy only (strictest pi mirror, no native path at all, rejected to keep the Promotion escape hatch).
6
+
7
+ Consequences: approval gating for proxy calls must live inside the Proxy Tool's `execute` (DSH does not gate new tools by default), keyed on the server name inside the call arguments, with the per-server Auto-allow toggle consulted there. Promoted tools rely on DSH's native surface instead.
@@ -0,0 +1,7 @@
1
+ # Config in the DSH settings namespace, not .mcp.json files
2
+
3
+ Server Config is stored in the Adapter's `mcp` namespace of the DSH settings service (persisted to `$DSH_HOME/settings.yaml`, hot-reloaded, revision-fenced), not in pi-mcp-adapter's layered `.mcp.json` files. We still adopt the standard `mcpServers`-shaped JSON as the Config schema, so users can paste configs from pi, Claude Desktop, Cursor, or VS Code.
4
+
5
+ Considered options: pi's multi-file merge chain (`~/.config/mcp/mcp.json` → agent dirs → workspace `.mcp.json`, plus cross-tool `imports`) was rejected because DSH users interact through the web UI, not dotfiles; a single global namespace with a Settings > MCP form matches how every other DSH settings surface works, and gives us validation, conflict detection, and live update events for free.
6
+
7
+ Consequences: per-workspace servers and config-file imports become a later feature layered on top of the namespace (a workspace source merged at resolve time), not a change to where the global Config lives. The settings page needs an explicit JSON import action, since there is no file to copy-paste into.
@@ -0,0 +1,45 @@
1
+ # v1 end-to-end verification
2
+
3
+ Date: 2026-08-30
4
+
5
+ ## Environment
6
+
7
+ - Package commit: `69f6b16` plus this verification record.
8
+ - Install: `link:/Users/augustine/projects/dsh-mcp-adapter` in the `web` profile.
9
+ - DSH profile: `/Users/augustine/.dsh/profiles/web`.
10
+ - Managed verification server: a fresh `dsh web --no-open --port 0` process.
11
+ - Browser: headless Google Chrome through the Chrome DevTools Protocol.
12
+ - Fixture: `test/fixtures/mcp-stdio-server.mjs`.
13
+
14
+ This run did not use a clean `$DSH_HOME`. The profile already contained unrelated model and UI settings. The `mcp` namespace was absent before the test. A separate managed web process loaded the current Host code without interrupting the active development session.
15
+
16
+ ## Build checks
17
+
18
+ - `pnpm install --frozen-lockfile`: passed.
19
+ - `pnpm build`: passed.
20
+ - `pnpm test`: 28 of 28 tests passed.
21
+ - `git diff --check`: passed.
22
+ - `npm pack --dry-run`: passed with a temporary npm cache. The user cache contains unrelated root-owned files.
23
+
24
+ ## Browser checks
25
+
26
+ 1. Opened **Settings > MCP** and confirmed the empty state.
27
+ 2. Added `e2e-fixture` as a stdio Server through the form.
28
+ 3. Confirmed `$DSH_HOME/settings.yaml` contained the command, args, defaults, and empty Promotion list.
29
+ 4. Confirmed the initial Server state was `disconnected` with zero cached tools.
30
+ 5. Used **Reconnect** and confirmed `connected`, `stdio`, and one cached `ping` tool.
31
+ 6. Promoted `ping` and confirmed `promotedTools: [ping]` in `settings.yaml`.
32
+ 7. Started an Agent session and used the Proxy Tool to search, describe, and call `e2e-fixture__ping`.
33
+ 8. Confirmed the call showed an approval request with the redacted argument preview.
34
+ 9. Selected **Allow once** and received the exact result `pong`.
35
+ 10. Enabled Auto-allow through Settings and confirmed `autoAllow: true` in `settings.yaml`.
36
+ 11. Called the Proxy Tool again and received `pong` without an approval request.
37
+ 12. Called the promoted native `e2e-fixture__ping` tool and received `pong`.
38
+ 13. Set `idleTimeoutMinutes` to `0.1` and confirmed an idle disconnect with the tool cache retained.
39
+ 14. Disabled the Server and confirmed state `disabled` with its cache cleared.
40
+ 15. Re-enabled the Server and confirmed it became available again.
41
+ 16. Deleted the Server and confirmed the empty state and `mcpServers: {}` in `settings.yaml`.
42
+
43
+ ## Rough edge
44
+
45
+ A persisted Promotion needs its MCP input schema after Host startup or Server re-enable. The Promotion registry currently connects that Server to rebuild metadata, then the normal idle timeout closes it. GitHub issue #14 tracks the lifecycle decision and documentation correction.