@plurnk/plurnk-mcp 1.6.1 → 1.8.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 (65) hide show
  1. package/.env.defaults +31 -4
  2. package/README.md +161 -42
  3. package/SPEC.md +486 -28
  4. package/dist/McpExecutor.d.ts +28 -5
  5. package/dist/McpExecutor.d.ts.map +1 -1
  6. package/dist/McpExecutor.js +144 -32
  7. package/dist/McpExecutor.js.map +1 -1
  8. package/dist/McpResources.d.ts +2 -2
  9. package/dist/McpResources.d.ts.map +1 -1
  10. package/dist/McpResources.js +114 -24
  11. package/dist/McpResources.js.map +1 -1
  12. package/dist/Module.d.ts +30 -5
  13. package/dist/Module.d.ts.map +1 -1
  14. package/dist/Module.js +857 -36
  15. package/dist/Module.js.map +1 -1
  16. package/dist/ToolPresentation.d.ts +7 -0
  17. package/dist/ToolPresentation.d.ts.map +1 -0
  18. package/dist/ToolPresentation.js +224 -0
  19. package/dist/ToolPresentation.js.map +1 -0
  20. package/dist/capabilityMatrix.d.ts +23 -0
  21. package/dist/capabilityMatrix.d.ts.map +1 -0
  22. package/dist/capabilityMatrix.js +403 -0
  23. package/dist/capabilityMatrix.js.map +1 -0
  24. package/dist/client.d.ts +27 -8
  25. package/dist/client.d.ts.map +1 -1
  26. package/dist/client.js +537 -91
  27. package/dist/client.js.map +1 -1
  28. package/dist/config.d.ts +14 -13
  29. package/dist/config.d.ts.map +1 -1
  30. package/dist/config.js +257 -51
  31. package/dist/config.js.map +1 -1
  32. package/dist/extensionChannel.d.ts +25 -0
  33. package/dist/extensionChannel.d.ts.map +1 -0
  34. package/dist/extensionChannel.js +195 -0
  35. package/dist/extensionChannel.js.map +1 -0
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +2 -2
  39. package/dist/index.js.map +1 -1
  40. package/dist/inputRequired.d.ts +36 -0
  41. package/dist/inputRequired.d.ts.map +1 -0
  42. package/dist/inputRequired.js +171 -0
  43. package/dist/inputRequired.js.map +1 -0
  44. package/dist/mcp-watchdog.mjs +106 -0
  45. package/dist/oauth.d.ts +28 -0
  46. package/dist/oauth.d.ts.map +1 -0
  47. package/dist/oauth.js +149 -0
  48. package/dist/oauth.js.map +1 -0
  49. package/dist/protocol.d.ts +8 -0
  50. package/dist/protocol.d.ts.map +1 -0
  51. package/dist/protocol.js +8 -0
  52. package/dist/protocol.js.map +1 -0
  53. package/dist/protocolHeaders.d.ts +4 -0
  54. package/dist/protocolHeaders.d.ts.map +1 -0
  55. package/dist/protocolHeaders.js +87 -0
  56. package/dist/protocolHeaders.js.map +1 -0
  57. package/dist/subscriptions.d.ts +15 -0
  58. package/dist/subscriptions.d.ts.map +1 -0
  59. package/dist/subscriptions.js +188 -0
  60. package/dist/subscriptions.js.map +1 -0
  61. package/dist/tasks.d.ts +19 -0
  62. package/dist/tasks.d.ts.map +1 -0
  63. package/dist/tasks.js +334 -0
  64. package/dist/tasks.js.map +1 -0
  65. package/package.json +12 -7
package/.env.defaults CHANGED
@@ -5,15 +5,42 @@
5
5
  PLURNK_MCP_CONNECT_TIMEOUT=30000
6
6
  PLURNK_MCP_REQUEST_TIMEOUT=86400000
7
7
 
