@try-works/dsh-model-as-tool 0.1.0 → 0.1.2

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 (79) hide show
  1. package/README.md +51 -0
  2. package/bin/dsh-tool-mode-mcp-stdio.mjs +80 -0
  3. package/catalog/desert-ant-models.json +77 -13
  4. package/lib/adapters/index.d.ts +19 -6
  5. package/lib/adapters/index.d.ts.map +1 -1
  6. package/lib/adapters/index.js +28 -13
  7. package/lib/adapters/tongue.d.ts +11 -3
  8. package/lib/adapters/tongue.d.ts.map +1 -1
  9. package/lib/adapters/tongue.js +12 -4
  10. package/lib/adapters/types.d.ts +11 -0
  11. package/lib/adapters/types.d.ts.map +1 -1
  12. package/lib/adapters/voz.d.ts +7 -1
  13. package/lib/adapters/voz.d.ts.map +1 -1
  14. package/lib/adapters/voz.js +16 -4
  15. package/lib/asset-acquisition.d.ts +137 -0
  16. package/lib/asset-acquisition.d.ts.map +1 -0
  17. package/lib/asset-acquisition.js +161 -0
  18. package/lib/authority.d.ts +153 -0
  19. package/lib/authority.d.ts.map +1 -0
  20. package/lib/authority.js +194 -0
  21. package/lib/bindings.d.ts +115 -0
  22. package/lib/bindings.d.ts.map +1 -0
  23. package/lib/bindings.js +239 -0
  24. package/lib/catalog.d.ts.map +1 -1
  25. package/lib/catalog.js +57 -0
  26. package/lib/contract-payload.d.ts +47 -0
  27. package/lib/contract-payload.d.ts.map +1 -0
  28. package/lib/contract-payload.js +137 -0
  29. package/lib/deployment-coordinator.d.ts +213 -0
  30. package/lib/deployment-coordinator.d.ts.map +1 -0
  31. package/lib/deployment-coordinator.js +274 -0
  32. package/lib/harness-budgets.d.ts +158 -0
  33. package/lib/harness-budgets.d.ts.map +1 -0
  34. package/lib/harness-budgets.js +152 -0
  35. package/lib/index.d.ts +41 -0
  36. package/lib/index.d.ts.map +1 -1
  37. package/lib/index.js +424 -16
  38. package/lib/licensing.d.ts +221 -0
  39. package/lib/licensing.d.ts.map +1 -0
  40. package/lib/licensing.js +188 -0
  41. package/lib/mcp/host-binding.d.ts +91 -0
  42. package/lib/mcp/host-binding.d.ts.map +1 -0
  43. package/lib/mcp/host-binding.js +133 -0
  44. package/lib/mcp/http.d.ts +130 -0
  45. package/lib/mcp/http.d.ts.map +1 -0
  46. package/lib/mcp/http.js +274 -0
  47. package/lib/mcp/protocol.d.ts +261 -0
  48. package/lib/mcp/protocol.d.ts.map +1 -0
  49. package/lib/mcp/protocol.js +387 -0
  50. package/lib/mcp/server.d.ts +115 -0
  51. package/lib/mcp/server.d.ts.map +1 -0
  52. package/lib/mcp/server.js +200 -0
  53. package/lib/mcp/stdio.d.ts +80 -0
  54. package/lib/mcp/stdio.d.ts.map +1 -0
  55. package/lib/mcp/stdio.js +176 -0
  56. package/lib/mcp/subscriptions.d.ts +135 -0
  57. package/lib/mcp/subscriptions.d.ts.map +1 -0
  58. package/lib/mcp/subscriptions.js +207 -0
  59. package/lib/provider-bridge.d.ts +69 -0
  60. package/lib/provider-bridge.d.ts.map +1 -0
  61. package/lib/provider-bridge.js +218 -0
  62. package/lib/publication.d.ts +160 -0
  63. package/lib/publication.d.ts.map +1 -0
  64. package/lib/publication.js +173 -0
  65. package/lib/receipt.d.ts +208 -0
  66. package/lib/receipt.d.ts.map +1 -0
  67. package/lib/receipt.js +150 -0
  68. package/lib/registrar.d.ts +13 -0
  69. package/lib/registrar.d.ts.map +1 -1
  70. package/lib/registrar.js +20 -3
  71. package/lib/resource-governance.d.ts +204 -0
  72. package/lib/resource-governance.d.ts.map +1 -0
  73. package/lib/resource-governance.js +213 -0
  74. package/lib/server-lifecycle.d.ts +175 -0
  75. package/lib/server-lifecycle.d.ts.map +1 -0
  76. package/lib/server-lifecycle.js +269 -0
  77. package/lib/types.d.ts +21 -0
  78. package/lib/types.d.ts.map +1 -1
  79. package/package.json +9 -2
