@agentwares/agentguard 0.1.6 → 0.1.7

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/dist/index.js CHANGED
@@ -840,514 +840,6 @@ import {
840
840
  classifyTool,
841
841
  upstreamHeaders
842
842
  } from "@agentwares/agentguard-core";
843
- var ProxyRuntime = class {
844
- loaded;
845
- guard;
846
- agent;
847
- defaultRunId;
848
- configured;
849
- sessions = /* @__PURE__ */ new Set();
850
- connections = /* @__PURE__ */ new Map();
851
- exposed = [];
852
- resourceOwner = /* @__PURE__ */ new Map();
853
- templateOwner = /* @__PURE__ */ new Map();
854
- promptOwner = /* @__PURE__ */ new Map();
855
- log;
856
- connectTimeoutMs;
857
- testClients;
858
- /** stop relaying upstream stderr once we are tearing down — shutdown noise is not the user's problem */
859
- closing = false;
860
- constructor(opts) {
861
- this.loaded = opts.loaded;
862
- this.guard = opts.guard;
863
- this.agent = opts.agent;
864
- this.defaultRunId = opts.defaultRunId;
865
- this.configured = opts.configured ?? true;
866
- this.log = opts.log ?? ((line) => process.stderr.write(`[agentguard] ${line}
867
- `));
868
- this.connectTimeoutMs = opts.connectTimeoutMs ?? 15e3;
869
- this.testClients = opts.clients ?? {};
870
- }
871
- get policy() {
872
- return this.loaded.policy;
873
- }
874
- async start() {
875
- await Promise.all(this.policy.upstreams.map((u) => this.connect(u)));
876
- for (const [name, client] of Object.entries(this.testClients)) {
877
- if (this.connections.has(name)) continue;
878
- const upstream = {
879
- name,
880
- command: "in-memory",
881
- args: [],
882
- env: {},
883
- headers: {},
884
- prefix: false,
885
- timeout_ms: 6e4
886
- };
887
- const conn = {
888
- upstream,
889
- client,
890
- tools: [],
891
- capabilities: client.getServerCapabilities(),
892
- connected: true
893
- };
894
- this.connections.set(name, conn);
895
- this.wire(conn);
896
- await this.refreshTools(name);
897
- }
898
- this.rebuildExposed();
899
- const status = this.upstreamStatus();
900
- this.log(
901
- `connected ${status.filter((s) => s.connected).length}/${status.length} upstreams, ${this.exposed.length} tools, mode ${this.policy.mode}`
902
- );
903
- }
904
- async connect(upstream) {
905
- const client = new Client(
906
- { name: "agentguard", version: version() },
907
- { capabilities: { sampling: {}, elicitation: {} } }
908
- );
909
- const conn = {
910
- upstream,
911
- client,
912
- tools: [],
913
- capabilities: void 0,
914
- connected: false
915
- };
916
- this.connections.set(upstream.name, conn);
917
- try {
918
- const transport = upstream.url ? new StreamableHTTPClientTransport(new URL(upstream.url), {
919
- requestInit: { headers: upstreamHeaders(upstream) }
920
- }) : new StdioClientTransport({
921
- command: upstream.command,
922
- args: upstream.args,
923
- env: { ...getDefaultEnvironment(), ...upstream.env },
924
- cwd: upstream.cwd,
925
- stderr: "pipe"
926
- });
927
- if (transport instanceof StdioClientTransport) {
928
- transport.stderr?.on("data", (chunk) => {
929
- if (this.closing) return;
930
- for (const line of chunk.toString("utf8").split("\n"))
931
- if (line.trim()) this.log(`${upstream.name}: ${line}`);
932
- });
933
- }
934
- await withTimeout(
935
- client.connect(transport),
936
- this.connectTimeoutMs,
937
- `connect to upstream "${upstream.name}"`
938
- );
939
- conn.capabilities = client.getServerCapabilities();
940
- conn.connected = true;
941
- this.wire(conn);
942
- await this.refreshTools(upstream.name);
943
- } catch (err) {
944
- conn.connected = false;
945
- conn.error = err instanceof Error ? err.message : String(err);
946
- this.log(`upstream "${upstream.name}" unavailable: ${conn.error}`);
947
- }
948
- }
949
- wire(conn) {
950
- const { client, upstream } = conn;
951
- client.onclose = () => {
952
- conn.connected = false;
953
- conn.error = "connection closed";
954
- if (!this.closing) this.log(`upstream "${upstream.name}" closed`);
955
- };
956
- client.setNotificationHandler(LoggingMessageNotificationSchema, async (n) => {
957
- await this.broadcast(upstream.name, n.method, n.params);
958
- });
959
- client.setNotificationHandler(ResourceUpdatedNotificationSchema, async (n) => {
960
- await this.broadcast(upstream.name, n.method, n.params);
961
- });
962
- client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
963
- this.resourceOwner.clear();
964
- await this.broadcast(upstream.name, "notifications/resources/list_changed", void 0);
965
- });
966
- client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {
967
- this.promptOwner.clear();
968
- await this.broadcast(upstream.name, "notifications/prompts/list_changed", void 0);
969
- });
970
- client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
971
- await this.refreshTools(upstream.name);
972
- this.rebuildExposed();
973
- for (const s of this.sessions) s.server.server.sendToolListChanged().catch(() => void 0);
974
- });
975
- try {
976
- client.setRequestHandler(CreateMessageRequestSchema, async (req) => {
977
- const session = this.pickSession(upstream.name);
978
- if (!session) throw new Error("no downstream client is connected to relay sampling to");
979
- const related = session.inflight.get(upstream.name)?.at(-1);
980
- return session.server.server.createMessage(req.params, { relatedRequestId: related });
981
- });
982
- client.setRequestHandler(ElicitRequestSchema, async (req) => {
983
- const session = this.pickSession(upstream.name);
984
- if (!session) throw new Error("no downstream client is connected to relay elicitation to");
985
- const related = session.inflight.get(upstream.name)?.at(-1);
986
- return session.server.server.elicitInput(req.params, { relatedRequestId: related });
987
- });
988
- } catch {
989
- }
990
- }
991
- pickSession(upstream) {
992
- let best;
993
- for (const s of this.sessions) {
994
- if ((s.inflight.get(upstream)?.length ?? 0) > 0) return s;
995
- if (!best || s.lastActive > best.lastActive) best = s;
996
- }
997
- return best;
998
- }
999
- async broadcast(upstream, method, params) {
1000
- for (const s of this.sessions) {
1001
- const related = s.inflight.get(upstream)?.at(-1);
1002
- try {
1003
- await s.server.server.notification(
1004
- { method, params },
1005
- related !== void 0 ? { relatedRequestId: related } : void 0
1006
- );
1007
- } catch {
1008
- }
1009
- }
1010
- }
1011
- async refreshTools(name) {
1012
- const conn = this.connections.get(name);
1013
- if (!conn?.connected) return;
1014
- if (conn.capabilities && !conn.capabilities.tools) {
1015
- conn.tools = [];
1016
- return;
1017
- }
1018
- try {
1019
- const tools = [];
1020
- let cursor;
1021
- do {
1022
- const page = await conn.client.listTools(cursor ? { cursor } : void 0, {
1023
- timeout: conn.upstream.timeout_ms
1024
- });
1025
- tools.push(...page.tools);
1026
- cursor = page.nextCursor;
1027
- } while (cursor);
1028
- conn.tools = tools;
1029
- } catch (err) {
1030
- this.log(
1031
- `tools/list failed for "${name}": ${err instanceof Error ? err.message : String(err)}`
1032
- );
1033
- conn.tools = [];
1034
- }
1035
- }
1036
- rebuildExposed() {
1037
- const taken = /* @__PURE__ */ new Set();
1038
- const out = [];
1039
- const order = [...this.policy.upstreams.map((u) => u.name), ...Object.keys(this.testClients)];
1040
- for (const name of order) {
1041
- const conn = this.connections.get(name);
1042
- if (!conn) continue;
1043
- const prefix = conn.upstream.prefix === true ? name : typeof conn.upstream.prefix === "string" ? conn.upstream.prefix : void 0;
1044
- for (const tool of conn.tools) {
1045
- let exposedName = prefix ? `${prefix}__${tool.name}` : tool.name;
1046
- if (taken.has(exposedName)) exposedName = `${name}__${tool.name}`;
1047
- if (taken.has(exposedName)) {
1048
- this.log(`skipping duplicate tool ${exposedName} from ${name}`);
1049
- continue;
1050
- }
1051
- taken.add(exposedName);
1052
- out.push({
1053
- name: exposedName,
1054
- upstream: name,
1055
- original: tool.name,
1056
- tool,
1057
- classification: classifyTool(
1058
- {
1059
- name: exposedName,
1060
- description: tool.description,
1061
- annotations: tool.annotations,
1062
- inputSchema: tool.inputSchema,
1063
- outputSchema: tool.outputSchema
1064
- },
1065
- this.policy
1066
- )
1067
- });
1068
- }
1069
- }
1070
- this.exposed = out;
1071
- }
1072
- listTools(agent) {
1073
- if (agent?.upstreams) return this.exposed.filter((t) => agent.upstreams.includes(t.upstream));
1074
- return this.exposed;
1075
- }
1076
- findTool(name) {
1077
- return this.exposed.find((t) => t.name === name);
1078
- }
1079
- upstreamStatus() {
1080
- return [...this.connections.values()].map((c) => ({
1081
- name: c.upstream.name,
1082
- connected: c.connected,
1083
- tools: c.tools.length,
1084
- transport: c.upstream.url ? "http" : "stdio",
1085
- error: c.error
1086
- }));
1087
- }
1088
- attach(session) {
1089
- this.sessions.add(session);
1090
- }
1091
- detach(session) {
1092
- this.sessions.delete(session);
1093
- }
1094
- /** Run a tool call through the policy engine and, if allowed, the upstream. */
1095
- async callTool(name, args, ctx) {
1096
- const tool = this.findTool(name);
1097
- const agent = ctx.agent === void 0 ? this.agent : ctx.agent;
1098
- if (!tool) {
1099
- const result2 = await this.guard.run(
1100
- { tool: { name }, args, runId: ctx.runId, agent, sessionId: ctx.sessionId },
1101
- async () => {
1102
- throw new GuardError({
1103
- code: "UNKNOWN_TOOL",
1104
- cause: `no upstream exposes a tool named "${name}"`,
1105
- fix: "call tools/list and use one of the listed names",
1106
- retryable: false
1107
- });
1108
- }
1109
- );
1110
- return { result: result2 };
1111
- }
1112
- const conn = this.connections.get(tool.upstream);
1113
- const track = () => {
1114
- if (!ctx.session || ctx.requestId === void 0) return () => void 0;
1115
- const list = ctx.session.inflight.get(tool.upstream) ?? [];
1116
- list.push(ctx.requestId);
1117
- ctx.session.inflight.set(tool.upstream, list);
1118
- return () => {
1119
- const l = ctx.session.inflight.get(tool.upstream) ?? [];
1120
- const i = l.indexOf(ctx.requestId);
1121
- if (i >= 0) l.splice(i, 1);
1122
- };
1123
- };
1124
- const result = await this.guard.run(
1125
- {
1126
- tool: {
1127
- name: tool.name,
1128
- description: tool.tool.description,
1129
- annotations: tool.tool.annotations,
1130
- inputSchema: tool.tool.inputSchema,
1131
- outputSchema: tool.tool.outputSchema
1132
- },
1133
- args,
1134
- runId: ctx.runId,
1135
- agent,
1136
- sessionId: ctx.sessionId,
1137
- upstream: tool.upstream
1138
- },
1139
- async (finalArgs) => {
1140
- if (!conn?.connected) {
1141
- throw new GuardError({
1142
- code: "UPSTREAM_ERROR",
1143
- cause: `upstream "${tool.upstream}" is not connected${conn?.error ? ` (${conn.error})` : ""}`,
1144
- fix: "check the upstream command/url in agentguard.yaml and restart the proxy",
1145
- retryable: true
1146
- });
1147
- }
1148
- const untrack = track();
1149
- try {
1150
- return await conn.client.callTool(
1151
- { name: tool.original, arguments: finalArgs ?? {} },
1152
- void 0,
1153
- {
1154
- timeout: conn.upstream.timeout_ms,
1155
- resetTimeoutOnProgress: true,
1156
- onprogress: ctx.onprogress
1157
- }
1158
- );
1159
- } finally {
1160
- untrack();
1161
- }
1162
- }
1163
- );
1164
- return { result, tool };
1165
- }
1166
- connectedWith(capability) {
1167
- return [...this.connections.values()].filter(
1168
- (c) => c.connected && (c.capabilities?.[capability] || c.capabilities === void 0)
1169
- );
1170
- }
1171
- async listResources() {
1172
- const resources = [];
1173
- for (const conn of this.connectedWith("resources")) {
1174
- try {
1175
- const page = await conn.client.listResources(void 0, {
1176
- timeout: conn.upstream.timeout_ms
1177
- });
1178
- for (const r of page.resources) {
1179
- this.resourceOwner.set(r.uri, conn.upstream.name);
1180
- resources.push(r);
1181
- }
1182
- } catch {
1183
- }
1184
- }
1185
- return { resources };
1186
- }
1187
- async listResourceTemplates() {
1188
- const resourceTemplates = [];
1189
- for (const conn of this.connectedWith("resources")) {
1190
- try {
1191
- const page = await conn.client.listResourceTemplates(void 0, {
1192
- timeout: conn.upstream.timeout_ms
1193
- });
1194
- for (const t of page.resourceTemplates) {
1195
- this.templateOwner.set(t.uriTemplate, conn.upstream.name);
1196
- resourceTemplates.push(t);
1197
- }
1198
- } catch {
1199
- }
1200
- }
1201
- return { resourceTemplates };
1202
- }
1203
- ownerForUri(uri) {
1204
- const owner = this.resourceOwner.get(uri);
1205
- if (owner && this.connections.get(owner)?.connected) return [this.connections.get(owner)];
1206
- for (const [template, name] of this.templateOwner) {
1207
- if (templateMatches(template, uri) && this.connections.get(name)?.connected)
1208
- return [this.connections.get(name)];
1209
- }
1210
- return this.connectedWith("resources");
1211
- }
1212
- async readResource(uri) {
1213
- let lastError;
1214
- for (const conn of this.ownerForUri(uri)) {
1215
- try {
1216
- const result = await conn.client.readResource(
1217
- { uri },
1218
- { timeout: conn.upstream.timeout_ms }
1219
- );
1220
- this.resourceOwner.set(uri, conn.upstream.name);
1221
- return result;
1222
- } catch (err) {
1223
- lastError = err;
1224
- }
1225
- }
1226
- throw lastError ?? new Error(`no upstream serves resource ${uri}`);
1227
- }
1228
- async subscribe(uri, on) {
1229
- for (const conn of this.ownerForUri(uri)) {
1230
- try {
1231
- if (on) await conn.client.subscribeResource({ uri });
1232
- else await conn.client.unsubscribeResource({ uri });
1233
- return;
1234
- } catch {
1235
- }
1236
- }
1237
- }
1238
- async listPrompts() {
1239
- const prompts = [];
1240
- const taken = /* @__PURE__ */ new Set();
1241
- this.promptOwner.clear();
1242
- for (const conn of this.connectedWith("prompts")) {
1243
- try {
1244
- const page = await conn.client.listPrompts(void 0, {
1245
- timeout: conn.upstream.timeout_ms
1246
- });
1247
- for (const p of page.prompts) {
1248
- const name = taken.has(p.name) ? `${conn.upstream.name}__${p.name}` : p.name;
1249
- taken.add(name);
1250
- this.promptOwner.set(name, { upstream: conn.upstream.name, original: p.name });
1251
- prompts.push({ ...p, name });
1252
- }
1253
- } catch {
1254
- }
1255
- }
1256
- return { prompts };
1257
- }
1258
- async getPrompt(name, args) {
1259
- if (this.promptOwner.size === 0) await this.listPrompts();
1260
- const owner = this.promptOwner.get(name);
1261
- const conns = owner ? [this.connections.get(owner.upstream)] : this.connectedWith("prompts");
1262
- let lastError;
1263
- for (const conn of conns) {
1264
- try {
1265
- return await conn.client.getPrompt(
1266
- { name: owner?.original ?? name, arguments: args },
1267
- { timeout: conn.upstream.timeout_ms }
1268
- );
1269
- } catch (err) {
1270
- lastError = err;
1271
- }
1272
- }
1273
- throw lastError ?? new Error(`no upstream serves prompt ${name}`);
1274
- }
1275
- async complete(params) {
1276
- let conns;
1277
- if (params.ref.type === "ref/prompt") {
1278
- if (this.promptOwner.size === 0) await this.listPrompts();
1279
- const owner = this.promptOwner.get(params.ref.name);
1280
- conns = owner ? [this.connections.get(owner.upstream)] : this.connectedWith("completions");
1281
- if (owner) params = { ...params, ref: { ...params.ref, name: owner.original } };
1282
- } else {
1283
- if (this.templateOwner.size === 0) await this.listResourceTemplates();
1284
- conns = this.ownerForUri(params.ref.uri);
1285
- }
1286
- let lastError;
1287
- for (const conn of conns) {
1288
- try {
1289
- return await conn.client.complete(params, { timeout: conn.upstream.timeout_ms });
1290
- } catch (err) {
1291
- lastError = err;
1292
- }
1293
- }
1294
- throw lastError ?? new Error("no upstream supports completions");
1295
- }
1296
- async setLevel(level) {
1297
- await Promise.all(
1298
- this.connectedWith("logging").map(
1299
- (c) => c.client.setLoggingLevel(level).catch(() => void 0)
1300
- )
1301
- );
1302
- }
1303
- async close() {
1304
- this.closing = true;
1305
- for (const conn of this.connections.values()) {
1306
- try {
1307
- await conn.client.close();
1308
- } catch {
1309
- }
1310
- }
1311
- this.connections.clear();
1312
- }
1313
- };
1314
- function templateMatches(template, uri) {
1315
- const re = new RegExp(
1316
- "^" + template.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\{[^}]+\\\}/g, "[^/]+") + "$"
1317
- );
1318
- return re.test(uri);
1319
- }
1320
- async function withTimeout(promise, ms, what) {
1321
- let timer;
1322
- const timeout = new Promise((_, reject) => {
1323
- timer = setTimeout(() => reject(new Error(`${what} timed out after ${ms}ms`)), ms);
1324
- });
1325
- try {
1326
- return await Promise.race([promise, timeout]);
1327
- } finally {
1328
- if (timer) clearTimeout(timer);
1329
- }
1330
- }
1331
-
1332
- // src/proxy/server.ts
1333
- import { McpServer as McpServer3 } from "@modelcontextprotocol/sdk/server/mcp.js";
1334
- import {
1335
- CallToolRequestSchema as CallToolRequestSchema2,
1336
- CompleteRequestSchema,
1337
- GetPromptRequestSchema,
1338
- ListPromptsRequestSchema,
1339
- ListResourceTemplatesRequestSchema,
1340
- ListResourcesRequestSchema,
1341
- ListToolsRequestSchema as ListToolsRequestSchema2,
1342
- ReadResourceRequestSchema,
1343
- SetLevelRequestSchema,
1344
- SubscribeRequestSchema as SubscribeRequestSchema2,
1345
- UnsubscribeRequestSchema as UnsubscribeRequestSchema2
1346
- } from "@modelcontextprotocol/sdk/types.js";
1347
- import {
1348
- keyFromHeaders,
1349
- resolveAgent
1350
- } from "@agentwares/agentguard-core";
1351
843
 
