@yolk-sdk/mcp 0.1.0-canary.13 → 0.1.0-canary.130
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/README.md +393 -40
- package/dist/client/client.d.mts +83 -19
- package/dist/client/client.d.mts.map +1 -1
- package/dist/client/client.mjs +599 -106
- package/dist/client/client.mjs.map +1 -1
- package/dist/client/config.d.mts +7 -10
- package/dist/client/config.d.mts.map +1 -1
- package/dist/client/config.mjs +1 -2
- package/dist/client/effect-fetch.d.mts +4 -0
- package/dist/client/effect-fetch.d.mts.map +1 -0
- package/dist/client/effect-fetch.mjs +35 -0
- package/dist/client/effect-fetch.mjs.map +1 -0
- package/dist/client/elicitation.d.mts +176 -0
- package/dist/client/elicitation.d.mts.map +1 -0
- package/dist/client/elicitation.mjs +508 -0
- package/dist/client/elicitation.mjs.map +1 -0
- package/dist/client/errors.d.mts +36 -7
- package/dist/client/errors.d.mts.map +1 -1
- package/dist/client/errors.mjs +39 -4
- package/dist/client/errors.mjs.map +1 -1
- package/dist/client/index.d.mts +6 -4
- package/dist/client/index.mjs +6 -4
- package/dist/client/node.d.mts +8 -11
- package/dist/client/node.d.mts.map +1 -1
- package/dist/client/node.mjs +2 -2
- package/dist/client/node.mjs.map +1 -1
- package/dist/client/protocol.d.mts +150 -56
- package/dist/client/protocol.d.mts.map +1 -1
- package/dist/client/protocol.mjs +268 -39
- package/dist/client/protocol.mjs.map +1 -1
- package/dist/conformance/auth-rejected.d.mts +4 -0
- package/dist/conformance/auth-rejected.d.mts.map +1 -0
- package/dist/conformance/auth-rejected.mjs +19 -0
- package/dist/conformance/auth-rejected.mjs.map +1 -0
- package/dist/conformance/call-gate.d.mts +14 -0
- package/dist/conformance/call-gate.d.mts.map +1 -0
- package/dist/conformance/call-gate.mjs +133 -0
- package/dist/conformance/call-gate.mjs.map +1 -0
- package/dist/conformance/call-read.d.mts +6 -0
- package/dist/conformance/call-read.d.mts.map +1 -0
- package/dist/conformance/call-read.mjs +24 -0
- package/dist/conformance/call-read.mjs.map +1 -0
- package/dist/conformance/call-tool-error.d.mts +5 -0
- package/dist/conformance/call-tool-error.d.mts.map +1 -0
- package/dist/conformance/call-tool-error.mjs +23 -0
- package/dist/conformance/call-tool-error.mjs.map +1 -0
- package/dist/conformance/cases.d.mts +25 -0
- package/dist/conformance/cases.d.mts.map +1 -0
- package/dist/conformance/cases.mjs +717 -0
- package/dist/conformance/cases.mjs.map +1 -0
- package/dist/conformance/elicitation-declaration.d.mts +6 -0
- package/dist/conformance/elicitation-declaration.d.mts.map +1 -0
- package/dist/conformance/elicitation-declaration.mjs +20 -0
- package/dist/conformance/elicitation-declaration.mjs.map +1 -0
- package/dist/conformance/index.d.mts +25 -0
- package/dist/conformance/index.d.mts.map +1 -0
- package/dist/conformance/index.mjs +42 -0
- package/dist/conformance/index.mjs.map +1 -0
- package/dist/conformance/json.d.mts +11 -0
- package/dist/conformance/json.d.mts.map +1 -0
- package/dist/conformance/json.mjs +30 -0
- package/dist/conformance/json.mjs.map +1 -0
- package/dist/conformance/legacy-session.d.mts +7 -0
- package/dist/conformance/legacy-session.d.mts.map +1 -0
- package/dist/conformance/legacy-session.mjs +15 -0
- package/dist/conformance/legacy-session.mjs.map +1 -0
- package/dist/conformance/modern-stateless.d.mts +7 -0
- package/dist/conformance/modern-stateless.d.mts.map +1 -0
- package/dist/conformance/modern-stateless.mjs +24 -0
- package/dist/conformance/modern-stateless.mjs.map +1 -0
- package/dist/conformance/negotiation-era.d.mts +6 -0
- package/dist/conformance/negotiation-era.d.mts.map +1 -0
- package/dist/conformance/negotiation-era.mjs +20 -0
- package/dist/conformance/negotiation-era.mjs.map +1 -0
- package/dist/conformance/observe.d.mts +78 -0
- package/dist/conformance/observe.d.mts.map +1 -0
- package/dist/conformance/observe.mjs +212 -0
- package/dist/conformance/observe.mjs.map +1 -0
- package/dist/conformance/param-value.d.mts +12 -0
- package/dist/conformance/param-value.d.mts.map +1 -0
- package/dist/conformance/param-value.mjs +22 -0
- package/dist/conformance/param-value.mjs.map +1 -0
- package/dist/conformance/response-encoding.d.mts +9 -0
- package/dist/conformance/response-encoding.d.mts.map +1 -0
- package/dist/conformance/response-encoding.mjs +23 -0
- package/dist/conformance/response-encoding.mjs.map +1 -0
- package/dist/conformance/sse.d.mts +14 -0
- package/dist/conformance/sse.d.mts.map +1 -0
- package/dist/conformance/sse.mjs +49 -0
- package/dist/conformance/sse.mjs.map +1 -0
- package/dist/conformance/synthetic.d.mts +127 -0
- package/dist/conformance/synthetic.d.mts.map +1 -0
- package/dist/conformance/synthetic.mjs +449 -0
- package/dist/conformance/synthetic.mjs.map +1 -0
- package/dist/conformance/target.d.mts +108 -0
- package/dist/conformance/target.d.mts.map +1 -0
- package/dist/conformance/target.mjs +77 -0
- package/dist/conformance/target.mjs.map +1 -0
- package/dist/conformance/tools-list.d.mts +6 -0
- package/dist/conformance/tools-list.d.mts.map +1 -0
- package/dist/conformance/tools-list.mjs +23 -0
- package/dist/conformance/tools-list.mjs.map +1 -0
- package/dist/conformance/unknown-tool.d.mts +9 -0
- package/dist/conformance/unknown-tool.d.mts.map +1 -0
- package/dist/conformance/unknown-tool.mjs +39 -0
- package/dist/conformance/unknown-tool.mjs.map +1 -0
- package/dist/core.d.mts +1 -0
- package/dist/core.mjs +2 -0
- package/dist/index.d.mts +1 -1
- package/dist/server/approval.d.mts +109 -0
- package/dist/server/approval.d.mts.map +1 -0
- package/dist/server/approval.mjs +155 -0
- package/dist/server/approval.mjs.map +1 -0
- package/dist/server/errors.d.mts +2 -5
- package/dist/server/errors.d.mts.map +1 -1
- package/dist/server/errors.mjs +2 -3
- package/dist/server/errors.mjs.map +1 -1
- package/dist/server/index.d.mts +4 -2
- package/dist/server/index.mjs +3 -1
- package/dist/server/node.d.mts +1 -0
- package/dist/server/node.mjs +2 -0
- package/dist/server/server.d.mts +35 -7
- package/dist/server/server.d.mts.map +1 -1
- package/dist/server/server.mjs +223 -73
- package/dist/server/server.mjs.map +1 -1
- package/dist/server/stdio.d.mts +1 -5
- package/dist/server/stdio.d.mts.map +1 -1
- package/dist/server/stdio.mjs +1 -2
- package/dist/server/stdio.mjs.map +1 -1
- package/package.json +26 -6
- package/src/client/README.md +19 -15
- package/src/client/client.ts +1108 -186
- package/src/client/effect-fetch.ts +64 -0
- package/src/client/elicitation.ts +936 -0
- package/src/client/errors.ts +49 -1
- package/src/client/index.ts +61 -4
- package/src/client/node.ts +2 -0
- package/src/client/protocol.ts +472 -50
- package/src/conformance/auth-rejected.ts +26 -0
- package/src/conformance/call-gate.ts +268 -0
- package/src/conformance/call-read.ts +37 -0
- package/src/conformance/call-tool-error.ts +39 -0
- package/src/conformance/cases.ts +1426 -0
- package/src/conformance/elicitation-declaration.ts +25 -0
- package/src/conformance/index.ts +166 -0
- package/src/conformance/json.ts +47 -0
- package/src/conformance/legacy-session.ts +13 -0
- package/src/conformance/modern-stateless.ts +25 -0
- package/src/conformance/negotiation-era.ts +20 -0
- package/src/conformance/observe.ts +375 -0
- package/src/conformance/param-value.ts +30 -0
- package/src/conformance/response-encoding.ts +23 -0
- package/src/conformance/sse.ts +66 -0
- package/src/conformance/synthetic.ts +511 -0
- package/src/conformance/target.ts +143 -0
- package/src/conformance/tools-list.ts +30 -0
- package/src/conformance/unknown-tool.ts +50 -0
- package/src/core.ts +1 -0
- package/src/server/README.md +11 -13
- package/src/server/approval.ts +292 -0
- package/src/server/errors.ts +1 -1
- package/src/server/index.ts +20 -1
- package/src/server/node.ts +1 -0
- package/src/server/server.ts +428 -65
package/README.md
CHANGED
|
@@ -1,83 +1,436 @@
|
|
|
1
1
|
# @yolk-sdk/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
MCP v2 (`2026-07-28`) client/server/protocol APIs, Effect/Yolk adapters, and legacy compatibility.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The root export is intentionally empty. Import APIs from explicit subpaths.
|
|
6
|
+
|
|
7
|
+
## Tool schema admission
|
|
8
|
+
|
|
9
|
+
Yolk's `tools/list` adapter admits `inputSchema` as the object arm of
|
|
10
|
+
`@yolk-sdk/agent/protocol`'s `ToolJsonSchema`. This is plain finite JSON-data representation admission,
|
|
11
|
+
not JSON Schema meta-validation. Boolean roots fail in the typed `McpError` validation channel;
|
|
12
|
+
omitted schemas still default to `{ type: 'object', additionalProperties: true }`.
|
|
13
|
+
Tool arguments/results remain opaque until their execution/provider boundary.
|
|
6
14
|
|
|
7
15
|
## Install
|
|
8
16
|
|
|
9
17
|
```bash
|
|
10
|
-
pnpm add @yolk-sdk/mcp@canary @yolk-sdk/agent@canary effect
|
|
18
|
+
pnpm add @yolk-sdk/mcp@canary @yolk-sdk/agent@canary effect@4.1.2
|
|
11
19
|
```
|
|
12
20
|
|
|
21
|
+
Running the experimental `@yolk-sdk/mcp/conformance` cases? Also add `@yolk-sdk/conformance@canary` (usually as a dev dependency); the examples import `@yolk-sdk/conformance/*` subpaths directly.
|
|
22
|
+
|
|
13
23
|
Canary APIs are unstable. Keep all `@yolk-sdk/*` packages on the same version.
|
|
24
|
+
Use the SDK's matching Effect version (`4.1.2`) in host code.
|
|
25
|
+
Published package metadata requires Node.js 22+; `client/node` and `server/node` are Node-only.
|
|
14
26
|
|
|
15
27
|
## Subpaths
|
|
16
28
|
|
|
17
|
-
| Subpath
|
|
18
|
-
|
|
|
19
|
-
| `@yolk-sdk/mcp/client`
|
|
20
|
-
| `@yolk-sdk/mcp/client/node` |
|
|
21
|
-
| `@yolk-sdk/mcp/
|
|
22
|
-
| `@yolk-sdk/mcp/
|
|
29
|
+
| Subpath | Purpose |
|
|
30
|
+
| --------------------------- | ---------------------------------------------------------------------- |
|
|
31
|
+
| `@yolk-sdk/mcp/client` | Official full-core client plus Effect/Yolk list and call helpers |
|
|
32
|
+
| `@yolk-sdk/mcp/client/node` | Official stdio client transport plus NodeServices convenience wrappers |
|
|
33
|
+
| `@yolk-sdk/mcp/conformance` | Experimental MCP conformance cases, target, seeds, and fixtures |
|
|
34
|
+
| `@yolk-sdk/mcp/core` | Official MCP v2 wire schemas |
|
|
35
|
+
| `@yolk-sdk/mcp/protocol` | Yolk JSON-RPC/MCP adapter helpers |
|
|
36
|
+
| `@yolk-sdk/mcp/server` | Official full-core server plus Yolk tool-only server primitives |
|
|
37
|
+
| `@yolk-sdk/mcp/server/node` | Official dual-era stdio server entrypoint |
|
|
38
|
+
|
|
39
|
+
Use `core` for the official full MCP wire-schema surface. Use `protocol` only for Yolk adapters and
|
|
40
|
+
legacy JSON-RPC helpers; it is not a replacement for the full-core APIs.
|
|
41
|
+
|
|
42
|
+
Yolk JSON-RPC initialize and tools/call construction uses Schema owners on both
|
|
43
|
+
`@yolk-sdk/mcp/client` and `@yolk-sdk/mcp/protocol` (same `protocol.ts`; no new export subpath):
|
|
44
|
+
|
|
45
|
+
| Symbol | Role |
|
|
46
|
+
| ------------------------- | ------------------------------------------------------------------------------ |
|
|
47
|
+
| `InitializeClientInfo` | `{ name, version }` |
|
|
48
|
+
| `InitializeParams` | `{ protocolVersion, capabilities, clientInfo }` |
|
|
49
|
+
| `InitializedNotification` | `{ jsonrpc: '2.0', method: 'notifications/initialized' }` (no `id` / `params`) |
|
|
50
|
+
| `ToolsCallParams` | `{ name, arguments? }` |
|
|
51
|
+
|
|
52
|
+
Prefer those Schema owners for new construction. Compatibility constructors
|
|
53
|
+
`makeJsonRpcRequest`, `makeInitializeParams`, and `makeInitializedNotification` remain and build
|
|
54
|
+
through the schemas. `makeJsonRpcRequest` still omits `params` when `undefined`.
|
|
23
55
|
|
|
24
56
|
## Imports
|
|
25
57
|
|
|
26
58
|
```ts
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import
|
|
30
|
-
import {
|
|
59
|
+
import { Client } from '@yolk-sdk/mcp/client'
|
|
60
|
+
import { listLocalMcpServerToolsNode } from '@yolk-sdk/mcp/client/node'
|
|
61
|
+
import * as McpCore from '@yolk-sdk/mcp/core'
|
|
62
|
+
import { McpServer } from '@yolk-sdk/mcp/server'
|
|
63
|
+
import { serveStdio } from '@yolk-sdk/mcp/server/node'
|
|
31
64
|
```
|
|
32
65
|
|
|
33
|
-
##
|
|
66
|
+
## Use the full MCP v2 client
|
|
67
|
+
|
|
68
|
+
The official client surface supports tools, resources, prompts, completions, MRTR, response caching, subscriptions, OAuth helpers, and legacy negotiation.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { Client, StreamableHTTPClientTransport } from '@yolk-sdk/mcp/client'
|
|
72
|
+
|
|
73
|
+
const client = new Client(
|
|
74
|
+
{ name: 'my-app', version: '1.0.0' },
|
|
75
|
+
{ versionNegotiation: { mode: 'auto' } }
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
await client.connect(new StreamableHTTPClientTransport(new URL('https://example.com/mcp')))
|
|
79
|
+
|
|
80
|
+
const { tools } = await client.listTools()
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`mode: 'auto'` prefers stateless MCP `2026-07-28` and falls back to an initialize-based server. Pin `{ pin: '2026-07-28' }` for modern-only behavior. The upstream `Client` default remains legacy for compatibility.
|
|
84
|
+
|
|
85
|
+
## Use Effect/Yolk tool adapters
|
|
86
|
+
|
|
87
|
+
The high-level remote helpers use the official v2 client over an Effect `HttpClient` bridge. They negotiate modern MCP automatically, aggregate paginated tool lists, honor v2 routing headers and cache hints, and fall back to legacy servers. Discovered tools preserve provider `title`, `inputSchema`, `outputSchema`, and `annotations` metadata. Adapted tools are typed ([ADR 0013](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0013-typed-tool-results.md)): `ToolDef.outputSchema` is `{ value, files }` (`value` the server's `outputSchema`, unknown without one) and a successful call's `structuredContent` is `{ value, files }`: `value` is the server's `structuredContent` (checked against the listed `outputSchema`, remote and local), else the text of its text blocks and embedded text resources parsed once when it is one JSON object or array, else the text (`resource_link` blocks never enter it); blobs, images and audio become file fields (`FileRef`, or `FileUnavailable` without a file store). The model still sees the server's content, unchanged for results without file blocks. Registrations of adapted tools set `decodeOutput: mcpToolOutputDecoder` (`resolveTools` checks every result with it and fails `output_validation_required` without it). Files are stored when the call runs, through the `ToolFileCapture` `resolveTools` provides to its registrations; a call outside one (a HITL route calling `resumeRemoteMcpServerToolCall`, a direct `callLocalMcpServerTool`) passes `fileCapture: makeToolFileCapture({ store })` from `@yolk-sdk/agent/tools` on its input, or every file is `FileUnavailable` (`no file store`) and the blob is lost. Pass `exposure` in the options (a `ToolExposure` value or `(tool, serverName) => ToolExposure`) to set code mode `callableBy`/`discovery` on the adapted definitions; `mcpToolToToolDef` takes the same option.
|
|
34
88
|
|
|
35
89
|
```ts
|
|
36
90
|
import { Effect } from 'effect'
|
|
91
|
+
import { FetchHttpClient } from 'effect/http'
|
|
37
92
|
import { listRemoteMcpServerTools } from '@yolk-sdk/mcp/client'
|
|
38
93
|
|
|
39
|
-
const tools =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
94
|
+
const tools = await Effect.runPromise(
|
|
95
|
+
listRemoteMcpServerTools({
|
|
96
|
+
name: 'docs',
|
|
97
|
+
type: 'remote',
|
|
98
|
+
url: 'https://example.com/mcp'
|
|
99
|
+
}).pipe(Effect.provide(FetchHttpClient.layer))
|
|
100
|
+
)
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Use `McpClientOptions.sdk` for official client options such as capabilities, MRTR, and shared response caching. Set `McpClientOptions.configureClient` to register elicitation or sampling handlers before connection. Use a persistent official `Client` directly for long-lived subscriptions and progress streams.
|
|
104
|
+
|
|
105
|
+
## Form elicitation for durable hosts (MRTR)
|
|
106
|
+
|
|
107
|
+
A server can pause a `tools/call` with an MCP `2026-07-28` `InputRequiredResult` (for example to
|
|
108
|
+
confirm a destructive tool with a form). A durable host cannot block on a person inside a tool
|
|
109
|
+
step, so Yolk returns the pause as data and resumes later, possibly in another process:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { Effect } from 'effect'
|
|
113
|
+
import { makeToolFileCapture } from '@yolk-sdk/agent/tools'
|
|
114
|
+
import {
|
|
115
|
+
callRemoteMcpServerToolResumable,
|
|
116
|
+
resumeRemoteMcpServerToolCall,
|
|
117
|
+
type McpClientOptions,
|
|
118
|
+
type McpElicitationResponse,
|
|
119
|
+
type McpElicitationResponses
|
|
120
|
+
} from '@yolk-sdk/mcp/client'
|
|
121
|
+
|
|
122
|
+
const options: McpClientOptions = { elicitation: { form: true } }
|
|
123
|
+
|
|
124
|
+
// A resume runs outside `resolveTools`: pass a capture (`makeToolFileCapture({ store })` from
|
|
125
|
+
// `@yolk-sdk/agent/tools`) or the resumed result's blobs are `FileUnavailable` and lost.
|
|
126
|
+
const call = {
|
|
127
|
+
config,
|
|
128
|
+
mcpToolName: 'delete-invoice',
|
|
129
|
+
toolCallId: 'call_1',
|
|
130
|
+
params,
|
|
131
|
+
options,
|
|
132
|
+
fileCapture: makeToolFileCapture({ store })
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const step = Effect.gen(function* () {
|
|
136
|
+
const outcome = yield* callRemoteMcpServerToolResumable(call)
|
|
137
|
+
|
|
138
|
+
if (outcome._tag === 'Complete') return outcome.result
|
|
139
|
+
|
|
140
|
+
// Integration fragment: persist outcome.inputRequired (a Schema class) and show its forms to a
|
|
141
|
+
// person; resume later, possibly in another process, with their decisions, one per form keyed
|
|
142
|
+
// by its `key`. This sketch declines every form (the safe default when nobody decides); never
|
|
143
|
+
// auto-accept a confirmation.
|
|
144
|
+
const decline: McpElicitationResponse = { action: 'decline' }
|
|
145
|
+
const responses: McpElicitationResponses = Object.fromEntries(
|
|
146
|
+
outcome.inputRequired.elicitations.map(form => [form.key, decline])
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return yield* resumeRemoteMcpServerToolCall({
|
|
150
|
+
...call,
|
|
151
|
+
inputRequired: outcome.inputRequired,
|
|
152
|
+
responses
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- `elicitation: { form: true }` is the opt-in. Only then do the listing and the resumable call
|
|
158
|
+
functions declare `elicitation.form`, in the per-request `_meta` client capabilities of a modern
|
|
159
|
+
connection. Nothing declares it in a legacy `initialize`, and `callRemoteMcpServerTool` (which
|
|
160
|
+
cannot represent a pause) never declares it.
|
|
161
|
+
- The outcome is `Complete` (a `ToolResult`) or `InputRequired` (`McpInputRequired`: Schema-decoded
|
|
162
|
+
form elicitations with `key`, `message` and `requestedSchema`, the opaque `requestState`, the
|
|
163
|
+
binding `mcpToolName` and `argumentsDigest`, and the listed tool definition `tool`).
|
|
164
|
+
- The bound is 256 KiB of JSON by default (`elicitation.maxInputRequiredBytes`, a positive
|
|
165
|
+
integer, checked before connecting) plus 16 requests, applied to two parts separately. The
|
|
166
|
+
server-provided pause (the `InputRequiredResult` and the decoded pause without its tool
|
|
167
|
+
definition) is checked after the response body is buffered, so it bounds what is decoded and
|
|
168
|
+
persisted, not what is received. The listed tool definition is checked before the call: a tool
|
|
169
|
+
whose definition alone exceeds the bound fails `too_large` with nothing sent, so a pause the
|
|
170
|
+
server already made is never lost to the bound. A persisted pause is at most about twice the
|
|
171
|
+
bound.
|
|
172
|
+
- The resume is re-sent as a new request on a new connection with the same tool call (checked
|
|
173
|
+
against the pause's binding), the exact `requestState`, and the decisions (`accept` with
|
|
174
|
+
`content`, `decline`, `cancel`) as `inputResponses`. It lists nothing: it calls with the pause's
|
|
175
|
+
tool definition (for `x-mcp-header` mirroring) and checks the result against its `outputSchema`.
|
|
176
|
+
A carried definition that is not a valid MCP tool fails `malformed` before sending. Because the
|
|
177
|
+
definition is passed as `toolDefinition`, the official client does not re-list and retry after a
|
|
178
|
+
`HEADER_MISMATCH` (`-32020`): a server that changed the tool's `x-mcp-header` declarations since
|
|
179
|
+
the pause answers `McpError` (`cause: 'protocol'`). Decisions are checked before anything is sent
|
|
180
|
+
(type (integer vs number), `required`, `const`, `enum`, titled `oneOf`, `minLength`/`maxLength`, `format` (email, uri, date, date-time), `minimum`/`maximum`, `items.enum`, titled `items.anyOf`, `minItems`/`maxItems`); the server validates them again. The server may pause again.
|
|
181
|
+
- The carried definition is `name`, `inputSchema` and `outputSchema`: the only `toolDefinition`
|
|
182
|
+
fields the pinned official client reads. `annotations`, `_meta` and `execution` (task support,
|
|
183
|
+
which its `2026-07-28` codec removes from listings) are not carried.
|
|
184
|
+
- The pause is decoded from the raw `input_required` response as the server sent it: the response
|
|
185
|
+
the official client resolves the call with (the first whose id matches under the client's own
|
|
186
|
+
`Number(id)` coercion), captured at the transport before the client normalises it (it would drop
|
|
187
|
+
a non-string `requestState` and turn non-object `inputRequests` into `{}`). Such a response, or a
|
|
188
|
+
matched one whose id is not identical to the call's (`"1"` for `1`), fails `malformed`; other
|
|
189
|
+
ids, notifications and later duplicates are ignored.
|
|
190
|
+
- Formats are syntax checks, all linear: `date`/`date-time` per RFC 3339 on the proleptic
|
|
191
|
+
Gregorian calendar (years 0000-9999; second `60` only at `23:59:60` UTC after the offset); `uri`
|
|
192
|
+
an absolute RFC 3986 URI (scheme, then unreserved, sub-delims and the delimiters, other characters
|
|
193
|
+
percent-encoded; IP literals per the `IPv6address` grammar or `IPvFuture`; no WHATWG
|
|
194
|
+
normalisation);
|
|
195
|
+
`email` a pragmatic mailbox: a dot-atom local part (RFC 5322 `atext` runs joined by single dots,
|
|
196
|
+
at most 64 characters; no quoted strings), `@`, and a hostname of at least two LDH labels.
|
|
197
|
+
- Typed failures: `McpInputRequiredError` (`malformed`, `too_large`, `unsupported_request` for URL
|
|
198
|
+
mode, sampling, roots or input without the opt-in, `invalid_responses`, `mismatched_resume`,
|
|
199
|
+
`unsupported_era`) and `McpClientCapabilityRequiredError` for MCP `-32021`.
|
|
200
|
+
- Legacy-era elicitation (a server-initiated request answered while the call's stream is open) is
|
|
201
|
+
not supported; resuming against a legacy connection fails with `unsupported_era`.
|
|
202
|
+
|
|
203
|
+
### Files in tool results
|
|
204
|
+
|
|
205
|
+
A successful call's `structuredContent` is `{ value, files }`
|
|
206
|
+
([ADR 0013](https://github.com/magoz/yolk-sdk/blob/main/docs/adr/0013-typed-tool-results.md)):
|
|
207
|
+
embedded text resources go into `value` with the text blocks, and blobs, images and audio become
|
|
208
|
+
`files`, each a `FileRef` `{ fileId, name, mimeType, size }` (blob names come from the URI) or a
|
|
209
|
+
`FileUnavailable` `{ unavailable, name, mimeType }`. The model sees blob resources as file labels
|
|
210
|
+
(never base64) and images and audio as the server sent them, followed by their label once stored.
|
|
211
|
+
|
|
212
|
+
Files are stored while the call runs. Inside a `resolveTools` registration they go to the
|
|
213
|
+
resolution's `files` store. A call made anywhere else (a HITL route resuming
|
|
214
|
+
`resumeRemoteMcpServerToolCall`, a direct `callRemoteMcpServerTool` or `callLocalMcpServerTool`)
|
|
215
|
+
passes `fileCapture: makeToolFileCapture({ store })` (`@yolk-sdk/agent/tools`); without it every
|
|
216
|
+
file is `FileUnavailable` (`no file store`), and the blob cannot be fetched again later. See
|
|
217
|
+
[Move files between tools](https://github.com/magoz/yolk-sdk/blob/main/apps/docs/content/docs/integrations/files.mdx).
|
|
218
|
+
|
|
219
|
+
When adapting Yolk tools into an MCP server (`makeMcpToolServer`), an inline `FilePart` leaves as
|
|
220
|
+
an embedded resource blob and a stored (or omitted) one as its label.
|
|
221
|
+
|
|
222
|
+
## Connect to a local stdio server
|
|
223
|
+
|
|
224
|
+
Node hosts can use the convenience wrappers from `client/node`:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { Effect } from 'effect'
|
|
228
|
+
import { listLocalMcpServerToolsNode } from '@yolk-sdk/mcp/client/node'
|
|
229
|
+
|
|
230
|
+
const tools = await Effect.runPromise(
|
|
231
|
+
listLocalMcpServerToolsNode(
|
|
232
|
+
{
|
|
233
|
+
name: 'local-tools',
|
|
234
|
+
type: 'local',
|
|
235
|
+
command: [process.execPath, './mcp-server.mjs'],
|
|
236
|
+
environment: {}
|
|
237
|
+
},
|
|
238
|
+
{ securityPolicy: { allowLocalServers: true, allowDevHttpLocalhost: false } }
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Local servers are disabled by default. The host must explicitly allow them, choose a trusted
|
|
244
|
+
command, and provide the complete child environment; configured environment values do not extend
|
|
245
|
+
the host environment.
|
|
246
|
+
|
|
247
|
+
## Build a full MCP server
|
|
248
|
+
|
|
249
|
+
Use the official server surface for tools, resources, prompts, completions, MRTR, and subscriptions:
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
import { McpServer, createMcpHandler } from '@yolk-sdk/mcp/server'
|
|
253
|
+
|
|
254
|
+
const handler = createMcpHandler(() => {
|
|
255
|
+
const server = new McpServer({ name: 'my-server', version: '1.0.0' })
|
|
256
|
+
// Register tools, resources, and prompts here.
|
|
257
|
+
return server
|
|
43
258
|
})
|
|
44
259
|
|
|
45
|
-
|
|
46
|
-
Effect.runPromise(tools)
|
|
260
|
+
export default { fetch: handler.fetch }
|
|
47
261
|
```
|
|
48
262
|
|
|
49
|
-
|
|
263
|
+
`createMcpHandler` serves stateless `2026-07-28` and legacy initialize-based HTTP clients from one endpoint. Validate `Origin` and `Host` before calling `handler.fetch`.
|
|
264
|
+
|
|
265
|
+
For dual-era Node stdio, import `serveStdio` from `@yolk-sdk/mcp/server/node`. This subpath owns the
|
|
266
|
+
Node stdio transport only; the host owns authorization, process lifecycle, logging, and deployment
|
|
267
|
+
policy.
|
|
268
|
+
|
|
269
|
+
## Adapt Yolk tools into MCP
|
|
50
270
|
|
|
51
271
|
```ts
|
|
52
|
-
import {
|
|
272
|
+
import { makeMcpToolServer, runStdioMcpServer } from '@yolk-sdk/mcp/server'
|
|
53
273
|
```
|
|
54
274
|
|
|
55
|
-
|
|
275
|
+
`makeMcpToolServer` exposes approved Yolk tools. Its HTTP handler accepts both stateless v2 and legacy requests, validates browser origins against the endpoint hostname by default, and preserves MCP content and structured results. No tool call outlives `handleHttpRequest` (an SSE answer is read to its end, and a read failure answers 500 with `-32603`; a call still running is interrupted and awaited), so its requirements may come from a scoped request layer; a cancelled request that carries `MCP-Protocol-Version` interrupts the tool. `subscriptions/listen` answers its acknowledgement plus a `complete` result: this tool-only server has no change notifications. `runStdioMcpServer` remains the Effect-native minimal stdio adapter; use `serveStdio` for the full modern stdio surface.
|
|
56
276
|
|
|
57
|
-
|
|
277
|
+
For legacy HTTP requests, an unreadable or already consumed body produces a JSON-RPC
|
|
278
|
+
invalid-request error (`-32600`) rather than an Effect defect. Malformed JSON remains a parse error
|
|
279
|
+
(`-32700`).
|
|
280
|
+
|
|
281
|
+
A tool may carry `annotations` (`title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`,
|
|
282
|
+
`openWorldHint`), listed as the MCP tool annotations.
|
|
283
|
+
|
|
284
|
+
### Ask the user before a tool runs
|
|
285
|
+
|
|
286
|
+
An approval tool (`McpServerApprovalTool`) runs only after the user accepts the call through MCP
|
|
287
|
+
form elicitation over multi round-trip requests (`2026-07-28`). Give the server `approvals`:
|
|
58
288
|
|
|
59
289
|
```ts
|
|
60
|
-
import {
|
|
290
|
+
import { Effect } from 'effect'
|
|
291
|
+
import { ToolDef, ToolResult } from '@yolk-sdk/agent/protocol'
|
|
292
|
+
import { makeMcpToolServer, type McpServerTool } from '@yolk-sdk/mcp/server'
|
|
293
|
+
|
|
294
|
+
declare const signingKey: string // at least 32 bytes, the same on every instance
|
|
295
|
+
declare const tokenId: string // the authenticated principal of this request
|
|
296
|
+
|
|
297
|
+
const send: McpServerTool = {
|
|
298
|
+
def: ToolDef.make({
|
|
299
|
+
name: 'send',
|
|
300
|
+
description: 'Send a message',
|
|
301
|
+
parameters: { type: 'object' }
|
|
302
|
+
}),
|
|
303
|
+
annotations: { destructiveHint: false },
|
|
304
|
+
approval: { message: call => Effect.succeed(`Send ${JSON.stringify(call.params)}?`) },
|
|
305
|
+
execute: (call, approved) =>
|
|
306
|
+
// Run the call at most once per `approved.approvalId`.
|
|
307
|
+
Effect.succeed(ToolResult.make({ toolCallId: call.id, content: 'sent' }))
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const server = makeMcpToolServer({
|
|
311
|
+
name: 'my-server',
|
|
312
|
+
version: '1.0.0',
|
|
313
|
+
tools: [send],
|
|
314
|
+
approvals: { key: signingKey, principal: tokenId }
|
|
315
|
+
})
|
|
61
316
|
```
|
|
62
317
|
|
|
63
|
-
The
|
|
64
|
-
|
|
318
|
+
- The first call answers an `input_required` result: one form elicitation under
|
|
319
|
+
`approvalInputKey` (`'approval'`, no fields: the client offers accept, decline and cancel) with
|
|
320
|
+
the policy's `message`, and a `requestState` signed by the SDK's `createRequestStateCodec`
|
|
321
|
+
(HMAC-SHA256, `ttlSeconds` default 600) and bound to `principal` and `tools/call`. Its payload
|
|
322
|
+
names the tool, the digest of the arguments (`mcpArgumentsDigest`) and a fresh `approvalId`.
|
|
323
|
+
- Only a retry that answers `accept` with a state that verifies for the same principal, tool and
|
|
324
|
+
arguments runs the tool, with `{ approvalId }`. A decline or a cancel answers an error result.
|
|
325
|
+
A state that fails verification, belongs to another call, or arrives without a decision asks
|
|
326
|
+
again with a new state.
|
|
327
|
+
- Build the server per request: `principal` is fixed when it is built. The state is also bound to
|
|
328
|
+
the server's `name`.
|
|
329
|
+
- The server keeps no state, so an accepted retry replays until the state expires: key once-only
|
|
330
|
+
execution on `approvalId`.
|
|
331
|
+
- A direct tool refuses a call that answers an approval prompt (a `requestState` or an answer under
|
|
332
|
+
`approvalInputKey`, `staleApprovalMessage`): when the host's policy turned an approval tool into a
|
|
333
|
+
direct one between the prompt and the answer, neither a decline nor a replayed accept becomes a
|
|
334
|
+
plain call.
|
|
335
|
+
- A request that does not declare form elicitation gets an error result and nothing runs.
|
|
336
|
+
Approval tools are not offered on 2025-era requests (stateless serving cannot route the
|
|
337
|
+
client's answer back to the open call) or on the header-less JSON path, and not at all without
|
|
338
|
+
`approvals`. Unusable `approvals` (a key under 32 bytes, an empty `principal`, a `ttlSeconds`
|
|
339
|
+
that is not a positive integer) leave them listed but answering an error result that names the
|
|
340
|
+
problem.
|
|
65
341
|
|
|
66
|
-
##
|
|
342
|
+
## Conformance cases (experimental)
|
|
67
343
|
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
344
|
+
`@yolk-sdk/mcp/conformance` holds nine `read` conformance cases for `@yolk-sdk/conformance/runner`,
|
|
345
|
+
plus one opt-in `read` case, `mcpElicitationDeclarationCase` (fixtures:
|
|
346
|
+
`mcpConformanceElicitationFixtures`), for hosts that set `McpClientOptions.elicitation`; it only
|
|
347
|
+
lists, so it never triggers a confirmation.
|
|
348
|
+
They check the wire claims the remote client relies on: era negotiation, the modern stateless
|
|
349
|
+
headers, the legacy session, response encoding, the tool listing, a read call, a tool error, an
|
|
350
|
+
unknown tool, and a rejected credential. Every case runs the real `listRemoteMcpServerTools` and
|
|
351
|
+
`callRemoteMcpServerTool` through an observing `HttpClient`. The observer never sends a request of
|
|
352
|
+
its own (it may refuse to forward one, see below). It never keeps `authorization` or any other
|
|
353
|
+
credential-named header, never keeps the URL query, and never keeps a raw `mcp-session-id` value
|
|
354
|
+
(only evidence: an equality class such as `session#1`). It keeps request and response bodies
|
|
355
|
+
exactly as received; they may reflect anything a server echoes, credentials and session ids
|
|
356
|
+
included, so they are sensitive: in memory only, never logged or persisted. Persisted or printed
|
|
357
|
+
output is the live runner's job.
|
|
71
358
|
|
|
72
|
-
|
|
359
|
+
A case that calls a tool (`mcp.modern.stateless`, `mcp.errors.unknown-tool`,
|
|
360
|
+
`mcp.tools.call-read`, `mcp.tools.call-tool-error`) is protected by the observer's fail-closed call
|
|
361
|
+
gate. The `tools/call` is forwarded only when every exchange of the call operation is fully
|
|
362
|
+
understood, that operation's own listing (made right before the call) is complete, and that
|
|
363
|
+
listing proves the call safe: the absent tool is not listed, or the read tool is marked
|
|
364
|
+
`readOnlyHint: true`. Anything else, including any uncertainty (a 202 answer to a request, a
|
|
365
|
+
message delivered on a GET, an unparseable body, an unterminated stream, two responses for one id,
|
|
366
|
+
an unknown shape), refuses to forward. A refusal before any forwarded call fails the precondition
|
|
367
|
+
with zero forwarded calls; a refused client retry after a forwarded call is reported as a retry.
|
|
368
|
+
Earlier preflight listings stay as friendly early failures. Answers are read as the SDK reads them:
|
|
369
|
+
JSON with `JSON.parse` semantics, and event streams with the SDK's own parser
|
|
370
|
+
(the same `eventsource-parser` the client resolves, verified in-repo by a parity test; a consumer
|
|
371
|
+
install whose package manager does not dedupe could still resolve two copies), fed the decoder
|
|
372
|
+
chunks the client's `TextDecoderStream` emits.
|
|
373
|
+
|
|
374
|
+
Mismatch messages carry only structural facts (methods, statuses, counts, positions, codes), never
|
|
375
|
+
body text or the target URL. A client failure a case re-raises is reported as the client words it
|
|
376
|
+
(it can quote a server body) and is sanitized by the runner. A host provides an `HttpClient`, an
|
|
377
|
+
`McpConformanceTarget` (server URL, headers, era, protocol version, timeout), and
|
|
378
|
+
`McpConformanceConfig` seeds. The cases name no product: provider targets and seeds live with the
|
|
379
|
+
provider. `selectMcpConformanceCases` leaves out the cases of the other era. The synthetic fixtures
|
|
380
|
+
replay on `https://mcp.example.test/modern/mcp` and `https://mcp.example.test/legacy/mcp`. See the
|
|
381
|
+
conformance API reference for every claim.
|
|
382
|
+
|
|
383
|
+
```ts
|
|
384
|
+
import { Effect, Layer } from 'effect'
|
|
385
|
+
import { FetchHttpClient } from 'effect/http'
|
|
386
|
+
import { runConformance } from '@yolk-sdk/conformance/runner'
|
|
387
|
+
import {
|
|
388
|
+
McpConformanceConfig,
|
|
389
|
+
McpConformanceTarget,
|
|
390
|
+
mcpConformanceCases,
|
|
391
|
+
selectMcpConformanceCases
|
|
392
|
+
} from '@yolk-sdk/mcp/conformance'
|
|
73
393
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
394
|
+
const target = {
|
|
395
|
+
name: 'docs',
|
|
396
|
+
url: 'https://example.com/mcp',
|
|
397
|
+
headers: {},
|
|
398
|
+
era: 'modern',
|
|
399
|
+
protocolVersion: '2026-07-28',
|
|
400
|
+
timeoutMs: 30_000
|
|
401
|
+
} as const
|
|
78
402
|
|
|
79
|
-
|
|
403
|
+
const { applicable } = selectMcpConformanceCases(mcpConformanceCases, target.era)
|
|
404
|
+
|
|
405
|
+
const report = await Effect.runPromise(
|
|
406
|
+
runConformance(applicable, {
|
|
407
|
+
target: { kind: 'live', account: 'practice' },
|
|
408
|
+
layer: () =>
|
|
409
|
+
Layer.mergeAll(
|
|
410
|
+
FetchHttpClient.layer,
|
|
411
|
+
Layer.succeed(McpConformanceTarget, target),
|
|
412
|
+
Layer.succeed(McpConformanceConfig, {})
|
|
413
|
+
)
|
|
414
|
+
})
|
|
415
|
+
)
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
No case is observed live yet. Only code under `src/conformance/` may import `@yolk-sdk/conformance`.
|
|
419
|
+
|
|
420
|
+
## Host responsibilities
|
|
421
|
+
|
|
422
|
+
- Own persisted server config, credentials, authorization policy, and enabled capabilities.
|
|
423
|
+
- Partition private MCP caches by authorization context.
|
|
424
|
+
- Validate HTTP `Origin` and `Host` at deployment boundaries.
|
|
425
|
+
- Keep Node stdio usage behind trusted Node hosts and explicitly control child commands and environments.
|
|
426
|
+
- Treat tool annotations, server identity, icons, and request state as untrusted input.
|
|
427
|
+
|
|
428
|
+
Remote MCP requires HTTPS by default; localhost HTTP is an explicit development policy.
|
|
429
|
+
|
|
430
|
+
## Boundaries
|
|
80
431
|
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
|
|
432
|
+
- MCP is external protocol infrastructure, not agent-loop or provider policy.
|
|
433
|
+
- `core`, `client`, and `server` expose protocol mechanics; Yolk adapters bridge generic tool and
|
|
434
|
+
content contracts only.
|
|
435
|
+
- App auth, credential storage, persisted server config, and product catalogs remain host-owned.
|
|
436
|
+
- Node process and stdio conveniences stay behind `client/node` and `server/node`.
|
package/dist/client/client.d.mts
CHANGED
|
@@ -1,40 +1,104 @@
|
|
|
1
1
|
import { McpClientInfo, McpLocalServerConfig, McpRemoteServerConfig, McpSecurityPolicy, McpServerConfig } from "./config.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { McpElicitationResponses, McpElicitationSupport, McpInputRequired, McpToolCallOutcome } from "./elicitation.mjs";
|
|
3
|
+
import { McpClientCapabilityRequiredError, McpError, McpInputRequiredError } from "./errors.mjs";
|
|
4
|
+
import { McpToolAnnotations, McpToolExposureResolver, mcpToolToToolDef } from "./protocol.mjs";
|
|
4
5
|
import { Effect } from "effect";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type McpClientOptions = {
|
|
6
|
+
import { Client, ClientOptions } from "@modelcontextprotocol/client";
|
|
7
|
+
import { HttpClient } from "effect/http";
|
|
8
|
+
import { ChildProcessSpawner } from "effect/process";
|
|
9
|
+
import { ToolFileCapture, ToolResult } from "@yolk-sdk/agent/protocol";
|
|
10
|
+
export type McpClientOptions = {
|
|
11
11
|
readonly clientInfo?: McpClientInfo;
|
|
12
12
|
readonly securityPolicy?: McpSecurityPolicy;
|
|
13
13
|
readonly timeoutMs?: number;
|
|
14
|
+
readonly sdk?: ClientOptions;
|
|
15
|
+
readonly configureClient?: (client: Client) => void;
|
|
16
|
+
/** Code mode exposure of the listed tools' definitions (listing functions only). */
|
|
17
|
+
readonly exposure?: McpToolExposureResolver;
|
|
18
|
+
/**
|
|
19
|
+
* Opt-in MCP form elicitation (multi round-trip requests, protocol `2026-07-28`). When set, the
|
|
20
|
+
* remote listing and the resumable call functions declare `elicitation.form` in the per-request
|
|
21
|
+
* `_meta` client capabilities of a modern connection. It is never declared in a legacy
|
|
22
|
+
* `initialize` (legacy elicitation is a server-initiated request the host would have to answer
|
|
23
|
+
* synchronously), and `callRemoteMcpServerTool`, which cannot represent a paused call, never
|
|
24
|
+
* declares it.
|
|
25
|
+
*/
|
|
26
|
+
readonly elicitation?: McpElicitationSupport;
|
|
14
27
|
};
|
|
15
|
-
type McpResolvedTool = {
|
|
28
|
+
export type McpResolvedTool = {
|
|
16
29
|
readonly serverName: string;
|
|
17
30
|
readonly mcpToolName: string;
|
|
31
|
+
readonly title?: string;
|
|
32
|
+
readonly outputSchema?: unknown;
|
|
33
|
+
readonly annotations?: McpToolAnnotations;
|
|
18
34
|
readonly def: ReturnType<typeof mcpToolToToolDef>;
|
|
19
35
|
};
|
|
20
|
-
declare const listRemoteMcpServerTools: (config: McpRemoteServerConfig, options?: McpClientOptions) => Effect.Effect<ReadonlyArray<McpResolvedTool>, McpError, HttpClient.HttpClient>;
|
|
21
|
-
declare const listLocalMcpServerTools: (config: McpLocalServerConfig, options?: McpClientOptions) => Effect.Effect<ReadonlyArray<McpResolvedTool>, McpError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
22
|
-
declare const listMcpServerTools: (config: McpServerConfig, options?: McpClientOptions) => Effect.Effect<readonly McpResolvedTool[], McpError,
|
|
23
|
-
type CallMcpServerToolInput = {
|
|
36
|
+
export declare const listRemoteMcpServerTools: (config: McpRemoteServerConfig, options?: McpClientOptions) => Effect.Effect<ReadonlyArray<McpResolvedTool>, McpError, HttpClient.HttpClient>;
|
|
37
|
+
export declare const listLocalMcpServerTools: (config: McpLocalServerConfig, options?: McpClientOptions) => Effect.Effect<ReadonlyArray<McpResolvedTool>, McpError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
38
|
+
export declare const listMcpServerTools: (config: McpServerConfig, options?: McpClientOptions) => Effect.Effect<readonly McpResolvedTool[], McpError, ChildProcessSpawner.ChildProcessSpawner | HttpClient.HttpClient>;
|
|
39
|
+
export type CallMcpServerToolInput = {
|
|
24
40
|
readonly config: McpServerConfig;
|
|
25
41
|
readonly mcpToolName: string;
|
|
26
42
|
readonly toolCallId: string;
|
|
27
43
|
readonly params: unknown;
|
|
28
44
|
readonly options?: McpClientOptions;
|
|
45
|
+
/**
|
|
46
|
+
* Stores the call's blobs, images and audio as file fields (ADR 0013), for example
|
|
47
|
+
* `makeToolFileCapture({ store })` from `@yolk-sdk/agent/tools`. Defaults to the ambient
|
|
48
|
+
* `ToolFileCapture`, which `resolveTools` provides around every registration; a call made
|
|
49
|
+
* outside one (a HITL route resuming a call, a host calling directly) needs this option, or
|
|
50
|
+
* every file is `FileUnavailable` (`no file store`).
|
|
51
|
+
*/
|
|
52
|
+
readonly fileCapture?: ToolFileCapture['Service'];
|
|
29
53
|
};
|
|
30
|
-
declare const callRemoteMcpServerTool: (input: Omit<CallMcpServerToolInput,
|
|
54
|
+
export declare const callRemoteMcpServerTool: (input: Omit<CallMcpServerToolInput, 'config'> & {
|
|
31
55
|
readonly config: McpRemoteServerConfig;
|
|
32
56
|
}) => Effect.Effect<ToolResult, McpError, HttpClient.HttpClient>;
|
|
33
|
-
|
|
57
|
+
export type CallRemoteMcpServerToolInput = Omit<CallMcpServerToolInput, 'config'> & {
|
|
58
|
+
readonly config: McpRemoteServerConfig;
|
|
59
|
+
};
|
|
60
|
+
export type ResumeRemoteMcpServerToolCallInput = CallRemoteMcpServerToolInput & {
|
|
61
|
+
/** The paused call, exactly as the previous step answered it (persisted by the host). */
|
|
62
|
+
readonly inputRequired: McpInputRequired;
|
|
63
|
+
/** One decision per elicitation, keyed by `McpFormElicitation.key`. */
|
|
64
|
+
readonly responses: McpElicitationResponses;
|
|
65
|
+
};
|
|
66
|
+
export type McpResumableToolCallError = McpError | McpInputRequiredError | McpClientCapabilityRequiredError;
|
|
67
|
+
/**
|
|
68
|
+
* Calls a remote MCP tool and answers a typed outcome instead of blocking on input:
|
|
69
|
+
* `Complete` (the adapted result) or `InputRequired` (a serializable `McpInputRequired` the host
|
|
70
|
+
* persists, decides on, and passes to `resumeRemoteMcpServerToolCall`). Like
|
|
71
|
+
* `callRemoteMcpServerTool`, it lists tools on its own connection before calling; the pause
|
|
72
|
+
* carries the listed definition. Set `options.elicitation` to declare form elicitation; without
|
|
73
|
+
* it a server may refuse a tool that needs confirmation (`McpClientCapabilityRequiredError` for
|
|
74
|
+
* MCP `-32021`, or a tool error result).
|
|
75
|
+
*/
|
|
76
|
+
export declare const callRemoteMcpServerToolResumable: (input: CallRemoteMcpServerToolInput) => Effect.Effect<McpToolCallOutcome, McpResumableToolCallError, HttpClient.HttpClient>;
|
|
77
|
+
/**
|
|
78
|
+
* Resumes a paused remote MCP tool call: the same tool call (same `mcpToolName` and `params`,
|
|
79
|
+
* checked against the pause's binding) is re-sent as a new request on a new connection, with the
|
|
80
|
+
* exact `requestState`, the host's decisions as `inputResponses`, and the pause's tool definition
|
|
81
|
+
* (no listing). The server may pause again (`InputRequired`). Fails with `McpInputRequiredError`
|
|
82
|
+
* before sending when the call does not match the pause (`mismatched_resume`) or `responses` do
|
|
83
|
+
* not match the elicitations (`invalid_responses`), and when the server now negotiates a legacy
|
|
84
|
+
* era (`unsupported_era`).
|
|
85
|
+
*/
|
|
86
|
+
export declare const resumeRemoteMcpServerToolCall: (input: ResumeRemoteMcpServerToolCallInput) => Effect.Effect<McpToolCallOutcome, McpResumableToolCallError, HttpClient.HttpClient>;
|
|
87
|
+
/**
|
|
88
|
+
* Calls a local stdio MCP tool in one session, in order: `initialize`, then `tools/list`, awaited
|
|
89
|
+
* and decoded, then the output validator compiled, and only then `tools/call`. So anything that
|
|
90
|
+
* fails before the call (an `initialize` error, an `outputSchema` that is unusable or does not
|
|
91
|
+
* compile) sends no `tools/call`, nor does a broken session (a stdout line that is no JSON-RPC
|
|
92
|
+
* response, an early end before the listing's answer). A listing answered with an error or an
|
|
93
|
+
* undecodable result, or one that does not hold the tool (the first page only), does not fail
|
|
94
|
+
* the call: it runs without output validation (a value-free warning is logged;
|
|
95
|
+
* `mcpToolOutputDecoder` still checks the `{ value, files }` envelope). A successful result of a
|
|
96
|
+
* tool with a usable `outputSchema` must carry `structuredContent` that passes it, as on the
|
|
97
|
+
* remote calls (`assertStructuredOutput`).
|
|
98
|
+
*/
|
|
99
|
+
export declare const callLocalMcpServerTool: (input: Omit<CallMcpServerToolInput, 'config'> & {
|
|
34
100
|
readonly config: McpLocalServerConfig;
|
|
35
101
|
}) => Effect.Effect<ToolResult, McpError, ChildProcessSpawner.ChildProcessSpawner>;
|
|
36
|
-
declare const callMcpServerTool: (input: CallMcpServerToolInput) => Effect.Effect<ToolResult, McpError, ChildProcessSpawner.ChildProcessSpawner | HttpClient.HttpClient>;
|
|
37
|
-
declare const listMcpTools: (configs: ReadonlyArray<McpServerConfig>, options?: McpClientOptions) => Effect.Effect<McpResolvedTool[], McpError,
|
|
38
|
-
//#endregion
|
|
39
|
-
export { CallMcpServerToolInput, McpClientOptions, McpResolvedTool, callLocalMcpServerTool, callMcpServerTool, callRemoteMcpServerTool, listLocalMcpServerTools, listMcpServerTools, listMcpTools, listRemoteMcpServerTools };
|
|
102
|
+
export declare const callMcpServerTool: (input: CallMcpServerToolInput) => Effect.Effect<ToolResult, McpError, ChildProcessSpawner.ChildProcessSpawner | HttpClient.HttpClient>;
|
|
103
|
+
export declare const listMcpTools: (configs: ReadonlyArray<McpServerConfig>, options?: McpClientOptions) => Effect.Effect<McpResolvedTool[], McpError, ChildProcessSpawner.ChildProcessSpawner | HttpClient.HttpClient>;
|
|
40
104
|
//# sourceMappingURL=client.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.mts","names":[],"sources":["../../src/client/client.ts"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"client.d.mts","names":["SdkClientOptions","SdkClient"],"sources":["../../src/client/client.ts"],"mappings":";;;;;;;;;YA8EY;WACD,aAAa;WACb,iBAAiB;WACjB;WACA,MAAMA;WACN,mBAAmB,QAAQC;;WAE3B,WAAW;;;;;;;;;WASX,cAAc;;YAGb;WACD;WACA;WACA;WACA;WACA,cAAc;WACd,KAAK,kBAAkB;;qBAoYrB,2BAAwB,QAC3B,uBAAqB,UACnB,qBACT,OAAO,OAAO,cAAc,kBAAkB,UAAU,WAAW;qBA6BzD,0BAAuB,QAC1B,sBAAoB,UAClB,qBACT,OAAO,OACR,cAAc,kBACd,UACA,oBAAoB;qBAwBT,qBAAkB,QAAY,iBAAe,UAAY,qBAAgB,OAAA,gBAAA,mBAAA,UAAA,oBAAA,sBAAA,WAAA;YAa1E;WACD,QAAQ;WACR;WACA;WACA;WACA,UAAU;;;;;;;;WAQV,cAAc;;qBAGZ,0BAAuB,OAC3B,KAAK;WAA+C,QAAQ;MAClE,OAAO,OAAO,YAAY,UAAU,WAAW;YAsBtC,+BAA+B,KAAK;WACrC,QAAQ;;YAGP,qCAAqC;;WAEtC,eAAe;;WAEf,WAAW;;YAGV,4BACR,WACA,wBACA;;;;;;;;;;qBAgeS,mCAAgC,OACpC,iCACN,OAAO,OAAO,oBAAoB,2BAA2B,WAAW;;;;;;;;;;qBAuB9D,gCAA6B,OACjC,uCACN,OAAO,OAAO,oBAAoB,2BAA2B,WAAW;;;;;;;;;;;;;qBA2L9D,yBAAsB,OAC1B,KAAK;WAA+C,QAAQ;MAClE,OAAO,OAAO,YAAY,UAAU,oBAAoB;qBA2E9C,oBAAiB,OACrB,2BACN,OAAO,OACR,YACA,UACA,oBAAoB,sBAAsB,WAAW;qBAM1C,eAAY,SAAa,cAAc,kBAAgB,UAAY,qBAAgB,OAAA,OAAA,mBAAA,UAAA,oBAAA,sBAAA,WAAA"}
|