8
- # Each configured server becomes `## EXEC0 [server]` and server://.
8
+ # Configured servers are available to clients. Only this exact JSON-array
9
+ # subset connects and becomes model-visible by default; workspaces may override it.
10
+ PLURNK_MCP_ENABLED=[]
11
+
12
+ # Turn 0 surveys enabled tool FAMILIES (one row per server, summary = its
13
+ # one-liner). Servers named here also expand their complete tool tree into
14
+ # the turn-0 survey:
15
+ # PLURNK_MCP_EXPANDED=[]
16
+
17
+ # Each configured server contributes its enabled `[server] (tool)` rows and server:// resources.
9
18
  #
10
19
  # Streamable HTTP:
11
20
  # PLURNK_MCP_github=https://example.test/mcp
12
- # PLURNK_MCP_github_HEADERS={"Authorization":"Bearer ${GITHUB_TOKEN}"}
21
+ # PLURNK_MCP_github_BEARER=${GITHUB_TOKEN}
22
+ # PLURNK_MCP_github_TOOLS=["issue_read","issue_search"]
23
+ # PLURNK_MCP_github_READ=["issue_read","issue_search"]
13
24
  #
14
- # stdio: the target is one executable. Arguments are a JSON array so Plurnk
15
- # does not invent or interpret a shell command language.
25
+ # stdio: the target is one exact executable path/name, including whitespace.
26
+ # Arguments are a JSON array so Plurnk does not invent or interpret a shell.
16
27
  # PLURNK_MCP_atlas=node
17
28
  # PLURNK_MCP_atlas_ARGS=["/absolute/path/to/atlas-server.mjs"]
18
29
  # PLURNK_MCP_atlas_CWD=/absolute/working/directory
19
30
  # PLURNK_MCP_atlas_ENV={"TOKEN":"${ATLAS_TOKEN}"}
31
+ #
32
+ # npx (installed-on-demand executables) — the documented Brave Search fixture,
33
+ # demo-tier only; credentials stay one ${NAME} reference in the operator env:
34
+ # PLURNK_MCP_BRAVE=npx
35
+ # PLURNK_MCP_BRAVE_ARGS=["-y","@brave/brave-search-mcp-server@2.1.0"]
36
+ # PLURNK_MCP_BRAVE_ENV={"BRAVE_API_KEY":"${BRAVE_API_KEY}"}
37
+ # PLURNK_MCP_BRAVE_TOOLS=["brave_web_search","brave_news_search"]
38
+ # PLURNK_MCP_BRAVE_READ=["brave_web_search","brave_news_search"]
39
+ #
40
+ # _SUMMARY companions are fallbacks only — declare one when the server's own
41
+ # summary metadata is missing, confusing, or garbage. The family row can carry
42
+ # its flagship invocation form directly:
43
+ # PLURNK_MCP_BRAVE_SUMMARY=EXEC [brave] (brave_web_search) <!-- Retrieve web results -->
44
+ # PLURNK_MCP_BRAVE_BRAVE_WEB_SEARCH_SUMMARY=General web search.
45
+ #
46
+ # Then list it above to make it model-visible, e.g. PLURNK_MCP_ENABLED=["brave"].
package/README.md CHANGED
@@ -1,35 +1,128 @@
1
1
  # @plurnk/plurnk-mcp
2
2
 