@@ -0,0 +1,387 @@
1
+ /**
2
+ * The MCP 2026-07-28 wire core.
3
+ *
4
+ * The published `@modelcontextprotocol/sdk` (1.32.1) declares
5
+ * `LATEST_PROTOCOL_VERSION = 2025-11-25` and does not list `2026-07-28` among its
6
+ * supported revisions, so this is the "separately reviewed, schema-conformant
7
+ * adaptation" MCP-01 permits where SDK support is incomplete. It is written
8
+ * against the revision's own requirements rather than by changing a version string
9
+ * on legacy behaviour, which MCP-01 explicitly says does not satisfy the
10
+ * requirement.
11
+ *
12
+ * What makes this revision different, and what this module exists to enforce:
13
+ *
14
+ * - **No handshake.** `tools/list` and `tools/call` must work as the FIRST
15
+ * application request. There is no `initialize`, no
16
+ * `notifications/initialized`, no prior discovery call and no `Mcp-Session-Id`
17
+ * (P26-01). So there is no session state here to get wrong.
18
+ * - **Per-request metadata.** Version and capabilities travel in `params._meta` on
19
+ * EVERY request, and are never inferred from an earlier one (P26-02). That is
20
+ * why `_meta` is parsed per request and not cached.
21
+ * - **Server identity in results.** Every result envelope carries `resultType`,
22
+ * and the revision's guidance puts `serverInfo` in result metadata.
23
+ * - **Errors stay in their lanes** (P26-04): a malformed protocol request is a
24
+ * JSON-RPC error, while an application tool failure is a tool-error RESULT. A
25
+ * failure wrapped as a successful payload is the specific mistake this prevents.
26
+ *
27
+ * @module @try-works/dsh-model-as-tool/mcp/protocol
28
+ */
29
+ /** The revision this server speaks. */
30
+ export const PROTOCOL_VERSION = '2026-07-28';
31
+ /**
32
+ * Revisions this server can also serve.
33
+ *
34
+ * Kept explicit and short. P26-03 requires an unsupported version to be answered
35
+ * with the supported list, so the list must be a fact rather than a guess.
36
+ */
37
+ export const SUPPORTED_PROTOCOL_VERSIONS = [PROTOCOL_VERSION];
38
+ /** The `_meta` keys the revision defines. */
39
+ export const META_KEYS = {
40
+ protocolVersion: 'io.modelcontextprotocol/protocolVersion',
41
+ clientInfo: 'io.modelcontextprotocol/clientInfo',
42
+ clientCapabilities: 'io.modelcontextprotocol/clientCapabilities',
43
+ serverInfo: 'io.modelcontextprotocol/serverInfo',
44
+ };
45
+ /**
46
+ * Error codes.
47
+ *
48
+ * The reserved range belongs to the protocol. P26-03 is explicit that custom
49
+ * errors must not be allocated there, so this module declares only codes the
50
+ * revision defines and refuses to mint new ones in that band.
51
+ */
52
+ export const ERROR_CODES = {
53
+ /** Standard JSON-RPC. */
54
+ parseError: -32700,
55
+ invalidRequest: -32600,
56
+ methodNotFound: -32601,
57
+ invalidParams: -32602,
58
+ internalError: -32603,
59
+ /** MCP-reserved. */
60
+ headerMismatch: -32020,
61
+ unsupportedClientCapability: -32021,
62
+ unsupportedProtocolVersion: -32022,
63
+ };
64
+ /** Raised for a request that must be answered with a JSON-RPC error. */
65
+ export class WireError extends Error {
66
+ name = 'WireError';
67
+ code;
68
+ /** Structured detail, as the revision's schema defines for the code. */
69
+ data;
70
+ constructor(code, message, data) {
71
+ super(message);
72
+ this.code = code;
73
+ if (data !== undefined)
74
+ this.data = data;
75
+ }
76
+ }
77
+ /** Whether a numeric code lies in the range reserved for the protocol. */
78
+ export function isReservedErrorCode(code) {
79
+ // JSON-RPC's own band plus MCP's -32000..-32099 allocation.
80
+ return (code >= -32768 && code <= -32000);
81
+ }
82
+ /**
83
+ * Parse `params._meta` from a request (P26-02).
84
+ *
85
+ * Missing required metadata is `invalid params`, not a defaulted value: inferring
86
+ * a version or a capability from a preceding request is exactly what P26-02
87
+ * forbids, and defaulting is inference with extra steps.
88
+ *
89
+ * The REQUIRED set is taken from the pinned revision schema's `RequestMetaObject`,
90
+ * which requires `clientCapabilities` and `protocolVersion` — and NOT `clientInfo`.
91
+ * Requiring `clientInfo` here would reject a request the schema admits, which is a
92
+ * conformance failure in the opposite direction from accepting too much.
93
+ *
94
+ * @param params - the request parameters.
95
+ * @returns the parsed metadata.
96
+ * @throws WireError `-32602` when a required key is absent or malformed.
97
+ */
98
+ export function parseRequestMetadata(params) {
99
+ const meta = params?._meta;
100
+ if (typeof meta !== 'object' || meta === null || Array.isArray(meta)) {
101
+ throw new WireError(ERROR_CODES.invalidParams, 'params._meta is required on every modern request and must be an object');
102
+ }
103
+ const record = meta;
104
+ const protocolVersion = record[META_KEYS.protocolVersion];
105
+ if (typeof protocolVersion !== 'string' || protocolVersion.length === 0) {
106
+ throw new WireError(ERROR_CODES.invalidParams, `params._meta["${META_KEYS.protocolVersion}"] is required and must be a string`);
107
+ }
108
+ const capabilities = record[META_KEYS.clientCapabilities];
109
+ if (typeof capabilities !== 'object' || capabilities === null || Array.isArray(capabilities)) {
110
+ throw new WireError(ERROR_CODES.invalidParams, `params._meta["${META_KEYS.clientCapabilities}"] is required and must be an object`);
111
+ }
112
+ // Optional in the schema, so absent is admitted; present-but-malformed is not,
113
+ // because a client that sends half an Implementation has sent a broken one.
114
+ const clientInfo = record[META_KEYS.clientInfo];
115
+ let info = { name: 'unknown', version: 'unknown' };
116
+ if (clientInfo !== undefined) {
117
+ if (typeof clientInfo !== 'object' || clientInfo === null) {
118
+ throw new WireError(ERROR_CODES.invalidParams, `params._meta["${META_KEYS.clientInfo}"], when present, must be an object`);
119
+ }
120
+ const candidate = clientInfo;
121
+ if (typeof candidate.name !== 'string' || typeof candidate.version !== 'string') {
122
+ throw new WireError(ERROR_CODES.invalidParams, 'clientInfo needs a name and a version');
123
+ }
124
+ info = { name: candidate.name, version: candidate.version };
125
+ }
126
+ return {
127
+ protocolVersion,
128
+ // Self-reported and therefore for DIAGNOSTICS only: P26-02 is explicit that
129
+ // clientInfo is not authentication, so nothing here is ever used to authorize.
130
+ clientInfo: info,
131
+ clientCapabilities: capabilities,
132
+ };
133
+ }
134
+ /**
135
+ * Negotiate the protocol version for one request (P26-03).
136
+ *
137
+ * @param metadata - the request metadata.
138
+ * @returns the negotiated version.
139
+ * @throws WireError `-32022` carrying the official `supported` and `requested` data.
140
+ */
141
+ export function negotiateVersion(metadata) {
142
+ if (!SUPPORTED_PROTOCOL_VERSIONS.includes(metadata.protocolVersion)) {
143
+ throw new WireError(ERROR_CODES.unsupportedProtocolVersion, `unsupported protocol version ${metadata.protocolVersion}`,
144
+ // The revision defines this data shape; a bare message would leave the client
145
+ // unable to choose a version it can speak.
146
+ { supported: [...SUPPORTED_PROTOCOL_VERSIONS], requested: metadata.protocolVersion });
147
+ }
148
+ return metadata.protocolVersion;
149
+ }
150
+ /**
151
+ * The advertised-feature matrix (P26-12).
152
+ *
153
+ * P26-12 forbids advertising Tasks, sampling, resource subscriptions, prompts or
154
+ * UI extensions merely because an SDK exports their types. Declaring the matrix as
155
+ * data — with `implemented: false` where that is the truth — means the server
156
+ * cannot advertise a feature it does not have by accident.
157
+ */
158
+ export const ADVERTISED_FEATURES = [
159
+ { feature: 'tools', implemented: true },
160
+ { feature: 'server/discover', implemented: true },
161
+ // Now implemented, for TOOL-catalog changes only. P26-12 forbids advertising a
162
+ // feature that is not implemented, and permits advertising one that is: the
163
+ // acknowledgement reports the supported subset, so the narrower reality is stated
164
+ // on the wire rather than implied here.
165
+ { feature: 'subscriptions/listen', implemented: true },
166
+ { feature: 'tasks', implemented: false },
167
+ { feature: 'sampling', implemented: false },
168
+ { feature: 'elicitation', implemented: false },
169
+ { feature: 'roots', implemented: false },
170
+ { feature: 'prompts', implemented: false },
171
+ { feature: 'resources/subscribe', implemented: false },
172
+ { feature: 'logging', implemented: false },
173
+ ];
174
+ /**
175
+ * The capabilities object this server may advertise.
176
+ *
177
+ * Derived from {@link ADVERTISED_FEATURES} rather than written twice, so the
178
+ * matrix and the advertised capabilities cannot disagree.
179
+ * @returns the capability names that are genuinely implemented.
180
+ */
181
+ export function implementedCapabilities() {
182
+ return ADVERTISED_FEATURES.filter(entry => entry.implemented).map(entry => entry.feature);
183
+ }
184
+ /**
185
+ * Whether a client's REQUIRED capability is one this server supports (P26-03).
186
+ *
187
+ * @param required - capability names the client declared as required.
188
+ * @returns the unsupported names, empty when all are supported.
189
+ */
190
+ export function unsupportedRequiredCapabilities(required) {
191
+ const implemented = new Set(implementedCapabilities());
192
+ // `tools` is the only capability a client can require of this server today; any
193
+ // other requirement cannot be met, and P26-03 wants that answered with -32021
194
+ // rather than attempted.
195
+ return required.filter(name => !implemented.has(name));
196
+ }
197
+ /**
198
+ * The caching fields every cacheable result must carry (P26-14).
199
+ *
200
+ * Taken from the pinned schema's `CacheableResult`, which REQUIRES `cacheScope` and
201
+ * `ttlMs` on `DiscoverResult` and `ListToolsResult` alike. Tool Mode's
202
+ * authorization-filtered catalogs are private, so the default TTL is zero and the
203
+ * scope is private — a shared cache keyed on tool names would leak one caller's
204
+ * permitted set to another.
205
+ * @returns the caching fields.
206
+ */
207
+ export function cacheableResultFields() {
208
+ return { cacheScope: 'private', ttlMs: 0 };
209
+ }
210
+ /**
211
+ * Build a successful result envelope (P26-04).
212
+ *
213
+ * Every modern result carries `resultType`, and `serverInfo` rides in result
214
+ * metadata per the revision's guidance — `ResultMetaObject` admits exactly that
215
+ * one key, which is what this writes.
216
+ * @param result - the method-specific fields.
217
+ * @param serverInfo - this server's identity.
218
+ * @returns the result object, including `resultType` and `_meta`.
219
+ */
220
+ export function successResult(result, serverInfo) {
221
+ // The metadata is MERGED rather than replaced. A method-specific result may carry
222
+ // its own `_meta` members that the revision requires —
223
+ // `SubscriptionsListenResult` must contain
224
+ // `io.modelcontextprotocol/subscriptionId` — and overwriting the object dropped
225
+ // it, sending a result with a required field missing. A subscription test caught
226
+ // this; the pinned schema would have caught it too, and did not only because the
227
+ // fixture corpus has no subscription case yet.
228
+ const existing = typeof result._meta === 'object' && result._meta !== null
229
+ ? result._meta
230
+ : {};
231
+ return {
232
+ ...result,
233
+ resultType: 'complete',
234
+ _meta: {
235
+ ...existing,
236
+ [META_KEYS.serverInfo]: { name: serverInfo.name, version: serverInfo.version },
237
+ },
238
+ };
239
+ }
240
+ /**
241
+ * Build a tool-error RESULT (P26-04).
242
+ *
243
+ * The distinction this preserves is the whole point: an application failure is a
244
+ * successful protocol exchange carrying `isError`, while a malformed request is a
245
+ * JSON-RPC error. Wrapping a domain failure as protocol success, or an
246
+ * infrastructure failure as a successful domain payload, are both forbidden.
247
+ * @param message - a bounded, model-readable explanation.
248
+ * @returns the tool-error result.
249
+ */
250
+ export function toolErrorResult(message) {
251
+ return {
252
+ // Truncated because a stack trace or an unbounded message would be neither
253
+ // model-readable nor safe to return.
254
+ isError: true,
255
+ content: [{ type: 'text', text: message.length > 2000 ? `${message.slice(0, 2000)}…` : message }],
256
+ };
257
+ }
258
+ /**
259
+ * Build a JSON-RPC error response.
260
+ *
261
+ * When the request id is UNKNOWN the `id` member is omitted rather than set to
262
+ * `null`. JSON-RPC 2.0 conventionally allows `id: null` for an undeterminable id,
263
+ * but the pinned revision schema types `RequestId` as `string | integer` and does
264
+ * not admit null — while `id` itself is optional. Omitting it is therefore the
265
+ * conformant way to say "unknown", and the independent probe caught this by
266
+ * rejecting a captured 401 whose id was null.
267
+ *
268
+ * @param id - the request id, or null when it could not be determined.
269
+ * @param error - the failure.
270
+ * @returns the response envelope.
271
+ */
272
+ export function errorResponse(id, error) {
273
+ const data = 'data' in error ? error.data : undefined;
274
+ return {
275
+ jsonrpc: '2.0',
276
+ ...id === null ? {} : { id },
277
+ error: {
278
+ code: error.code,
279
+ message: error.message,
280
+ ...data === undefined ? {} : { data },
281
+ },
282
+ };
283
+ }
284
+ /**
285
+ * Decode the revision's Base64 sentinel encoding (P26-05).
286
+ *
287
+ * A header value may be encoded with the official `=?base64?…?=` sentinel, and it
288
+ * must be decoded BEFORE comparison. Comparing the encoded form would let a client
289
+ * present a value that decodes to something else entirely.
290
+ * @param value - the raw header value.
291
+ * @returns the decoded value.
292
+ */
293
+ export function decodeHeaderValue(value) {
294
+ const match = /^=\?base64\?(.*)\?=$/s.exec(value);
295
+ if (match === null)
296
+ return value;
297
+ try {
298
+ return Buffer.from(match[1], 'base64').toString('utf8');
299
+ }
300
+ catch {
301
+ // A malformed sentinel is left as-is so the comparison against the body fails
302
+ // and reports a mismatch, rather than being silently accepted as something.
303
+ return value;
304
+ }
305
+ }
306
+ /**
307
+ * Check the required headers against the body (P26-05).
308
+ *
309
+ * Headers are checked against BODY FIELDS, so a request cannot claim one method in
310
+ * a header and another in its body. Every mismatch is `HeaderMismatch` (-32020),
311
+ * which the HTTP layer reports as 400.
312
+ * @param headers - the relevant request headers.
313
+ * @param body - the parsed request.
314
+ * @returns nothing when the headers agree.
315
+ * @throws WireError `-32020` naming the first disagreement.
316
+ */
317
+ export function assertHeadersMatch(headers, body) {
318
+ const fail = (detail) => {
319
+ throw new WireError(ERROR_CODES.headerMismatch, detail);
320
+ };
321
+ const version = headers.protocolVersion === undefined ? undefined : decodeHeaderValue(headers.protocolVersion);
322
+ if (version === undefined) {
323
+ return fail('the MCP-Protocol-Version header is required');
324
+ }
325
+ const bodyVersion = body.params?._meta?.[META_KEYS.protocolVersion];
326
+ if (typeof bodyVersion === 'string' && version !== bodyVersion) {
327
+ return fail(`the MCP-Protocol-Version header (${version}) does not match the request body (${bodyVersion})`);
328
+ }
329
+ const method = headers.method === undefined ? undefined : decodeHeaderValue(headers.method);
330
+ if (method !== undefined && method !== body.method) {
331
+ return fail(`the Mcp-Method header (${method}) does not match the request method (${body.method})`);
332
+ }
333
+ // `Mcp-Name` is required only for a named call. Requiring it universally would
334
+ // reject a correct `tools/list`, which has no name.
335
+ if (body.method === 'tools/call') {
336
+ const name = headers.name === undefined ? undefined : decodeHeaderValue(headers.name);
337
+ if (name === undefined)
338
+ return fail('the Mcp-Name header is required for tools/call');
339
+ const bodyName = body.params?.name;
340
+ if (typeof bodyName === 'string' && name !== bodyName) {
341
+ return fail(`the Mcp-Name header (${name}) does not match the request name (${bodyName})`);
342
+ }
343
+ }
344
+ }
345
+ /**
346
+ * Parse a newline-delimited stdio frame (P26-08).
347
+ *
348
+ * Stdio carries protocol traffic on stdout and diagnostics on stderr, so a line
349
+ * that is not a JSON object is a protocol error rather than something to log and
350
+ * skip: silently dropping it would leave a client waiting for a response that
351
+ * never comes.
352
+ * @param line - one line of input.
353
+ * @returns the parsed request, or undefined for a blank line.
354
+ * @throws WireError `-32700` when the line is not a JSON object.
355
+ */
356
+ export function parseStdioLine(line) {
357
+ const trimmed = line.trim();
358
+ if (trimmed.length === 0)
359
+ return undefined;
360
+ let parsed;
361
+ try {
362
+ parsed = JSON.parse(trimmed);
363
+ }
364
+ catch {
365
+ throw new WireError(ERROR_CODES.parseError, 'the frame is not valid JSON');
366
+ }
367
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
368
+ throw new WireError(ERROR_CODES.invalidRequest, 'the frame is not a JSON-RPC object');
369
+ }
370
+ const request = parsed;
371
+ if (request.jsonrpc !== '2.0' || typeof request.method !== 'string') {
372
+ throw new WireError(ERROR_CODES.invalidRequest, 'the frame is not a JSON-RPC 2.0 request');
373
+ }
374
+ return request;
375
+ }
376
+ /**
377
+ * Serialize one stdio frame.
378
+ * @param message - the response or notification.
379
+ * @returns the line, newline-terminated.
380
+ */
381
+ export function serializeStdioFrame(message) {
382
+ // A newline inside the JSON would produce two frames and desynchronise the
383
+ // stream, so the compact form is used and embedded newlines are escaped by
384
+ // JSON.stringify itself.
385
+ return `${JSON.stringify(message)}\n`;
386
+ }
387
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1,115 @@
1
+ /**
2
+ * MCP method dispatch (MCP-05, MCP-06, MCP-08, MCP-09, MCP-13).
3
+ *
4
+ * The server is STATELESS by construction, which is what P26-01 requires: a
5
+ * `tools/list` or `tools/call` must be processable as the first application
6
+ * request. There is no session table here to require one, so the requirement is
7
+ * satisfied by the shape of the code rather than by remembering to skip a check.
8
+ *
9
+ * Dispatch resolves ONE authorized definition and calls it through the host's
10
+ * execution path (MCP-08), rather than reaching into a registry by name — the
11
+ * difference matters because the host's path applies the grant, the receipt and
12
+ * the result policy, while a direct lookup would bypass all three.
13
+ *
14
+ * @module @try-works/dsh-model-as-tool/mcp/server
15
+ */
16
+ import { type HeaderInput, type WireRequest } from './protocol.ts';
17
+ import type { SubscriptionRegistry } from './subscriptions.ts';
18
+ /** One tool as the MCP surface describes it. */
19
+ export interface McpToolDefinition {
20
+ /** The caller-facing name. */
21
+ readonly name: string;
22
+ /** A short human-readable title, when the contract declares one. */
23
+ readonly title?: string;
24
+ /** What the tool does, written for a model. */
25
+ readonly description: string;
26
+ /** The canonical input schema, JSON Schema 2020-12. */
27
+ readonly inputSchema: Readonly<Record<string, unknown>>;
28
+ /** The canonical OUTPUT schema (MCP-09). */
29
+ readonly outputSchema: Readonly<Record<string, unknown>>;
30
+ /** Whether this tool was imported from another MCP server. */
31
+ readonly importedFromMcp: boolean;
32
+ }
33
+ /** The outcome of invoking one tool. */
34
+ export interface ToolInvocationOutcome {
35
+ /** The finalized, post-policy canonical value. */
36
+ readonly structured: unknown;
37
+ /** A bounded, model-readable rendering. */
38
+ readonly text: string;
39
+ /** Whether the tool itself failed. */
40
+ readonly isError?: boolean;
41
+ }
42
+ /** What dispatch needs from the host. */
43
+ export interface McpHost {
44
+ /** This server's identity, reported in result metadata. */
45
+ readonly serverInfo: {
46
+ readonly name: string;
47
+ readonly version: string;
48
+ };
49
+ /**
50
+ * The tools this caller may see, in deterministic order (MCP-06).
51
+ * @returns the authorized definitions.
52
+ */
53
+ listTools(): readonly McpToolDefinition[];
54
+ /**
55
+ * Invoke one authorized tool through the host execution path (MCP-08).
56
+ * @param name - the tool name.
57
+ * @param args - the tool arguments.
58
+ * @param signal - the caller's abort signal.
59
+ * @returns the outcome.
60
+ */
61
+ callTool(name: string, args: Readonly<Record<string, unknown>>, signal: AbortSignal): Promise<ToolInvocationOutcome>;
62
+ }
63
+ /** One dispatched response. */
64
+ export interface DispatchResult {
65
+ /** The response envelope to send, or undefined for a notification. */
66
+ readonly response?: Record<string, unknown>;
67
+ /** The HTTP status the transport should use. */
68
+ readonly httpStatus: number;
69
+ /**
70
+ * Notifications the transport must deliver after the response (P26-09).
71
+ *
72
+ * Carried on the result rather than written into the body, because a notification
73
+ * is a separate message: embedding one inside a result would produce a frame that
74
+ * is not a valid result and not a valid notification.
75
+ */
76
+ readonly followUp?: readonly Record<string, unknown>[];
77
+ }
78
+ /**
79
+ * Project a definition into the MCP tool shape.
80
+ *
81
+ * `outputSchema` is taken from the resolved definition rather than from DSH's
82
+ * model-facing `schemas()` projection, which intentionally omits `output`: a
83
+ * schema-only export built from that projection would be missing the very field
84
+ * MCP-09 requires.
85
+ * @param definition - the resolved definition.
86
+ * @returns the MCP tool descriptor.
87
+ */
88
+ export declare function toMcpTool(definition: McpToolDefinition): Record<string, unknown>;
89
+ /**
90
+ * Dispatch one request.
91
+ *
92
+ * Stateless: nothing is retained between calls, so a valid request works as the
93
+ * first one.
94
+ * @param request - the parsed request.
95
+ * @param host - the host surface.
96
+ * @param options - headers and the caller's abort signal.
97
+ * @returns the response and the HTTP status.
98
+ */
99
+ export declare function dispatch(request: WireRequest, host: McpHost, options?: {
100
+ readonly headers?: HeaderInput;
101
+ readonly signal?: AbortSignal;
102
+ /** Whether the transport checks headers at all; stdio has none to check. */
103
+ readonly checkHeaders?: boolean;
104
+ /**
105
+ * The catalog subscription registry (P26-09).
106
+ *
107
+ * Optional so a host that offers no subscriptions does not have to construct one;
108
+ * subscriptions/listen then reports the method as unsupported rather than
109
+ * accepting a subscription it cannot serve.
110
+ */
111
+ readonly subscriptions?: SubscriptionRegistry;
112
+ /** The authenticated client, which a subscription is bound to. */
113
+ readonly clientId?: string;
114
+ }): Promise<DispatchResult>;
115
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAaL,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAE9D,gDAAgD;AAChD,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACvD,4CAA4C;IAC5C,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACxD,8DAA8D;IAC9D,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;CAClC;AAED,wCAAwC;AACxC,MAAM,WAAW,qBAAqB;IACpC,kDAAkD;IAClD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAC3B;AAED,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IACxE;;;OAGG;IACH,SAAS,IAAI,SAAS,iBAAiB,EAAE,CAAA;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;CACrH;AAED,+BAA+B;AAC/B,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,gDAAgD;IAChD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;CACvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQhF;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE;IACP,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,oBAAoB,CAAA;IAC7C,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CACtB,GACL,OAAO,CAAC,cAAc,CAAC,CAsFzB"}