@openrouter/mcp 0.0.1
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 +127 -0
- package/esm/auth/auth-resolver.d.ts +14 -0
- package/esm/auth/auth-resolver.d.ts.map +1 -0
- package/esm/auth/auth-resolver.js +27 -0
- package/esm/auth/auth-resolver.js.map +1 -0
- package/esm/auth/auth-types.d.ts +25 -0
- package/esm/auth/auth-types.d.ts.map +1 -0
- package/esm/auth/auth-types.js +4 -0
- package/esm/auth/auth-types.js.map +1 -0
- package/esm/build-tools.d.ts +27 -0
- package/esm/build-tools.d.ts.map +1 -0
- package/esm/build-tools.js +77 -0
- package/esm/build-tools.js.map +1 -0
- package/esm/cache/cache-store.d.ts +24 -0
- package/esm/cache/cache-store.d.ts.map +1 -0
- package/esm/cache/cache-store.js +20 -0
- package/esm/cache/cache-store.js.map +1 -0
- package/esm/cache/cache-types.d.ts +54 -0
- package/esm/cache/cache-types.d.ts.map +1 -0
- package/esm/cache/cache-types.js +41 -0
- package/esm/cache/cache-types.js.map +1 -0
- package/esm/cache/serialize.d.ts +25 -0
- package/esm/cache/serialize.d.ts.map +1 -0
- package/esm/cache/serialize.js +85 -0
- package/esm/cache/serialize.js.map +1 -0
- package/esm/create-mcp-tools.d.ts +13 -0
- package/esm/create-mcp-tools.d.ts.map +1 -0
- package/esm/create-mcp-tools.js +75 -0
- package/esm/create-mcp-tools.js.map +1 -0
- package/esm/elicitation.d.ts +11 -0
- package/esm/elicitation.d.ts.map +1 -0
- package/esm/elicitation.js +51 -0
- package/esm/elicitation.js.map +1 -0
- package/esm/errors.d.ts +35 -0
- package/esm/errors.d.ts.map +1 -0
- package/esm/errors.js +39 -0
- package/esm/errors.js.map +1 -0
- package/esm/handle.d.ts +41 -0
- package/esm/handle.d.ts.map +1 -0
- package/esm/handle.js +221 -0
- package/esm/handle.js.map +1 -0
- package/esm/index.d.ts +13 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +11 -0
- package/esm/index.js.map +1 -0
- package/esm/mcp-connection.d.ts +35 -0
- package/esm/mcp-connection.d.ts.map +1 -0
- package/esm/mcp-connection.js +147 -0
- package/esm/mcp-connection.js.map +1 -0
- package/esm/rehydrate.d.ts +41 -0
- package/esm/rehydrate.d.ts.map +1 -0
- package/esm/rehydrate.js +173 -0
- package/esm/rehydrate.js.map +1 -0
- package/esm/resource-tools.d.ts +17 -0
- package/esm/resource-tools.d.ts.map +1 -0
- package/esm/resource-tools.js +133 -0
- package/esm/resource-tools.js.map +1 -0
- package/esm/result-mapper.d.ts +19 -0
- package/esm/result-mapper.d.ts.map +1 -0
- package/esm/result-mapper.js +40 -0
- package/esm/result-mapper.js.map +1 -0
- package/esm/schema/json-schema-guards.d.ts +14 -0
- package/esm/schema/json-schema-guards.d.ts.map +1 -0
- package/esm/schema/json-schema-guards.js +19 -0
- package/esm/schema/json-schema-guards.js.map +1 -0
- package/esm/schema/json-schema-to-zod.d.ts +20 -0
- package/esm/schema/json-schema-to-zod.d.ts.map +1 -0
- package/esm/schema/json-schema-to-zod.js +72 -0
- package/esm/schema/json-schema-to-zod.js.map +1 -0
- package/esm/tool-wrapper.d.ts +26 -0
- package/esm/tool-wrapper.d.ts.map +1 -0
- package/esm/tool-wrapper.js +118 -0
- package/esm/tool-wrapper.js.map +1 -0
- package/esm/transport-types.d.ts +3 -0
- package/esm/transport-types.d.ts.map +1 -0
- package/esm/transport-types.js +2 -0
- package/esm/transport-types.js.map +1 -0
- package/esm/types.d.ts +104 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/types.js +2 -0
- package/esm/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
// SSEClientTransport is deprecated upstream but intentionally supported here for
|
|
3
|
+
// legacy MCP servers that haven't migrated to Streamable HTTP.
|
|
4
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
5
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
6
|
+
import { ElicitRequestSchema, ToolListChangedNotificationSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { resolveAuth } from './auth/auth-resolver.js';
|
|
8
|
+
import { makeElicitationRequestHandler } from './elicitation.js';
|
|
9
|
+
import { MCPConnectionError } from './errors.js';
|
|
10
|
+
const DEFAULT_CLIENT_INFO = {
|
|
11
|
+
name: '@openrouter/mcp',
|
|
12
|
+
version: '0.1.0',
|
|
13
|
+
};
|
|
14
|
+
function buildStreamableHttp(options) {
|
|
15
|
+
const { headers, authProvider } = resolveAuth(options.auth);
|
|
16
|
+
return new StreamableHTTPClientTransport(options.url, {
|
|
17
|
+
requestInit: {
|
|
18
|
+
headers,
|
|
19
|
+
},
|
|
20
|
+
...(authProvider !== undefined && {
|
|
21
|
+
authProvider,
|
|
22
|
+
}),
|
|
23
|
+
...(options.fetch !== undefined && {
|
|
24
|
+
fetch: options.fetch,
|
|
25
|
+
}),
|
|
26
|
+
...(options.sessionId !== undefined && {
|
|
27
|
+
sessionId: options.sessionId,
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function buildSse(options) {
|
|
32
|
+
const { headers, authProvider } = resolveAuth(options.auth);
|
|
33
|
+
return new SSEClientTransport(options.url, {
|
|
34
|
+
requestInit: {
|
|
35
|
+
headers,
|
|
36
|
+
},
|
|
37
|
+
...(authProvider !== undefined && {
|
|
38
|
+
authProvider,
|
|
39
|
+
}),
|
|
40
|
+
...(options.fetch !== undefined && {
|
|
41
|
+
fetch: options.fetch,
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Runtime narrowing to `Transport`. The SDK's transport classes implement the
|
|
47
|
+
* interface, but their `.d.ts` types `sessionId` as `string | undefined` rather
|
|
48
|
+
* than `sessionId?: string`, which `exactOptionalPropertyTypes` rejects at the
|
|
49
|
+
* `connect()` call site. We confirm the structural contract at runtime instead
|
|
50
|
+
* of asserting past the variance with `as`.
|
|
51
|
+
*/
|
|
52
|
+
function isTransport(value) {
|
|
53
|
+
return (typeof value.start === 'function' &&
|
|
54
|
+
typeof value.send === 'function' &&
|
|
55
|
+
typeof value.close === 'function');
|
|
56
|
+
}
|
|
57
|
+
function makeClient(options, listChanged) {
|
|
58
|
+
const client = new Client(options.clientInfo ?? DEFAULT_CLIENT_INFO, {
|
|
59
|
+
capabilities: {
|
|
60
|
+
elicitation: {},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
client.setRequestHandler(ElicitRequestSchema, makeElicitationRequestHandler(options.onElicitation));
|
|
64
|
+
client.setNotificationHandler(ToolListChangedNotificationSchema, () => {
|
|
65
|
+
listChanged.handler?.();
|
|
66
|
+
});
|
|
67
|
+
return client;
|
|
68
|
+
}
|
|
69
|
+
async function connectWith(client, transport) {
|
|
70
|
+
if (!isTransport(transport)) {
|
|
71
|
+
throw new MCPConnectionError('MCP transport does not implement the Transport contract');
|
|
72
|
+
}
|
|
73
|
+
await client.connect(transport);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Connect a `Client` to the MCP server. Defaults to Streamable HTTP and falls
|
|
77
|
+
* back to SSE on connection failure (legacy servers), unless a transport is
|
|
78
|
+
* pinned explicitly. Auth, the elicitation handler, and the list_changed
|
|
79
|
+
* subscription are wired into the single connected client so they apply to
|
|
80
|
+
* discovery and every tool call.
|
|
81
|
+
*/
|
|
82
|
+
export async function connect(options) {
|
|
83
|
+
const preferred = options.transport ?? 'streamableHttp';
|
|
84
|
+
const listChanged = {
|
|
85
|
+
handler: undefined,
|
|
86
|
+
};
|
|
87
|
+
if (preferred === 'sse') {
|
|
88
|
+
const client = makeClient(options, listChanged);
|
|
89
|
+
await connectWith(client, buildSse(options));
|
|
90
|
+
return wrap({
|
|
91
|
+
client,
|
|
92
|
+
transport: 'sse',
|
|
93
|
+
listChanged,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Streamable HTTP, with SSE fallback when the transport wasn't pinned.
|
|
97
|
+
const client = makeClient(options, listChanged);
|
|
98
|
+
try {
|
|
99
|
+
const http = buildStreamableHttp(options);
|
|
100
|
+
await connectWith(client, http);
|
|
101
|
+
return wrap({
|
|
102
|
+
client,
|
|
103
|
+
transport: 'streamableHttp',
|
|
104
|
+
listChanged,
|
|
105
|
+
...(http.sessionId !== undefined && {
|
|
106
|
+
sessionId: http.sessionId,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (httpErr) {
|
|
111
|
+
if (options.transport === 'streamableHttp') {
|
|
112
|
+
throw new MCPConnectionError('Failed to connect over Streamable HTTP', {
|
|
113
|
+
cause: httpErr,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Fall back to SSE on a fresh client (the failed one may be half-initialized).
|
|
117
|
+
const sseClient = makeClient(options, listChanged);
|
|
118
|
+
try {
|
|
119
|
+
await connectWith(sseClient, buildSse(options));
|
|
120
|
+
return wrap({
|
|
121
|
+
client: sseClient,
|
|
122
|
+
transport: 'sse',
|
|
123
|
+
listChanged,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
catch (sseErr) {
|
|
127
|
+
throw new MCPConnectionError('Failed to connect over Streamable HTTP and SSE', {
|
|
128
|
+
cause: sseErr,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function wrap(args) {
|
|
134
|
+
const { client, transport, listChanged, sessionId } = args;
|
|
135
|
+
return {
|
|
136
|
+
client,
|
|
137
|
+
transport,
|
|
138
|
+
...(sessionId !== undefined && {
|
|
139
|
+
sessionId,
|
|
140
|
+
}),
|
|
141
|
+
setToolListChangedHandler: (handler) => {
|
|
142
|
+
listChanged.handler = handler;
|
|
143
|
+
},
|
|
144
|
+
close: () => client.close(),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=mcp-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-connection.js","sourceRoot":"","sources":["../src/mcp-connection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { MCPAuth } from './auth/auth-types.js';
|
|
2
|
+
import type { MCPCacheStore } from './cache/cache-store.js';
|
|
3
|
+
import type { SerializedMCPServer } from './cache/cache-types.js';
|
|
4
|
+
import type { UnconvertibleSchemaMode } from './schema/json-schema-to-zod.js';
|
|
5
|
+
import type { ElicitationHandler, MCPToolsHandle, ResourcesOption } from './types.js';
|
|
6
|
+
export interface RehydrateMCPToolsOptions {
|
|
7
|
+
snapshot: SerializedMCPServer;
|
|
8
|
+
/** Required when the snapshot carries no cached credentials. */
|
|
9
|
+
auth?: MCPAuth;
|
|
10
|
+
fetch?: typeof fetch;
|
|
11
|
+
onUnconvertibleSchema?: UnconvertibleSchemaMode;
|
|
12
|
+
onElicitation?: ElicitationHandler;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
/** Cache to refresh on reconnect/fallback. */
|
|
15
|
+
cache?: {
|
|
16
|
+
store: MCPCacheStore;
|
|
17
|
+
key?: string;
|
|
18
|
+
};
|
|
19
|
+
/** On expiry / missing creds / connection failure, do a full reconnect. Default true. */
|
|
20
|
+
reconnectOnExpiry?: boolean;
|
|
21
|
+
toolNamePrefix?: string;
|
|
22
|
+
includeTools?: readonly string[];
|
|
23
|
+
excludeTools?: readonly string[];
|
|
24
|
+
resources?: ResourcesOption;
|
|
25
|
+
emitProgress?: boolean;
|
|
26
|
+
autoRefreshOnListChanged?: boolean;
|
|
27
|
+
cacheCredentials?: boolean;
|
|
28
|
+
clientInfo?: {
|
|
29
|
+
name: string;
|
|
30
|
+
version: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Rebuild an {@link MCPToolsHandle} from a cached snapshot. On the happy path we
|
|
35
|
+
* reconnect the transport and rebuild tools directly from the snapshot —
|
|
36
|
+
* skipping `listTools()`. If cached tokens are expired, credentials are missing,
|
|
37
|
+
* or the connection fails, we transparently fall back to a full
|
|
38
|
+
* {@link createMCPTools} (unless `reconnectOnExpiry` is false).
|
|
39
|
+
*/
|
|
40
|
+
export declare function rehydrateMCPTools(options: RehydrateMCPToolsOptions): Promise<MCPToolsHandle>;
|
|
41
|
+
//# sourceMappingURL=rehydrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rehydrate.d.ts","sourceRoot":"","sources":["../src/rehydrate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAKlE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE9E,OAAO,KAAK,EAEV,kBAAkB,EAClB,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAKpB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,qBAAqB,CAAC,EAAE,uBAAuB,CAAC;IAChD,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8CAA8C;IAC9C,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,aAAa,CAAC;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAG5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AA2GD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,cAAc,CAAC,CA+DzB"}
|
package/esm/rehydrate.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { defaultCacheKey } from './cache/cache-store.js';
|
|
2
|
+
import { isSerializedMCPServer } from './cache/cache-types.js';
|
|
3
|
+
import { MCPCacheError } from './errors.js';
|
|
4
|
+
import { freshConnect, makeHandle } from './handle.js';
|
|
5
|
+
import { connect } from './mcp-connection.js';
|
|
6
|
+
/** Clock skew (ms) treated as "already expired" when checking cached tokens. */
|
|
7
|
+
const EXPIRY_SKEW_MS = 30000;
|
|
8
|
+
function snapshotToToolDefs(snapshot) {
|
|
9
|
+
return snapshot.tools.map((t) => ({
|
|
10
|
+
name: t.name,
|
|
11
|
+
...(t.description !== undefined && {
|
|
12
|
+
description: t.description,
|
|
13
|
+
}),
|
|
14
|
+
inputSchema: {
|
|
15
|
+
...t.inputSchema,
|
|
16
|
+
},
|
|
17
|
+
...(t.outputSchema !== undefined && {
|
|
18
|
+
outputSchema: {
|
|
19
|
+
...t.outputSchema,
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
/** Cached tokens are unusable if they have a known expiry within the skew window. */
|
|
25
|
+
function tokensExpired(snapshot) {
|
|
26
|
+
const expiresAt = snapshot.auth?.tokens?.expiresAt;
|
|
27
|
+
if (expiresAt === undefined) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return expiresAt - Date.now() <= EXPIRY_SKEW_MS;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Reconstruct an {@link MCPAuth} from credentials persisted in a snapshot (only
|
|
34
|
+
* present when it was serialized with `cacheCredentials: true`). Prefer static
|
|
35
|
+
* headers when present; otherwise fall back to the OAuth/bearer access token.
|
|
36
|
+
* Returns undefined when the snapshot carries no usable credentials.
|
|
37
|
+
*/
|
|
38
|
+
function authFromSnapshot(snapshot) {
|
|
39
|
+
const auth = snapshot.auth;
|
|
40
|
+
if (auth === undefined) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
if (auth.headers !== undefined && Object.keys(auth.headers).length > 0) {
|
|
44
|
+
return {
|
|
45
|
+
kind: 'headers',
|
|
46
|
+
headers: auth.headers,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (auth.tokens?.accessToken !== undefined) {
|
|
50
|
+
return {
|
|
51
|
+
kind: 'bearer',
|
|
52
|
+
token: auth.tokens.accessToken,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
function toCreateOptions(options, snapshot, effectiveAuth) {
|
|
58
|
+
return {
|
|
59
|
+
url: snapshot.url,
|
|
60
|
+
transport: snapshot.transport,
|
|
61
|
+
...(effectiveAuth !== undefined && {
|
|
62
|
+
auth: effectiveAuth,
|
|
63
|
+
}),
|
|
64
|
+
...(options.fetch !== undefined && {
|
|
65
|
+
fetch: options.fetch,
|
|
66
|
+
}),
|
|
67
|
+
...(options.onUnconvertibleSchema !== undefined && {
|
|
68
|
+
onUnconvertibleSchema: options.onUnconvertibleSchema,
|
|
69
|
+
}),
|
|
70
|
+
...(options.onElicitation !== undefined && {
|
|
71
|
+
onElicitation: options.onElicitation,
|
|
72
|
+
}),
|
|
73
|
+
...(options.signal !== undefined && {
|
|
74
|
+
signal: options.signal,
|
|
75
|
+
}),
|
|
76
|
+
...(options.clientInfo !== undefined && {
|
|
77
|
+
clientInfo: options.clientInfo,
|
|
78
|
+
}),
|
|
79
|
+
...(options.toolNamePrefix !== undefined && {
|
|
80
|
+
toolNamePrefix: options.toolNamePrefix,
|
|
81
|
+
}),
|
|
82
|
+
...(options.includeTools !== undefined && {
|
|
83
|
+
includeTools: options.includeTools,
|
|
84
|
+
}),
|
|
85
|
+
...(options.excludeTools !== undefined && {
|
|
86
|
+
excludeTools: options.excludeTools,
|
|
87
|
+
}),
|
|
88
|
+
...(options.resources !== undefined && {
|
|
89
|
+
resources: options.resources,
|
|
90
|
+
}),
|
|
91
|
+
...(options.emitProgress !== undefined && {
|
|
92
|
+
emitProgress: options.emitProgress,
|
|
93
|
+
}),
|
|
94
|
+
...(options.autoRefreshOnListChanged !== undefined && {
|
|
95
|
+
autoRefreshOnListChanged: options.autoRefreshOnListChanged,
|
|
96
|
+
}),
|
|
97
|
+
...(options.cacheCredentials !== undefined && {
|
|
98
|
+
cacheCredentials: options.cacheCredentials,
|
|
99
|
+
}),
|
|
100
|
+
...(options.cache !== undefined && {
|
|
101
|
+
cache: options.cache,
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Rebuild an {@link MCPToolsHandle} from a cached snapshot. On the happy path we
|
|
107
|
+
* reconnect the transport and rebuild tools directly from the snapshot —
|
|
108
|
+
* skipping `listTools()`. If cached tokens are expired, credentials are missing,
|
|
109
|
+
* or the connection fails, we transparently fall back to a full
|
|
110
|
+
* {@link createMCPTools} (unless `reconnectOnExpiry` is false).
|
|
111
|
+
*/
|
|
112
|
+
export async function rehydrateMCPTools(options) {
|
|
113
|
+
const { snapshot } = options;
|
|
114
|
+
if (!isSerializedMCPServer(snapshot)) {
|
|
115
|
+
throw new MCPCacheError('Invalid MCP snapshot: failed structural validation');
|
|
116
|
+
}
|
|
117
|
+
const reconnectOnExpiry = options.reconnectOnExpiry ?? true;
|
|
118
|
+
const url = new URL(snapshot.url);
|
|
119
|
+
const cacheKey = options.cache?.key ?? defaultCacheKey(url.href);
|
|
120
|
+
// Fall back to credentials cached in the snapshot when the caller didn't pass
|
|
121
|
+
// any — otherwise a credential-bearing snapshot would reconnect unauthenticated.
|
|
122
|
+
const effectiveAuth = options.auth ?? authFromSnapshot(snapshot);
|
|
123
|
+
const hasCredentials = effectiveAuth !== undefined;
|
|
124
|
+
// Route the fallback through `freshConnect`, NOT `createMCPTools`: the latter
|
|
125
|
+
// would re-read this same snapshot and re-enter rehydrate, recursing without
|
|
126
|
+
// bound on any no-credential / expired-token snapshot. `freshConnect` still
|
|
127
|
+
// writes the refreshed result back to the cache via `makeHandle`.
|
|
128
|
+
const createOptions = toCreateOptions(options, snapshot, effectiveAuth);
|
|
129
|
+
if ((tokensExpired(snapshot) || !hasCredentials) && reconnectOnExpiry) {
|
|
130
|
+
return freshConnect(createOptions, url, cacheKey);
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
const connection = await connect({
|
|
134
|
+
url,
|
|
135
|
+
transport: snapshot.transport,
|
|
136
|
+
...(effectiveAuth !== undefined && {
|
|
137
|
+
auth: effectiveAuth,
|
|
138
|
+
}),
|
|
139
|
+
...(options.fetch !== undefined && {
|
|
140
|
+
fetch: options.fetch,
|
|
141
|
+
}),
|
|
142
|
+
...(options.clientInfo !== undefined && {
|
|
143
|
+
clientInfo: options.clientInfo,
|
|
144
|
+
}),
|
|
145
|
+
...(snapshot.sessionId !== undefined && {
|
|
146
|
+
sessionId: snapshot.sessionId,
|
|
147
|
+
}),
|
|
148
|
+
...(options.onElicitation !== undefined && {
|
|
149
|
+
onElicitation: options.onElicitation,
|
|
150
|
+
}),
|
|
151
|
+
});
|
|
152
|
+
// Rebuild tools from the snapshot — no listTools() round-trip.
|
|
153
|
+
return makeHandle({
|
|
154
|
+
connection,
|
|
155
|
+
options: createOptions,
|
|
156
|
+
context: {
|
|
157
|
+
url,
|
|
158
|
+
transport: connection.transport,
|
|
159
|
+
cacheKey,
|
|
160
|
+
},
|
|
161
|
+
initialToolDefs: snapshotToToolDefs(snapshot),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
if (reconnectOnExpiry) {
|
|
166
|
+
return freshConnect(createOptions, url, cacheKey);
|
|
167
|
+
}
|
|
168
|
+
throw new MCPCacheError('Failed to rehydrate MCP connection from snapshot', {
|
|
169
|
+
cause: err,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=rehydrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rehydrate.js","sourceRoot":"","sources":["../src/rehydrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import type { McpBranded } from '@openrouter/agent/tool-types';
|
|
3
|
+
export interface ResourceToolsOptions {
|
|
4
|
+
client: Client;
|
|
5
|
+
namePrefix?: string;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Build synthetic tools that let the model browse and read MCP resources
|
|
10
|
+
* through the normal tool loop:
|
|
11
|
+
* - `list_resources`: concrete resources plus resource templates.
|
|
12
|
+
* - `read_resource`: fetch a resource's contents by URI.
|
|
13
|
+
*
|
|
14
|
+
* Only call this when the server advertises the `resources` capability.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildResourceTools(options: ResourceToolsOptions): McpBranded[];
|
|
17
|
+
//# sourceMappingURL=resource-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-tools.d.ts","sourceRoot":"","sources":["../src/resource-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAExE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAG/D,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA0ED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU,EAAE,CAiG9E"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { markMcp, tool } from '@openrouter/agent/tool';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
// Hard cap on pagination pages. A well-behaved server terminates the cursor
|
|
4
|
+
// chain by omitting `nextCursor`; this bounds a misbehaving one that never does.
|
|
5
|
+
const MAX_LIST_PAGES = 1000;
|
|
6
|
+
/**
|
|
7
|
+
* Normalize a paginated `nextCursor` field: treat anything that is not a
|
|
8
|
+
* non-empty string as "no more pages" so a malformed cursor terminates the loop.
|
|
9
|
+
*/
|
|
10
|
+
function nextCursorOrUndefined(value) {
|
|
11
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Walk a paginated MCP list endpoint, following `nextCursor` (passed back as
|
|
15
|
+
* `{ cursor }`) until exhausted, and return the flattened items. Stops when the
|
|
16
|
+
* server omits `nextCursor`, repeats the same cursor, or the page cap is hit.
|
|
17
|
+
*/
|
|
18
|
+
async function collectPages(fetchPage, requestOptions) {
|
|
19
|
+
const collected = [];
|
|
20
|
+
let cursor;
|
|
21
|
+
for (let page = 0; page < MAX_LIST_PAGES; page += 1) {
|
|
22
|
+
const params = cursor !== undefined
|
|
23
|
+
? {
|
|
24
|
+
cursor,
|
|
25
|
+
}
|
|
26
|
+
: undefined;
|
|
27
|
+
const { items, nextCursor } = await fetchPage(params, requestOptions);
|
|
28
|
+
collected.push(...items);
|
|
29
|
+
const next = nextCursorOrUndefined(nextCursor);
|
|
30
|
+
if (next === undefined || next === cursor) {
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
cursor = next;
|
|
34
|
+
}
|
|
35
|
+
return collected;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build synthetic tools that let the model browse and read MCP resources
|
|
39
|
+
* through the normal tool loop:
|
|
40
|
+
* - `list_resources`: concrete resources plus resource templates.
|
|
41
|
+
* - `read_resource`: fetch a resource's contents by URI.
|
|
42
|
+
*
|
|
43
|
+
* Only call this when the server advertises the `resources` capability.
|
|
44
|
+
*/
|
|
45
|
+
export function buildResourceTools(options) {
|
|
46
|
+
const prefix = options.namePrefix ?? '';
|
|
47
|
+
const requestOptions = options.signal !== undefined
|
|
48
|
+
? {
|
|
49
|
+
signal: options.signal,
|
|
50
|
+
}
|
|
51
|
+
: undefined;
|
|
52
|
+
const listResources = tool({
|
|
53
|
+
name: `${prefix}list_resources`,
|
|
54
|
+
description: 'List the resources and resource templates exposed by the MCP server.',
|
|
55
|
+
inputSchema: z.object({}),
|
|
56
|
+
execute: async () => {
|
|
57
|
+
const [resources, resourceTemplates] = await Promise.all([
|
|
58
|
+
collectPages(async (params, opts) => {
|
|
59
|
+
const page = await options.client.listResources(params, opts);
|
|
60
|
+
return {
|
|
61
|
+
items: page.resources,
|
|
62
|
+
nextCursor: page.nextCursor,
|
|
63
|
+
};
|
|
64
|
+
}, requestOptions),
|
|
65
|
+
// Templates are optional: a server may not support them. The whole
|
|
66
|
+
// paginated fetch degrades gracefully to an empty list on any error.
|
|
67
|
+
collectPages(async (params, opts) => {
|
|
68
|
+
const page = await options.client.listResourceTemplates(params, opts);
|
|
69
|
+
return {
|
|
70
|
+
items: page.resourceTemplates,
|
|
71
|
+
nextCursor: page.nextCursor,
|
|
72
|
+
};
|
|
73
|
+
}, requestOptions).catch(() => []),
|
|
74
|
+
]);
|
|
75
|
+
return {
|
|
76
|
+
resources: resources.map((r) => ({
|
|
77
|
+
uri: r.uri,
|
|
78
|
+
name: r.name,
|
|
79
|
+
...(r.description !== undefined && {
|
|
80
|
+
description: r.description,
|
|
81
|
+
}),
|
|
82
|
+
...(r.mimeType !== undefined && {
|
|
83
|
+
mimeType: r.mimeType,
|
|
84
|
+
}),
|
|
85
|
+
})),
|
|
86
|
+
resourceTemplates: resourceTemplates.map((t) => ({
|
|
87
|
+
uriTemplate: t.uriTemplate,
|
|
88
|
+
name: t.name,
|
|
89
|
+
...(t.description !== undefined && {
|
|
90
|
+
description: t.description,
|
|
91
|
+
}),
|
|
92
|
+
})),
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
const readResource = tool({
|
|
97
|
+
name: `${prefix}read_resource`,
|
|
98
|
+
description: 'Read the contents of an MCP resource by its URI.',
|
|
99
|
+
inputSchema: z.object({
|
|
100
|
+
uri: z.string().describe('Resource URI to read'),
|
|
101
|
+
}),
|
|
102
|
+
execute: async (args) => {
|
|
103
|
+
const result = await options.client.readResource({
|
|
104
|
+
uri: args.uri,
|
|
105
|
+
}, requestOptions);
|
|
106
|
+
return {
|
|
107
|
+
contents: result.contents.map((c) => {
|
|
108
|
+
if ('text' in c) {
|
|
109
|
+
return {
|
|
110
|
+
uri: c.uri,
|
|
111
|
+
text: c.text,
|
|
112
|
+
...(c.mimeType !== undefined && {
|
|
113
|
+
mimeType: c.mimeType,
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
uri: c.uri,
|
|
119
|
+
blob: c.blob,
|
|
120
|
+
...(c.mimeType !== undefined && {
|
|
121
|
+
mimeType: c.mimeType,
|
|
122
|
+
}),
|
|
123
|
+
};
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
return [
|
|
129
|
+
markMcp(listResources),
|
|
130
|
+
markMcp(readResource),
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=resource-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-tools.js","sourceRoot":"","sources":["../src/resource-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The subset of an MCP `CallToolResult` we read. The SDK types it more richly,
|
|
3
|
+
* but we narrow defensively from `unknown`-ish content rather than trusting the
|
|
4
|
+
* wire shape.
|
|
5
|
+
*/
|
|
6
|
+
export interface RawCallToolResult {
|
|
7
|
+
content?: unknown;
|
|
8
|
+
structuredContent?: unknown;
|
|
9
|
+
isError?: boolean;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Map an MCP tool result into a value `callModel` can hand back to the model.
|
|
14
|
+
* Prefers `structuredContent` (already JSON), otherwise the collapsed text
|
|
15
|
+
* content. Throws {@link MCPToolCallError} when the server flags `isError`, so
|
|
16
|
+
* the agent loop reports the failure instead of treating error text as success.
|
|
17
|
+
*/
|
|
18
|
+
export declare function mapCallToolResult(toolName: string, result: RawCallToolResult): unknown;
|
|
19
|
+
//# sourceMappingURL=result-mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-mapper.d.ts","sourceRoot":"","sources":["../src/result-mapper.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA2BD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAStF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MCPToolCallError } from './errors.js';
|
|
2
|
+
import { isJsonSchemaObject } from './schema/json-schema-guards.js';
|
|
3
|
+
function isTextBlock(block) {
|
|
4
|
+
return isJsonSchemaObject(block) && block['type'] === 'text' && typeof block['text'] === 'string';
|
|
5
|
+
}
|
|
6
|
+
/** Collapse the content array into a single string for the model. */
|
|
7
|
+
function contentToText(content) {
|
|
8
|
+
if (!Array.isArray(content)) {
|
|
9
|
+
return '';
|
|
10
|
+
}
|
|
11
|
+
const parts = [];
|
|
12
|
+
for (const block of content) {
|
|
13
|
+
if (isTextBlock(block)) {
|
|
14
|
+
parts.push(block.text);
|
|
15
|
+
}
|
|
16
|
+
else if (isJsonSchemaObject(block) && typeof block['type'] === 'string') {
|
|
17
|
+
// Non-text blocks (image/audio/resource) aren't passed through as media
|
|
18
|
+
// in v1 — surface a typed placeholder so the model knows it exists.
|
|
19
|
+
parts.push(`[${block['type']} content]`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return parts.join('\n');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Map an MCP tool result into a value `callModel` can hand back to the model.
|
|
26
|
+
* Prefers `structuredContent` (already JSON), otherwise the collapsed text
|
|
27
|
+
* content. Throws {@link MCPToolCallError} when the server flags `isError`, so
|
|
28
|
+
* the agent loop reports the failure instead of treating error text as success.
|
|
29
|
+
*/
|
|
30
|
+
export function mapCallToolResult(toolName, result) {
|
|
31
|
+
if (result.isError === true) {
|
|
32
|
+
const message = contentToText(result.content) || 'MCP tool returned an error';
|
|
33
|
+
throw new MCPToolCallError(toolName, message);
|
|
34
|
+
}
|
|
35
|
+
if (result.structuredContent !== undefined) {
|
|
36
|
+
return result.structuredContent;
|
|
37
|
+
}
|
|
38
|
+
return contentToText(result.content);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=result-mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-mapper.js","sourceRoot":"","sources":["../src/result-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAcpE,SAAS,WAAW,CAAC,KAAc;IAIjC,OAAO,kBAAkB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC;AACpG,CAAC;AAED,qEAAqE;AACrE,SAAS,aAAa,CAAC,OAAgB;IACrC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,kBAAkB,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1E,wEAAwE;YACxE,oEAAoE;YACpE,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,MAAyB;IAC3E,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,4BAA4B,CAAC;QAC9E,MAAM,IAAI,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,MAAM,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAClC,CAAC;IACD,OAAO,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typeguards over the raw JSON-Schema-shaped values that arrive from an MCP
|
|
3
|
+
* server. MCP tool input/output schemas are untrusted `unknown` data, so we
|
|
4
|
+
* narrow them with runtime checks rather than `as` casts.
|
|
5
|
+
*/
|
|
6
|
+
/** A non-null, non-array object — the shape every JSON Schema node takes. */
|
|
7
|
+
export declare function isJsonSchemaObject(value: unknown): value is Record<string, unknown>;
|
|
8
|
+
/** A JSON Schema whose top-level `type` is `"object"`. */
|
|
9
|
+
export declare function isObjectJsonSchema(value: unknown): value is Record<string, unknown> & {
|
|
10
|
+
type: 'object';
|
|
11
|
+
};
|
|
12
|
+
/** The `properties` map of an object schema, when present and well-formed. */
|
|
13
|
+
export declare function getSchemaProperties(schema: Record<string, unknown>): Record<string, unknown> | undefined;
|
|
14
|
+
//# sourceMappingURL=json-schema-guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-schema-guards.d.ts","sourceRoot":"","sources":["../../src/schema/json-schema-guards.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEnF;AAED,0DAA0D;AAC1D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IACrF,IAAI,EAAE,QAAQ,CAAC;CAChB,CAEA;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAGrC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typeguards over the raw JSON-Schema-shaped values that arrive from an MCP
|
|
3
|
+
* server. MCP tool input/output schemas are untrusted `unknown` data, so we
|
|
4
|
+
* narrow them with runtime checks rather than `as` casts.
|
|
5
|
+
*/
|
|
6
|
+
/** A non-null, non-array object — the shape every JSON Schema node takes. */
|
|
7
|
+
export function isJsonSchemaObject(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
/** A JSON Schema whose top-level `type` is `"object"`. */
|
|
11
|
+
export function isObjectJsonSchema(value) {
|
|
12
|
+
return isJsonSchemaObject(value) && value['type'] === 'object';
|
|
13
|
+
}
|
|
14
|
+
/** The `properties` map of an object schema, when present and well-formed. */
|
|
15
|
+
export function getSchemaProperties(schema) {
|
|
16
|
+
const { properties } = schema;
|
|
17
|
+
return isJsonSchemaObject(properties) ? properties : undefined;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=json-schema-guards.js.map
|