@agentwares/agentguard 0.1.7 → 0.1.10
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 +108 -0
- package/README.md +223 -16
- package/dist/audit-5LUDXZLG.js +18 -0
- package/dist/audit-5LUDXZLG.js.map +1 -0
- package/dist/chunk-2QDPPTPY.js +179 -0
- package/dist/chunk-2QDPPTPY.js.map +1 -0
- package/dist/chunk-4WTFMFRY.js +1270 -0
- package/dist/chunk-4WTFMFRY.js.map +1 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-5WRI5ZAA.js.map +1 -0
- package/dist/chunk-DEVXG3IB.js +113 -0
- package/dist/chunk-DEVXG3IB.js.map +1 -0
- package/dist/chunk-F73VDY3W.js +202 -0
- package/dist/chunk-F73VDY3W.js.map +1 -0
- package/dist/chunk-IEJK7N3B.js +275 -0
- package/dist/chunk-IEJK7N3B.js.map +1 -0
- package/dist/chunk-IS3DAHZI.js +1698 -0
- package/dist/chunk-IS3DAHZI.js.map +1 -0
- package/dist/chunk-JSELR4SG.js +780 -0
- package/dist/chunk-JSELR4SG.js.map +1 -0
- package/dist/chunk-OM5L7A32.js +199 -0
- package/dist/chunk-OM5L7A32.js.map +1 -0
- package/dist/chunk-SWZQMPDG.js +206 -0
- package/dist/chunk-SWZQMPDG.js.map +1 -0
- package/dist/chunk-TJXZBOHL.js +529 -0
- package/dist/chunk-TJXZBOHL.js.map +1 -0
- package/dist/chunk-XOBFANL4.js +119 -0
- package/dist/chunk-XOBFANL4.js.map +1 -0
- package/dist/chunk-XPNBYSIN.js +23 -0
- package/dist/chunk-XPNBYSIN.js.map +1 -0
- package/dist/chunk-YBVD6HTT.js +1036 -0
- package/dist/chunk-YBVD6HTT.js.map +1 -0
- package/dist/chunk-ZG4LGUJE.js +847 -0
- package/dist/chunk-ZG4LGUJE.js.map +1 -0
- package/dist/cli.js +10 -4775
- package/dist/cli.js.map +1 -1
- package/dist/fixtures/crm-server.js +6 -1272
- package/dist/fixtures/crm-server.js.map +1 -1
- package/dist/fixtures/demo-agent.js +4 -115
- package/dist/fixtures/demo-agent.js.map +1 -1
- package/dist/index.d.ts +73 -14
- package/dist/index.js +247 -5138
- package/dist/index.js.map +1 -1
- package/dist/init-MKPQU2JG.js +17 -0
- package/dist/init-MKPQU2JG.js.map +1 -0
- package/dist/proxy-6GP63TLD.js +146 -0
- package/dist/proxy-6GP63TLD.js.map +1 -0
- package/dist/tools-XS7PMTLT.js +15 -0
- package/dist/tools-XS7PMTLT.js.map +1 -0
- package/llms.txt +10 -4
- package/package.json +16 -4
- package/server.json +9 -9
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readAllPages
|
|
3
|
+
} from "./chunk-IS3DAHZI.js";
|
|
4
|
+
import {
|
|
5
|
+
version
|
|
6
|
+
} from "./chunk-4WTFMFRY.js";
|
|
7
|
+
|
|
8
|
+
// src/proxy/runtime.ts
|
|
9
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10
|
+
import {
|
|
11
|
+
getDefaultEnvironment,
|
|
12
|
+
StdioClientTransport
|
|
13
|
+
} from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
14
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
15
|
+
import {
|
|
16
|
+
CreateMessageRequestSchema,
|
|
17
|
+
ElicitRequestSchema,
|
|
18
|
+
LoggingMessageNotificationSchema,
|
|
19
|
+
PromptListChangedNotificationSchema,
|
|
20
|
+
ResourceListChangedNotificationSchema,
|
|
21
|
+
ResourceUpdatedNotificationSchema,
|
|
22
|
+
ToolListChangedNotificationSchema
|
|
23
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
24
|
+
import {
|
|
25
|
+
GuardError,
|
|
26
|
+
classifyTool,
|
|
27
|
+
upstreamHeaders
|
|
28
|
+
} from "@agentwares/agentguard-core";
|
|
29
|
+
var ProxyRuntime = class {
|
|
30
|
+
loaded;
|
|
31
|
+
guard;
|
|
32
|
+
agent;
|
|
33
|
+
defaultRunId;
|
|
34
|
+
configured;
|
|
35
|
+
sessions = /* @__PURE__ */ new Set();
|
|
36
|
+
connections = /* @__PURE__ */ new Map();
|
|
37
|
+
exposed = [];
|
|
38
|
+
resourceOwner = /* @__PURE__ */ new Map();
|
|
39
|
+
templateOwner = /* @__PURE__ */ new Map();
|
|
40
|
+
promptOwner = /* @__PURE__ */ new Map();
|
|
41
|
+
log;
|
|
42
|
+
connectTimeoutMs;
|
|
43
|
+
testClients;
|
|
44
|
+
/** stop relaying upstream stderr once we are tearing down — shutdown noise is not the user's problem */
|
|
45
|
+
closing = false;
|
|
46
|
+
constructor(opts) {
|
|
47
|
+
this.loaded = opts.loaded;
|
|
48
|
+
this.guard = opts.guard;
|
|
49
|
+
this.agent = opts.agent;
|
|
50
|
+
this.defaultRunId = opts.defaultRunId;
|
|
51
|
+
this.configured = opts.configured ?? true;
|
|
52
|
+
this.log = opts.log ?? ((line) => process.stderr.write(`[okgate] ${line}
|
|
53
|
+
`));
|
|
54
|
+
this.connectTimeoutMs = opts.connectTimeoutMs ?? 15e3;
|
|
55
|
+
this.testClients = opts.clients ?? {};
|
|
56
|
+
}
|
|
57
|
+
get policy() {
|
|
58
|
+
return this.loaded.policy;
|
|
59
|
+
}
|
|
60
|
+
async start() {
|
|
61
|
+
await Promise.all(this.policy.upstreams.map((u) => this.connect(u)));
|
|
62
|
+
for (const [name, client] of Object.entries(this.testClients)) {
|
|
63
|
+
if (this.connections.has(name)) continue;
|
|
64
|
+
const upstream = {
|
|
65
|
+
name,
|
|
66
|
+
command: "in-memory",
|
|
67
|
+
args: [],
|
|
68
|
+
env: {},
|
|
69
|
+
headers: {},
|
|
70
|
+
prefix: false,
|
|
71
|
+
timeout_ms: 6e4
|
|
72
|
+
};
|
|
73
|
+
const conn = {
|
|
74
|
+
upstream,
|
|
75
|
+
client,
|
|
76
|
+
tools: [],
|
|
77
|
+
capabilities: client.getServerCapabilities(),
|
|
78
|
+
connected: true
|
|
79
|
+
};
|
|
80
|
+
this.connections.set(name, conn);
|
|
81
|
+
this.wire(conn);
|
|
82
|
+
await this.refreshTools(name);
|
|
83
|
+
}
|
|
84
|
+
this.rebuildExposed();
|
|
85
|
+
const status = this.upstreamStatus();
|
|
86
|
+
this.log(
|
|
87
|
+
`connected ${status.filter((s) => s.connected).length}/${status.length} upstreams, ${this.exposed.length} tools, mode ${this.policy.mode}`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
async connect(upstream) {
|
|
91
|
+
const client = new Client(
|
|
92
|
+
{ name: "okgate", version: version() },
|
|
93
|
+
{ capabilities: { sampling: {}, elicitation: {} } }
|
|
94
|
+
);
|
|
95
|
+
const conn = {
|
|
96
|
+
upstream,
|
|
97
|
+
client,
|
|
98
|
+
tools: [],
|
|
99
|
+
capabilities: void 0,
|
|
100
|
+
connected: false
|
|
101
|
+
};
|
|
102
|
+
this.connections.set(upstream.name, conn);
|
|
103
|
+
try {
|
|
104
|
+
const transport = upstream.url ? new StreamableHTTPClientTransport(new URL(upstream.url), {
|
|
105
|
+
requestInit: { headers: upstreamHeaders(upstream) }
|
|
106
|
+
}) : new StdioClientTransport({
|
|
107
|
+
command: upstream.command,
|
|
108
|
+
args: upstream.args,
|
|
109
|
+
env: { ...getDefaultEnvironment(), ...upstream.env },
|
|
110
|
+
cwd: upstream.cwd,
|
|
111
|
+
stderr: "pipe"
|
|
112
|
+
});
|
|
113
|
+
if (transport instanceof StdioClientTransport) {
|
|
114
|
+
transport.stderr?.on("data", (chunk) => {
|
|
115
|
+
if (this.closing) return;
|
|
116
|
+
for (const line of chunk.toString("utf8").split("\n"))
|
|
117
|
+
if (line.trim()) this.log(`${upstream.name}: ${line}`);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
await withTimeout(
|
|
121
|
+
client.connect(transport),
|
|
122
|
+
this.connectTimeoutMs,
|
|
123
|
+
`connect to upstream "${upstream.name}"`
|
|
124
|
+
);
|
|
125
|
+
conn.capabilities = client.getServerCapabilities();
|
|
126
|
+
conn.connected = true;
|
|
127
|
+
this.wire(conn);
|
|
128
|
+
await this.refreshTools(upstream.name);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
conn.connected = false;
|
|
131
|
+
conn.error = err instanceof Error ? err.message : String(err);
|
|
132
|
+
this.log(`upstream "${upstream.name}" unavailable: ${conn.error}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
wire(conn) {
|
|
136
|
+
const { client, upstream } = conn;
|
|
137
|
+
client.onclose = () => {
|
|
138
|
+
conn.connected = false;
|
|
139
|
+
conn.error = "connection closed";
|
|
140
|
+
if (!this.closing) this.log(`upstream "${upstream.name}" closed`);
|
|
141
|
+
};
|
|
142
|
+
client.setNotificationHandler(LoggingMessageNotificationSchema, async (n) => {
|
|
143
|
+
await this.broadcast(upstream.name, n.method, n.params);
|
|
144
|
+
});
|
|
145
|
+
client.setNotificationHandler(ResourceUpdatedNotificationSchema, async (n) => {
|
|
146
|
+
await this.broadcast(upstream.name, n.method, n.params);
|
|
147
|
+
});
|
|
148
|
+
client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
|
|
149
|
+
this.resourceOwner.clear();
|
|
150
|
+
await this.broadcast(upstream.name, "notifications/resources/list_changed", void 0);
|
|
151
|
+
});
|
|
152
|
+
client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {
|
|
153
|
+
this.promptOwner.clear();
|
|
154
|
+
await this.broadcast(upstream.name, "notifications/prompts/list_changed", void 0);
|
|
155
|
+
});
|
|
156
|
+
client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
|
|
157
|
+
await this.refreshTools(upstream.name);
|
|
158
|
+
this.rebuildExposed();
|
|
159
|
+
for (const s of this.sessions) s.server.server.sendToolListChanged().catch(() => void 0);
|
|
160
|
+
});
|
|
161
|
+
try {
|
|
162
|
+
client.setRequestHandler(CreateMessageRequestSchema, async (req) => {
|
|
163
|
+
const session = this.pickSession(upstream.name);
|
|
164
|
+
if (!session) throw new Error("no downstream client is connected to relay sampling to");
|
|
165
|
+
const related = session.inflight.get(upstream.name)?.at(-1);
|
|
166
|
+
return session.server.server.createMessage(req.params, { relatedRequestId: related });
|
|
167
|
+
});
|
|
168
|
+
client.setRequestHandler(ElicitRequestSchema, async (req) => {
|
|
169
|
+
const session = this.pickSession(upstream.name);
|
|
170
|
+
if (!session) throw new Error("no downstream client is connected to relay elicitation to");
|
|
171
|
+
const related = session.inflight.get(upstream.name)?.at(-1);
|
|
172
|
+
return session.server.server.elicitInput(req.params, { relatedRequestId: related });
|
|
173
|
+
});
|
|
174
|
+
} catch {
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
pickSession(upstream) {
|
|
178
|
+
let best;
|
|
179
|
+
for (const s of this.sessions) {
|
|
180
|
+
if ((s.inflight.get(upstream)?.length ?? 0) > 0) return s;
|
|
181
|
+
if (!best || s.lastActive > best.lastActive) best = s;
|
|
182
|
+
}
|
|
183
|
+
return best;
|
|
184
|
+
}
|
|
185
|
+
async broadcast(upstream, method, params) {
|
|
186
|
+
for (const s of this.sessions) {
|
|
187
|
+
const related = s.inflight.get(upstream)?.at(-1);
|
|
188
|
+
try {
|
|
189
|
+
await s.server.server.notification(
|
|
190
|
+
{ method, params },
|
|
191
|
+
related !== void 0 ? { relatedRequestId: related } : void 0
|
|
192
|
+
);
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Re-read an upstream's tools, every page (mcp-kit's `readAllPages`): at most 20 requests, each
|
|
199
|
+
* under the upstream's `timeout_ms`, ending at a cursor already followed. It used to follow
|
|
200
|
+
* `nextCursor` with no bound, so an upstream that echoed its cursor kept the proxy asking for
|
|
201
|
+
* the same page forever. A refresh that fails, or stops at the 20-page / 2,000-tool ceiling,
|
|
202
|
+
* changes nothing: the agent keeps the last good list, and the log says why.
|
|
203
|
+
*/
|
|
204
|
+
async refreshTools(name) {
|
|
205
|
+
const conn = this.connections.get(name);
|
|
206
|
+
if (!conn?.connected) return;
|
|
207
|
+
if (conn.capabilities && !conn.capabilities.tools) {
|
|
208
|
+
conn.tools = [];
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const kept = () => `keeping the last good list (${conn.tools.length} tool${conn.tools.length === 1 ? "" : "s"})`;
|
|
212
|
+
try {
|
|
213
|
+
const read = await readAllPages(async (cursor) => {
|
|
214
|
+
const page = await conn.client.listTools(cursor ? { cursor } : void 0, {
|
|
215
|
+
timeout: conn.upstream.timeout_ms
|
|
216
|
+
});
|
|
217
|
+
return { items: page.tools, nextCursor: page.nextCursor };
|
|
218
|
+
});
|
|
219
|
+
if (read.truncated) {
|
|
220
|
+
this.log(`tools/list for "${name}" not applied: ${read.truncated.reason}; ${kept()}`);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
conn.tools = read.items;
|
|
224
|
+
} catch (err) {
|
|
225
|
+
this.log(
|
|
226
|
+
`tools/list failed for "${name}": ${err instanceof Error ? err.message : String(err)}; ${kept()}`
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
rebuildExposed() {
|
|
231
|
+
const taken = /* @__PURE__ */ new Set();
|
|
232
|
+
const out = [];
|
|
233
|
+
const order = [...this.policy.upstreams.map((u) => u.name), ...Object.keys(this.testClients)];
|
|
234
|
+
for (const name of order) {
|
|
235
|
+
const conn = this.connections.get(name);
|
|
236
|
+
if (!conn) continue;
|
|
237
|
+
const prefix = conn.upstream.prefix === true ? name : typeof conn.upstream.prefix === "string" ? conn.upstream.prefix : void 0;
|
|
238
|
+
for (const tool of conn.tools) {
|
|
239
|
+
let exposedName = prefix ? `${prefix}__${tool.name}` : tool.name;
|
|
240
|
+
if (taken.has(exposedName)) exposedName = `${name}__${tool.name}`;
|
|
241
|
+
if (taken.has(exposedName)) {
|
|
242
|
+
this.log(`skipping duplicate tool ${exposedName} from ${name}`);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
taken.add(exposedName);
|
|
246
|
+
out.push({
|
|
247
|
+
name: exposedName,
|
|
248
|
+
upstream: name,
|
|
249
|
+
original: tool.name,
|
|
250
|
+
tool,
|
|
251
|
+
classification: classifyTool(
|
|
252
|
+
{
|
|
253
|
+
name: exposedName,
|
|
254
|
+
description: tool.description,
|
|
255
|
+
annotations: tool.annotations,
|
|
256
|
+
inputSchema: tool.inputSchema,
|
|
257
|
+
outputSchema: tool.outputSchema
|
|
258
|
+
},
|
|
259
|
+
this.policy
|
|
260
|
+
)
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
this.exposed = out;
|
|
265
|
+
}
|
|
266
|
+
listTools(agent) {
|
|
267
|
+
if (agent?.upstreams) return this.exposed.filter((t) => agent.upstreams.includes(t.upstream));
|
|
268
|
+
return this.exposed;
|
|
269
|
+
}
|
|
270
|
+
findTool(name) {
|
|
271
|
+
return this.exposed.find((t) => t.name === name);
|
|
272
|
+
}
|
|
273
|
+
upstreamStatus() {
|
|
274
|
+
return [...this.connections.values()].map((c) => ({
|
|
275
|
+
name: c.upstream.name,
|
|
276
|
+
connected: c.connected,
|
|
277
|
+
tools: c.tools.length,
|
|
278
|
+
transport: c.upstream.url ? "http" : "stdio",
|
|
279
|
+
error: c.error
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
attach(session) {
|
|
283
|
+
this.sessions.add(session);
|
|
284
|
+
}
|
|
285
|
+
detach(session) {
|
|
286
|
+
this.sessions.delete(session);
|
|
287
|
+
}
|
|
288
|
+
/** Run a tool call through the policy engine and, if allowed, the upstream. */
|
|
289
|
+
async callTool(name, args, ctx) {
|
|
290
|
+
const tool = this.findTool(name);
|
|
291
|
+
const agent = ctx.agent === void 0 ? this.agent : ctx.agent;
|
|
292
|
+
if (!tool) {
|
|
293
|
+
const result2 = await this.guard.run(
|
|
294
|
+
{ tool: { name }, args, runId: ctx.runId, agent, sessionId: ctx.sessionId },
|
|
295
|
+
async () => {
|
|
296
|
+
throw new GuardError({
|
|
297
|
+
code: "UNKNOWN_TOOL",
|
|
298
|
+
cause: `no upstream exposes a tool named "${name}"`,
|
|
299
|
+
fix: "call tools/list and use one of the listed names",
|
|
300
|
+
retryable: false
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
);
|
|
304
|
+
return { result: result2 };
|
|
305
|
+
}
|
|
306
|
+
const conn = this.connections.get(tool.upstream);
|
|
307
|
+
const track = () => {
|
|
308
|
+
if (!ctx.session || ctx.requestId === void 0) return () => void 0;
|
|
309
|
+
const list = ctx.session.inflight.get(tool.upstream) ?? [];
|
|
310
|
+
list.push(ctx.requestId);
|
|
311
|
+
ctx.session.inflight.set(tool.upstream, list);
|
|
312
|
+
return () => {
|
|
313
|
+
const l = ctx.session.inflight.get(tool.upstream) ?? [];
|
|
314
|
+
const i = l.indexOf(ctx.requestId);
|
|
315
|
+
if (i >= 0) l.splice(i, 1);
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
const result = await this.guard.run(
|
|
319
|
+
{
|
|
320
|
+
tool: {
|
|
321
|
+
name: tool.name,
|
|
322
|
+
description: tool.tool.description,
|
|
323
|
+
annotations: tool.tool.annotations,
|
|
324
|
+
inputSchema: tool.tool.inputSchema,
|
|
325
|
+
outputSchema: tool.tool.outputSchema
|
|
326
|
+
},
|
|
327
|
+
args,
|
|
328
|
+
runId: ctx.runId,
|
|
329
|
+
agent,
|
|
330
|
+
sessionId: ctx.sessionId,
|
|
331
|
+
upstream: tool.upstream
|
|
332
|
+
},
|
|
333
|
+
async (finalArgs) => {
|
|
334
|
+
if (!conn?.connected) {
|
|
335
|
+
throw new GuardError({
|
|
336
|
+
code: "UPSTREAM_ERROR",
|
|
337
|
+
cause: `upstream "${tool.upstream}" is not connected${conn?.error ? ` (${conn.error})` : ""}`,
|
|
338
|
+
fix: "check the upstream command/url in okgate.yaml and restart the proxy",
|
|
339
|
+
retryable: true
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
const untrack = track();
|
|
343
|
+
try {
|
|
344
|
+
return await conn.client.callTool(
|
|
345
|
+
{ name: tool.original, arguments: finalArgs ?? {} },
|
|
346
|
+
void 0,
|
|
347
|
+
{
|
|
348
|
+
timeout: conn.upstream.timeout_ms,
|
|
349
|
+
resetTimeoutOnProgress: true,
|
|
350
|
+
onprogress: ctx.onprogress
|
|
351
|
+
}
|
|
352
|
+
);
|
|
353
|
+
} finally {
|
|
354
|
+
untrack();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
);
|
|
358
|
+
return { result, tool };
|
|
359
|
+
}
|
|
360
|
+
connectedWith(capability) {
|
|
361
|
+
return [...this.connections.values()].filter(
|
|
362
|
+
(c) => c.connected && (c.capabilities?.[capability] || c.capabilities === void 0)
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
async listResources() {
|
|
366
|
+
const resources = [];
|
|
367
|
+
for (const conn of this.connectedWith("resources")) {
|
|
368
|
+
try {
|
|
369
|
+
const page = await conn.client.listResources(void 0, {
|
|
370
|
+
timeout: conn.upstream.timeout_ms
|
|
371
|
+
});
|
|
372
|
+
for (const r of page.resources) {
|
|
373
|
+
this.resourceOwner.set(r.uri, conn.upstream.name);
|
|
374
|
+
resources.push(r);
|
|
375
|
+
}
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return { resources };
|
|
380
|
+
}
|
|
381
|
+
async listResourceTemplates() {
|
|
382
|
+
const resourceTemplates = [];
|
|
383
|
+
for (const conn of this.connectedWith("resources")) {
|
|
384
|
+
try {
|
|
385
|
+
const page = await conn.client.listResourceTemplates(void 0, {
|
|
386
|
+
timeout: conn.upstream.timeout_ms
|
|
387
|
+
});
|
|
388
|
+
for (const t of page.resourceTemplates) {
|
|
389
|
+
this.templateOwner.set(t.uriTemplate, conn.upstream.name);
|
|
390
|
+
resourceTemplates.push(t);
|
|
391
|
+
}
|
|
392
|
+
} catch {
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return { resourceTemplates };
|
|
396
|
+
}
|
|
397
|
+
ownerForUri(uri) {
|
|
398
|
+
const owner = this.resourceOwner.get(uri);
|
|
399
|
+
if (owner && this.connections.get(owner)?.connected) return [this.connections.get(owner)];
|
|
400
|
+
for (const [template, name] of this.templateOwner) {
|
|
401
|
+
if (templateMatches(template, uri) && this.connections.get(name)?.connected)
|
|
402
|
+
return [this.connections.get(name)];
|
|
403
|
+
}
|
|
404
|
+
return this.connectedWith("resources");
|
|
405
|
+
}
|
|
406
|
+
async readResource(uri) {
|
|
407
|
+
let lastError;
|
|
408
|
+
for (const conn of this.ownerForUri(uri)) {
|
|
409
|
+
try {
|
|
410
|
+
const result = await conn.client.readResource(
|
|
411
|
+
{ uri },
|
|
412
|
+
{ timeout: conn.upstream.timeout_ms }
|
|
413
|
+
);
|
|
414
|
+
this.resourceOwner.set(uri, conn.upstream.name);
|
|
415
|
+
return result;
|
|
416
|
+
} catch (err) {
|
|
417
|
+
lastError = err;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
throw lastError ?? new Error(`no upstream serves resource ${uri}`);
|
|
421
|
+
}
|
|
422
|
+
async subscribe(uri, on) {
|
|
423
|
+
for (const conn of this.ownerForUri(uri)) {
|
|
424
|
+
try {
|
|
425
|
+
if (on) await conn.client.subscribeResource({ uri });
|
|
426
|
+
else await conn.client.unsubscribeResource({ uri });
|
|
427
|
+
return;
|
|
428
|
+
} catch {
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async listPrompts() {
|
|
433
|
+
const prompts = [];
|
|
434
|
+
const taken = /* @__PURE__ */ new Set();
|
|
435
|
+
this.promptOwner.clear();
|
|
436
|
+
for (const conn of this.connectedWith("prompts")) {
|
|
437
|
+
try {
|
|
438
|
+
const page = await conn.client.listPrompts(void 0, {
|
|
439
|
+
timeout: conn.upstream.timeout_ms
|
|
440
|
+
});
|
|
441
|
+
for (const p of page.prompts) {
|
|
442
|
+
const name = taken.has(p.name) ? `${conn.upstream.name}__${p.name}` : p.name;
|
|
443
|
+
taken.add(name);
|
|
444
|
+
this.promptOwner.set(name, { upstream: conn.upstream.name, original: p.name });
|
|
445
|
+
prompts.push({ ...p, name });
|
|
446
|
+
}
|
|
447
|
+
} catch {
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return { prompts };
|
|
451
|
+
}
|
|
452
|
+
async getPrompt(name, args) {
|
|
453
|
+
if (this.promptOwner.size === 0) await this.listPrompts();
|
|
454
|
+
const owner = this.promptOwner.get(name);
|
|
455
|
+
const conns = owner ? [this.connections.get(owner.upstream)] : this.connectedWith("prompts");
|
|
456
|
+
let lastError;
|
|
457
|
+
for (const conn of conns) {
|
|
458
|
+
try {
|
|
459
|
+
return await conn.client.getPrompt(
|
|
460
|
+
{ name: owner?.original ?? name, arguments: args },
|
|
461
|
+
{ timeout: conn.upstream.timeout_ms }
|
|
462
|
+
);
|
|
463
|
+
} catch (err) {
|
|
464
|
+
lastError = err;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
throw lastError ?? new Error(`no upstream serves prompt ${name}`);
|
|
468
|
+
}
|
|
469
|
+
async complete(params) {
|
|
470
|
+
let conns;
|
|
471
|
+
if (params.ref.type === "ref/prompt") {
|
|
472
|
+
if (this.promptOwner.size === 0) await this.listPrompts();
|
|
473
|
+
const owner = this.promptOwner.get(params.ref.name);
|
|
474
|
+
conns = owner ? [this.connections.get(owner.upstream)] : this.connectedWith("completions");
|
|
475
|
+
if (owner) params = { ...params, ref: { ...params.ref, name: owner.original } };
|
|
476
|
+
} else {
|
|
477
|
+
if (this.templateOwner.size === 0) await this.listResourceTemplates();
|
|
478
|
+
conns = this.ownerForUri(params.ref.uri);
|
|
479
|
+
}
|
|
480
|
+
let lastError;
|
|
481
|
+
for (const conn of conns) {
|
|
482
|
+
try {
|
|
483
|
+
return await conn.client.complete(params, { timeout: conn.upstream.timeout_ms });
|
|
484
|
+
} catch (err) {
|
|
485
|
+
lastError = err;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
throw lastError ?? new Error("no upstream supports completions");
|
|
489
|
+
}
|
|
490
|
+
async setLevel(level) {
|
|
491
|
+
await Promise.all(
|
|
492
|
+
this.connectedWith("logging").map(
|
|
493
|
+
(c) => c.client.setLoggingLevel(level).catch(() => void 0)
|
|
494
|
+
)
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
async close() {
|
|
498
|
+
this.closing = true;
|
|
499
|
+
for (const conn of this.connections.values()) {
|
|
500
|
+
try {
|
|
501
|
+
await conn.client.close();
|
|
502
|
+
} catch {
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
this.connections.clear();
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
function templateMatches(template, uri) {
|
|
509
|
+
const re = new RegExp(
|
|
510
|
+
"^" + template.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\{[^}]+\\\}/g, "[^/]+") + "$"
|
|
511
|
+
);
|
|
512
|
+
return re.test(uri);
|
|
513
|
+
}
|
|
514
|
+
async function withTimeout(promise, ms, what) {
|
|
515
|
+
let timer;
|
|
516
|
+
const timeout = new Promise((_, reject) => {
|
|
517
|
+
timer = setTimeout(() => reject(new Error(`${what} timed out after ${ms}ms`)), ms);
|
|
518
|
+
});
|
|
519
|
+
try {
|
|
520
|
+
return await Promise.race([promise, timeout]);
|
|
521
|
+
} finally {
|
|
522
|
+
if (timer) clearTimeout(timer);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export {
|
|
527
|
+
ProxyRuntime
|
|
528
|
+
};
|
|
529
|
+
//# sourceMappingURL=chunk-TJXZBOHL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/proxy/runtime.ts"],"sourcesContent":["/**\n * Upstream side of the proxy: one MCP client per upstream (stdio or Streamable HTTP), the merged\n * tool table, resource/prompt routing, notification fan-out to downstream sessions, and\n * `callTool` through the policy engine.\n */\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { version as cliVersion } from \"../version.js\";\nimport {\n getDefaultEnvironment,\n StdioClientTransport,\n} from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport {\n CreateMessageRequestSchema,\n ElicitRequestSchema,\n LoggingMessageNotificationSchema,\n PromptListChangedNotificationSchema,\n ResourceListChangedNotificationSchema,\n ResourceUpdatedNotificationSchema,\n ToolListChangedNotificationSchema,\n type CallToolResult,\n type CompleteRequest,\n type CompleteResult,\n type GetPromptResult,\n type ListPromptsResult,\n type ListResourceTemplatesResult,\n type ListResourcesResult,\n type LoggingLevel,\n type Prompt,\n type ReadResourceResult,\n type Resource,\n type ResourceTemplate,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { RequestId } from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n GuardError,\n classifyTool,\n upstreamHeaders,\n type AgentScope,\n type Classification,\n type Guard,\n type GuardResult,\n type Upstream,\n} from \"@agentwares/agentguard-core\";\nimport type { LoadedPolicy } from \"@agentwares/agentguard-core/node\";\n// The root export, not `@agentwares/mcp-kit/paging`: tsup bundles mcp-kit into the published CLI\n// by an exact-name match, and a subpath would be left as an undeclared runtime dependency.\nimport { readAllPages } from \"@agentwares/mcp-kit\";\n\nexport interface ExposedTool {\n /** the name the agent sees */\n name: string;\n upstream: string;\n /** the name the upstream knows */\n original: string;\n tool: Tool;\n classification: Classification;\n}\n\nexport interface DownstreamSession {\n id: string;\n server: McpServer;\n lastActive: number;\n /** upstream name → downstream request ids currently waiting on it (newest last) */\n inflight: Map<string, RequestId[]>;\n}\n\nexport interface UpstreamStatus {\n name: string;\n connected: boolean;\n tools: number;\n transport: \"stdio\" | \"http\";\n error?: string;\n}\n\ninterface Connection {\n upstream: Upstream;\n client: Client;\n tools: Tool[];\n capabilities: ReturnType<Client[\"getServerCapabilities\"]>;\n connected: boolean;\n error?: string;\n}\n\nexport interface RuntimeOptions {\n loaded: LoadedPolicy;\n guard: Guard;\n /** fixed agent scope for stdio (`--agent`) */\n agent?: AgentScope | null;\n /** run id when neither `X-Run-Id` nor `_meta.runId` is present */\n defaultRunId: string;\n log?: (line: string) => void;\n /** connect timeout per upstream (ms) */\n connectTimeoutMs?: number;\n /** in-process upstreams for tests: name → already-connected client */\n clients?: Record<string, Client>;\n /**\n * false when no policy file was found and the proxy runs on the default policy with no\n * upstreams, serving only its own read-only tools (default true)\n */\n configured?: boolean;\n}\n\nexport interface CallContext {\n runId: string;\n agent?: AgentScope | null;\n sessionId?: string;\n onprogress?: (progress: { progress: number; total?: number; message?: string }) => void;\n /** downstream session + request id, so upstream notifications can be related to this call */\n session?: DownstreamSession;\n requestId?: RequestId;\n}\n\nexport class ProxyRuntime {\n readonly loaded: LoadedPolicy;\n readonly guard: Guard;\n readonly agent: AgentScope | null | undefined;\n readonly defaultRunId: string;\n readonly configured: boolean;\n readonly sessions = new Set<DownstreamSession>();\n private readonly connections = new Map<string, Connection>();\n private exposed: ExposedTool[] = [];\n private readonly resourceOwner = new Map<string, string>();\n private readonly templateOwner = new Map<string, string>();\n private readonly promptOwner = new Map<string, { upstream: string; original: string }>();\n private readonly log: (line: string) => void;\n private readonly connectTimeoutMs: number;\n private readonly testClients: Record<string, Client>;\n /** stop relaying upstream stderr once we are tearing down — shutdown noise is not the user's problem */\n private closing = false;\n\n constructor(opts: RuntimeOptions) {\n this.loaded = opts.loaded;\n this.guard = opts.guard;\n this.agent = opts.agent;\n this.defaultRunId = opts.defaultRunId;\n this.configured = opts.configured ?? true;\n this.log = opts.log ?? ((line) => process.stderr.write(`[okgate] ${line}\\n`));\n this.connectTimeoutMs = opts.connectTimeoutMs ?? 15_000;\n this.testClients = opts.clients ?? {};\n }\n\n get policy() {\n return this.loaded.policy;\n }\n\n async start(): Promise<void> {\n await Promise.all(this.policy.upstreams.map((u) => this.connect(u)));\n for (const [name, client] of Object.entries(this.testClients)) {\n if (this.connections.has(name)) continue;\n const upstream: Upstream = {\n name,\n command: \"in-memory\",\n args: [],\n env: {},\n headers: {},\n prefix: false,\n timeout_ms: 60_000,\n };\n const conn: Connection = {\n upstream,\n client,\n tools: [],\n capabilities: client.getServerCapabilities(),\n connected: true,\n };\n this.connections.set(name, conn);\n this.wire(conn);\n await this.refreshTools(name);\n }\n this.rebuildExposed();\n const status = this.upstreamStatus();\n this.log(\n `connected ${status.filter((s) => s.connected).length}/${status.length} upstreams, ${this.exposed.length} tools, mode ${this.policy.mode}`,\n );\n }\n\n private async connect(upstream: Upstream): Promise<void> {\n const client = new Client(\n { name: \"okgate\", version: cliVersion() },\n { capabilities: { sampling: {}, elicitation: {} } },\n );\n const conn: Connection = {\n upstream,\n client,\n tools: [],\n capabilities: undefined,\n connected: false,\n };\n this.connections.set(upstream.name, conn);\n try {\n const transport = upstream.url\n ? new StreamableHTTPClientTransport(new URL(upstream.url), {\n requestInit: { headers: upstreamHeaders(upstream) },\n })\n : new StdioClientTransport({\n command: upstream.command!,\n args: upstream.args,\n env: { ...getDefaultEnvironment(), ...upstream.env },\n cwd: upstream.cwd,\n stderr: \"pipe\",\n });\n if (transport instanceof StdioClientTransport) {\n transport.stderr?.on(\"data\", (chunk: Buffer) => {\n if (this.closing) return;\n for (const line of chunk.toString(\"utf8\").split(\"\\n\"))\n if (line.trim()) this.log(`${upstream.name}: ${line}`);\n });\n }\n await withTimeout(\n client.connect(transport),\n this.connectTimeoutMs,\n `connect to upstream \"${upstream.name}\"`,\n );\n conn.capabilities = client.getServerCapabilities();\n conn.connected = true;\n this.wire(conn);\n await this.refreshTools(upstream.name);\n } catch (err) {\n conn.connected = false;\n conn.error = err instanceof Error ? err.message : String(err);\n this.log(`upstream \"${upstream.name}\" unavailable: ${conn.error}`);\n }\n }\n\n private wire(conn: Connection): void {\n const { client, upstream } = conn;\n client.onclose = () => {\n conn.connected = false;\n conn.error = \"connection closed\";\n if (!this.closing) this.log(`upstream \"${upstream.name}\" closed`);\n };\n client.setNotificationHandler(LoggingMessageNotificationSchema, async (n) => {\n await this.broadcast(upstream.name, n.method, n.params);\n });\n client.setNotificationHandler(ResourceUpdatedNotificationSchema, async (n) => {\n await this.broadcast(upstream.name, n.method, n.params);\n });\n client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {\n this.resourceOwner.clear();\n await this.broadcast(upstream.name, \"notifications/resources/list_changed\", undefined);\n });\n client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {\n this.promptOwner.clear();\n await this.broadcast(upstream.name, \"notifications/prompts/list_changed\", undefined);\n });\n client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {\n await this.refreshTools(upstream.name);\n this.rebuildExposed();\n for (const s of this.sessions) s.server.server.sendToolListChanged().catch(() => undefined);\n });\n // Relay server→client requests (sampling, elicitation) to the downstream session that is\n // waiting on this upstream. Clients created without those capabilities (tests) skip this.\n try {\n client.setRequestHandler(CreateMessageRequestSchema, async (req) => {\n const session = this.pickSession(upstream.name);\n if (!session) throw new Error(\"no downstream client is connected to relay sampling to\");\n const related = session.inflight.get(upstream.name)?.at(-1);\n return session.server.server.createMessage(req.params, { relatedRequestId: related });\n });\n client.setRequestHandler(ElicitRequestSchema, async (req) => {\n const session = this.pickSession(upstream.name);\n if (!session) throw new Error(\"no downstream client is connected to relay elicitation to\");\n const related = session.inflight.get(upstream.name)?.at(-1);\n return session.server.server.elicitInput(req.params, { relatedRequestId: related });\n });\n } catch {\n // client declared no sampling/elicitation capability\n }\n }\n\n private pickSession(upstream: string): DownstreamSession | undefined {\n let best: DownstreamSession | undefined;\n for (const s of this.sessions) {\n if ((s.inflight.get(upstream)?.length ?? 0) > 0) return s;\n if (!best || s.lastActive > best.lastActive) best = s;\n }\n return best;\n }\n\n private async broadcast(upstream: string, method: string, params: unknown): Promise<void> {\n for (const s of this.sessions) {\n const related = s.inflight.get(upstream)?.at(-1);\n try {\n await s.server.server.notification(\n { method, params: params as Record<string, unknown> | undefined },\n related !== undefined ? { relatedRequestId: related } : undefined,\n );\n } catch {\n // session gone\n }\n }\n }\n\n /**\n * Re-read an upstream's tools, every page (mcp-kit's `readAllPages`): at most 20 requests, each\n * under the upstream's `timeout_ms`, ending at a cursor already followed. It used to follow\n * `nextCursor` with no bound, so an upstream that echoed its cursor kept the proxy asking for\n * the same page forever. A refresh that fails, or stops at the 20-page / 2,000-tool ceiling,\n * changes nothing: the agent keeps the last good list, and the log says why.\n */\n private async refreshTools(name: string): Promise<void> {\n const conn = this.connections.get(name);\n if (!conn?.connected) return;\n if (conn.capabilities && !conn.capabilities.tools) {\n conn.tools = [];\n return;\n }\n const kept = () =>\n `keeping the last good list (${conn.tools.length} tool${conn.tools.length === 1 ? \"\" : \"s\"})`;\n try {\n const read = await readAllPages<Tool>(async (cursor) => {\n const page = await conn.client.listTools(cursor ? { cursor } : undefined, {\n timeout: conn.upstream.timeout_ms,\n });\n return { items: page.tools, nextCursor: page.nextCursor };\n });\n if (read.truncated) {\n this.log(`tools/list for \"${name}\" not applied: ${read.truncated.reason}; ${kept()}`);\n return;\n }\n conn.tools = read.items;\n } catch (err) {\n this.log(\n `tools/list failed for \"${name}\": ${err instanceof Error ? err.message : String(err)}; ${kept()}`,\n );\n }\n }\n\n private rebuildExposed(): void {\n const taken = new Set<string>();\n const out: ExposedTool[] = [];\n const order = [...this.policy.upstreams.map((u) => u.name), ...Object.keys(this.testClients)];\n for (const name of order) {\n const conn = this.connections.get(name);\n if (!conn) continue;\n const prefix =\n conn.upstream.prefix === true\n ? name\n : typeof conn.upstream.prefix === \"string\"\n ? conn.upstream.prefix\n : undefined;\n for (const tool of conn.tools) {\n let exposedName = prefix ? `${prefix}__${tool.name}` : tool.name;\n if (taken.has(exposedName)) exposedName = `${name}__${tool.name}`;\n if (taken.has(exposedName)) {\n this.log(`skipping duplicate tool ${exposedName} from ${name}`);\n continue;\n }\n taken.add(exposedName);\n out.push({\n name: exposedName,\n upstream: name,\n original: tool.name,\n tool,\n classification: classifyTool(\n {\n name: exposedName,\n description: tool.description,\n annotations: tool.annotations,\n inputSchema: tool.inputSchema,\n outputSchema: tool.outputSchema,\n },\n this.policy,\n ),\n });\n }\n }\n this.exposed = out;\n }\n\n listTools(agent?: AgentScope | null): ExposedTool[] {\n if (agent?.upstreams) return this.exposed.filter((t) => agent.upstreams!.includes(t.upstream));\n return this.exposed;\n }\n\n findTool(name: string): ExposedTool | undefined {\n return this.exposed.find((t) => t.name === name);\n }\n\n upstreamStatus(): UpstreamStatus[] {\n return [...this.connections.values()].map((c) => ({\n name: c.upstream.name,\n connected: c.connected,\n tools: c.tools.length,\n transport: c.upstream.url ? \"http\" : \"stdio\",\n error: c.error,\n }));\n }\n\n attach(session: DownstreamSession): void {\n this.sessions.add(session);\n }\n detach(session: DownstreamSession): void {\n this.sessions.delete(session);\n }\n\n /** Run a tool call through the policy engine and, if allowed, the upstream. */\n async callTool(\n name: string,\n args: unknown,\n ctx: CallContext,\n ): Promise<{ result: GuardResult; tool?: ExposedTool }> {\n const tool = this.findTool(name);\n const agent = ctx.agent === undefined ? this.agent : ctx.agent;\n if (!tool) {\n const result = await this.guard.run(\n { tool: { name }, args, runId: ctx.runId, agent, sessionId: ctx.sessionId },\n async () => {\n throw new GuardError({\n code: \"UNKNOWN_TOOL\",\n cause: `no upstream exposes a tool named \"${name}\"`,\n fix: \"call tools/list and use one of the listed names\",\n retryable: false,\n });\n },\n );\n return { result };\n }\n const conn = this.connections.get(tool.upstream);\n const track = (): (() => void) => {\n if (!ctx.session || ctx.requestId === undefined) return () => undefined;\n const list = ctx.session.inflight.get(tool.upstream) ?? [];\n list.push(ctx.requestId);\n ctx.session.inflight.set(tool.upstream, list);\n return () => {\n const l = ctx.session!.inflight.get(tool.upstream) ?? [];\n const i = l.indexOf(ctx.requestId!);\n if (i >= 0) l.splice(i, 1);\n };\n };\n const result = await this.guard.run(\n {\n tool: {\n name: tool.name,\n description: tool.tool.description,\n annotations: tool.tool.annotations,\n inputSchema: tool.tool.inputSchema,\n outputSchema: tool.tool.outputSchema,\n },\n args,\n runId: ctx.runId,\n agent,\n sessionId: ctx.sessionId,\n upstream: tool.upstream,\n },\n async (finalArgs) => {\n if (!conn?.connected) {\n throw new GuardError({\n code: \"UPSTREAM_ERROR\",\n cause: `upstream \"${tool.upstream}\" is not connected${conn?.error ? ` (${conn.error})` : \"\"}`,\n fix: \"check the upstream command/url in okgate.yaml and restart the proxy\",\n retryable: true,\n });\n }\n const untrack = track();\n try {\n return (await conn.client.callTool(\n { name: tool.original, arguments: (finalArgs ?? {}) as Record<string, unknown> },\n undefined,\n {\n timeout: conn.upstream.timeout_ms,\n resetTimeoutOnProgress: true,\n onprogress: ctx.onprogress,\n },\n )) as CallToolResult;\n } finally {\n untrack();\n }\n },\n );\n return { result, tool };\n }\n\n private connectedWith(\n capability: \"resources\" | \"prompts\" | \"completions\" | \"logging\",\n ): Connection[] {\n return [...this.connections.values()].filter(\n (c) => c.connected && (c.capabilities?.[capability] || c.capabilities === undefined),\n );\n }\n\n async listResources(): Promise<ListResourcesResult> {\n const resources: Resource[] = [];\n for (const conn of this.connectedWith(\"resources\")) {\n try {\n const page = await conn.client.listResources(undefined, {\n timeout: conn.upstream.timeout_ms,\n });\n for (const r of page.resources) {\n this.resourceOwner.set(r.uri, conn.upstream.name);\n resources.push(r);\n }\n } catch {\n // upstream has no resources\n }\n }\n return { resources };\n }\n\n async listResourceTemplates(): Promise<ListResourceTemplatesResult> {\n const resourceTemplates: ResourceTemplate[] = [];\n for (const conn of this.connectedWith(\"resources\")) {\n try {\n const page = await conn.client.listResourceTemplates(undefined, {\n timeout: conn.upstream.timeout_ms,\n });\n for (const t of page.resourceTemplates) {\n this.templateOwner.set(t.uriTemplate, conn.upstream.name);\n resourceTemplates.push(t);\n }\n } catch {\n // none\n }\n }\n return { resourceTemplates };\n }\n\n private ownerForUri(uri: string): Connection[] {\n const owner = this.resourceOwner.get(uri);\n if (owner && this.connections.get(owner)?.connected) return [this.connections.get(owner)!];\n for (const [template, name] of this.templateOwner) {\n if (templateMatches(template, uri) && this.connections.get(name)?.connected)\n return [this.connections.get(name)!];\n }\n return this.connectedWith(\"resources\");\n }\n\n async readResource(uri: string): Promise<ReadResourceResult> {\n let lastError: unknown;\n for (const conn of this.ownerForUri(uri)) {\n try {\n const result = await conn.client.readResource(\n { uri },\n { timeout: conn.upstream.timeout_ms },\n );\n this.resourceOwner.set(uri, conn.upstream.name);\n return result;\n } catch (err) {\n lastError = err;\n }\n }\n throw lastError ?? new Error(`no upstream serves resource ${uri}`);\n }\n\n async subscribe(uri: string, on: boolean): Promise<void> {\n for (const conn of this.ownerForUri(uri)) {\n try {\n if (on) await conn.client.subscribeResource({ uri });\n else await conn.client.unsubscribeResource({ uri });\n return;\n } catch {\n // try next\n }\n }\n }\n\n async listPrompts(): Promise<ListPromptsResult> {\n const prompts: Prompt[] = [];\n const taken = new Set<string>();\n this.promptOwner.clear();\n for (const conn of this.connectedWith(\"prompts\")) {\n try {\n const page = await conn.client.listPrompts(undefined, {\n timeout: conn.upstream.timeout_ms,\n });\n for (const p of page.prompts) {\n const name = taken.has(p.name) ? `${conn.upstream.name}__${p.name}` : p.name;\n taken.add(name);\n this.promptOwner.set(name, { upstream: conn.upstream.name, original: p.name });\n prompts.push({ ...p, name });\n }\n } catch {\n // none\n }\n }\n return { prompts };\n }\n\n async getPrompt(\n name: string,\n args: Record<string, string> | undefined,\n ): Promise<GetPromptResult> {\n if (this.promptOwner.size === 0) await this.listPrompts();\n const owner = this.promptOwner.get(name);\n const conns = owner ? [this.connections.get(owner.upstream)!] : this.connectedWith(\"prompts\");\n let lastError: unknown;\n for (const conn of conns) {\n try {\n return await conn.client.getPrompt(\n { name: owner?.original ?? name, arguments: args },\n { timeout: conn.upstream.timeout_ms },\n );\n } catch (err) {\n lastError = err;\n }\n }\n throw lastError ?? new Error(`no upstream serves prompt ${name}`);\n }\n\n async complete(params: CompleteRequest[\"params\"]): Promise<CompleteResult> {\n let conns: Connection[];\n if (params.ref.type === \"ref/prompt\") {\n if (this.promptOwner.size === 0) await this.listPrompts();\n const owner = this.promptOwner.get(params.ref.name);\n conns = owner ? [this.connections.get(owner.upstream)!] : this.connectedWith(\"completions\");\n if (owner) params = { ...params, ref: { ...params.ref, name: owner.original } };\n } else {\n if (this.templateOwner.size === 0) await this.listResourceTemplates();\n conns = this.ownerForUri(params.ref.uri);\n }\n let lastError: unknown;\n for (const conn of conns) {\n try {\n return await conn.client.complete(params, { timeout: conn.upstream.timeout_ms });\n } catch (err) {\n lastError = err;\n }\n }\n throw lastError ?? new Error(\"no upstream supports completions\");\n }\n\n async setLevel(level: LoggingLevel): Promise<void> {\n await Promise.all(\n this.connectedWith(\"logging\").map((c) =>\n c.client.setLoggingLevel(level).catch(() => undefined),\n ),\n );\n }\n\n async close(): Promise<void> {\n this.closing = true;\n for (const conn of this.connections.values()) {\n try {\n await conn.client.close();\n } catch {\n // already closed\n }\n }\n this.connections.clear();\n }\n}\n\nfunction templateMatches(template: string, uri: string): boolean {\n const re = new RegExp(\n \"^\" + template.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\\\\\{[^}]+\\\\\\}/g, \"[^/]+\") + \"$\",\n );\n return re.test(uri);\n}\n\nexport async function withTimeout<T>(promise: Promise<T>, ms: number, what: string): Promise<T> {\n let timer: NodeJS.Timeout | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`${what} timed out after ${ms}ms`)), ms);\n });\n try {\n return await Promise.race([promise, timeout]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"],"mappings":"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","names":["result"]}
|