1352
844
  // ../../packages/mcp-kit/dist/chunk-7LRFDQNC.js
1353
845
  import { completable } from "@modelcontextprotocol/sdk/server/completable.js";
@@ -2052,391 +1544,951 @@ function contextFromExtra(extra) {
2052
1544
  }
2053
1545
  };
2054
1546
  }
2055
- function createMcpServer(opts) {
2056
- const byName = /* @__PURE__ */ new Map();
2057
- for (const tool of opts.tools) {
2058
- if (byName.has(tool.name)) throw new Error(`duplicate tool name: ${tool.name}`);
2059
- byName.set(tool.name, tool);
2060
- }
2061
- const server = new McpServer(
2062
- { name: opts.name, version: opts.version, title: opts.title, websiteUrl: opts.websiteUrl },
2063
- { instructions: opts.instructions, capabilities: { logging: {}, ...opts.capabilities } }
2064
- );
2065
- const registered = /* @__PURE__ */ new Map();
2066
- for (const tool of byName.values()) {
2067
- const config = {
2068
- title: tool.title,
2069
- description: tool.description,
2070
- inputSchema: tool.input,
2071
- annotations: tool.annotations
2072
- };
2073
- if (isZodObject(tool.output)) config.outputSchema = tool.output;
2074
- registered.set(
2075
- tool.name,
2076
- server.registerTool(tool.name, config, () => {
2077
- throw new Error("unreachable: mcp-kit dispatches tools/call itself");
2078
- })
2079
- );
2080
- }
2081
- if (byName.size > 0) {
2082
- server.server.setRequestHandler(ListToolsRequestSchema, async () => {
2083
- const enabled = [...byName.values()].filter(
2084
- (tool) => registered.get(tool.name)?.enabled !== false
2085
- );
2086
- return {
2087
- tools: listToolManifest(enabled).map((entry) => ({
2088
- ...entry,
2089
- inputSchema: entry.inputSchema,
2090
- outputSchema: entry.outputSchema
2091
- }))
2092
- };
2093
- });
2094
- server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
2095
- const name = request.params.name;
2096
- const tool = byName.get(name);
2097
- const entry = registered.get(name);
2098
- if (!tool || !entry) throw new McpError(ErrorCode.InvalidParams, `Tool ${name} not found`);
2099
- if (!entry.enabled) throw new McpError(ErrorCode.InvalidParams, `Tool ${name} disabled`);
2100
- return tool.invoke(request.params.arguments ?? {}, contextFromExtra(extra));
1547
+ function createMcpServer(opts) {
1548
+ const byName = /* @__PURE__ */ new Map();
1549
+ for (const tool of opts.tools) {
1550
+ if (byName.has(tool.name)) throw new Error(`duplicate tool name: ${tool.name}`);
1551
+ byName.set(tool.name, tool);
1552
+ }
1553
+ const server = new McpServer(
1554
+ { name: opts.name, version: opts.version, title: opts.title, websiteUrl: opts.websiteUrl },
1555
+ { instructions: opts.instructions, capabilities: { logging: {}, ...opts.capabilities } }
1556
+ );
1557
+ const registered = /* @__PURE__ */ new Map();
1558
+ for (const tool of byName.values()) {
1559
+ const config = {
1560
+ title: tool.title,
1561
+ description: tool.description,
1562
+ inputSchema: tool.input,
1563
+ annotations: tool.annotations
1564
+ };
1565
+ if (isZodObject(tool.output)) config.outputSchema = tool.output;
1566
+ registered.set(
1567
+ tool.name,
1568
+ server.registerTool(tool.name, config, () => {
1569
+ throw new Error("unreachable: mcp-kit dispatches tools/call itself");
1570
+ })
1571
+ );
1572
+ }
1573
+ if (byName.size > 0) {
1574
+ server.server.setRequestHandler(ListToolsRequestSchema, async () => {
1575
+ const enabled = [...byName.values()].filter(
1576
+ (tool) => registered.get(tool.name)?.enabled !== false
1577
+ );
1578
+ return {
1579
+ tools: listToolManifest(enabled).map((entry) => ({
1580
+ ...entry,
1581
+ inputSchema: entry.inputSchema,
1582
+ outputSchema: entry.outputSchema
1583
+ }))
1584
+ };
1585
+ });
1586
+ server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
1587
+ const name = request.params.name;
1588
+ const tool = byName.get(name);
1589
+ const entry = registered.get(name);
1590
+ if (!tool || !entry) throw new McpError(ErrorCode.InvalidParams, `Tool ${name} not found`);
1591
+ if (!entry.enabled) throw new McpError(ErrorCode.InvalidParams, `Tool ${name} disabled`);
1592
+ return tool.invoke(request.params.arguments ?? {}, contextFromExtra(extra));
1593
+ });
1594
+ }
1595
+ return server;
1596
+ }
1597
+ function toJsonSchema(schema, io = "input") {
1598
+ const json2 = z4.toJSONSchema(schema, { io, target: "draft-2020-12" });
1599
+ if (isZodObject(schema) && schema._zod.def.catchall === void 0 && json2.additionalProperties === void 0) {
1600
+ json2.additionalProperties = false;
1601
+ }
1602
+ return json2;
1603
+ }
1604
+ function listToolManifest(tools) {
1605
+ return tools.map((tool) => {
1606
+ const entry = {
1607
+ name: tool.name,
1608
+ description: tool.description,
1609
+ inputSchema: toJsonSchema(tool.input, "input")
1610
+ };
1611
+ if (tool.title !== void 0) entry.title = tool.title;
1612
+ if (isZodObject(tool.output)) entry.outputSchema = toJsonSchema(tool.output, "output");
1613
+ if (tool.annotations !== void 0) entry.annotations = tool.annotations;
1614
+ return entry;
1615
+ });
1616
+ }
1617
+ var DEFAULT_CORS = {
1618
+ origin: "*",
1619
+ methods: "GET, POST, DELETE, OPTIONS",
1620
+ headers: "Content-Type, Accept, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, PAYMENT, X-PAYMENT",
1621
+ exposeHeaders: "Mcp-Session-Id, Mcp-Protocol-Version, WWW-Authenticate, X-Payment-Requirements, PAYMENT-REQUIRED",
1622
+ maxAge: 86400
1623
+ };
1624
+ var DEFAULT_SESSION_TTL_MS = 30 * 6e4;
1625
+ function corsHeaders(cors) {
1626
+ if (!cors) return {};
1627
+ const c = { ...DEFAULT_CORS, ...typeof cors === "object" ? cors : {} };
1628
+ return {
1629
+ "Access-Control-Allow-Origin": c.origin,
1630
+ "Access-Control-Allow-Methods": c.methods,
1631
+ "Access-Control-Allow-Headers": c.headers,
1632
+ "Access-Control-Expose-Headers": c.exposeHeaders,
1633
+ "Access-Control-Max-Age": String(c.maxAge)
1634
+ };
1635
+ }
1636
+ function jsonResponse(body, status, headers = {}) {
1637
+ return new Response(JSON.stringify(body), {
1638
+ status,
1639
+ headers: { "Content-Type": "application/json", "Cache-Control": "no-store", ...headers }
1640
+ });
1641
+ }
1642
+ function methodNotAllowed(method, allow, cors) {
1643
+ return jsonResponse(
1644
+ {
1645
+ code: "METHOD_NOT_ALLOWED",
1646
+ cause: `${method} is not supported here without a session`,
1647
+ fix: "send JSON-RPC over POST with `Accept: application/json, text/event-stream` (start with `initialize`)",
1648
+ retryable: false
1649
+ },
1650
+ 405,
1651
+ { Allow: allow, ...cors }
1652
+ );
1653
+ }
1654
+ function splitOptions(opts, transport) {
1655
+ if (typeof opts === "function") return { factory: opts, transport };
1656
+ const {
1657
+ cors,
1658
+ jsonResponse: jsonResponse2,
1659
+ sessions,
1660
+ allowedHosts,
1661
+ allowedOrigins,
1662
+ enableDnsRebindingProtection,
1663
+ ...server
1664
+ } = opts;
1665
+ return {
1666
+ factory: () => createMcpServer(server),
1667
+ transport: {
1668
+ cors,
1669
+ jsonResponse: jsonResponse2,
1670
+ sessions,
1671
+ allowedHosts,
1672
+ allowedOrigins,
1673
+ enableDnsRebindingProtection,
1674
+ ...transport
1675
+ }
1676
+ };
1677
+ }
1678
+ function withCors(response, cors) {
1679
+ const keys = Object.keys(cors);
1680
+ if (keys.length === 0) return response;
1681
+ const headers = new Headers(response.headers);
1682
+ for (const key of keys) headers.set(key, cors[key] ?? "");
1683
+ return new Response(response.body, {
1684
+ status: response.status,
1685
+ statusText: response.statusText,
1686
+ headers
1687
+ });
1688
+ }
1689
+ function errorResponse(err, cors) {
1690
+ const error = normalizeError(err);
1691
+ return jsonResponse(error.toJSON(), error.httpStatus, cors);
1692
+ }
1693
+ function createStatelessHandler({ factory, cors, transportBase }) {
1694
+ return async (request) => {
1695
+ if (request.method !== "POST") return methodNotAllowed(request.method, "POST, OPTIONS", cors);
1696
+ const server = factory();
1697
+ const transport = new WebStandardStreamableHTTPServerTransport({
1698
+ ...transportBase,
1699
+ sessionIdGenerator: void 0
1700
+ });
1701
+ let closed = false;
1702
+ const cleanup = async () => {
1703
+ if (closed) return;
1704
+ closed = true;
1705
+ try {
1706
+ await server.close();
1707
+ } catch {
1708
+ }
1709
+ };
1710
+ try {
1711
+ await server.connect(transport);
1712
+ const response = withCors(await transport.handleRequest(request), cors);
1713
+ if (!response.body) {
1714
+ await cleanup();
1715
+ return response;
1716
+ }
1717
+ request.signal?.addEventListener("abort", () => void cleanup(), { once: true });
1718
+ const body = response.body.pipeThrough(
1719
+ new TransformStream({ flush: () => cleanup() })
1720
+ );
1721
+ return new Response(body, {
1722
+ status: response.status,
1723
+ statusText: response.statusText,
1724
+ headers: response.headers
1725
+ });
1726
+ } catch (err) {
1727
+ await cleanup();
1728
+ return errorResponse(err, cors);
1729
+ }
1730
+ };
1731
+ }
1732
+ function createStatefulHandler({ factory, cors, transportBase }, options) {
1733
+ const ttlMs = options.ttlMs ?? DEFAULT_SESSION_TTL_MS;
1734
+ const sessions = /* @__PURE__ */ new Map();
1735
+ const drop = (id) => {
1736
+ const session = sessions.get(id);
1737
+ if (!session) return;
1738
+ sessions.delete(id);
1739
+ session.server.close().catch(() => void 0);
1740
+ };
1741
+ const sweep = () => {
1742
+ const now = Date.now();
1743
+ for (const [id, session] of sessions) if (now - session.lastSeen > ttlMs) drop(id);
1744
+ };
1745
+ return async (request) => {
1746
+ const sessionId = request.headers.get("mcp-session-id");
1747
+ if (sessionId) {
1748
+ const session = sessions.get(sessionId);
1749
+ if (!session) {
1750
+ return jsonResponse(
1751
+ {
1752
+ code: "NOT_FOUND",
1753
+ cause: "unknown or expired Mcp-Session-Id",
1754
+ fix: "send `initialize` again without an Mcp-Session-Id header and use the id from the response",
1755
+ retryable: true
1756
+ },
1757
+ 404,
1758
+ cors
1759
+ );
1760
+ }
1761
+ session.lastSeen = Date.now();
1762
+ try {
1763
+ return withCors(await session.transport.handleRequest(request), cors);
1764
+ } catch (err) {
1765
+ return errorResponse(err, cors);
1766
+ }
1767
+ }
1768
+ if (request.method !== "POST") return methodNotAllowed(request.method, "POST, OPTIONS", cors);
1769
+ sweep();
1770
+ const server = factory();
1771
+ const transport = new WebStandardStreamableHTTPServerTransport({
1772
+ ...transportBase,
1773
+ sessionIdGenerator: () => crypto.randomUUID(),
1774
+ onsessioninitialized: (id) => {
1775
+ sessions.set(id, { server, transport, lastSeen: Date.now() });
1776
+ },
1777
+ onsessionclosed: (id) => {
1778
+ sessions.delete(id);
1779
+ }
2101
1780
  });
2102
- }
2103
- return server;
1781
+ try {
1782
+ await server.connect(transport);
1783
+ const previousOnClose = transport.onclose;
1784
+ transport.onclose = () => {
1785
+ previousOnClose?.();
1786
+ if (transport.sessionId) sessions.delete(transport.sessionId);
1787
+ };
1788
+ const response = withCors(await transport.handleRequest(request), cors);
1789
+ if (!transport.sessionId) server.close().catch(() => void 0);
1790
+ return response;
1791
+ } catch (err) {
1792
+ server.close().catch(() => void 0);
1793
+ return errorResponse(err, cors);
1794
+ }
1795
+ };
2104
1796
  }