3
3
  The current [Model Context Protocol](https://modelcontextprotocol.io/) host
4
- module for [Plurnk](https://github.com/plurnk/plurnk-service).
4
+ module for [Plurnk](https://github.com/plurnk/plurnk-service). It projects
5
+ trusted MCP servers through Plurnk's existing executor, resource, proposal,
6
+ entry, Problem, lifecycle, and AG-UI contracts.
7
+
8
+ The module's own wire authority is protocol revision `2026-07-28`
9
+ ({§mcp-authority}). Connection setup negotiates-and-degrades: a server that
10
+ offers the pinned revision and `server/discover` gets the complete extension
11
+ wire; a server the SDK negotiated below the pin is an ordinary MCP peer that
12
+ serves its standard surface at its own negotiated revision. Plurnk does not
13
+ downgrade its own extension wire, but it does not reject an older supported
14
+ revision.
15
+
16
+ ## Manage workspace servers
17
+
18
+ Service environment variables provide available servers for every workspace;
19
+ `PLURNK_MCP_ENABLED` selects the exact cold-enabled subset. Users can add,
20
+ enable, disable, or remove workspace servers without restarting the daemon. An
21
+ existing AG-UI connection sends the ordinary management-action form under
22
+ `forwardedProps.plurnk.action`:
23
+
24
+ ```json
25
+ {
26
+ "forwardedProps": {
27
+ "plurnk": {
28
+ "workspace": "example",
29
+ "action": {
30
+ "kind": "workspace.mcp.add",
31
+ "alias": "project",
32
+ "target": "/opt/mcp/current-server",
33
+ "options": {
34
+ "args": ["--stdio"],
35
+ "env": { "PROJECT_TOKEN": "${PROJECT_TOKEN}" },
36
+ "tools": ["issue_read", "issue_write"],
37
+ "read": ["issue_read"]
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ The standard `plurnk.action.result` event reports success or exact RFC 9457
46
+ Problem Details. The definition is durable and workspace-shared; symbolic
47
+ environment references remain unexpanded at rest.
5
48
 
6
- Each configured MCP server becomes a model-facing executor and resource
7
- authority:
49
+ Available workspace actions are:
8
50
 
9
- ```plurnk
10
- ## READ0 (github:///)
51
+ | Action | Parameters |
52
+ |---|---|
53
+ | `workspace.mcp.list` | optional client `overlay` |
54
+ | `workspace.mcp.add` | `alias`, `target`; optional `options` |
55
+ | `workspace.mcp.enable` | `alias`; optional client `overlay` and explicit `options` |
56
+ | `workspace.mcp.disable` | `alias` |
57
+ | `workspace.mcp.remove` | `alias` |
58
+ | `workspace.mcp.oauth.complete` | `alias`, complete `callbackUrl` |
59
+ | `workspace.mcp.complete` | `server`, completion `ref` and `argument`; optional `context` |
11
60
 
12
- ## EXEC0 [github] (create_issue)
13
- {"title":"Bug"}
61
+ The owning [specification](./SPEC.md) defines the complete action and server
62
+ definition contracts.
14
63
 
15
- ## FIND0 (github:///resources/**)
64
+ Client and project configuration can specialize a cold service definition
65
+ without copying it or restarting the daemon. For example, a service catalog
66
+ can provide the executable while one project's `.env` supplies its identity:
16
67
 
17
- ## READ0 (github:///resources/https%3A%2F%2Fexample.test%2Fdocument)
68
+ ```text
69
+ # $XDG_CONFIG_HOME/plurnk/.env, read by the service
70
+ PLURNK_MCP_GITEA=/usr/local/bin/possumtech-gitea-mcp
71
+ PLURNK_MCP_ENABLED=[]
72
+
73
+ # <project>/.env, read by the client
74
+ PLURNK_MCP_GITEA_ARGS=["plurnk_pk"]
18
75
  ```
19
76
 
20
- The module requires protocol revision `2026-07-28`. It does not negotiate or
21
- fall back to a legacy revision.
77
+ The client carries its raw declarations while listing and enabling. Listing is
78
+ inert. `/mcp enable gitea` (or `plurnk mcp enable gitea` in a named workspace)
79
+ composes service, durable workspace, client, and optional command-file fields
80
+ in that order, prepares the connection, then persists the complete unexpanded
81
+ workspace specialization. Arrays and maps replace rather than append or merge.
82
+
83
+ ## Demo fixtures
84
+
85
+ Web discovery is an ordinary MCP attachment ({§web-search-retrieval}); the demo
86
+ tier exercises search through a documented fixture rather than an owned
87
+ runtime. Two service-owned definitions are permitted to participate in demos
88
+ of MCP and model behavior — Gitea (above) and Brave Search:
89
+
90
+ ```text
91
+ # $XDG_CONFIG_HOME/plurnk/.env, read by the service — demo fixtures; never default-enabled
92
+ PLURNK_MCP_BRAVE=npx
93
+ PLURNK_MCP_BRAVE_ARGS=["-y","@brave/brave-search-mcp-server@2.1.0"]
94
+ PLURNK_MCP_BRAVE_ENV={"BRAVE_API_KEY":"${BRAVE_API_KEY}"}
95
+ PLURNK_MCP_BRAVE_TOOLS=["brave_web_search","brave_news_search"]
96
+ PLURNK_MCP_BRAVE_READ=["brave_web_search","brave_news_search"]
97
+ PLURNK_MCP_ENABLED=[]
98
+ ```
22
99
 
23
- ## Configuration
100
+ The credential is one symbolic reference — the authoritative `BRAVE_API_KEY`
101
+ environment value is expanded only while preparing the connection, never
102
+ copied. The fixture admits exactly the web/news search tools and classifies
103
+ them read-only; the rest of the vendor catalog is not admitted.
24
104
 
25
- Configuration is daemon-owned. One `PLURNK_MCP_<server>` variable declares
26
- each server; the suffix case-folds to the executor and URI authority name.
105
+ **Pinned release and revision.** `@brave/brave-search-mcp-server@2.1.0`
106
+ (stdio) pins `@modelcontextprotocol/sdk@1.29.0`, whose latest protocol
107
+ revision is `2025-11-25` and which does not implement `server/discover`. The
108
+ host negotiates-and-degrades ({§mcp-authority}), so the fixture connects at
109
+ `2025-11-25` with the standard tool surface — verified live: the demo story
110
+ `{§web-search-retrieval}` researched through the real Brave MCP tool and
111
+ answered from it.
112
+
113
+ ## Service defaults
114
+
115
+ One `PLURNK_MCP_<server>` variable declares each available server. Its suffix
116
+ case-folds to an `[a-z][a-z0-9-]*` executor and URI-authority name.
27
117
 
28
118
  Streamable HTTP:
29
119
 
30
120
  ```text
31
121
  PLURNK_MCP_github=https://example.test/mcp
32
- PLURNK_MCP_github_HEADERS={"Authorization":"Bearer ${GITHUB_TOKEN}"}
122
+ PLURNK_MCP_github_BEARER=${GITHUB_TOKEN}
123
+ PLURNK_MCP_github_TOOLS=["issue_read","issue_search"]
124
+ PLURNK_MCP_github_READ=["issue_read","issue_search"]
125
+ PLURNK_MCP_ENABLED=["github"]
33
126
  ```
34
127
 
35
128
  Stdio:
@@ -41,33 +134,59 @@ PLURNK_MCP_local_CWD=/absolute/working/directory
41
134
  PLURNK_MCP_local_ENV={"TOKEN":"${LOCAL_TOKEN}"}
42
135
  ```
43
136
 
44
- The stdio target is exactly one executable. Arguments are a JSON array; the
45
- module never parses or invokes a shell command. `${NAME}` references read the
46
- daemon's inherited environment at startup, so secrets do not need to be copied
47
- into Plurnk environment files.
48
-
49
- Portable timeout defaults and complete examples live in
50
- [`.env.defaults`](./.env.defaults).
51
-
52
- ## Current surface
53
-
54
- - `## READ0 (server:///)` returns the live tools, resources, resource templates, and
55
- prompts catalog.
56
- - `## EXEC0 [server] (tool)` calls a tool with one JSON object in the body.
57
- - `server:///resources` exposes the resource catalog through ordinary Plurnk
58
- `FIND` and `READ` sections.
59
- - `server:///resources/<encoded-uri>` reads a concrete MCP resource and stores
60
- it as an ordinary entry, after which normal projection and slicing apply.
61
- - A tool's `readOnlyHint` selects Plurnk's read effect. Unknown or mutating
62
- tools retain the host effect.
63
-
64
- Prompt retrieval, resource subscriptions, current multi-round-trip input,
65
- current task methods, and OAuth/OIDC authorization are not part of this
66
- vertical slice. They will use the same module and connection seams; no legacy
67
- protocol surface is retained as a fallback.
137
+ The stdio target is one exact executable path or name, including literal
138
+ whitespace. Arguments are a JSON array; the module never parses or invokes a
139
+ shell command. `${NAME}` references resolve from the daemon's inherited
140
+ environment only while preparing a connection.
141
+
142
+ `PLURNK_MCP_<server>_TOOLS` is an optional JSON array of exact names. Absence
143
+ enables every listed server tool; an array enables exactly those names; `[]`
144
+ enables none. `PLURNK_MCP_<server>_READ` is an exact enabled-tool subset whose
145
+ calls use Plurnk's `read` effect. Every other enabled tool conservatively uses
146
+ the proposal-gated `host` effect. Remote annotations never grant effect
147
+ authority.
148
+
149
+ Portable timeouts and complete examples live in [`.env.defaults`](./.env.defaults).
150
+
151
+ ## Plurnk projection
152
+
153
+ | MCP surface | Plurnk surface |
154
+ |---|---|
155
+ | Server tools | `worker://plurnk/tools/<server>.md` family summary |
156
+ | Enabled tool | Exact `worker://plurnk/tools/<server>/<encoded-tool>.md` document and `## EXEC0 [server] (tool)` |
157
+ | Resource catalog | `server:///` or `server:///resources` |
158
+ | Resource | `server:///resources/<encoded-uri>` through ordinary `FIND` and `READ` |
159
+ | Prompt catalog | `server:///prompts` |
160
+ | Prompt retrieval | `server:///prompts/<encoded-name>?argument=value` through ordinary `READ` |
161
+ | Completion | Client-owned `workspace.mcp.complete` action |
162
+
163
+ Tool results, resource bodies, prompt messages, and failures become ordinary
164
+ Plurnk entries and channels. Disabled tools appear in neither teaching nor
165
+ admission. There is no MCP-specific model discovery grammar.
166
+
167
+ Current pagination, cache hints, unified subscriptions, progress,
168
+ cancellation, multi-round-trip input, elicitation, and negotiated Tasks remain
169
+ inside the owning operation. Client input uses the standard AG-UI interrupt and
170
+ resume lifecycle; protocol continuation state is never exposed to the model or
171
+ client.
172
+
173
+ ## Authorization
174
+
175
+ HTTP definitions support bearer references, client credentials, and
176
+ interactive OAuth. Stdio never receives OAuth. Interactive add or enable returns
177
+ `{ "status": 202, "authorization": { "url": "..." } }` without publishing a
178
+ partial server. After the user completes that URL, the client submits its
179
+ complete callback URL through `workspace.mcp.oauth.complete`. PKCE, issuer and
180
+ resource validation, refresh, scope escalation, and credentials remain inside
181
+ the host connection.
68
182
 
69
183
  ## Verification
70
184
 
71
- `npm test` type-checks the module and exercises exact current-version
72
- negotiation, configuration, tool calls, resource reads, runtime registration,
73
- and rejection of ambiguous shell and secret configuration.
185
+ ```sh
186
+ npm test -w @plurnk/plurnk-mcp
187
+ npm run test:mcp:dogfood -w @plurnk/plurnk-service
188
+ ```
189
+
190
+ The package gate runs the exact current SDK and official conformance
191
+ requirements. The opt-in dogfood gate composes representative current stdio
192
+ and Streamable HTTP servers through the assembled daemon and AG-UI product.