@warlock.js/ai-tools 5.30.0 → 5.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -1
- package/README.md +25 -13
- package/cjs/index.cjs +843 -101
- package/cjs/index.cjs.map +1 -1
- package/esm/contracts/index.d.mts +2 -1
- package/esm/contracts/mcp-serve.type.d.mts +257 -0
- package/esm/contracts/mcp-serve.type.d.mts.map +1 -0
- package/esm/contracts/mcp.type.d.mts +16 -59
- package/esm/contracts/mcp.type.d.mts.map +1 -1
- package/esm/errors.d.mts +36 -1
- package/esm/errors.d.mts.map +1 -1
- package/esm/errors.mjs +20 -1
- package/esm/errors.mjs.map +1 -1
- package/esm/http/http-request.d.mts.map +1 -1
- package/esm/http/http-request.mjs.map +1 -1
- package/esm/index.d.mts +6 -4
- package/esm/index.mjs +3 -2
- package/esm/mcp/client.mjs +35 -5
- package/esm/mcp/client.mjs.map +1 -1
- package/esm/mcp/index.d.mts +12 -5
- package/esm/mcp/index.d.mts.map +1 -1
- package/esm/mcp/index.mjs +1 -0
- package/esm/mcp/index.mjs.map +1 -1
- package/esm/mcp/protocol.d.mts +16 -0
- package/esm/mcp/protocol.d.mts.map +1 -0
- package/esm/mcp/protocol.mjs +23 -0
- package/esm/mcp/protocol.mjs.map +1 -0
- package/esm/mcp/serve-http.mjs +443 -0
- package/esm/mcp/serve-http.mjs.map +1 -0
- package/esm/mcp/serve.d.mts +45 -26
- package/esm/mcp/serve.d.mts.map +1 -1
- package/esm/mcp/serve.mjs +325 -92
- package/esm/mcp/serve.mjs.map +1 -1
- package/esm/mcp/transport.d.mts.map +1 -1
- package/esm/mcp/transport.mjs.map +1 -1
- package/esm/register.d.mts +12 -1
- package/esm/register.d.mts.map +1 -1
- package/esm/register.mjs +3 -2
- package/esm/register.mjs.map +1 -1
- package/esm/schema.mjs.map +1 -1
- package/esm/utility/calculator.d.mts.map +1 -1
- package/esm/utility/calculator.mjs.map +1 -1
- package/esm/utility/date-time.d.mts.map +1 -1
- package/esm/utility/date-time.mjs.map +1 -1
- package/esm/utility/schema.mjs.map +1 -1
- package/esm/web/fetch-url.d.mts.map +1 -1
- package/esm/web/fetch-url.mjs.map +1 -1
- package/esm/web/schema.mjs.map +1 -1
- package/esm/web/web-search.mjs.map +1 -1
- package/llms-full.txt +194 -57
- package/llms.txt +3 -3
- package/package.json +2 -6
- package/skills/connect-mcp-server/SKILL.md +28 -6
- package/skills/expose-as-mcp-server/SKILL.md +117 -36
- package/skills/index.md +5 -2
- package/skills/use-web-and-http-tools/SKILL.md +49 -15
package/esm/index.d.mts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { FetchUrlExtract, FetchUrlInput, FetchUrlOptions, FetchUrlResult, SearchProvider, WebSearchInput, WebSearchOptions, WebSearchResult, WebSearchResultItem } from "./contracts/web.type.mjs";
|
|
2
2
|
import { HttpMethod, HttpRequestInput, HttpRequestOptions, HttpRequestResult } from "./contracts/http.type.mjs";
|
|
3
3
|
import { CalculatorInput, CalculatorOptions, CalculatorResult, DateTimeInput, DateTimeOp, DateTimeOptions, DateTimeResult } from "./contracts/utility.type.mjs";
|
|
4
|
-
import { JsonRpcError, JsonRpcId, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, JsonRpcVersion, McpClient, McpClientOptions, McpContentBlock,
|
|
5
|
-
import {
|
|
4
|
+
import { JsonRpcError, JsonRpcId, JsonRpcMessage, JsonRpcNotification, JsonRpcRequest, JsonRpcResponse, JsonRpcVersion, McpClient, McpClientOptions, McpContentBlock, McpToolCallResult, McpToolDescriptor, McpTransport } from "./contracts/mcp.type.mjs";
|
|
5
|
+
import { McpGroupedToolSource, McpHttpAuth, McpHttpRequestInfo, McpHttpServeHandle, McpHttpServeTransport, McpPromptArgument, McpPromptMessage, McpServeCallContext, McpServeHandle, McpServeOptions, McpServePrompt, McpServeResource, McpServeSource, McpServeTransport, McpServer, McpToolSource } from "./contracts/mcp-serve.type.mjs";
|
|
6
|
+
import { McpServeRequestHandler, createServeHandler, serve } from "./mcp/serve.mjs";
|
|
7
|
+
import { SUPPORTED_PROTOCOL_VERSIONS } from "./mcp/protocol.mjs";
|
|
6
8
|
import { jsonSchemaToStandard } from "./mcp/json-schema-to-standard.mjs";
|
|
7
9
|
import { McpTransportClient } from "./mcp/transport.type.mjs";
|
|
8
10
|
import { JsonRpcClientHandle, createJsonRpcClient, createTransport } from "./mcp/transport.mjs";
|
|
@@ -13,7 +15,7 @@ import { fetchUrlTool } from "./web/fetch-url.mjs";
|
|
|
13
15
|
import { httpRequestTool } from "./http/http-request.mjs";
|
|
14
16
|
import { calculatorTool } from "./utility/calculator.mjs";
|
|
15
17
|
import { dateTimeTool } from "./utility/date-time.mjs";
|
|
16
|
-
import { CalculatorError, CalculatorErrorOptions, CalculatorFailure, DateTimeError, DateTimeErrorOptions, DateTimeFailure, HttpPolicyError, HttpPolicyErrorOptions, HttpPolicyFailure, McpTransportError, McpTransportErrorOptions, McpTransportFailure, WebToolError, WebToolErrorOptions, WebToolFailure } from "./errors.mjs";
|
|
17
|
-
export { type AiToolsNamespace, CalculatorError, type CalculatorErrorOptions, type CalculatorFailure, type CalculatorInput, type CalculatorOptions, type CalculatorResult, DateTimeError, type DateTimeErrorOptions, type DateTimeFailure, type DateTimeInput, type DateTimeOp, type DateTimeOptions, type DateTimeResult, type FetchUrlExtract, type FetchUrlInput, type FetchUrlOptions, type FetchUrlResult, type HttpMethod, HttpPolicyError, type HttpPolicyErrorOptions, type HttpPolicyFailure, type HttpRequestInput, type HttpRequestOptions, type HttpRequestResult, type JsonRpcClientHandle, type JsonRpcError, type JsonRpcId, type JsonRpcMessage, type JsonRpcNotification, type JsonRpcRequest, type JsonRpcResponse, type JsonRpcVersion, type McpClient, type McpClientOptions, type McpContentBlock, type McpFactory, type McpServeOptions, type McpServeSource, type McpServeTransport, type McpServer, type McpToolCallResult, type McpToolDescriptor, type McpTransport, type McpTransportClient, McpTransportError, type McpTransportErrorOptions, type McpTransportFailure, type SearchProvider, type WebSearchInput, type WebSearchOptions, type WebSearchResult, type WebSearchResultItem, WebToolError, type WebToolErrorOptions, type WebToolFailure, calculatorTool, createJsonRpcClient, createServeHandler, createTransport, dateTimeTool, fetchUrlTool, httpRequestTool, jsonSchemaToStandard, mcp, serve, webSearchTool };
|
|
18
|
+
import { CalculatorError, CalculatorErrorOptions, CalculatorFailure, DateTimeError, DateTimeErrorOptions, DateTimeFailure, HttpPolicyError, HttpPolicyErrorOptions, HttpPolicyFailure, McpServeError, McpServeErrorOptions, McpServeFailure, McpTransportError, McpTransportErrorOptions, McpTransportFailure, WebToolError, WebToolErrorOptions, WebToolFailure } from "./errors.mjs";
|
|
19
|
+
export { type AiToolsNamespace, CalculatorError, type CalculatorErrorOptions, type CalculatorFailure, type CalculatorInput, type CalculatorOptions, type CalculatorResult, DateTimeError, type DateTimeErrorOptions, type DateTimeFailure, type DateTimeInput, type DateTimeOp, type DateTimeOptions, type DateTimeResult, type FetchUrlExtract, type FetchUrlInput, type FetchUrlOptions, type FetchUrlResult, type HttpMethod, HttpPolicyError, type HttpPolicyErrorOptions, type HttpPolicyFailure, type HttpRequestInput, type HttpRequestOptions, type HttpRequestResult, type JsonRpcClientHandle, type JsonRpcError, type JsonRpcId, type JsonRpcMessage, type JsonRpcNotification, type JsonRpcRequest, type JsonRpcResponse, type JsonRpcVersion, type McpClient, type McpClientOptions, type McpContentBlock, type McpFactory, type McpGroupedToolSource, type McpHttpAuth, type McpHttpRequestInfo, type McpHttpServeHandle, type McpHttpServeTransport, type McpPromptArgument, type McpPromptMessage, type McpServeCallContext, McpServeError, type McpServeErrorOptions, type McpServeFailure, type McpServeHandle, type McpServeOptions, type McpServePrompt, type McpServeRequestHandler, type McpServeResource, type McpServeSource, type McpServeTransport, type McpServer, type McpToolCallResult, type McpToolDescriptor, type McpToolSource, type McpTransport, type McpTransportClient, McpTransportError, type McpTransportErrorOptions, type McpTransportFailure, SUPPORTED_PROTOCOL_VERSIONS, type SearchProvider, type WebSearchInput, type WebSearchOptions, type WebSearchResult, type WebSearchResultItem, WebToolError, type WebToolErrorOptions, type WebToolFailure, calculatorTool, createJsonRpcClient, createServeHandler, createTransport, dateTimeTool, fetchUrlTool, httpRequestTool, jsonSchemaToStandard, mcp, serve, webSearchTool };
|
|
18
20
|
import "./mcp/index.mjs";
|
|
19
21
|
import "./register.mjs";
|
package/esm/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { CalculatorError, DateTimeError, HttpPolicyError, McpTransportError, WebToolError } from "./errors.mjs";
|
|
1
|
+
import { CalculatorError, DateTimeError, HttpPolicyError, McpServeError, McpTransportError, WebToolError } from "./errors.mjs";
|
|
2
2
|
import { httpRequestTool } from "./http/http-request.mjs";
|
|
3
3
|
import { jsonSchemaToStandard } from "./mcp/json-schema-to-standard.mjs";
|
|
4
4
|
import { createJsonRpcClient, createTransport } from "./mcp/transport.mjs";
|
|
5
|
+
import { SUPPORTED_PROTOCOL_VERSIONS } from "./mcp/protocol.mjs";
|
|
5
6
|
import { createServeHandler, serve } from "./mcp/serve.mjs";
|
|
6
7
|
import { mcp } from "./mcp/index.mjs";
|
|
7
8
|
import { calculatorTool } from "./utility/calculator.mjs";
|
|
@@ -12,4 +13,4 @@ import "./register.mjs";
|
|
|
12
13
|
import "./web/index.mjs";
|
|
13
14
|
import "./utility/index.mjs";
|
|
14
15
|
|
|
15
|
-
export { CalculatorError, DateTimeError, HttpPolicyError, McpTransportError, WebToolError, calculatorTool, createJsonRpcClient, createServeHandler, createTransport, dateTimeTool, fetchUrlTool, httpRequestTool, jsonSchemaToStandard, mcp, serve, webSearchTool };
|
|
16
|
+
export { CalculatorError, DateTimeError, HttpPolicyError, McpServeError, McpTransportError, SUPPORTED_PROTOCOL_VERSIONS, WebToolError, calculatorTool, createJsonRpcClient, createServeHandler, createTransport, dateTimeTool, fetchUrlTool, httpRequestTool, jsonSchemaToStandard, mcp, serve, webSearchTool };
|
package/esm/mcp/client.mjs
CHANGED
|
@@ -20,8 +20,24 @@ const PROTOCOL_VERSION = "2025-06-18";
|
|
|
20
20
|
var McpClientImpl = class {
|
|
21
21
|
constructor(source, options = {}) {
|
|
22
22
|
this.initialized = false;
|
|
23
|
+
this.onAbort = () => {
|
|
24
|
+
this.close().catch(() => void 0);
|
|
25
|
+
};
|
|
23
26
|
this.rpc = createJsonRpcClient(source);
|
|
24
27
|
this.options = options;
|
|
28
|
+
const signal = options.signal;
|
|
29
|
+
if (signal?.aborted) this.onAbort();
|
|
30
|
+
else signal?.addEventListener("abort", this.onAbort, { once: true });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Reject with a typed `"closed"` error once the client was closed or its
|
|
34
|
+
* `signal` aborted, so no request is sent on a dead transport.
|
|
35
|
+
*/
|
|
36
|
+
assertOpen(method) {
|
|
37
|
+
if (this.closing || this.options.signal?.aborted) throw new McpTransportError(`MCP client is closed; "${method}" was not sent.`, {
|
|
38
|
+
type: "closed",
|
|
39
|
+
method
|
|
40
|
+
});
|
|
25
41
|
}
|
|
26
42
|
/**
|
|
27
43
|
* Run the MCP `initialize` handshake exactly once, then send the
|
|
@@ -31,6 +47,7 @@ var McpClientImpl = class {
|
|
|
31
47
|
*/
|
|
32
48
|
async handshake() {
|
|
33
49
|
if (this.initialized) return;
|
|
50
|
+
this.assertOpen("initialize");
|
|
34
51
|
try {
|
|
35
52
|
await this.rpc.call("initialize", {
|
|
36
53
|
protocolVersion: PROTOCOL_VERSION,
|
|
@@ -39,7 +56,7 @@ var McpClientImpl = class {
|
|
|
39
56
|
name: "@warlock.js/ai-tools",
|
|
40
57
|
version: "4.4.0"
|
|
41
58
|
}
|
|
42
|
-
});
|
|
59
|
+
}, { signal: this.options.signal });
|
|
43
60
|
await this.rpc.notify("notifications/initialized");
|
|
44
61
|
} catch (cause) {
|
|
45
62
|
if (cause instanceof McpTransportError) throw cause;
|
|
@@ -68,7 +85,8 @@ var McpClientImpl = class {
|
|
|
68
85
|
*/
|
|
69
86
|
async listAndAdapt() {
|
|
70
87
|
await this.handshake();
|
|
71
|
-
|
|
88
|
+
this.assertOpen("tools/list");
|
|
89
|
+
const descriptors = (await this.rpc.call("tools/list", void 0, { signal: this.options.signal })).tools ?? [];
|
|
72
90
|
const filter = this.options.filter;
|
|
73
91
|
return (filter ? descriptors.filter((d) => filter(d.name)) : descriptors).map((descriptor) => this.adapt(descriptor));
|
|
74
92
|
}
|
|
@@ -89,11 +107,12 @@ var McpClientImpl = class {
|
|
|
89
107
|
description: descriptor.description ?? `Invoke the remote MCP tool "${remoteName}".`,
|
|
90
108
|
input,
|
|
91
109
|
execute: async (args, ctx) => {
|
|
110
|
+
this.assertOpen("tools/call");
|
|
92
111
|
const result = await this.rpc.call("tools/call", {
|
|
93
112
|
name: remoteName,
|
|
94
113
|
arguments: args ?? {}
|
|
95
114
|
}, {
|
|
96
|
-
signal: ctx?.signal,
|
|
115
|
+
signal: combineSignals(ctx?.signal, this.options.signal),
|
|
97
116
|
timeoutMs
|
|
98
117
|
});
|
|
99
118
|
if (result.isError) throw new McpTransportError(`MCP tool "${remoteName}" returned an error: ${unwrapContent(result.content)}`, {
|
|
@@ -105,10 +124,20 @@ var McpClientImpl = class {
|
|
|
105
124
|
});
|
|
106
125
|
}
|
|
107
126
|
close() {
|
|
108
|
-
|
|
127
|
+
this.options.signal?.removeEventListener("abort", this.onAbort);
|
|
128
|
+
this.closing ??= this.rpc.close();
|
|
129
|
+
return this.closing;
|
|
109
130
|
}
|
|
110
131
|
};
|
|
111
132
|
/**
|
|
133
|
+
* The signal a `tools/call` honors: the per-call `ctx.signal`, the
|
|
134
|
+
* client-level `options.signal`, both (whichever aborts first), or none.
|
|
135
|
+
*/
|
|
136
|
+
function combineSignals(callSignal, clientSignal) {
|
|
137
|
+
if (!callSignal || !clientSignal) return callSignal ?? clientSignal;
|
|
138
|
+
return AbortSignal.any([callSignal, clientSignal]);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
112
141
|
* Flatten an MCP `tools/call` result's content blocks into the value a
|
|
113
142
|
* tool returns. Text blocks are concatenated; a single block whose text is
|
|
114
143
|
* valid JSON is parsed so structured tool output flows back as an object
|
|
@@ -180,7 +209,8 @@ function tryParseJson(text) {
|
|
|
180
209
|
* @param server - The transport config (`{ type: "stdio" }` /
|
|
181
210
|
* `{ type: "http" }`). A pre-built transport client may be injected for
|
|
182
211
|
* testing.
|
|
183
|
-
* @param options - Prefix / filter / per-call timeout
|
|
212
|
+
* @param options - Prefix / filter / per-call timeout, and a `signal` that
|
|
213
|
+
* closes the client when it aborts.
|
|
184
214
|
* @returns An {@link McpClient} handle.
|
|
185
215
|
*
|
|
186
216
|
* @example
|
package/esm/mcp/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":[],"sources":["../../../../../../../../packages/ai-tools/src/mcp/client.ts"],"sourcesContent":["import { tool, type ToolContract } from \"@warlock.js/ai\";\nimport type {\n McpClient,\n McpClientOptions,\n McpContentBlock,\n McpToolCallResult,\n McpToolDescriptor,\n McpTransport,\n} from \"../contracts\";\nimport { McpTransportError } from \"../errors\";\nimport { jsonSchemaToStandard } from \"./json-schema-to-standard\";\nimport { createJsonRpcClient, type JsonRpcClientHandle } from \"./transport\";\nimport type { McpTransportClient } from \"./transport.type\";\n\n/** Default per-call timeout for `tools/call`. */\nconst DEFAULT_CALL_TIMEOUT_MS = 30_000;\n\n/** The MCP protocol version this client advertises in `initialize`. */\nconst PROTOCOL_VERSION = \"2025-06-18\";\n\n/** The `tools/list` response slice we read. */\ninterface ToolsListResult {\n tools?: McpToolDescriptor[];\n}\n\n/**\n * The internal {@link McpClient} implementation. Owns one JSON-RPC client\n * over a transport, runs the `initialize` handshake on first use, lists\n * the server's tools, and adapts each into a {@link ToolContract} whose\n * `execute` issues `tools/call`. The adapted contracts are cached after\n * the first `tools()` so repeat calls don't re-handshake.\n *\n * Constructed via {@link mcp}; the class itself is internal.\n */\nclass McpClientImpl implements McpClient {\n /** The JSON-RPC client over the transport. */\n private readonly rpc: JsonRpcClientHandle;\n\n /** Construction-time options (prefix / filter / timeout). */\n private readonly options: McpClientOptions;\n\n /** Resolved + cached adapted tools, set after the first `tools()`. */\n private cached: ToolContract[] | undefined;\n\n /** In-flight `tools()` so concurrent callers share one handshake. */\n private pending: Promise<ToolContract[]> | undefined;\n\n /** Flipped once the handshake completes so we only do it once. */\n private initialized = false;\n\n public constructor(\n source: McpTransport | McpTransportClient,\n options: McpClientOptions = {},\n ) {\n this.rpc = createJsonRpcClient(source);\n this.options = options;\n }\n\n /**\n * Run the MCP `initialize` handshake exactly once, then send the\n * `notifications/initialized` notification the protocol requires before\n * any other request. Wraps a handshake failure as a typed\n * {@link McpTransportError} of type `\"connect\"`.\n */\n private async handshake(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n try {\n await this.rpc.call(\"initialize\", {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: { name: \"@warlock.js/ai-tools\", version: \"4.4.0\" },\n });\n\n await this.rpc.notify(\"notifications/initialized\");\n } catch (cause) {\n if (cause instanceof McpTransportError) {\n throw cause;\n }\n\n const message = cause instanceof Error ? cause.message : String(cause);\n\n throw new McpTransportError(`MCP initialize handshake failed: ${message}`, {\n type: \"connect\",\n method: \"initialize\",\n cause,\n });\n }\n\n this.initialized = true;\n }\n\n public tools(): Promise<ToolContract[]> {\n if (this.cached) {\n return Promise.resolve(this.cached);\n }\n\n if (this.pending) {\n return this.pending;\n }\n\n this.pending = this.listAndAdapt()\n .then((tools) => {\n this.cached = tools;\n\n return tools;\n })\n .finally(() => {\n this.pending = undefined;\n });\n\n return this.pending;\n }\n\n /**\n * Handshake, `tools/list`, and adapt each descriptor into a\n * {@link ToolContract}, applying the `filter` and `namePrefix` options.\n */\n private async listAndAdapt(): Promise<ToolContract[]> {\n await this.handshake();\n\n const result = await this.rpc.call<ToolsListResult>(\"tools/list\");\n const descriptors = result.tools ?? [];\n\n const filter = this.options.filter;\n const selected = filter ? descriptors.filter((d) => filter(d.name)) : descriptors;\n\n return selected.map((descriptor) => this.adapt(descriptor));\n }\n\n /**\n * Adapt one remote tool descriptor into a {@link ToolContract}: build\n * the input schema from its JSON Schema via {@link jsonSchemaToStandard},\n * prefix the name, and route `execute` through a `tools/call` that\n * honors `ctx.signal`, unwraps the content blocks, and throws on an\n * `isError` result so `tool()` wraps it.\n */\n private adapt(descriptor: McpToolDescriptor): ToolContract {\n const prefixedName = `${this.options.namePrefix ?? \"\"}${descriptor.name}`;\n const remoteName = descriptor.name;\n const timeoutMs = this.options.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;\n const input = jsonSchemaToStandard(descriptor.inputSchema);\n\n return tool<unknown, unknown>({\n name: prefixedName,\n description:\n descriptor.description ?? `Invoke the remote MCP tool \"${remoteName}\".`,\n input,\n execute: async (args, ctx) => {\n const result = await this.rpc.call<McpToolCallResult>(\n \"tools/call\",\n { name: remoteName, arguments: args ?? {} },\n { signal: ctx?.signal, timeoutMs },\n );\n\n // An `isError` result is a tool-level failure — throw it so the\n // surrounding `tool()` wraps it as a `ToolExecutionError` and the\n // agent reads it as `{ error }` data and self-corrects.\n if (result.isError) {\n throw new McpTransportError(\n `MCP tool \"${remoteName}\" returned an error: ${unwrapContent(result.content)}`,\n { type: \"protocol\", method: \"tools/call\" },\n );\n }\n\n return unwrapResult(result.content);\n },\n });\n }\n\n public close(): Promise<void> {\n return this.rpc.close();\n }\n}\n\n/**\n * Flatten an MCP `tools/call` result's content blocks into the value a\n * tool returns. Text blocks are concatenated; a single block whose text is\n * valid JSON is parsed so structured tool output flows back as an object\n * rather than a string. Non-text blocks are preserved as `type`-tagged\n * objects (MCP's wire `type` is kept; any inbound `kind` is normalized to\n * `type`).\n */\nfunction unwrapResult(content: McpContentBlock[] | undefined): unknown {\n const blocks = content ?? [];\n\n // The overwhelmingly common case: a single text block. Parse JSON when\n // it is one, so structured results come back typed; otherwise the string.\n if (blocks.length === 1 && blocks[0].type === \"text\") {\n const text = blocks[0].text ?? \"\";\n\n return tryParseJson(text);\n }\n\n // Multiple / mixed blocks: return a normalized array, each tagged by\n // `type` (never `kind`).\n return blocks.map((block) => normalizeBlock(block));\n}\n\n/**\n * Render content blocks to a short human string for error messages — the\n * concatenated text of every text block.\n */\nfunction unwrapContent(content: McpContentBlock[] | undefined): string {\n return (content ?? [])\n .filter((block) => block.type === \"text\" && typeof block.text === \"string\")\n .map((block) => block.text)\n .join(\" \")\n .trim();\n}\n\n/**\n * Normalize one content block onto our `type`-only shape: translate an\n * inbound `kind` discriminator to `type` (and strip `kind`) so the value a\n * tool returns never carries MCP's `kind` vocabulary.\n */\nfunction normalizeBlock(block: McpContentBlock): Record<string, unknown> {\n const { kind, ...rest } = block as McpContentBlock & { kind?: string };\n const type = block.type ?? kind ?? \"unknown\";\n\n return { ...rest, type };\n}\n\n/**\n * Parse a string as JSON, returning the parsed value on success or the\n * original string when it is not JSON — so a plain-text tool result stays\n * a string while a JSON tool result becomes an object.\n */\nfunction tryParseJson(text: string): unknown {\n const trimmed = text.trim();\n\n if (!trimmed) {\n return text;\n }\n\n const first = trimmed[0];\n\n // Only attempt a parse for plausibly-structured payloads, so a bare\n // sentence isn't mangled by a lenient parse.\n if (first !== \"{\" && first !== \"[\") {\n return text;\n }\n\n try {\n return JSON.parse(trimmed);\n } catch {\n return text;\n }\n}\n\n/**\n * Connect to an external MCP server and adapt its tools as agent tools\n * (Direction A: server → local agent tools).\n *\n * Opens the transport lazily and exposes {@link McpClient.tools}, which on\n * first call runs the `initialize` handshake, lists the server's tools via\n * `tools/list`, and maps each into a {@link ToolContract}:\n * - **input schema** — the remote tool's JSON Schema is wrapped as a\n * Standard Schema via {@link jsonSchemaToStandard} (Ajv-backed, an\n * optional peer);\n * - **execute** — issues `tools/call` honoring `ctx.signal` and the\n * configured `timeoutMs`, unwraps the result content, and throws on an\n * `isError` result so the `tool()` wrapper surfaces it as `{ error }`;\n * - **name** — prefixed with `options.namePrefix` to avoid local\n * collisions; only tools passing `options.filter` are adapted.\n *\n * The adapted contracts are cached after the first `tools()` call, so the\n * handshake + list happen exactly once. The returned contracts drop\n * straight into `ai.agent({ tools: [...] })`.\n *\n * @param server - The transport config (`{ type: \"stdio\" }` /\n * `{ type: \"http\" }`). A pre-built transport client may be injected for\n * testing.\n * @param options - Prefix / filter / per-call timeout.\n * @returns An {@link McpClient} handle.\n *\n * @example\n * const github = mcp(\n * { type: \"stdio\", command: \"npx\", args: [\"-y\", \"@modelcontextprotocol/server-github\"] },\n * { namePrefix: \"github.\" },\n * );\n * const dev = ai.agent({ model, tools: [...(await github.tools())] });\n */\nexport function mcp(\n server: McpTransport | McpTransportClient,\n options?: McpClientOptions,\n): McpClient {\n return new McpClientImpl(server, options);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.mjs","names":[],"sources":["../../../../../../../../packages/ai-tools/src/mcp/client.ts"],"sourcesContent":["import { tool, type ToolContract } from \"@warlock.js/ai\";\nimport type {\n McpClient,\n McpClientOptions,\n McpContentBlock,\n McpToolCallResult,\n McpToolDescriptor,\n McpTransport,\n} from \"../contracts\";\nimport { McpTransportError } from \"../errors\";\nimport { jsonSchemaToStandard } from \"./json-schema-to-standard\";\nimport { createJsonRpcClient, type JsonRpcClientHandle } from \"./transport\";\nimport type { McpTransportClient } from \"./transport.type\";\n\n/** Default per-call timeout for `tools/call`. */\nconst DEFAULT_CALL_TIMEOUT_MS = 30_000;\n\n/** The MCP protocol version this client advertises in `initialize`. */\nconst PROTOCOL_VERSION = \"2025-06-18\";\n\n/** The `tools/list` response slice we read. */\ninterface ToolsListResult {\n tools?: McpToolDescriptor[];\n}\n\n/**\n * The internal {@link McpClient} implementation. Owns one JSON-RPC client\n * over a transport, runs the `initialize` handshake on first use, lists\n * the server's tools, and adapts each into a {@link ToolContract} whose\n * `execute` issues `tools/call`. The adapted contracts are cached after\n * the first `tools()` so repeat calls don't re-handshake.\n *\n * Constructed via {@link mcp}; the class itself is internal.\n */\nclass McpClientImpl implements McpClient {\n /** The JSON-RPC client over the transport. */\n private readonly rpc: JsonRpcClientHandle;\n\n /** Construction-time options (prefix / filter / timeout). */\n private readonly options: McpClientOptions;\n\n /** Resolved + cached adapted tools, set after the first `tools()`. */\n private cached: ToolContract[] | undefined;\n\n /** In-flight `tools()` so concurrent callers share one handshake. */\n private pending: Promise<ToolContract[]> | undefined;\n\n /** Flipped once the handshake completes so we only do it once. */\n private initialized = false;\n\n /** The in-flight / settled `close()`, so closing is idempotent. */\n private closing: Promise<void> | undefined;\n\n /** Closes the client when `options.signal` aborts. */\n private readonly onAbort = (): void => {\n void this.close().catch(() => undefined);\n };\n\n public constructor(source: McpTransport | McpTransportClient, options: McpClientOptions = {}) {\n this.rpc = createJsonRpcClient(source);\n this.options = options;\n\n const signal = options.signal;\n\n if (signal?.aborted) {\n this.onAbort();\n } else {\n signal?.addEventListener(\"abort\", this.onAbort, { once: true });\n }\n }\n\n /**\n * Reject with a typed `\"closed\"` error once the client was closed or its\n * `signal` aborted, so no request is sent on a dead transport.\n */\n private assertOpen(method: string): void {\n if (this.closing || this.options.signal?.aborted) {\n throw new McpTransportError(`MCP client is closed; \"${method}\" was not sent.`, {\n type: \"closed\",\n method,\n });\n }\n }\n\n /**\n * Run the MCP `initialize` handshake exactly once, then send the\n * `notifications/initialized` notification the protocol requires before\n * any other request. Wraps a handshake failure as a typed\n * {@link McpTransportError} of type `\"connect\"`.\n */\n private async handshake(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n this.assertOpen(\"initialize\");\n\n try {\n await this.rpc.call(\n \"initialize\",\n {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: { name: \"@warlock.js/ai-tools\", version: \"4.4.0\" },\n },\n { signal: this.options.signal },\n );\n\n await this.rpc.notify(\"notifications/initialized\");\n } catch (cause) {\n if (cause instanceof McpTransportError) {\n throw cause;\n }\n\n const message = cause instanceof Error ? cause.message : String(cause);\n\n throw new McpTransportError(`MCP initialize handshake failed: ${message}`, {\n type: \"connect\",\n method: \"initialize\",\n cause,\n });\n }\n\n this.initialized = true;\n }\n\n public tools(): Promise<ToolContract[]> {\n if (this.cached) {\n return Promise.resolve(this.cached);\n }\n\n if (this.pending) {\n return this.pending;\n }\n\n this.pending = this.listAndAdapt()\n .then((tools) => {\n this.cached = tools;\n\n return tools;\n })\n .finally(() => {\n this.pending = undefined;\n });\n\n return this.pending;\n }\n\n /**\n * Handshake, `tools/list`, and adapt each descriptor into a\n * {@link ToolContract}, applying the `filter` and `namePrefix` options.\n */\n private async listAndAdapt(): Promise<ToolContract[]> {\n await this.handshake();\n\n this.assertOpen(\"tools/list\");\n\n const result = await this.rpc.call<ToolsListResult>(\"tools/list\", undefined, {\n signal: this.options.signal,\n });\n const descriptors = result.tools ?? [];\n\n const filter = this.options.filter;\n const selected = filter ? descriptors.filter((d) => filter(d.name)) : descriptors;\n\n return selected.map((descriptor) => this.adapt(descriptor));\n }\n\n /**\n * Adapt one remote tool descriptor into a {@link ToolContract}: build\n * the input schema from its JSON Schema via {@link jsonSchemaToStandard},\n * prefix the name, and route `execute` through a `tools/call` that\n * honors `ctx.signal`, unwraps the content blocks, and throws on an\n * `isError` result so `tool()` wraps it.\n */\n private adapt(descriptor: McpToolDescriptor): ToolContract {\n const prefixedName = `${this.options.namePrefix ?? \"\"}${descriptor.name}`;\n const remoteName = descriptor.name;\n const timeoutMs = this.options.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;\n const input = jsonSchemaToStandard(descriptor.inputSchema);\n\n return tool<unknown, unknown>({\n name: prefixedName,\n description: descriptor.description ?? `Invoke the remote MCP tool \"${remoteName}\".`,\n input,\n execute: async (args, ctx) => {\n this.assertOpen(\"tools/call\");\n\n const result = await this.rpc.call<McpToolCallResult>(\n \"tools/call\",\n { name: remoteName, arguments: args ?? {} },\n { signal: combineSignals(ctx?.signal, this.options.signal), timeoutMs },\n );\n\n // An `isError` result is a tool-level failure — throw it so the\n // surrounding `tool()` wraps it as a `ToolExecutionError` and the\n // agent reads it as `{ error }` data and self-corrects.\n if (result.isError) {\n throw new McpTransportError(\n `MCP tool \"${remoteName}\" returned an error: ${unwrapContent(result.content)}`,\n { type: \"protocol\", method: \"tools/call\" },\n );\n }\n\n return unwrapResult(result.content);\n },\n });\n }\n\n public close(): Promise<void> {\n this.options.signal?.removeEventListener(\"abort\", this.onAbort);\n this.closing ??= this.rpc.close();\n\n return this.closing;\n }\n}\n\n/**\n * The signal a `tools/call` honors: the per-call `ctx.signal`, the\n * client-level `options.signal`, both (whichever aborts first), or none.\n */\nfunction combineSignals(\n callSignal: AbortSignal | undefined,\n clientSignal: AbortSignal | undefined,\n): AbortSignal | undefined {\n if (!callSignal || !clientSignal) {\n return callSignal ?? clientSignal;\n }\n\n return AbortSignal.any([callSignal, clientSignal]);\n}\n\n/**\n * Flatten an MCP `tools/call` result's content blocks into the value a\n * tool returns. Text blocks are concatenated; a single block whose text is\n * valid JSON is parsed so structured tool output flows back as an object\n * rather than a string. Non-text blocks are preserved as `type`-tagged\n * objects (MCP's wire `type` is kept; any inbound `kind` is normalized to\n * `type`).\n */\nfunction unwrapResult(content: McpContentBlock[] | undefined): unknown {\n const blocks = content ?? [];\n\n // The overwhelmingly common case: a single text block. Parse JSON when\n // it is one, so structured results come back typed; otherwise the string.\n if (blocks.length === 1 && blocks[0].type === \"text\") {\n const text = blocks[0].text ?? \"\";\n\n return tryParseJson(text);\n }\n\n // Multiple / mixed blocks: return a normalized array, each tagged by\n // `type` (never `kind`).\n return blocks.map((block) => normalizeBlock(block));\n}\n\n/**\n * Render content blocks to a short human string for error messages — the\n * concatenated text of every text block.\n */\nfunction unwrapContent(content: McpContentBlock[] | undefined): string {\n return (content ?? [])\n .filter((block) => block.type === \"text\" && typeof block.text === \"string\")\n .map((block) => block.text)\n .join(\" \")\n .trim();\n}\n\n/**\n * Normalize one content block onto our `type`-only shape: translate an\n * inbound `kind` discriminator to `type` (and strip `kind`) so the value a\n * tool returns never carries MCP's `kind` vocabulary.\n */\nfunction normalizeBlock(block: McpContentBlock): Record<string, unknown> {\n const { kind, ...rest } = block as McpContentBlock & { kind?: string };\n const type = block.type ?? kind ?? \"unknown\";\n\n return { ...rest, type };\n}\n\n/**\n * Parse a string as JSON, returning the parsed value on success or the\n * original string when it is not JSON — so a plain-text tool result stays\n * a string while a JSON tool result becomes an object.\n */\nfunction tryParseJson(text: string): unknown {\n const trimmed = text.trim();\n\n if (!trimmed) {\n return text;\n }\n\n const first = trimmed[0];\n\n // Only attempt a parse for plausibly-structured payloads, so a bare\n // sentence isn't mangled by a lenient parse.\n if (first !== \"{\" && first !== \"[\") {\n return text;\n }\n\n try {\n return JSON.parse(trimmed);\n } catch {\n return text;\n }\n}\n\n/**\n * Connect to an external MCP server and adapt its tools as agent tools\n * (Direction A: server → local agent tools).\n *\n * Opens the transport lazily and exposes {@link McpClient.tools}, which on\n * first call runs the `initialize` handshake, lists the server's tools via\n * `tools/list`, and maps each into a {@link ToolContract}:\n * - **input schema** — the remote tool's JSON Schema is wrapped as a\n * Standard Schema via {@link jsonSchemaToStandard} (Ajv-backed, an\n * optional peer);\n * - **execute** — issues `tools/call` honoring `ctx.signal` and the\n * configured `timeoutMs`, unwraps the result content, and throws on an\n * `isError` result so the `tool()` wrapper surfaces it as `{ error }`;\n * - **name** — prefixed with `options.namePrefix` to avoid local\n * collisions; only tools passing `options.filter` are adapted.\n *\n * The adapted contracts are cached after the first `tools()` call, so the\n * handshake + list happen exactly once. The returned contracts drop\n * straight into `ai.agent({ tools: [...] })`.\n *\n * @param server - The transport config (`{ type: \"stdio\" }` /\n * `{ type: \"http\" }`). A pre-built transport client may be injected for\n * testing.\n * @param options - Prefix / filter / per-call timeout, and a `signal` that\n * closes the client when it aborts.\n * @returns An {@link McpClient} handle.\n *\n * @example\n * const github = mcp(\n * { type: \"stdio\", command: \"npx\", args: [\"-y\", \"@modelcontextprotocol/server-github\"] },\n * { namePrefix: \"github.\" },\n * );\n * const dev = ai.agent({ model, tools: [...(await github.tools())] });\n */\nexport function mcp(\n server: McpTransport | McpTransportClient,\n options?: McpClientOptions,\n): McpClient {\n return new McpClientImpl(server, options);\n}\n"],"mappings":"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"}
|
package/esm/mcp/index.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { McpClient, McpClientOptions,
|
|
2
|
-
import {
|
|
1
|
+
import { McpClient, McpClientOptions, McpTransport } from "../contracts/mcp.type.mjs";
|
|
2
|
+
import { McpHttpServeHandle, McpHttpServeTransport, McpServeOptions, McpServeSource, McpServer } from "../contracts/mcp-serve.type.mjs";
|
|
3
|
+
import { McpServeRequestHandler, createServeHandler, serve } from "./serve.mjs";
|
|
4
|
+
import { SUPPORTED_PROTOCOL_VERSIONS } from "./protocol.mjs";
|
|
3
5
|
import { jsonSchemaToStandard } from "./json-schema-to-standard.mjs";
|
|
4
6
|
import { McpTransportClient } from "./transport.type.mjs";
|
|
5
7
|
import { JsonRpcClientHandle, createJsonRpcClient, createTransport } from "./transport.mjs";
|
|
@@ -17,16 +19,21 @@ interface McpFactory {
|
|
|
17
19
|
* Connect to an external MCP server and adapt its tools as agent tools.
|
|
18
20
|
*
|
|
19
21
|
* @param server - The transport config (`{ type: "stdio" }` / `{ type: "http" }`).
|
|
20
|
-
* @param options - Prefix / filter / per-call timeout
|
|
22
|
+
* @param options - Prefix / filter / per-call timeout, and a `signal`
|
|
23
|
+
* that closes the client (and fails its calls) when it aborts.
|
|
21
24
|
*/
|
|
22
25
|
(server: McpTransport, options?: McpClientOptions): McpClient;
|
|
23
26
|
/**
|
|
24
27
|
* Expose a built agent / supervisor / orchestrator (or a literal
|
|
25
|
-
* `ToolContract[]`) AS an MCP server.
|
|
28
|
+
* `ToolContract[]`, or named `{ groups }`) AS an MCP server. Over
|
|
29
|
+
* `{ type: "http" }`, `start()` resolves `{ url, close }`.
|
|
26
30
|
*
|
|
27
31
|
* @param source - The tools to expose.
|
|
28
|
-
* @param options - Server name, version, transport,
|
|
32
|
+
* @param options - Server name, version, transport, schema dialect, resources, prompts.
|
|
29
33
|
*/
|
|
34
|
+
serve(source: McpServeSource, options: McpServeOptions & {
|
|
35
|
+
transport: McpHttpServeTransport;
|
|
36
|
+
}): McpServer<McpHttpServeHandle>;
|
|
30
37
|
serve(source: McpServeSource, options: McpServeOptions): McpServer;
|
|
31
38
|
}
|
|
32
39
|
/**
|
package/esm/mcp/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../../../../../packages/ai-tools/src/mcp/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../../../../../../packages/ai-tools/src/mcp/index.ts"],"mappings":";;;;;;;;;;;AA4BA;;;;;UAAiB,UAAA;EAkBL;;;;;;;EAAA,CAVT,MAAA,EAAQ,YAAA,EAAc,OAAA,GAAU,gBAAA,GAAmB,SAAA;EAac;;;;;;;;EAJlE,KAAA,CACE,MAAA,EAAQ,cAAA,EACR,OAAA,EAAS,eAAA;IAAoB,SAAA,EAAW,qBAAA;EAAA,IACvC,SAAA,CAAU,kBAAA;EACb,KAAA,CAAM,MAAA,EAAQ,cAAA,EAAgB,OAAA,EAAS,eAAA,GAAkB,SAAA;AAAA;;;;;;;;;cAW9C,GAAA,EAAK,UAGjB"}
|
package/esm/mcp/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsonSchemaToStandard } from "./json-schema-to-standard.mjs";
|
|
2
2
|
import { createJsonRpcClient, createTransport } from "./transport.mjs";
|
|
3
3
|
import { mcp as mcp$1 } from "./client.mjs";
|
|
4
|
+
import { SUPPORTED_PROTOCOL_VERSIONS } from "./protocol.mjs";
|
|
4
5
|
import { createServeHandler, serve } from "./serve.mjs";
|
|
5
6
|
|
|
6
7
|
//#region ../../packages/ai-tools/src/mcp/index.ts
|
package/esm/mcp/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["mcpClient"],"sources":["../../../../../../../../packages/ai-tools/src/mcp/index.ts"],"sourcesContent":["import type {\n McpClient,\n McpClientOptions,\n McpServeOptions,\n McpServeSource,\n McpServer,\n McpTransport,\n} from \"../contracts\";\nimport { mcp as mcpClient } from \"./client\";\nimport { serve } from \"./serve\";\n\nexport { serve, createServeHandler } from \"./serve\";\nexport { jsonSchemaToStandard } from \"./json-schema-to-standard\";\nexport { createJsonRpcClient, createTransport } from \"./transport\";\nexport type { JsonRpcClientHandle } from \"./transport\";\nexport type { McpTransportClient } from \"./transport.type\";\n\n/**\n * The callable `ai.mcp` surface — a factory that connects to an external\n * MCP server (Direction A) and also carries `.serve` to expose a local\n * primitive AS an MCP server (Direction B). Modeled as a function with an\n * attached `serve` property, mirroring how `ai.mcp(server).tools()` and\n * `ai.mcp.serve(source, options).start()` read in the design.\n */\nexport interface McpFactory {\n /**\n * Connect to an external MCP server and adapt its tools as agent tools.\n *\n * @param server - The transport config (`{ type: \"stdio\" }` / `{ type: \"http\" }`).\n * @param options - Prefix / filter / per-call timeout.\n */\n (server: McpTransport, options?: McpClientOptions): McpClient;\n /**\n * Expose a built agent / supervisor / orchestrator (or a literal\n * `ToolContract[]`) AS an MCP server
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["mcpClient"],"sources":["../../../../../../../../packages/ai-tools/src/mcp/index.ts"],"sourcesContent":["import type {\n McpClient,\n McpClientOptions,\n McpHttpServeHandle,\n McpHttpServeTransport,\n McpServeOptions,\n McpServeSource,\n McpServer,\n McpTransport,\n} from \"../contracts\";\nimport { mcp as mcpClient } from \"./client\";\nimport { serve } from \"./serve\";\n\nexport { serve, createServeHandler } from \"./serve\";\nexport type { McpServeRequestHandler } from \"./serve\";\nexport { SUPPORTED_PROTOCOL_VERSIONS } from \"./protocol\";\nexport { jsonSchemaToStandard } from \"./json-schema-to-standard\";\nexport { createJsonRpcClient, createTransport } from \"./transport\";\nexport type { JsonRpcClientHandle } from \"./transport\";\nexport type { McpTransportClient } from \"./transport.type\";\n\n/**\n * The callable `ai.mcp` surface — a factory that connects to an external\n * MCP server (Direction A) and also carries `.serve` to expose a local\n * primitive AS an MCP server (Direction B). Modeled as a function with an\n * attached `serve` property, mirroring how `ai.mcp(server).tools()` and\n * `ai.mcp.serve(source, options).start()` read in the design.\n */\nexport interface McpFactory {\n /**\n * Connect to an external MCP server and adapt its tools as agent tools.\n *\n * @param server - The transport config (`{ type: \"stdio\" }` / `{ type: \"http\" }`).\n * @param options - Prefix / filter / per-call timeout, and a `signal`\n * that closes the client (and fails its calls) when it aborts.\n */\n (server: McpTransport, options?: McpClientOptions): McpClient;\n /**\n * Expose a built agent / supervisor / orchestrator (or a literal\n * `ToolContract[]`, or named `{ groups }`) AS an MCP server. Over\n * `{ type: \"http\" }`, `start()` resolves `{ url, close }`.\n *\n * @param source - The tools to expose.\n * @param options - Server name, version, transport, schema dialect, resources, prompts.\n */\n serve(\n source: McpServeSource,\n options: McpServeOptions & { transport: McpHttpServeTransport },\n ): McpServer<McpHttpServeHandle>;\n serve(source: McpServeSource, options: McpServeOptions): McpServer;\n}\n\n/**\n * The `ai.mcp` factory value: the client factory with `.serve` attached.\n * `Object.assign` keeps `mcp` callable (Direction A) while widening it with\n * the `serve` member (Direction B) — one object, both directions. The\n * `declare module \"@warlock.js/ai\"` augmentation and the runtime\n * registration (`ai.mcp = mcp`) live in `../register`, so this barrel is a\n * pure value/type module the registrar consumes.\n */\nexport const mcp: McpFactory = Object.assign(\n (server: McpTransport, options?: McpClientOptions): McpClient => mcpClient(server, options),\n { serve },\n);\n"],"mappings":";;;;;;;;;;;;;;;AA4DA,MAAa,MAAkB,OAAO,QACnC,QAAsB,YAA0CA,MAAU,QAAQ,OAAO,GAC1F,EAAE,MAAM,CACV"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region ../../packages/ai-tools/src/mcp/protocol.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* MCP protocol versions the `ai.mcp.serve` server speaks, newest first.
|
|
4
|
+
* `initialize` echoes the client's requested version when it is listed
|
|
5
|
+
* here and otherwise answers with the newest one (lifecycle, version
|
|
6
|
+
* negotiation). The HTTP transport rejects any other value in the
|
|
7
|
+
* `MCP-Protocol-Version` header with 400.
|
|
8
|
+
*
|
|
9
|
+
* Source: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
|
|
10
|
+
* and https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
|
|
11
|
+
* (checked 2026-10-17).
|
|
12
|
+
*/
|
|
13
|
+
declare const SUPPORTED_PROTOCOL_VERSIONS: readonly string[];
|
|
14
|
+
//#endregion
|
|
15
|
+
export { SUPPORTED_PROTOCOL_VERSIONS };
|
|
16
|
+
//# sourceMappingURL=protocol.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.d.mts","names":[],"sources":["../../../../../../../../packages/ai-tools/src/mcp/protocol.ts"],"mappings":";;AAWA;;;;AAIC;;;;;;cAJY,2BAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region ../../packages/ai-tools/src/mcp/protocol.ts
|
|
2
|
+
/**
|
|
3
|
+
* MCP protocol versions the `ai.mcp.serve` server speaks, newest first.
|
|
4
|
+
* `initialize` echoes the client's requested version when it is listed
|
|
5
|
+
* here and otherwise answers with the newest one (lifecycle, version
|
|
6
|
+
* negotiation). The HTTP transport rejects any other value in the
|
|
7
|
+
* `MCP-Protocol-Version` header with 400.
|
|
8
|
+
*
|
|
9
|
+
* Source: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle
|
|
10
|
+
* and https://modelcontextprotocol.io/specification/2025-11-25/basic/transports
|
|
11
|
+
* (checked 2026-10-17).
|
|
12
|
+
*/
|
|
13
|
+
const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
14
|
+
"2025-11-25",
|
|
15
|
+
"2025-06-18",
|
|
16
|
+
"2025-03-26"
|
|
17
|
+
];
|
|
18
|
+
/** The newest MCP protocol version the server speaks. */
|
|
19
|
+
const LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS };
|
|
23
|
+
//# sourceMappingURL=protocol.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.mjs","names":[],"sources":["../../../../../../../../packages/ai-tools/src/mcp/protocol.ts"],"sourcesContent":["/**\n * MCP protocol versions the `ai.mcp.serve` server speaks, newest first.\n * `initialize` echoes the client's requested version when it is listed\n * here and otherwise answers with the newest one (lifecycle, version\n * negotiation). The HTTP transport rejects any other value in the\n * `MCP-Protocol-Version` header with 400.\n *\n * Source: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle\n * and https://modelcontextprotocol.io/specification/2025-11-25/basic/transports\n * (checked 2026-10-17).\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS: readonly string[] = [\n \"2025-11-25\",\n \"2025-06-18\",\n \"2025-03-26\",\n];\n\n/** The newest MCP protocol version the server speaks. */\nexport const LATEST_PROTOCOL_VERSION = \"2025-11-25\";\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,8BAAiD;CAC5D;CACA;CACA;AACF;;AAGA,MAAa,0BAA0B"}
|