2105
- function toJsonSchema(schema, io = "input") {
2106
- const json2 = z4.toJSONSchema(schema, { io, target: "draft-2020-12" });
2107
- if (isZodObject(schema) && schema._zod.def.catchall === void 0 && json2.additionalProperties === void 0) {
2108
- json2.additionalProperties = false;
2109
- }
2110
- return json2;
1797
+ function createHttpHandler(opts, transportOptions = {}) {
1798
+ const { factory, transport: t } = splitOptions(opts, transportOptions);
1799
+ const cors = corsHeaders(t.cors);
1800
+ const sessions = t.sessions ? typeof t.sessions === "object" ? t.sessions : {} : void 0;
1801
+ const context = {
1802
+ factory,
1803
+ cors,
1804
+ transportBase: {
1805
+ enableJsonResponse: t.jsonResponse ?? sessions === void 0,
1806
+ allowedHosts: t.allowedHosts,
1807
+ allowedOrigins: t.allowedOrigins,
1808
+ enableDnsRebindingProtection: t.enableDnsRebindingProtection
1809
+ }
1810
+ };
1811
+ const handler = sessions ? createStatefulHandler(context, sessions) : createStatelessHandler(context);
1812
+ const allow = sessions ? "GET, POST, DELETE, OPTIONS" : "POST, OPTIONS";
1813
+ return async (request) => {
1814
+ if (request.method === "OPTIONS") {
1815
+ return new Response(null, { status: 204, headers: { Allow: allow, ...cors } });
1816
+ }
1817
+ return handler(request);
1818
+ };
2111
1819
  }
2112
- function listToolManifest(tools) {
2113
- return tools.map((tool) => {
2114
- const entry = {
2115
- name: tool.name,
2116
- description: tool.description,
2117
- inputSchema: toJsonSchema(tool.input, "input")
2118
- };
2119
- if (tool.title !== void 0) entry.title = tool.title;
2120
- if (isZodObject(tool.output)) entry.outputSchema = toJsonSchema(tool.output, "output");
2121
- if (tool.annotations !== void 0) entry.annotations = tool.annotations;
2122
- return entry;
2123
- });
1820
+ function localhostHosts(port) {
1821
+ const hosts = ["localhost", "127.0.0.1", "[::1]"];
1822
+ return [...hosts, ...hosts.map((h) => `${h}:${port}`)];
2124
1823
  }
2125
- var DEFAULT_CORS = {
2126
- origin: "*",
2127
- methods: "GET, POST, DELETE, OPTIONS",
2128
- headers: "Content-Type, Accept, Authorization, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, PAYMENT, X-PAYMENT",
2129
- exposeHeaders: "Mcp-Session-Id, Mcp-Protocol-Version, WWW-Authenticate, X-Payment-Requirements, PAYMENT-REQUIRED",
2130
- maxAge: 86400
2131
- };
2132
- var DEFAULT_SESSION_TTL_MS = 30 * 6e4;
2133
- function corsHeaders(cors) {
2134
- if (!cors) return {};
2135
- const c = { ...DEFAULT_CORS, ...typeof cors === "object" ? cors : {} };
2136
- return {
2137
- "Access-Control-Allow-Origin": c.origin,
2138
- "Access-Control-Allow-Methods": c.methods,
2139
- "Access-Control-Allow-Headers": c.headers,
2140
- "Access-Control-Expose-Headers": c.exposeHeaders,
2141
- "Access-Control-Max-Age": String(c.maxAge)
2142
- };
1824
+ function handleHealth(info) {
1825
+ const tools = typeof info.tools === "number" ? info.tools : info.tools.length;
1826
+ return jsonResponse({ ok: true, name: info.name, version: info.version, tools }, 200);
2143
1827
  }
2144
- function jsonResponse(body, status, headers = {}) {
2145
- return new Response(JSON.stringify(body), {
2146
- status,
2147
- headers: { "Content-Type": "application/json", "Cache-Control": "no-store", ...headers }
1828
+ async function serveNodeHttp(opts) {
1829
+ const http = await import("http");
1830
+ const host = opts.host ?? "127.0.0.1";
1831
+ const path2 = opts.path ?? "/mcp";
1832
+ const server = http.createServer((req, res) => {
1833
+ void (async () => {
1834
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? host}`);
1835
+ let response;
1836
+ if (url.pathname === path2) {
1837
+ const controller = new AbortController();
1838
+ res.on("close", () => {
1839
+ if (!res.writableFinished) controller.abort();
1840
+ });
1841
+ const headers = new Headers();
1842
+ for (const [key, value] of Object.entries(req.headers)) {
1843
+ if (Array.isArray(value)) for (const item of value) headers.append(key, item);
1844
+ else if (typeof value === "string") headers.set(key, value);
1845
+ }
1846
+ const method = req.method ?? "GET";
1847
+ let body;
1848
+ if (method !== "GET" && method !== "HEAD") {
1849
+ const chunks = [];
1850
+ for await (const chunk of req) chunks.push(chunk);
1851
+ body = new Uint8Array(Buffer.concat(chunks));
1852
+ }
1853
+ response = await opts.handler(
1854
+ new Request(url, { method, headers, body, signal: controller.signal })
1855
+ );
1856
+ } else if (url.pathname === "/health" && opts.health) {
1857
+ response = opts.health();
1858
+ } else {
1859
+ response = new Response(
1860
+ JSON.stringify({
1861
+ code: "NOT_FOUND",
1862
+ cause: `no route for ${url.pathname}`,
1863
+ fix: `POST JSON-RPC to ${path2}`,
1864
+ retryable: false
1865
+ }),
1866
+ { status: 404, headers: { "Content-Type": "application/json" } }
1867
+ );
1868
+ }
1869
+ const outHeaders = {};
1870
+ response.headers.forEach((value, key) => {
1871
+ outHeaders[key] = value;
1872
+ });
1873
+ res.writeHead(response.status, outHeaders);
1874
+ if (!response.body) {
1875
+ res.end();
1876
+ return;
1877
+ }
1878
+ const reader = response.body.getReader();
1879
+ try {
1880
+ for (; ; ) {
1881
+ const { done, value } = await reader.read();
1882
+ if (done) break;
1883
+ res.write(value);
1884
+ }
1885
+ } catch {
1886
+ }
1887
+ res.end();
1888
+ })().catch((err) => {
1889
+ if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
1890
+ res.end(
1891
+ JSON.stringify({
1892
+ code: "INTERNAL",
1893
+ cause: err instanceof Error ? err.message : String(err),
1894
+ fix: "retry; if it persists, report the request id",
1895
+ retryable: false
1896
+ })
1897
+ );
1898
+ });
1899
+ });
1900
+ await new Promise((resolve5, reject) => {
1901
+ server.once("error", reject);
1902
+ server.listen(opts.port ?? 8765, host, () => resolve5());
2148
1903
  });
2149
- }
2150
- function methodNotAllowed(method, allow, cors) {
2151
- return jsonResponse(
2152
- {
2153
- code: "METHOD_NOT_ALLOWED",
2154
- cause: `${method} is not supported here without a session`,
2155
- fix: "send JSON-RPC over POST with `Accept: application/json, text/event-stream` (start with `initialize`)",
2156
- retryable: false
2157
- },
2158
- 405,
2159
- { Allow: allow, ...cors }
2160
- );
2161
- }
2162
- function splitOptions(opts, transport) {
2163
- if (typeof opts === "function") return { factory: opts, transport };
2164
- const {
2165
- cors,
2166
- jsonResponse: jsonResponse2,
2167
- sessions,
2168
- allowedHosts,
2169
- allowedOrigins,
2170
- enableDnsRebindingProtection,
2171
- ...server
2172
- } = opts;
1904
+ const address = server.address();
1905
+ const port = typeof address === "object" && address ? address.port : opts.port ?? 8765;
2173
1906
  return {
2174
- factory: () => createMcpServer(server),
2175
- transport: {
2176
- cors,
2177
- jsonResponse: jsonResponse2,
2178
- sessions,
2179
- allowedHosts,
2180
- allowedOrigins,
2181
- enableDnsRebindingProtection,
2182
- ...transport
2183
- }
1907
+ port,
1908
+ url: `http://${host}:${port}${path2}`,
1909
+ close: () => new Promise((resolve5, reject) => {
1910
+ server.closeAllConnections();
1911
+ server.close((err) => err ? reject(err) : resolve5());
1912
+ })
2184
1913
  };
2185
1914
  }
2186
- function withCors(response, cors) {
2187
- const keys = Object.keys(cors);
2188
- if (keys.length === 0) return response;
2189
- const headers = new Headers(response.headers);
2190
- for (const key of keys) headers.set(key, cors[key] ?? "");
2191
- return new Response(response.body, {
2192
- status: response.status,
2193
- statusText: response.statusText,
2194
- headers
2195
- });
1915
+
1916
+ // ../../packages/mcp-kit/dist/chunk-M567BWMA.js
1917
+ var LIST_MAX_PAGES = 20;
1918
+ var LIST_MAX_ITEMS = 2e3;
1919
+ async function readAllPages(fetchPage, opts = {}) {
1920
+ const maxPages = opts.maxPages ?? LIST_MAX_PAGES;
1921
+ const maxItems = opts.maxItems ?? LIST_MAX_ITEMS;
1922
+ const method = opts.method ?? "tools/list";
1923
+ const items = [];
1924
+ const followed = /* @__PURE__ */ new Set();
1925
+ let cursor;
1926
+ for (let page = 1; ; page++) {
1927
+ const res = await fetchPage(cursor, page);
1928
+ if (Array.isArray(res.items)) items.push(...res.items);
1929
+ const next = res.nextCursor;
1930
+ const more = typeof next === "string" && next !== "";
1931
+ if (items.length > maxItems) {
1932
+ return {
1933
+ items,
1934
+ pages: page,
1935
+ truncated: {
1936
+ ceiling: "items",
1937
+ reason: `${method} listed more than ${maxItems} items in ${page} page${page === 1 ? "" : "s"}${more ? " and had more" : ""}; at most ${maxItems} are read`
1938
+ }
1939
+ };
1940
+ }
1941
+ if (!more) return { items, pages: page };
1942
+ if (followed.has(next)) return { items, pages: page, repeatedCursor: true };
1943
+ if (page >= maxPages) {
1944
+ return {
1945
+ items,
1946
+ pages: page,
1947
+ truncated: {
1948
+ ceiling: "pages",
1949
+ reason: `${method} had more than ${maxPages} pages (${items.length} items read); at most ${maxPages} pages are read`
1950
+ }
1951
+ };
1952
+ }
1953
+ followed.add(next);
1954
+ cursor = next;
1955
+ }
2196
1956
  }
2197
- function errorResponse(err, cors) {
2198
- const error = normalizeError(err);
2199
- return jsonResponse(error.toJSON(), error.httpStatus, cors);
1957
+
1958
+ // ../../packages/mcp-kit/dist/index.js
1959
+ import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
1960
+ async function serveStdio(serverOrOpts) {
1961
+ const server = serverOrOpts instanceof McpServer2 ? serverOrOpts : createMcpServer(serverOrOpts);
1962
+ const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
1963
+ const transport = new StdioServerTransport();
1964
+ await server.connect(transport);
1965
+ await new Promise((resolve5) => {
1966
+ const previous = transport.onclose;
1967
+ transport.onclose = () => {
1968
+ previous?.();
1969
+ resolve5();
1970
+ };
1971
+ });
2200
1972
  }
2201
- function createStatelessHandler({ factory, cors, transportBase }) {
2202
- return async (request) => {
2203
- if (request.method !== "POST") return methodNotAllowed(request.method, "POST, OPTIONS", cors);
2204
- const server = factory();
2205
- const transport = new WebStandardStreamableHTTPServerTransport({
2206
- ...transportBase,
2207
- sessionIdGenerator: void 0
2208
- });
2209
- let closed = false;
2210
- const cleanup = async () => {
2211
- if (closed) return;
2212
- closed = true;
2213
- try {
2214
- await server.close();
2215
- } catch {
2216
- }
1973
+
1974
+ // src/proxy/runtime.ts
1975
+ var ProxyRuntime = class {
1976
+ loaded;
1977
+ guard;
1978
+ agent;
1979
+ defaultRunId;
1980
+ configured;
1981
+ sessions = /* @__PURE__ */ new Set();
1982
+ connections = /* @__PURE__ */ new Map();
1983
+ exposed = [];
1984
+ resourceOwner = /* @__PURE__ */ new Map();
1985
+ templateOwner = /* @__PURE__ */ new Map();
1986
+ promptOwner = /* @__PURE__ */ new Map();
1987
+ log;
1988
+ connectTimeoutMs;
1989
+ testClients;
1990
+ /** stop relaying upstream stderr once we are tearing down — shutdown noise is not the user's problem */
1991
+ closing = false;
1992
+ constructor(opts) {
1993
+ this.loaded = opts.loaded;
1994
+ this.guard = opts.guard;
1995
+ this.agent = opts.agent;
1996
+ this.defaultRunId = opts.defaultRunId;
1997
+ this.configured = opts.configured ?? true;
1998
+ this.log = opts.log ?? ((line) => process.stderr.write(`[agentguard] ${line}
1999
+ `));
2000
+ this.connectTimeoutMs = opts.connectTimeoutMs ?? 15e3;
2001
+ this.testClients = opts.clients ?? {};
2002
+ }
2003
+ get policy() {
2004
+ return this.loaded.policy;
2005
+ }
2006
+ async start() {
2007
+ await Promise.all(this.policy.upstreams.map((u) => this.connect(u)));
2008
+ for (const [name, client] of Object.entries(this.testClients)) {
2009
+ if (this.connections.has(name)) continue;
2010
+ const upstream = {
2011
+ name,
2012
+ command: "in-memory",
2013
+ args: [],
2014
+ env: {},
2015
+ headers: {},
2016
+ prefix: false,
2017
+ timeout_ms: 6e4
2018
+ };
2019
+ const conn = {
2020
+ upstream,
2021
+ client,
2022
+ tools: [],
2023
+ capabilities: client.getServerCapabilities(),
2024
+ connected: true
2025
+ };
2026
+ this.connections.set(name, conn);
2027
+ this.wire(conn);
2028
+ await this.refreshTools(name);
2029
+ }
2030
+ this.rebuildExposed();
2031
+ const status = this.upstreamStatus();
2032
+ this.log(
2033
+ `connected ${status.filter((s) => s.connected).length}/${status.length} upstreams, ${this.exposed.length} tools, mode ${this.policy.mode}`
2034
+ );
2035
+ }
2036
+ async connect(upstream) {
2037
+ const client = new Client(
2038
+ { name: "agentguard", version: version() },
2039
+ { capabilities: { sampling: {}, elicitation: {} } }
2040
+ );
2041
+ const conn = {
2042
+ upstream,
2043
+ client,
2044
+ tools: [],
2045
+ capabilities: void 0,
2046
+ connected: false
2217
2047
  };
2048
+ this.connections.set(upstream.name, conn);
2218
2049
  try {
2219
- await server.connect(transport);
2220
- const response = withCors(await transport.handleRequest(request), cors);
2221
- if (!response.body) {
2222
- await cleanup();
2223
- return response;
2050
+ const transport = upstream.url ? new StreamableHTTPClientTransport(new URL(upstream.url), {
2051
+ requestInit: { headers: upstreamHeaders(upstream) }
2052
+ }) : new StdioClientTransport({
2053
+ command: upstream.command,
2054
+ args: upstream.args,
2055
+ env: { ...getDefaultEnvironment(), ...upstream.env },
2056
+ cwd: upstream.cwd,
2057
+ stderr: "pipe"
2058
+ });
2059
+ if (transport instanceof StdioClientTransport) {
2060
+ transport.stderr?.on("data", (chunk) => {
2061
+ if (this.closing) return;
2062
+ for (const line of chunk.toString("utf8").split("\n"))
2063
+ if (line.trim()) this.log(`${upstream.name}: ${line}`);
2064
+ });
2224
2065
  }
2225
- request.signal?.addEventListener("abort", () => void cleanup(), { once: true });
2226
- const body = response.body.pipeThrough(
2227
- new TransformStream({ flush: () => cleanup() })
2066
+ await withTimeout(
2067
+ client.connect(transport),
2068
+ this.connectTimeoutMs,
2069
+ `connect to upstream "${upstream.name}"`
2228
2070
  );
2229
- return new Response(body, {
2230
- status: response.status,
2231
- statusText: response.statusText,
2232
- headers: response.headers
2233
- });
2071
+ conn.capabilities = client.getServerCapabilities();
2072
+ conn.connected = true;
2073
+ this.wire(conn);
2074
+ await this.refreshTools(upstream.name);
2234
2075
  } catch (err) {
2235
- await cleanup();
2236
- return errorResponse(err, cors);
2076
+ conn.connected = false;
2077
+ conn.error = err instanceof Error ? err.message : String(err);
2078
+ this.log(`upstream "${upstream.name}" unavailable: ${conn.error}`);
2079
+ }
2080
+ }
2081
+ wire(conn) {
2082
+ const { client, upstream } = conn;
2083
+ client.onclose = () => {
2084
+ conn.connected = false;
2085
+ conn.error = "connection closed";
2086
+ if (!this.closing) this.log(`upstream "${upstream.name}" closed`);
2087
+ };
2088
+ client.setNotificationHandler(LoggingMessageNotificationSchema, async (n) => {
2089
+ await this.broadcast(upstream.name, n.method, n.params);
2090
+ });
2091
+ client.setNotificationHandler(ResourceUpdatedNotificationSchema, async (n) => {
2092
+ await this.broadcast(upstream.name, n.method, n.params);
2093
+ });
2094
+ client.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
2095
+ this.resourceOwner.clear();
2096
+ await this.broadcast(upstream.name, "notifications/resources/list_changed", void 0);
2097
+ });
2098
+ client.setNotificationHandler(PromptListChangedNotificationSchema, async () => {
2099
+ this.promptOwner.clear();
2100
+ await this.broadcast(upstream.name, "notifications/prompts/list_changed", void 0);
2101
+ });
2102
+ client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
2103
+ await this.refreshTools(upstream.name);
2104
+ this.rebuildExposed();
2105
+ for (const s of this.sessions) s.server.server.sendToolListChanged().catch(() => void 0);
2106
+ });
2107
+ try {
2108
+ client.setRequestHandler(CreateMessageRequestSchema, async (req) => {
2109
+ const session = this.pickSession(upstream.name);
2110
+ if (!session) throw new Error("no downstream client is connected to relay sampling to");
2111
+ const related = session.inflight.get(upstream.name)?.at(-1);
2112
+ return session.server.server.createMessage(req.params, { relatedRequestId: related });
2113
+ });
2114
+ client.setRequestHandler(ElicitRequestSchema, async (req) => {
2115
+ const session = this.pickSession(upstream.name);
2116
+ if (!session) throw new Error("no downstream client is connected to relay elicitation to");
2117
+ const related = session.inflight.get(upstream.name)?.at(-1);
2118
+ return session.server.server.elicitInput(req.params, { relatedRequestId: related });
2119
+ });
2120
+ } catch {
2237
2121
  }
2238
- };
2239
- }
2240
- function createStatefulHandler({ factory, cors, transportBase }, options) {
2241
- const ttlMs = options.ttlMs ?? DEFAULT_SESSION_TTL_MS;
2242
- const sessions = /* @__PURE__ */ new Map();
2243
- const drop = (id) => {
2244
- const session = sessions.get(id);
2245
- if (!session) return;
2246
- sessions.delete(id);
2247
- session.server.close().catch(() => void 0);
2248
- };
2249
- const sweep = () => {
2250
- const now = Date.now();
2251
- for (const [id, session] of sessions) if (now - session.lastSeen > ttlMs) drop(id);
2252
- };
2253
- return async (request) => {
2254
- const sessionId = request.headers.get("mcp-session-id");
2255
- if (sessionId) {
2256
- const session = sessions.get(sessionId);
2257
- if (!session) {
2258
- return jsonResponse(
2259
- {
2260
- code: "NOT_FOUND",
2261
- cause: "unknown or expired Mcp-Session-Id",
2262
- fix: "send `initialize` again without an Mcp-Session-Id header and use the id from the response",
2263
- retryable: true
2264
- },
2265
- 404,
2266
- cors
2267
- );
2268
- }
2269
- session.lastSeen = Date.now();
2122
+ }
2123
+ pickSession(upstream) {
2124
+ let best;
2125
+ for (const s of this.sessions) {
2126
+ if ((s.inflight.get(upstream)?.length ?? 0) > 0) return s;
2127
+ if (!best || s.lastActive > best.lastActive) best = s;
2128
+ }
2129
+ return best;
2130
+ }
2131
+ async broadcast(upstream, method, params) {
2132
+ for (const s of this.sessions) {
2133
+ const related = s.inflight.get(upstream)?.at(-1);
2270
2134
  try {
2271
- return withCors(await session.transport.handleRequest(request), cors);
2272
- } catch (err) {
2273
- return errorResponse(err, cors);
2135
+ await s.server.server.notification(
2136
+ { method, params },
2137
+ related !== void 0 ? { relatedRequestId: related } : void 0
2138
+ );
2139
+ } catch {
2274
2140
  }
2275
2141
  }
2276
- if (request.method !== "POST") return methodNotAllowed(request.method, "POST, OPTIONS", cors);
2277
- sweep();
2278
- const server = factory();
2279
- const transport = new WebStandardStreamableHTTPServerTransport({
2280
- ...transportBase,
2281
- sessionIdGenerator: () => crypto.randomUUID(),
2282
- onsessioninitialized: (id) => {
2283
- sessions.set(id, { server, transport, lastSeen: Date.now() });
2284
- },
2285
- onsessionclosed: (id) => {
2286
- sessions.delete(id);
2287
- }
2288
- });
2142
+ }
2143
+ /**
2144
+ * Re-read an upstream's tools, every page (mcp-kit's `readAllPages`): at most 20 requests, each
2145
+ * under the upstream's `timeout_ms`, ending at a cursor already followed. It used to follow
2146
+ * `nextCursor` with no bound, so an upstream that echoed its cursor kept the proxy asking for
2147
+ * the same page forever. A refresh that fails, or stops at the 20-page / 2,000-tool ceiling,
2148
+ * changes nothing: the agent keeps the last good list, and the log says why.
2149
+ */
2150
+ async refreshTools(name) {
2151
+ const conn = this.connections.get(name);
2152
+ if (!conn?.connected) return;
2153
+ if (conn.capabilities && !conn.capabilities.tools) {
2154
+ conn.tools = [];
2155
+ return;
2156
+ }
2157
+ const kept = () => `keeping the last good list (${conn.tools.length} tool${conn.tools.length === 1 ? "" : "s"})`;
2289
2158
  try {
2290
- await server.connect(transport);
2291
- const previousOnClose = transport.onclose;
2292
- transport.onclose = () => {
2293
- previousOnClose?.();
2294
- if (transport.sessionId) sessions.delete(transport.sessionId);
2295
- };
2296
- const response = withCors(await transport.handleRequest(request), cors);
2297
- if (!transport.sessionId) server.close().catch(() => void 0);
2298
- return response;
2159
+ const read = await readAllPages(async (cursor) => {
2160
+ const page = await conn.client.listTools(cursor ? { cursor } : void 0, {
2161
+ timeout: conn.upstream.timeout_ms
2162
+ });
2163
+ return { items: page.tools, nextCursor: page.nextCursor };
2164
+ });
2165
+ if (read.truncated) {
2166
+ this.log(`tools/list for "${name}" not applied: ${read.truncated.reason}; ${kept()}`);
2167
+ return;
2168
+ }
2169
+ conn.tools = read.items;
2299
2170
  } catch (err) {
2300
- server.close().catch(() => void 0);
2301
- return errorResponse(err, cors);
2171
+ this.log(
2172
+ `tools/list failed for "${name}": ${err instanceof Error ? err.message : String(err)}; ${kept()}`
2173
+ );
2302
2174
  }
2303
- };
2304
- }
2305
- function createHttpHandler(opts, transportOptions = {}) {
2306
- const { factory, transport: t } = splitOptions(opts, transportOptions);
2307
- const cors = corsHeaders(t.cors);
2308
- const sessions = t.sessions ? typeof t.sessions === "object" ? t.sessions : {} : void 0;
2309
- const context = {
2310
- factory,
2311
- cors,
2312
- transportBase: {
2313
- enableJsonResponse: t.jsonResponse ?? sessions === void 0,
2314
- allowedHosts: t.allowedHosts,
2315
- allowedOrigins: t.allowedOrigins,
2316
- enableDnsRebindingProtection: t.enableDnsRebindingProtection
2175
+ }
2176
+ rebuildExposed() {
2177
+ const taken = /* @__PURE__ */ new Set();
2178
+ const out = [];
2179
+ const order = [...this.policy.upstreams.map((u) => u.name), ...Object.keys(this.testClients)];
2180
+ for (const name of order) {
2181
+ const conn = this.connections.get(name);
2182
+ if (!conn) continue;
2183
+ const prefix = conn.upstream.prefix === true ? name : typeof conn.upstream.prefix === "string" ? conn.upstream.prefix : void 0;
2184
+ for (const tool of conn.tools) {
2185
+ let exposedName = prefix ? `${prefix}__${tool.name}` : tool.name;
2186
+ if (taken.has(exposedName)) exposedName = `${name}__${tool.name}`;
2187
+ if (taken.has(exposedName)) {
2188
+ this.log(`skipping duplicate tool ${exposedName} from ${name}`);
2189
+ continue;
2190
+ }
2191
+ taken.add(exposedName);
2192
+ out.push({
2193
+ name: exposedName,
2194
+ upstream: name,
2195
+ original: tool.name,
2196
+ tool,
2197
+ classification: classifyTool(
2198
+ {
2199
+ name: exposedName,
2200
+ description: tool.description,
2201
+ annotations: tool.annotations,
2202
+ inputSchema: tool.inputSchema,
2203
+ outputSchema: tool.outputSchema
2204
+ },
2205
+ this.policy
2206
+ )
2207
+ });
2208
+ }
2317
2209
  }
2318
- };
2319
- const handler = sessions ? createStatefulHandler(context, sessions) : createStatelessHandler(context);
2320
- const allow = sessions ? "GET, POST, DELETE, OPTIONS" : "POST, OPTIONS";
2321
- return async (request) => {
2322
- if (request.method === "OPTIONS") {
2323
- return new Response(null, { status: 204, headers: { Allow: allow, ...cors } });
2210
+ this.exposed = out;
2211
+ }
2212
+ listTools(agent) {
2213
+ if (agent?.upstreams) return this.exposed.filter((t) => agent.upstreams.includes(t.upstream));
2214
+ return this.exposed;
2215
+ }
2216
+ findTool(name) {
2217
+ return this.exposed.find((t) => t.name === name);
2218
+ }
2219
+ upstreamStatus() {
2220
+ return [...this.connections.values()].map((c) => ({
2221
+ name: c.upstream.name,
2222
+ connected: c.connected,
2223
+ tools: c.tools.length,
2224
+ transport: c.upstream.url ? "http" : "stdio",
2225
+ error: c.error
2226
+ }));
2227
+ }
2228
+ attach(session) {
2229
+ this.sessions.add(session);
2230
+ }
2231
+ detach(session) {
2232
+ this.sessions.delete(session);
2233
+ }
2234
+ /** Run a tool call through the policy engine and, if allowed, the upstream. */
2235
+ async callTool(name, args, ctx) {
2236
+ const tool = this.findTool(name);
2237
+ const agent = ctx.agent === void 0 ? this.agent : ctx.agent;
2238
+ if (!tool) {
2239
+ const result2 = await this.guard.run(
2240
+ { tool: { name }, args, runId: ctx.runId, agent, sessionId: ctx.sessionId },
2241
+ async () => {
2242
+ throw new GuardError({
2243
+ code: "UNKNOWN_TOOL",
2244
+ cause: `no upstream exposes a tool named "${name}"`,
2245
+ fix: "call tools/list and use one of the listed names",
2246
+ retryable: false
2247
+ });
2248
+ }
2249
+ );
2250
+ return { result: result2 };
2324
2251
  }
2325
- return handler(request);
2326
- };
2327
- }
2328
- function localhostHosts(port) {
2329
- const hosts = ["localhost", "127.0.0.1", "[::1]"];
2330
- return [...hosts, ...hosts.map((h) => `${h}:${port}`)];
2331
- }
2332
- function handleHealth(info) {
2333
- const tools = typeof info.tools === "number" ? info.tools : info.tools.length;
2334
- return jsonResponse({ ok: true, name: info.name, version: info.version, tools }, 200);
2335
- }
2336
- async function serveNodeHttp(opts) {
2337
- const http = await import("http");
2338
- const host = opts.host ?? "127.0.0.1";
2339
- const path2 = opts.path ?? "/mcp";
2340
- const server = http.createServer((req, res) => {
2341
- void (async () => {
2342
- const url = new URL(req.url ?? "/", `http://${req.headers.host ?? host}`);
2343
- let response;
2344
- if (url.pathname === path2) {
2345
- const controller = new AbortController();
2346
- res.on("close", () => {
2347
- if (!res.writableFinished) controller.abort();
2252
+ const conn = this.connections.get(tool.upstream);
2253
+ const track = () => {
2254
+ if (!ctx.session || ctx.requestId === void 0) return () => void 0;
2255
+ const list = ctx.session.inflight.get(tool.upstream) ?? [];
2256
+ list.push(ctx.requestId);
2257
+ ctx.session.inflight.set(tool.upstream, list);
2258
+ return () => {
2259
+ const l = ctx.session.inflight.get(tool.upstream) ?? [];
2260
+ const i = l.indexOf(ctx.requestId);
2261
+ if (i >= 0) l.splice(i, 1);
2262
+ };
2263
+ };
2264
+ const result = await this.guard.run(
2265
+ {
2266
+ tool: {
2267
+ name: tool.name,
2268
+ description: tool.tool.description,
2269
+ annotations: tool.tool.annotations,
2270
+ inputSchema: tool.tool.inputSchema,
2271
+ outputSchema: tool.tool.outputSchema
2272
+ },
2273
+ args,
2274
+ runId: ctx.runId,
2275
+ agent,
2276
+ sessionId: ctx.sessionId,
2277
+ upstream: tool.upstream
2278
+ },
2279
+ async (finalArgs) => {
2280
+ if (!conn?.connected) {
2281
+ throw new GuardError({
2282
+ code: "UPSTREAM_ERROR",
2283
+ cause: `upstream "${tool.upstream}" is not connected${conn?.error ? ` (${conn.error})` : ""}`,
2284
+ fix: "check the upstream command/url in agentguard.yaml and restart the proxy",
2285
+ retryable: true
2286
+ });
2287
+ }
2288
+ const untrack = track();
2289
+ try {
2290
+ return await conn.client.callTool(
2291
+ { name: tool.original, arguments: finalArgs ?? {} },
2292
+ void 0,
2293
+ {
2294
+ timeout: conn.upstream.timeout_ms,
2295
+ resetTimeoutOnProgress: true,
2296
+ onprogress: ctx.onprogress
2297
+ }
2298
+ );
2299
+ } finally {
2300
+ untrack();
2301
+ }
2302
+ }
2303
+ );
2304
+ return { result, tool };
2305
+ }
2306
+ connectedWith(capability) {
2307
+ return [...this.connections.values()].filter(
2308
+ (c) => c.connected && (c.capabilities?.[capability] || c.capabilities === void 0)
2309
+ );
2310
+ }
2311
+ async listResources() {
2312
+ const resources = [];
2313
+ for (const conn of this.connectedWith("resources")) {
2314
+ try {
2315
+ const page = await conn.client.listResources(void 0, {
2316
+ timeout: conn.upstream.timeout_ms
2348
2317
  });
2349
- const headers = new Headers();
2350
- for (const [key, value] of Object.entries(req.headers)) {
2351
- if (Array.isArray(value)) for (const item of value) headers.append(key, item);
2352
- else if (typeof value === "string") headers.set(key, value);
2318
+ for (const r of page.resources) {
2319
+ this.resourceOwner.set(r.uri, conn.upstream.name);
2320
+ resources.push(r);
2353
2321
  }
2354
- const method = req.method ?? "GET";
2355
- let body;
2356
- if (method !== "GET" && method !== "HEAD") {
2357
- const chunks = [];
2358
- for await (const chunk of req) chunks.push(chunk);
2359
- body = new Uint8Array(Buffer.concat(chunks));
2322
+ } catch {
2323
+ }
2324
+ }
2325
+ return { resources };
2326
+ }
2327
+ async listResourceTemplates() {
2328
+ const resourceTemplates = [];
2329
+ for (const conn of this.connectedWith("resources")) {
2330
+ try {
2331
+ const page = await conn.client.listResourceTemplates(void 0, {
2332
+ timeout: conn.upstream.timeout_ms
2333
+ });
2334
+ for (const t of page.resourceTemplates) {
2335
+ this.templateOwner.set(t.uriTemplate, conn.upstream.name);
2336
+ resourceTemplates.push(t);
2360
2337
  }
2361
- response = await opts.handler(
2362
- new Request(url, { method, headers, body, signal: controller.signal })
2363
- );
2364
- } else if (url.pathname === "/health" && opts.health) {
2365
- response = opts.health();
2366
- } else {
2367
- response = new Response(
2368
- JSON.stringify({
2369
- code: "NOT_FOUND",
2370
- cause: `no route for ${url.pathname}`,
2371
- fix: `POST JSON-RPC to ${path2}`,
2372
- retryable: false
2373
- }),
2374
- { status: 404, headers: { "Content-Type": "application/json" } }
2338
+ } catch {
2339
+ }
2340
+ }
2341
+ return { resourceTemplates };
2342
+ }
2343
+ ownerForUri(uri) {
2344
+ const owner = this.resourceOwner.get(uri);
2345
+ if (owner && this.connections.get(owner)?.connected) return [this.connections.get(owner)];
2346
+ for (const [template, name] of this.templateOwner) {
2347
+ if (templateMatches(template, uri) && this.connections.get(name)?.connected)
2348
+ return [this.connections.get(name)];
2349
+ }
2350
+ return this.connectedWith("resources");
2351
+ }
2352
+ async readResource(uri) {
2353
+ let lastError;
2354
+ for (const conn of this.ownerForUri(uri)) {
2355
+ try {
2356
+ const result = await conn.client.readResource(
2357
+ { uri },
2358
+ { timeout: conn.upstream.timeout_ms }
2375
2359
  );
2360
+ this.resourceOwner.set(uri, conn.upstream.name);
2361
+ return result;
2362
+ } catch (err) {
2363
+ lastError = err;
2376
2364
  }
2377
- const outHeaders = {};
2378
- response.headers.forEach((value, key) => {
2379
- outHeaders[key] = value;
2380
- });
2381
- res.writeHead(response.status, outHeaders);
2382
- if (!response.body) {
2383
- res.end();
2365
+ }
2366
+ throw lastError ?? new Error(`no upstream serves resource ${uri}`);
2367
+ }
2368
+ async subscribe(uri, on) {
2369
+ for (const conn of this.ownerForUri(uri)) {
2370
+ try {
2371
+ if (on) await conn.client.subscribeResource({ uri });
2372
+ else await conn.client.unsubscribeResource({ uri });
2384
2373
  return;
2374
+ } catch {
2385
2375
  }
2386
- const reader = response.body.getReader();
2376
+ }
2377
+ }
2378
+ async listPrompts() {
2379
+ const prompts = [];
2380
+ const taken = /* @__PURE__ */ new Set();
2381
+ this.promptOwner.clear();
2382
+ for (const conn of this.connectedWith("prompts")) {
2387
2383
  try {
2388
- for (; ; ) {
2389
- const { done, value } = await reader.read();
2390
- if (done) break;
2391
- res.write(value);
2384
+ const page = await conn.client.listPrompts(void 0, {
2385
+ timeout: conn.upstream.timeout_ms
2386
+ });
2387
+ for (const p of page.prompts) {
2388
+ const name = taken.has(p.name) ? `${conn.upstream.name}__${p.name}` : p.name;
2389
+ taken.add(name);
2390
+ this.promptOwner.set(name, { upstream: conn.upstream.name, original: p.name });
2391
+ prompts.push({ ...p, name });
2392
2392
  }
2393
2393
  } catch {
2394
2394
  }
2395
- res.end();
2396
- })().catch((err) => {
2397
- if (!res.headersSent) res.writeHead(500, { "Content-Type": "application/json" });
2398
- res.end(
2399
- JSON.stringify({
2400
- code: "INTERNAL",
2401
- cause: err instanceof Error ? err.message : String(err),
2402
- fix: "retry; if it persists, report the request id",
2403
- retryable: false
2404
- })
2405
- );
2406
- });
2407
- });
2408
- await new Promise((resolve5, reject) => {
2409
- server.once("error", reject);
2410
- server.listen(opts.port ?? 8765, host, () => resolve5());
2411
- });
2412
- const address = server.address();
2413
- const port = typeof address === "object" && address ? address.port : opts.port ?? 8765;
2414
- return {
2415
- port,
2416
- url: `http://${host}:${port}${path2}`,
2417
- close: () => new Promise((resolve5, reject) => {
2418
- server.closeAllConnections();
2419
- server.close((err) => err ? reject(err) : resolve5());
2420
- })
2421
- };
2395
+ }
2396
+ return { prompts };
2397
+ }
2398
+ async getPrompt(name, args) {
2399
+ if (this.promptOwner.size === 0) await this.listPrompts();
2400
+ const owner = this.promptOwner.get(name);
2401
+ const conns = owner ? [this.connections.get(owner.upstream)] : this.connectedWith("prompts");
2402
+ let lastError;
2403
+ for (const conn of conns) {
2404
+ try {
2405
+ return await conn.client.getPrompt(
2406
+ { name: owner?.original ?? name, arguments: args },
2407
+ { timeout: conn.upstream.timeout_ms }
2408
+ );
2409
+ } catch (err) {
2410
+ lastError = err;
2411
+ }
2412
+ }
2413
+ throw lastError ?? new Error(`no upstream serves prompt ${name}`);
2414
+ }
2415
+ async complete(params) {
2416
+ let conns;
2417
+ if (params.ref.type === "ref/prompt") {
2418
+ if (this.promptOwner.size === 0) await this.listPrompts();
2419
+ const owner = this.promptOwner.get(params.ref.name);
2420
+ conns = owner ? [this.connections.get(owner.upstream)] : this.connectedWith("completions");
2421
+ if (owner) params = { ...params, ref: { ...params.ref, name: owner.original } };
2422
+ } else {
2423
+ if (this.templateOwner.size === 0) await this.listResourceTemplates();
2424
+ conns = this.ownerForUri(params.ref.uri);
2425
+ }
2426
+ let lastError;
2427
+ for (const conn of conns) {
2428
+ try {
2429
+ return await conn.client.complete(params, { timeout: conn.upstream.timeout_ms });
2430
+ } catch (err) {
2431
+ lastError = err;
2432
+ }
2433
+ }
2434
+ throw lastError ?? new Error("no upstream supports completions");
2435
+ }
2436
+ async setLevel(level) {
2437
+ await Promise.all(
2438
+ this.connectedWith("logging").map(
2439
+ (c) => c.client.setLoggingLevel(level).catch(() => void 0)
2440
+ )
2441
+ );
2442
+ }
2443
+ async close() {
2444
+ this.closing = true;
2445
+ for (const conn of this.connections.values()) {
2446
+ try {
2447
+ await conn.client.close();
2448
+ } catch {
2449
+ }
2450
+ }
2451
+ this.connections.clear();
2452
+ }
2453
+ };
2454
+ function templateMatches(template, uri) {
2455
+ const re = new RegExp(
2456
+ "^" + template.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\{[^}]+\\\}/g, "[^/]+") + "$"
2457
+ );
2458
+ return re.test(uri);
2422
2459
  }
2423
-
2424
- // ../../packages/mcp-kit/dist/index.js
2425
- import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
2426
- async function serveStdio(serverOrOpts) {
2427
- const server = serverOrOpts instanceof McpServer2 ? serverOrOpts : createMcpServer(serverOrOpts);
2428
- const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
2429
- const transport = new StdioServerTransport();
2430
- await server.connect(transport);
2431
- await new Promise((resolve5) => {
2432
- const previous = transport.onclose;
2433
- transport.onclose = () => {
2434
- previous?.();
2435
- resolve5();
2436
- };
2460
+ async function withTimeout(promise, ms, what) {
2461
+ let timer;
2462
+ const timeout = new Promise((_, reject) => {
2463
+ timer = setTimeout(() => reject(new Error(`${what} timed out after ${ms}ms`)), ms);
2437
2464
  });
2465
+ try {
2466
+ return await Promise.race([promise, timeout]);
2467
+ } finally {
2468
+ if (timer) clearTimeout(timer);
2469
+ }
2438
2470
  }
2439
2471
 
2472
+ // src/proxy/server.ts
2473
+ import { McpServer as McpServer3 } from "@modelcontextprotocol/sdk/server/mcp.js";
2474
+ import {
2475
+ CallToolRequestSchema as CallToolRequestSchema2,
2476
+ CompleteRequestSchema,
2477
+ GetPromptRequestSchema,
2478
+ ListPromptsRequestSchema,
2479
+ ListResourceTemplatesRequestSchema,
2480
+ ListResourcesRequestSchema,
2481
+ ListToolsRequestSchema as ListToolsRequestSchema2,
2482
+ ReadResourceRequestSchema,
2483
+ SetLevelRequestSchema,
2484
+ SubscribeRequestSchema as SubscribeRequestSchema2,
2485
+ UnsubscribeRequestSchema as UnsubscribeRequestSchema2
2486
+ } from "@modelcontextprotocol/sdk/types.js";
2487
+ import {
2488
+ keyFromHeaders,
2489
+ resolveAgent
2490
+ } from "@agentwares/agentguard-core";
2491
+
2440
2492
  // src/proxy/own-tools.ts
2441
2493
  import {
2442
2494
  buildReport,