@agent-vm/mcp-portal 0.0.76 → 0.0.78
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/bin/mcp-portal.js +5 -5
- package/dist/bin/mcp-portal.js.map +1 -1
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +4 -4
- package/dist/index.d.ts +39 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -3
- package/dist/mcp-proxy/index.d.ts +2 -2
- package/dist/mcp-proxy/index.js +1 -1
- package/dist/{portal-core-BPSvDGvi.js → portal-core-B5cRpZMG.js} +26 -17
- package/dist/portal-core-B5cRpZMG.js.map +1 -0
- package/dist/{portal-core-CZQI7Ob6.d.ts → portal-core-Ckq-Mrzb.d.ts} +19 -2
- package/dist/portal-core-Ckq-Mrzb.d.ts.map +1 -0
- package/dist/{portal-session-DG2CUjIo.d.ts → portal-session-5ksK1G9Z.d.ts} +19 -4
- package/dist/portal-session-5ksK1G9Z.d.ts.map +1 -0
- package/dist/{portal-tools-DKci1szO.js → portal-tools-DA7j2pyv.js} +25 -8
- package/dist/portal-tools-DA7j2pyv.js.map +1 -0
- package/dist/{resolve-agent-identity-FQL02YdW.d.ts → resolve-agent-identity-C9Jc2NhJ.d.ts} +3 -3
- package/dist/{resolve-agent-identity-FQL02YdW.d.ts.map → resolve-agent-identity-C9Jc2NhJ.d.ts.map} +1 -1
- package/dist/{resolve-agent-identity-DnC_Pmnh.js → resolve-agent-identity-ZMMY2Wqm.js} +3 -3
- package/dist/{resolve-agent-identity-DnC_Pmnh.js.map → resolve-agent-identity-ZMMY2Wqm.js.map} +1 -1
- package/dist/{serve-command-CV1s-Eln.js → serve-command-Dz6nvnzQ.js} +8 -8
- package/dist/serve-command-Dz6nvnzQ.js.map +1 -0
- package/dist/{upstream-mcp-client-runtime-DbPkS6Rk.js → upstream-mcp-client-runtime-Be_cw6pV.js} +64 -15
- package/dist/upstream-mcp-client-runtime-Be_cw6pV.js.map +1 -0
- package/dist/upstream-response-middleware-1MZnAD9C.d.ts.map +1 -1
- package/dist/{upstream-response-middleware-BjUWZ2G8.js → upstream-response-middleware-Cd1MxA6A.js} +57 -3
- package/dist/upstream-response-middleware-Cd1MxA6A.js.map +1 -0
- package/package.json +3 -3
- package/dist/portal-core-BPSvDGvi.js.map +0 -1
- package/dist/portal-core-CZQI7Ob6.d.ts.map +0 -1
- package/dist/portal-session-DG2CUjIo.d.ts.map +0 -1
- package/dist/portal-tools-DKci1szO.js.map +0 -1
- package/dist/serve-command-CV1s-Eln.js.map +0 -1
- package/dist/upstream-mcp-client-runtime-DbPkS6Rk.js.map +0 -1
- package/dist/upstream-response-middleware-BjUWZ2G8.js.map +0 -1
|
@@ -23,12 +23,12 @@ interface PortalAccessPolicyConfig {
|
|
|
23
23
|
readonly defaultPolicy?: PortalDefaultPolicy;
|
|
24
24
|
readonly enabledNamespaces?: readonly string[];
|
|
25
25
|
readonly enabledNamespacesByAgent: Readonly<Record<string, readonly string[]>>;
|
|
26
|
-
readonly
|
|
26
|
+
readonly enabledToolsByNamespaceByAgent?: Readonly<Record<string, Readonly<Record<string, readonly string[]>>>>;
|
|
27
27
|
readonly hiddenToolsByAgent: Readonly<Record<string, readonly PortalToolSelector[]>>;
|
|
28
28
|
}
|
|
29
29
|
interface ResolvedPortalAccessPolicy {
|
|
30
30
|
readonly allowedNamespaces: readonly string[];
|
|
31
|
-
readonly
|
|
31
|
+
readonly enabledToolsByNamespace: Readonly<Record<string, readonly string[]>>;
|
|
32
32
|
readonly hiddenTools: readonly PortalToolSelector[];
|
|
33
33
|
}
|
|
34
34
|
declare function createPortalAgentIdentity(input: {
|
|
@@ -101,12 +101,18 @@ interface ToolSafetySummary {
|
|
|
101
101
|
readonly destructiveHint?: boolean;
|
|
102
102
|
readonly readOnlyHint?: boolean;
|
|
103
103
|
}
|
|
104
|
+
type ToolSchemaHintNext = 'call_ready' | 'describe_before_call';
|
|
105
|
+
interface ToolSchemaHint {
|
|
106
|
+
readonly message: string;
|
|
107
|
+
readonly next: ToolSchemaHintNext;
|
|
108
|
+
}
|
|
104
109
|
interface ToolSummary {
|
|
105
110
|
readonly description?: string;
|
|
106
111
|
readonly input: ToolSchemaSummary;
|
|
107
112
|
readonly namespace: string;
|
|
108
113
|
readonly output?: ToolSchemaSummary;
|
|
109
114
|
readonly safety: ToolSafetySummary;
|
|
115
|
+
readonly schemaHint?: ToolSchemaHint;
|
|
110
116
|
readonly title?: string;
|
|
111
117
|
readonly toolName: string;
|
|
112
118
|
readonly toolRef: string;
|
|
@@ -147,8 +153,17 @@ interface PortalCatalogSnapshot {
|
|
|
147
153
|
readonly tools: readonly PortalToolRecord[];
|
|
148
154
|
}
|
|
149
155
|
interface PortalDiscoveryFailure {
|
|
156
|
+
readonly causeMessage?: string;
|
|
157
|
+
readonly elapsedMs?: number;
|
|
158
|
+
readonly hint?: string;
|
|
159
|
+
readonly kind: string;
|
|
150
160
|
readonly message: string;
|
|
151
161
|
readonly namespace: string;
|
|
162
|
+
readonly operation?: string;
|
|
163
|
+
readonly phase?: string;
|
|
164
|
+
readonly timeoutMs?: number;
|
|
165
|
+
readonly toolName?: string;
|
|
166
|
+
readonly transport?: unknown;
|
|
152
167
|
}
|
|
153
168
|
interface PortalSession {
|
|
154
169
|
readonly catalog: PortalCatalogSnapshot;
|
|
@@ -180,5 +195,5 @@ interface PortalSessionManager {
|
|
|
180
195
|
}
|
|
181
196
|
declare function createPortalSessionManager(options: PortalSessionManagerOptions): PortalSessionManager;
|
|
182
197
|
//#endregion
|
|
183
|
-
export {
|
|
184
|
-
//# sourceMappingURL=portal-session-
|
|
198
|
+
export { ToolRef as A, portalAgentScopeKey as B, ToolGraph as C, ToolRelationshipType as D, ToolRelationshipEndpoint as E, PortalAgentScopeSource as F, PortalDefaultPolicy as I, PortalToolSelector as L, encodeToolRef as M, PortalAccessPolicyConfig as N, buildToolGraph as O, PortalAgentIdentity as P, ResolvedPortalAccessPolicy as R, SkillGraphInput as S, ToolRelationship as T, resolvePortalAccessPolicy as V, ToolSchemaSummary as _, PortalSessionManagerOptions as a, summarizeJsonSchema as b, SearchIndex as c, ToolRelationshipHint as d, ToolSearchResult as f, ToolSchemaHintNext as g, ToolSchemaHint as h, PortalSessionManager as i, decodeToolRef as j, ToolIdentity as k, SearchQuery as l, ToolSafetySummary as m, PortalDiscoveryFailure as n, PortalSessionRuntime as o, createSearchIndex as p, PortalSession as r, createPortalSessionManager as s, PortalCatalogSnapshot as t, SearchResultSet as u, ToolSummary as v, ToolGraphInput as w, ScopedSkillGraphEntry as x, createToolSummary as y, createPortalAgentIdentity as z };
|
|
199
|
+
//# sourceMappingURL=portal-session-5ksK1G9Z.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal-session-5ksK1G9Z.d.ts","names":[],"sources":["../src/portal-access-policy.ts","../src/tool-ref.ts","../src/tool-graph.ts","../src/tool-summary.ts","../src/search-index.ts","../src/portal-session.ts"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { l as jsonObjectSchema, n as decodeToolRef, t as buildZodValidatorFromJsonSchema } from "./zod-schema-loader-yNekKNpm.js";
|
|
2
|
-
import {
|
|
2
|
+
import { h as createToolSummary, m as upstreamMcpFailureDetailsFromUnknown, v as portalAgentScopeKey } from "./upstream-response-middleware-Cd1MxA6A.js";
|
|
3
3
|
import { t as generateTypescriptCatalogArtifact } from "./typescript-artifact-BVLt3Ifd.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
//#region src/core/portal-call-validation.ts
|
|
@@ -79,6 +79,14 @@ const callExecutionInputSchema = z.object({
|
|
|
79
79
|
calls: z.array(callRequestSchema).min(1),
|
|
80
80
|
portalApprovalToken: z.string().min(1).optional()
|
|
81
81
|
}).strict();
|
|
82
|
+
const describeBeforeCallSchemaHint = {
|
|
83
|
+
message: "Use mcp_portal_describe for exact input schema before calling.",
|
|
84
|
+
next: "describe_before_call"
|
|
85
|
+
};
|
|
86
|
+
const callReadySchemaHint = {
|
|
87
|
+
message: "Full input schema included.",
|
|
88
|
+
next: "call_ready"
|
|
89
|
+
};
|
|
82
90
|
function isToolSchemaProperties(value) {
|
|
83
91
|
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry));
|
|
84
92
|
}
|
|
@@ -133,9 +141,8 @@ function itemOutput(props) {
|
|
|
133
141
|
}
|
|
134
142
|
function discoveryDiagnostics(session) {
|
|
135
143
|
return session.catalog.discoveryFailures.map((failure) => ({
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
namespace: failure.namespace
|
|
144
|
+
...failure,
|
|
145
|
+
kind: failure.kind === "upstream_mcp_failed" ? "upstream_mcp_failed" : "upstream_discovery_failed"
|
|
139
146
|
}));
|
|
140
147
|
}
|
|
141
148
|
function portalBatchResult(results, diagnostics = []) {
|
|
@@ -233,6 +240,7 @@ function describeToolOutput(props) {
|
|
|
233
240
|
annotations: props.tool.annotations ?? {},
|
|
234
241
|
namespace: props.tool.namespace,
|
|
235
242
|
related: props.includeRelated ? props.session.graph.relationships.filter((relationship) => relationship.from.toolRef === toolSummary.toolRef || relationship.to.toolRef === toolSummary.toolRef) : [],
|
|
243
|
+
schemaHint: callReadySchemaHint,
|
|
236
244
|
toolName: props.tool.toolName,
|
|
237
245
|
toolRef: toolSummary.toolRef
|
|
238
246
|
};
|
|
@@ -253,6 +261,7 @@ function searchOutputWithFullSchema(session, summary) {
|
|
|
253
261
|
input: summary.input,
|
|
254
262
|
namespace: summary.namespace,
|
|
255
263
|
safety: summary.safety,
|
|
264
|
+
schemaHint: callReadySchemaHint,
|
|
256
265
|
toolName: summary.toolName,
|
|
257
266
|
toolRef: summary.toolRef
|
|
258
267
|
};
|
|
@@ -267,6 +276,12 @@ function searchOutputWithFullSchema(session, summary) {
|
|
|
267
276
|
}
|
|
268
277
|
return result;
|
|
269
278
|
}
|
|
279
|
+
function toolSummaryWithSchemaHint(summary) {
|
|
280
|
+
return Object.assign({}, summary, { schemaHint: describeBeforeCallSchemaHint });
|
|
281
|
+
}
|
|
282
|
+
function toolSearchResultWithSchemaHint(summary) {
|
|
283
|
+
return Object.assign({}, summary, { schemaHint: describeBeforeCallSchemaHint });
|
|
284
|
+
}
|
|
270
285
|
function listRequestResult(session, request) {
|
|
271
286
|
const filteredTools = applyExactFilters(session.catalog.tools, {
|
|
272
287
|
...request.namespaces !== void 0 ? { namespaces: request.namespaces } : {},
|
|
@@ -277,7 +292,7 @@ function listRequestResult(session, request) {
|
|
|
277
292
|
error: filteredTools.error,
|
|
278
293
|
input: request
|
|
279
294
|
});
|
|
280
|
-
const page = paginate(filteredTools.tools.map((tool) => createToolSummary(tool)), request.limit, request.cursor);
|
|
295
|
+
const page = paginate(filteredTools.tools.map((tool) => toolSummaryWithSchemaHint(createToolSummary(tool))), request.limit, request.cursor);
|
|
281
296
|
return itemOutput({
|
|
282
297
|
input: request,
|
|
283
298
|
output: {
|
|
@@ -295,7 +310,7 @@ function searchRequestResult(session, request) {
|
|
|
295
310
|
});
|
|
296
311
|
return itemOutput({
|
|
297
312
|
input: request,
|
|
298
|
-
output: { tools: request.schemaDetail === "full" ? result.results.map((summary) => searchOutputWithFullSchema(session, summary)) : result.results }
|
|
313
|
+
output: { tools: request.schemaDetail === "full" ? result.results.map((summary) => searchOutputWithFullSchema(session, summary)) : result.results.map((summary) => toolSearchResultWithSchemaHint(summary)) }
|
|
299
314
|
});
|
|
300
315
|
}
|
|
301
316
|
function describeRequestResult(session, request) {
|
|
@@ -377,12 +392,14 @@ async function executePreparedPortalCall(call, identity, runtime) {
|
|
|
377
392
|
}
|
|
378
393
|
});
|
|
379
394
|
} catch (error) {
|
|
395
|
+
const upstream = upstreamMcpFailureDetailsFromUnknown(error);
|
|
380
396
|
return itemError({
|
|
381
397
|
error: {
|
|
382
398
|
kind: "upstream_call_failed",
|
|
383
399
|
message: messageFromError(error),
|
|
384
400
|
namespace: call.tool.namespace,
|
|
385
|
-
toolName: call.tool.toolName
|
|
401
|
+
toolName: call.tool.toolName,
|
|
402
|
+
...upstream === null ? {} : { upstream }
|
|
386
403
|
},
|
|
387
404
|
input
|
|
388
405
|
});
|
|
@@ -525,4 +542,4 @@ function createPortalToolHandlers(runtime) {
|
|
|
525
542
|
//#endregion
|
|
526
543
|
export { portalToolInputSchemas as n, validatePortalToolArguments as r, createPortalToolHandlers as t };
|
|
527
544
|
|
|
528
|
-
//# sourceMappingURL=portal-tools-
|
|
545
|
+
//# sourceMappingURL=portal-tools-DA7j2pyv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal-tools-DA7j2pyv.js","names":[],"sources":["../src/core/portal-call-validation.ts","../src/core/portal-tools.ts"],"sourcesContent":["import type { PortalToolRecord } from '../catalog-types.js';\nimport type { JsonObject } from '../json-schema.js';\nimport { buildZodValidatorFromJsonSchema } from '../zod-schema-loader.js';\n\nexport function validatePortalToolArguments(\n\ttool: PortalToolRecord,\n\targumentsValue: JsonObject,\n):\n\t| { readonly ok: true; readonly value: unknown }\n\t| {\n\t\t\treadonly error:\n\t\t\t\t| {\n\t\t\t\t\t\treadonly issues: readonly {\n\t\t\t\t\t\t\treadonly code: string;\n\t\t\t\t\t\t\treadonly message: string;\n\t\t\t\t\t\t\treadonly path: readonly (number | string)[];\n\t\t\t\t\t\t}[];\n\t\t\t\t\t\treadonly kind: 'input_validation';\n\t\t\t\t\t\treadonly namespace: string;\n\t\t\t\t\t\treadonly toolName: string;\n\t\t\t\t }\n\t\t\t\t| {\n\t\t\t\t\t\treadonly feature: string;\n\t\t\t\t\t\treadonly kind: 'schema_validation_unavailable';\n\t\t\t\t\t\treadonly message: string;\n\t\t\t\t\t\treadonly namespace: string;\n\t\t\t\t\t\treadonly path: readonly (number | string)[];\n\t\t\t\t\t\treadonly toolName: string;\n\t\t\t\t };\n\t\t\treadonly ok: false;\n\t } {\n\tconst validator = buildZodValidatorFromJsonSchema(tool.inputSchema);\n\tif (!validator.ok) {\n\t\treturn {\n\t\t\terror: { ...validator.error, namespace: tool.namespace, toolName: tool.toolName },\n\t\t\tok: false,\n\t\t};\n\t}\n\n\tconst result = validator.validate(argumentsValue);\n\tif (!result.ok) {\n\t\treturn {\n\t\t\terror: { ...result.error, namespace: tool.namespace, toolName: tool.toolName },\n\t\t\tok: false,\n\t\t};\n\t}\n\n\treturn result;\n}\n","import type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\n\nimport type { PortalToolRecord } from '../catalog-types.js';\nimport { jsonObjectSchema, type JsonObject } from '../json-schema.js';\nimport {\n\tportalAgentScopeKey,\n\ttype PortalAgentIdentity,\n\ttype PortalToolSelector,\n} from '../portal-access-policy.js';\nimport { generateTypescriptCatalogArtifact } from '../portal-config/typescript-artifact.js';\nimport type { PortalSession } from '../portal-session.js';\nimport type { ToolSearchResult } from '../search-index.js';\nimport { decodeToolRef } from '../tool-ref.js';\nimport { createToolSummary, type ToolSchemaHint, type ToolSummary } from '../tool-summary.js';\nimport { upstreamMcpFailureDetailsFromUnknown } from '../upstream-mcp-errors.js';\nimport { validatePortalToolArguments } from './portal-call-validation.js';\n\nexport interface PortalToolSuccess {\n\treadonly input: Readonly<Record<string, unknown>>;\n\treadonly ok: true;\n\treadonly output: Readonly<Record<string, unknown>>;\n}\n\nexport interface PortalToolFailure {\n\treadonly error: unknown;\n\treadonly input: Readonly<Record<string, unknown>>;\n\treadonly ok: false;\n}\n\nexport type PortalToolResult = PortalToolFailure | PortalToolSuccess;\nexport type PortalToolResultMap = Readonly<Record<string, PortalToolResult>>;\n\nexport interface PortalBatchError {\n\treadonly id?: string;\n\treadonly kind: string;\n\treadonly message: string;\n}\n\nexport interface PortalBatchDiagnostic {\n\treadonly causeMessage?: string;\n\treadonly elapsedMs?: number;\n\treadonly hint?: string;\n\treadonly kind: string;\n\treadonly message: string;\n\treadonly namespace?: string;\n\treadonly operation?: string;\n\treadonly phase?: string;\n\treadonly timeoutMs?: number;\n\treadonly toolName?: string;\n\treadonly transport?: unknown;\n}\n\nexport interface PortalBatchResult {\n\treadonly diagnostics: readonly PortalBatchDiagnostic[];\n\treadonly errors: readonly PortalBatchError[];\n\treadonly ok: boolean;\n\treadonly results: PortalToolResultMap;\n}\n\nexport interface PortalApprovalCall {\n\treadonly arguments: JsonObject;\n\treadonly id: string;\n\treadonly namespace: string;\n\treadonly tool: PortalToolRecord;\n\treadonly toolName: string;\n}\n\ntype SelectorInputResult =\n\t| { readonly error: PortalBatchError; readonly ok: false }\n\t| { readonly ok: true; readonly selectors: readonly PortalToolSelector[] };\ntype ExactFilterResult =\n\t| { readonly error: PortalBatchError; readonly ok: false }\n\t| { readonly ok: true; readonly tools: readonly PortalToolRecord[] };\n\nconst requestIdSchema = z.string().min(1);\nconst reservedRequestIds = new Set(['__proto__', 'constructor', 'prototype']);\nconst safeRequestIdSchema = requestIdSchema.refine((id) => !reservedRequestIds.has(id), {\n\tmessage: 'Portal request id uses a reserved object property name.',\n});\nconst namespaceToolSelectorSchema = z\n\t.object({ namespace: z.string().min(1), toolName: z.string().min(1) })\n\t.strict();\nconst listRequestSchema = z\n\t.object({\n\t\tcursor: z.string().regex(/^\\d+$/u).optional(),\n\t\tid: safeRequestIdSchema,\n\t\tlimit: z.number().int().positive().max(100).default(20),\n\t\tnamespaces: z.array(z.string()).optional(),\n\t\trefs: z.array(z.string()).optional(),\n\t\ttools: z.array(namespaceToolSelectorSchema).optional(),\n\t})\n\t.strict();\nconst searchRequestSchema = z\n\t.object({\n\t\tid: safeRequestIdSchema,\n\t\tlimit: z.number().int().positive().max(50).default(10),\n\t\tnamespaces: z.array(z.string()).optional(),\n\t\tquery: z.string().optional(),\n\t\tschemaDetail: z.enum(['none', 'summary', 'full']).default('summary'),\n\t})\n\t.strict();\nconst describeRequestSchema = z\n\t.object({\n\t\tid: safeRequestIdSchema,\n\t\tincludeJsonSchema: z.boolean().default(true),\n\t\tincludeRelated: z.boolean().default(true),\n\t\tincludeTypescriptHelper: z.boolean().default(false),\n\t\tincludeZod: z.boolean().default(false),\n\t\trefs: z.array(z.string()).optional(),\n\t\ttools: z.array(namespaceToolSelectorSchema).optional(),\n\t})\n\t.strict();\nconst callRequestSchema = z\n\t.object({\n\t\targuments: jsonObjectSchema,\n\t\tid: safeRequestIdSchema,\n\t\tnamespace: z.string().min(1),\n\t\ttoolName: z.string().min(1),\n\t})\n\t.strict();\nconst listInputSchema = z.object({ requests: z.array(listRequestSchema).min(1) }).strict();\nconst searchInputSchema = z.object({ requests: z.array(searchRequestSchema).min(1) }).strict();\nconst describeInputSchema = z.object({ requests: z.array(describeRequestSchema).min(1) }).strict();\nconst callInputSchema = z.object({ calls: z.array(callRequestSchema).min(1) }).strict();\nconst callExecutionInputSchema = z\n\t.object({\n\t\tcalls: z.array(callRequestSchema).min(1),\n\t\tportalApprovalToken: z.string().min(1).optional(),\n\t})\n\t.strict();\n\ntype ListRequest = z.infer<typeof listRequestSchema>;\ntype SearchRequest = z.infer<typeof searchRequestSchema>;\ntype DescribeRequest = z.infer<typeof describeRequestSchema>;\ntype CallRequest = z.infer<typeof callRequestSchema>;\n\ninterface PreparedPortalCall {\n\treadonly input: CallRequest;\n\treadonly validatedArguments: JsonObject;\n\treadonly tool: PortalToolRecord;\n}\n\nconst describeBeforeCallSchemaHint = {\n\tmessage: 'Use mcp_portal_describe for exact input schema before calling.',\n\tnext: 'describe_before_call',\n} as const satisfies ToolSchemaHint;\n\nconst callReadySchemaHint = {\n\tmessage: 'Full input schema included.',\n\tnext: 'call_ready',\n} as const satisfies ToolSchemaHint;\n\nfunction isToolSchemaProperties(value: unknown): value is Record<string, object> {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t!Array.isArray(value) &&\n\t\tObject.values(value).every(\n\t\t\t(entry) => typeof entry === 'object' && entry !== null && !Array.isArray(entry),\n\t\t)\n\t);\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === 'string');\n}\n\nfunction toPortalInputJsonSchema(schema: z.ZodType): Tool['inputSchema'] {\n\tconst jsonSchema = jsonObjectSchema.parse(z.toJSONSchema(schema, { io: 'input' }));\n\tif (jsonSchema.type !== 'object') {\n\t\tthrow new Error('MCP Portal tool input schemas must be JSON Schema objects.');\n\t}\n\tconst properties = isToolSchemaProperties(jsonSchema.properties)\n\t\t? jsonSchema.properties\n\t\t: undefined;\n\tconst required = isStringArray(jsonSchema.required) ? jsonSchema.required : undefined;\n\n\treturn {\n\t\t...jsonSchema,\n\t\t...(properties !== undefined ? { properties } : {}),\n\t\t...(required !== undefined ? { required } : {}),\n\t\ttype: 'object',\n\t};\n}\n\nexport const portalToolInputSchemas = {\n\tmcp_portal_call: toPortalInputJsonSchema(callInputSchema),\n\tmcp_portal_describe: toPortalInputJsonSchema(describeInputSchema),\n\tmcp_portal_list: toPortalInputJsonSchema(listInputSchema),\n\tmcp_portal_search: toPortalInputJsonSchema(searchInputSchema),\n} as const;\n\nexport interface PortalToolHandlerCall {\n\treadonly identity: PortalAgentIdentity;\n\treadonly input: unknown;\n}\n\nexport interface PortalCallUpstreamTool {\n\treadonly arguments: JsonObject;\n\treadonly agentScopeId: string;\n\treadonly namespace: string;\n\treadonly onEvent?: (event: PortalUpstreamEvent) => Promise<void> | void;\n\treadonly requestId: string;\n\treadonly signal?: AbortSignal;\n\treadonly toolName: string;\n}\n\nexport type PortalUpstreamEvent =\n\t| {\n\t\t\treadonly kind: 'progress';\n\t\t\treadonly message?: string;\n\t\t\treadonly progress?: number;\n\t\t\treadonly total?: number;\n\t }\n\t| {\n\t\t\treadonly kind: 'upstream_notification';\n\t\t\treadonly method: string;\n\t\t\treadonly params: unknown;\n\t }\n\t| {\n\t\t\treadonly content:\n\t\t\t\t| { readonly text: string; readonly type: 'text' }\n\t\t\t\t| { readonly type: 'json'; readonly value: unknown };\n\t\t\treadonly kind: 'partial_content';\n\t };\n\nexport interface PortalToolRuntime {\n\treadonly approval?: (\n\t\tcalls: readonly PortalApprovalCall[],\n\t\tidentity: PortalAgentIdentity,\n\t\tapprovalToken: string | undefined,\n\t) =>\n\t\t| { readonly kind: 'allow' }\n\t\t| { readonly kind: 'approval_token_invalid'; readonly reason: string }\n\t\t| { readonly kind: 'approval_token_missing' }\n\t\t| { readonly kind: 'approval_required'; readonly level: 'critical' | 'standard' };\n\treadonly callUpstreamTool: (call: PortalCallUpstreamTool) => Promise<unknown>;\n\treadonly getSession: (identity: PortalAgentIdentity) => Promise<PortalSession>;\n}\n\ntype PortalApprovalDecision =\n\t| { readonly kind: 'allow' }\n\t| { readonly kind: 'approval_configuration_missing' }\n\t| { readonly kind: 'approval_required'; readonly level: 'critical' | 'standard' }\n\t| { readonly kind: 'approval_token_invalid'; readonly reason: string }\n\t| { readonly kind: 'approval_token_missing' };\n\nexport interface PortalToolHandlers {\n\treadonly call: (call: PortalToolHandlerCall) => Promise<PortalBatchResult>;\n\treadonly describe: (call: PortalToolHandlerCall) => Promise<PortalBatchResult>;\n\treadonly list: (call: PortalToolHandlerCall) => Promise<PortalBatchResult>;\n\treadonly search: (call: PortalToolHandlerCall) => Promise<PortalBatchResult>;\n}\n\nfunction messageFromError(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nfunction invalidPortalInput(error: unknown): PortalBatchResult {\n\treturn {\n\t\tdiagnostics: [],\n\t\terrors: [{ kind: 'invalid_portal_input', message: messageFromError(error) }],\n\t\tok: false,\n\t\tresults: {},\n\t};\n}\n\nfunction itemError(props: {\n\treadonly error: unknown;\n\treadonly input: Readonly<Record<string, unknown>>;\n}): PortalToolResult {\n\treturn {\n\t\terror: props.error,\n\t\tinput: props.input,\n\t\tok: false,\n\t};\n}\n\nfunction itemOutput(props: {\n\treadonly input: Readonly<Record<string, unknown>>;\n\treadonly output: Readonly<Record<string, unknown>>;\n}): PortalToolResult {\n\treturn {\n\t\tinput: props.input,\n\t\tok: true,\n\t\toutput: props.output,\n\t};\n}\n\nfunction discoveryDiagnostics(session: PortalSession): readonly PortalBatchDiagnostic[] {\n\treturn session.catalog.discoveryFailures.map((failure) => ({\n\t\t...failure,\n\t\tkind:\n\t\t\tfailure.kind === 'upstream_mcp_failed' ? 'upstream_mcp_failed' : 'upstream_discovery_failed',\n\t}));\n}\n\nfunction portalBatchResult(\n\tresults: PortalToolResultMap,\n\tdiagnostics: readonly PortalBatchDiagnostic[] = [],\n): PortalBatchResult {\n\tconst allItemsOk = Object.values(results).every((result) => result.ok);\n\treturn { diagnostics, errors: [], ok: allItemsOk, results };\n}\n\nfunction duplicateIdErrors(items: readonly { readonly id: string }[]): readonly PortalBatchError[] {\n\tconst seenIds = new Set<string>();\n\tconst duplicateIds = new Set<string>();\n\tfor (const item of items) {\n\t\tif (seenIds.has(item.id)) {\n\t\t\tduplicateIds.add(item.id);\n\t\t}\n\t\tseenIds.add(item.id);\n\t}\n\n\treturn [...duplicateIds].toSorted().map((id) => ({\n\t\tid,\n\t\tkind: 'duplicate_id',\n\t\tmessage: `Duplicate portal request id \"${id}\". Each request id must be unique.`,\n\t}));\n}\n\nfunction duplicateIdResult(items: readonly { readonly id: string }[]): PortalBatchResult | null {\n\tconst errors = duplicateIdErrors(items);\n\treturn errors.length > 0 ? { diagnostics: [], errors, ok: false, results: {} } : null;\n}\n\nfunction findTool(session: PortalSession, selector: PortalToolSelector): PortalToolRecord | null {\n\treturn (\n\t\tsession.catalog.tools.find(\n\t\t\t(tool) => tool.namespace === selector.namespace && tool.toolName === selector.toolName,\n\t\t) ?? null\n\t);\n}\n\nfunction selectorsFromInput(\n\ttools?: readonly PortalToolSelector[],\n\trefs?: readonly string[],\n): SelectorInputResult {\n\tconst selectors: PortalToolSelector[] = [...(tools ?? [])];\n\tfor (const toolRef of refs ?? []) {\n\t\ttry {\n\t\t\tselectors.push(decodeToolRef(toolRef));\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\terror: { kind: 'invalid_portal_input', message: messageFromError(error) },\n\t\t\t\tok: false,\n\t\t\t};\n\t\t}\n\t}\n\n\treturn { ok: true, selectors };\n}\n\nfunction applyExactFilters(\n\ttools: readonly PortalToolRecord[],\n\tfilters: {\n\t\treadonly namespaces?: readonly string[];\n\t\treadonly refs?: readonly string[];\n\t\treadonly tools?: readonly PortalToolSelector[];\n\t},\n): ExactFilterResult {\n\tconst namespaceFilter = new Set(filters.namespaces ?? []);\n\tconst selectorResult = selectorsFromInput(filters.tools, filters.refs);\n\tif (!selectorResult.ok) {\n\t\treturn selectorResult;\n\t}\n\tconst exactSelectors = selectorResult.selectors;\n\tif (exactSelectors.length === 0) {\n\t\treturn {\n\t\t\tok: true,\n\t\t\ttools: tools.filter(\n\t\t\t\t(tool) => namespaceFilter.size === 0 || namespaceFilter.has(tool.namespace),\n\t\t\t),\n\t\t};\n\t}\n\n\treturn {\n\t\tok: true,\n\t\ttools: tools.filter(\n\t\t\t(tool) =>\n\t\t\t\t(namespaceFilter.size === 0 || namespaceFilter.has(tool.namespace)) &&\n\t\t\t\texactSelectors.some(\n\t\t\t\t\t(selector) =>\n\t\t\t\t\t\tselector.namespace === tool.namespace && selector.toolName === tool.toolName,\n\t\t\t\t),\n\t\t),\n\t};\n}\n\nfunction selectorKey(selector: PortalToolSelector): string {\n\treturn `${selector.namespace}\\n${selector.toolName}`;\n}\n\nfunction missingSelectorError(\n\trequestedSelectors: readonly PortalToolSelector[],\n\tselectedTools: readonly PortalToolRecord[],\n): PortalBatchError | null {\n\tconst foundKeys = new Set(\n\t\tselectedTools.map((tool) =>\n\t\t\tselectorKey({ namespace: tool.namespace, toolName: tool.toolName }),\n\t\t),\n\t);\n\tconst missingSelectors = requestedSelectors.filter(\n\t\t(selector) => !foundKeys.has(selectorKey(selector)),\n\t);\n\tif (missingSelectors.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tkind: 'unknown_or_denied_tool',\n\t\tmessage: 'One or more requested tools are unknown or denied for this portal agent scope.',\n\t};\n}\n\nfunction paginate<TItem>(\n\titems: readonly TItem[],\n\tlimit: number,\n\tcursor?: string,\n): { readonly items: readonly TItem[]; readonly nextCursor?: string } {\n\tconst offset = cursor ? Number.parseInt(cursor, 10) : 0;\n\tconst safeOffset = Number.isFinite(offset) && offset > 0 ? offset : 0;\n\tconst page = items.slice(safeOffset, safeOffset + limit);\n\tconst nextOffset = safeOffset + page.length;\n\n\treturn {\n\t\titems: page,\n\t\t...(nextOffset < items.length ? { nextCursor: String(nextOffset) } : {}),\n\t};\n}\n\nfunction describeToolOutput(props: {\n\treadonly includeJsonSchema: boolean;\n\treadonly includeRelated: boolean;\n\treadonly includeTypescriptHelper: boolean;\n\treadonly includeZod: boolean;\n\treadonly session: PortalSession;\n\treadonly tool: PortalToolRecord;\n}): Readonly<Record<string, unknown>> {\n\tconst toolSummary = createToolSummary(props.tool);\n\tconst result: Record<string, unknown> = {\n\t\tannotations: props.tool.annotations ?? {},\n\t\tnamespace: props.tool.namespace,\n\t\trelated: props.includeRelated\n\t\t\t? props.session.graph.relationships.filter(\n\t\t\t\t\t(relationship) =>\n\t\t\t\t\t\trelationship.from.toolRef === toolSummary.toolRef ||\n\t\t\t\t\t\trelationship.to.toolRef === toolSummary.toolRef,\n\t\t\t\t)\n\t\t\t: [],\n\t\tschemaHint: callReadySchemaHint,\n\t\ttoolName: props.tool.toolName,\n\t\ttoolRef: toolSummary.toolRef,\n\t};\n\n\tif (props.includeJsonSchema) {\n\t\tresult.inputSchema = props.tool.inputSchema;\n\t\tresult.outputSchema = props.tool.outputSchema;\n\t}\n\tif (props.includeZod) {\n\t\tresult.zod = { experimental: true, source: 'z.fromJSONSchema(inputSchema)' };\n\t}\n\tif (props.includeTypescriptHelper) {\n\t\tresult.typescriptHelper = generateTypescriptCatalogArtifact({ tools: [props.tool] });\n\t}\n\n\treturn result;\n}\n\nfunction searchOutputWithFullSchema(\n\tsession: PortalSession,\n\tsummary: ToolSearchResult,\n): Readonly<Record<string, unknown>> {\n\tconst tool = findTool(session, summary);\n\tconst result: Record<string, unknown> = {\n\t\tinput: summary.input,\n\t\tnamespace: summary.namespace,\n\t\tsafety: summary.safety,\n\t\tschemaHint: callReadySchemaHint,\n\t\ttoolName: summary.toolName,\n\t\ttoolRef: summary.toolRef,\n\t};\n\n\tif (summary.description !== undefined) {\n\t\tresult.description = summary.description;\n\t}\n\tif (summary.output !== undefined) {\n\t\tresult.output = summary.output;\n\t}\n\tif (summary.relationshipHints !== undefined) {\n\t\tresult.relationshipHints = summary.relationshipHints;\n\t}\n\tif (summary.schemaFieldMatches !== undefined) {\n\t\tresult.schemaFieldMatches = summary.schemaFieldMatches;\n\t}\n\tif (summary.title !== undefined) {\n\t\tresult.title = summary.title;\n\t}\n\n\tif (tool) {\n\t\tresult.inputSchema = tool.inputSchema;\n\t\tresult.outputSchema = tool.outputSchema;\n\t}\n\n\treturn result;\n}\n\nfunction toolSummaryWithSchemaHint(summary: ToolSummary): ToolSummary {\n\treturn Object.assign({}, summary, { schemaHint: describeBeforeCallSchemaHint });\n}\n\nfunction toolSearchResultWithSchemaHint(\n\tsummary: ToolSearchResult,\n): ToolSearchResult & { readonly schemaHint: ToolSchemaHint } {\n\treturn Object.assign({}, summary, { schemaHint: describeBeforeCallSchemaHint });\n}\n\nfunction listRequestResult(session: PortalSession, request: ListRequest): PortalToolResult {\n\tconst filteredTools = applyExactFilters(session.catalog.tools, {\n\t\t...(request.namespaces !== undefined ? { namespaces: request.namespaces } : {}),\n\t\t...(request.refs !== undefined ? { refs: request.refs } : {}),\n\t\t...(request.tools !== undefined ? { tools: request.tools } : {}),\n\t});\n\tif (!filteredTools.ok) {\n\t\treturn itemError({ error: filteredTools.error, input: request });\n\t}\n\tconst page = paginate(\n\t\tfilteredTools.tools.map((tool) => toolSummaryWithSchemaHint(createToolSummary(tool))),\n\t\trequest.limit,\n\t\trequest.cursor,\n\t);\n\tconst output = {\n\t\tnamespaces: [...new Set(filteredTools.tools.map((tool) => tool.namespace))].toSorted(),\n\t\t...(page.nextCursor !== undefined ? { nextCursor: page.nextCursor } : {}),\n\t\ttools: page.items,\n\t} satisfies {\n\t\treadonly namespaces: readonly string[];\n\t\treadonly nextCursor?: string;\n\t\treadonly tools: readonly ToolSummary[];\n\t};\n\n\treturn itemOutput({ input: request, output });\n}\n\nfunction searchRequestResult(session: PortalSession, request: SearchRequest): PortalToolResult {\n\tconst result = session.searchIndex.search({\n\t\tlimit: request.limit,\n\t\t...(request.namespaces ? { namespaces: request.namespaces } : {}),\n\t\t...(request.query !== undefined ? { query: request.query } : {}),\n\t});\n\tconst tools =\n\t\trequest.schemaDetail === 'full'\n\t\t\t? result.results.map((summary) => searchOutputWithFullSchema(session, summary))\n\t\t\t: result.results.map((summary) => toolSearchResultWithSchemaHint(summary));\n\n\treturn itemOutput({ input: request, output: { tools } });\n}\n\nfunction describeRequestResult(session: PortalSession, request: DescribeRequest): PortalToolResult {\n\tconst selectorResult = selectorsFromInput(request.tools, request.refs);\n\tif (!selectorResult.ok) {\n\t\treturn itemError({ error: selectorResult.error, input: request });\n\t}\n\tconst selectors = selectorResult.selectors;\n\tconst selectedTools = selectors\n\t\t.map((selector) => findTool(session, selector))\n\t\t.filter((tool): tool is PortalToolRecord => tool !== null);\n\tconst missingError = missingSelectorError(selectors, selectedTools);\n\tif (missingError) {\n\t\treturn itemError({\n\t\t\terror: {\n\t\t\t\t...missingError,\n\t\t\t\ttools: selectors.filter((selector) => findTool(session, selector) === null),\n\t\t\t},\n\t\t\tinput: request,\n\t\t});\n\t}\n\n\tconst tools = selectedTools.map((tool) =>\n\t\tdescribeToolOutput({\n\t\t\tincludeJsonSchema: request.includeJsonSchema,\n\t\t\tincludeRelated: request.includeRelated,\n\t\t\tincludeTypescriptHelper: request.includeTypescriptHelper,\n\t\t\tincludeZod: request.includeZod,\n\t\t\tsession,\n\t\t\ttool,\n\t\t}),\n\t);\n\treturn itemOutput({ input: request, output: { tools } });\n}\n\nfunction preparePortalCall(\n\tsession: PortalSession,\n\trequest: CallRequest,\n): PreparedPortalCall | PortalToolResult {\n\tconst tool = findTool(session, request);\n\tif (!tool) {\n\t\treturn itemError({\n\t\t\terror: {\n\t\t\t\tkind: 'unknown_or_denied_tool',\n\t\t\t\tmessage: 'The requested tool is unknown or denied for this portal agent scope.',\n\t\t\t\tnamespace: request.namespace,\n\t\t\t\ttoolName: request.toolName,\n\t\t\t},\n\t\t\tinput: request,\n\t\t});\n\t}\n\n\tconst validation = validatePortalToolArguments(tool, request.arguments);\n\tif (!validation.ok) {\n\t\treturn itemError({ error: validation.error, input: request });\n\t}\n\tconst validatedArgumentsResult = jsonObjectSchema.safeParse(validation.value);\n\tif (!validatedArgumentsResult.success) {\n\t\treturn itemError({\n\t\t\terror: {\n\t\t\t\tkind: 'invalid_portal_input',\n\t\t\t\tmessage: validatedArgumentsResult.error.message,\n\t\t\t},\n\t\t\tinput: request,\n\t\t});\n\t}\n\n\treturn { input: request, tool, validatedArguments: validatedArgumentsResult.data };\n}\n\nasync function executePreparedPortalCall(\n\tcall: PreparedPortalCall,\n\tidentity: PortalAgentIdentity,\n\truntime: PortalToolRuntime,\n): Promise<PortalToolResult> {\n\tconst input = { ...call.input, arguments: call.validatedArguments };\n\ttry {\n\t\treturn itemOutput({\n\t\t\tinput,\n\t\t\toutput: {\n\t\t\t\tnamespace: call.tool.namespace,\n\t\t\t\tresult: await runtime.callUpstreamTool({\n\t\t\t\t\targuments: call.validatedArguments,\n\t\t\t\t\tagentScopeId: portalAgentScopeKey(identity),\n\t\t\t\t\tnamespace: call.tool.namespace,\n\t\t\t\t\trequestId: call.input.id,\n\t\t\t\t\ttoolName: call.tool.toolName,\n\t\t\t\t}),\n\t\t\t\ttoolName: call.tool.toolName,\n\t\t\t},\n\t\t});\n\t} catch (error) {\n\t\tconst upstream = upstreamMcpFailureDetailsFromUnknown(error);\n\t\treturn itemError({\n\t\t\terror: {\n\t\t\t\tkind: 'upstream_call_failed',\n\t\t\t\tmessage: messageFromError(error),\n\t\t\t\tnamespace: call.tool.namespace,\n\t\t\t\ttoolName: call.tool.toolName,\n\t\t\t\t...(upstream === null ? {} : { upstream }),\n\t\t\t},\n\t\t\tinput,\n\t\t});\n\t}\n}\n\nfunction isPreparedPortalCall(\n\tvalue: PreparedPortalCall | PortalToolResult,\n): value is PreparedPortalCall {\n\treturn 'validatedArguments' in value;\n}\n\nasync function addExecutableCallResults(props: {\n\treadonly identity: PortalAgentIdentity;\n\treadonly preparedCalls: readonly PreparedPortalCall[];\n\treadonly results: Record<string, PortalToolResult>;\n\treadonly runtime: PortalToolRuntime;\n}): Promise<void> {\n\tawait Promise.all(\n\t\tprops.preparedCalls.map(async (preparedCall): Promise<void> => {\n\t\t\tprops.results[preparedCall.input.id] = await executePreparedPortalCall(\n\t\t\t\tpreparedCall,\n\t\t\t\tprops.identity,\n\t\t\t\tprops.runtime,\n\t\t\t);\n\t\t}),\n\t);\n}\n\nexport function createPortalToolHandlers(runtime: PortalToolRuntime): PortalToolHandlers {\n\treturn {\n\t\tasync call(call: PortalToolHandlerCall): Promise<PortalBatchResult> {\n\t\t\tconst parsedInput = callExecutionInputSchema.safeParse(call.input);\n\t\t\tif (!parsedInput.success) {\n\t\t\t\treturn invalidPortalInput(parsedInput.error);\n\t\t\t}\n\t\t\tconst duplicateResult = duplicateIdResult(parsedInput.data.calls);\n\t\t\tif (duplicateResult) {\n\t\t\t\treturn duplicateResult;\n\t\t\t}\n\n\t\t\tconst session = await runtime.getSession(call.identity);\n\t\t\tconst preparedResults = parsedInput.data.calls.map((request) =>\n\t\t\t\tpreparePortalCall(session, request),\n\t\t\t);\n\t\t\tconst executableCalls = preparedResults.filter(isPreparedPortalCall);\n\t\t\tconst approvalCalls = executableCalls.map(\n\t\t\t\t(executableCall) =>\n\t\t\t\t\t({\n\t\t\t\t\t\targuments: executableCall.validatedArguments,\n\t\t\t\t\t\tid: executableCall.input.id,\n\t\t\t\t\t\tnamespace: executableCall.tool.namespace,\n\t\t\t\t\t\ttool: executableCall.tool,\n\t\t\t\t\t\ttoolName: executableCall.tool.toolName,\n\t\t\t\t\t}) satisfies PortalApprovalCall,\n\t\t\t);\n\t\t\tconst allowDecision = { kind: 'allow' } satisfies PortalApprovalDecision;\n\t\t\tconst approval: PortalApprovalDecision =\n\t\t\t\tapprovalCalls.length === 0\n\t\t\t\t\t? allowDecision\n\t\t\t\t\t: (runtime.approval?.(\n\t\t\t\t\t\t\tapprovalCalls,\n\t\t\t\t\t\t\tcall.identity,\n\t\t\t\t\t\t\tparsedInput.data.portalApprovalToken,\n\t\t\t\t\t\t) ?? { kind: 'approval_configuration_missing' });\n\n\t\t\tconst results: Record<string, PortalToolResult> = {};\n\t\t\tconst callsToExecute: PreparedPortalCall[] = [];\n\t\t\tfor (const preparedResult of preparedResults) {\n\t\t\t\tif (!isPreparedPortalCall(preparedResult)) {\n\t\t\t\t\tconst input = preparedResult.input;\n\t\t\t\t\tif (typeof input === 'object' && input !== null && 'id' in input) {\n\t\t\t\t\t\tconst id = input.id;\n\t\t\t\t\t\tif (typeof id === 'string') {\n\t\t\t\t\t\t\tresults[id] = preparedResult;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (approval.kind === 'approval_required') {\n\t\t\t\t\tresults[preparedResult.input.id] = itemError({\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tkind: 'approval_required',\n\t\t\t\t\t\t\tlevel: approval.level,\n\t\t\t\t\t\t\tmessage: 'Operator approval is required before this batch can run.',\n\t\t\t\t\t\t\tnamespace: preparedResult.tool.namespace,\n\t\t\t\t\t\t\ttoolName: preparedResult.tool.toolName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinput: { ...preparedResult.input, arguments: preparedResult.validatedArguments },\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (approval.kind === 'approval_token_missing') {\n\t\t\t\t\tresults[preparedResult.input.id] = itemError({\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tkind: 'approval_token_missing',\n\t\t\t\t\t\t\tmessage: 'An MCP Portal approval token is required before this batch can run.',\n\t\t\t\t\t\t\tnamespace: preparedResult.tool.namespace,\n\t\t\t\t\t\t\ttoolName: preparedResult.tool.toolName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinput: { ...preparedResult.input, arguments: preparedResult.validatedArguments },\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (approval.kind === 'approval_token_invalid') {\n\t\t\t\t\tresults[preparedResult.input.id] = itemError({\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tkind: 'approval_token_invalid',\n\t\t\t\t\t\t\tmessage: `MCP Portal approval token is invalid: ${approval.reason}.`,\n\t\t\t\t\t\t\tnamespace: preparedResult.tool.namespace,\n\t\t\t\t\t\t\treason: approval.reason,\n\t\t\t\t\t\t\ttoolName: preparedResult.tool.toolName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinput: { ...preparedResult.input, arguments: preparedResult.validatedArguments },\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (approval.kind === 'approval_configuration_missing') {\n\t\t\t\t\tresults[preparedResult.input.id] = itemError({\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tkind: 'approval_configuration_missing',\n\t\t\t\t\t\t\tmessage: 'MCP Portal approval evaluation is not configured.',\n\t\t\t\t\t\t\tnamespace: preparedResult.tool.namespace,\n\t\t\t\t\t\t\ttoolName: preparedResult.tool.toolName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinput: { ...preparedResult.input, arguments: preparedResult.validatedArguments },\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcallsToExecute.push(preparedResult);\n\t\t\t}\n\t\t\tawait addExecutableCallResults({\n\t\t\t\tidentity: call.identity,\n\t\t\t\tpreparedCalls: callsToExecute,\n\t\t\t\tresults,\n\t\t\t\truntime,\n\t\t\t});\n\n\t\t\treturn portalBatchResult(results, discoveryDiagnostics(session));\n\t\t},\n\t\tasync describe(call: PortalToolHandlerCall): Promise<PortalBatchResult> {\n\t\t\tconst parsedInput = describeInputSchema.safeParse(call.input);\n\t\t\tif (!parsedInput.success) {\n\t\t\t\treturn invalidPortalInput(parsedInput.error);\n\t\t\t}\n\t\t\tconst duplicateResult = duplicateIdResult(parsedInput.data.requests);\n\t\t\tif (duplicateResult) {\n\t\t\t\treturn duplicateResult;\n\t\t\t}\n\n\t\t\tconst session = await runtime.getSession(call.identity);\n\t\t\treturn portalBatchResult(\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tparsedInput.data.requests.map((request) => [\n\t\t\t\t\t\trequest.id,\n\t\t\t\t\t\tdescribeRequestResult(session, request),\n\t\t\t\t\t]),\n\t\t\t\t),\n\t\t\t\tdiscoveryDiagnostics(session),\n\t\t\t);\n\t\t},\n\t\tasync list(call: PortalToolHandlerCall): Promise<PortalBatchResult> {\n\t\t\tconst parsedInput = listInputSchema.safeParse(call.input);\n\t\t\tif (!parsedInput.success) {\n\t\t\t\treturn invalidPortalInput(parsedInput.error);\n\t\t\t}\n\t\t\tconst duplicateResult = duplicateIdResult(parsedInput.data.requests);\n\t\t\tif (duplicateResult) {\n\t\t\t\treturn duplicateResult;\n\t\t\t}\n\n\t\t\tconst session = await runtime.getSession(call.identity);\n\t\t\treturn portalBatchResult(\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tparsedInput.data.requests.map((request) => [\n\t\t\t\t\t\trequest.id,\n\t\t\t\t\t\tlistRequestResult(session, request),\n\t\t\t\t\t]),\n\t\t\t\t),\n\t\t\t\tdiscoveryDiagnostics(session),\n\t\t\t);\n\t\t},\n\t\tasync search(call: PortalToolHandlerCall): Promise<PortalBatchResult> {\n\t\t\tconst parsedInput = searchInputSchema.safeParse(call.input);\n\t\t\tif (!parsedInput.success) {\n\t\t\t\treturn invalidPortalInput(parsedInput.error);\n\t\t\t}\n\t\t\tconst duplicateResult = duplicateIdResult(parsedInput.data.requests);\n\t\t\tif (duplicateResult) {\n\t\t\t\treturn duplicateResult;\n\t\t\t}\n\n\t\t\tconst session = await runtime.getSession(call.identity);\n\t\t\treturn portalBatchResult(\n\t\t\t\tObject.fromEntries(\n\t\t\t\t\tparsedInput.data.requests.map((request) => [\n\t\t\t\t\t\trequest.id,\n\t\t\t\t\t\tsearchRequestResult(session, request),\n\t\t\t\t\t]),\n\t\t\t\t),\n\t\t\t\tdiscoveryDiagnostics(session),\n\t\t\t);\n\t\t},\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as PortalCore, y as PortalApprovalCall } from "./portal-core-
|
|
1
|
+
import { P as PortalAgentIdentity, z as createPortalAgentIdentity } from "./portal-session-5ksK1G9Z.js";
|
|
2
|
+
import { a as PortalCore, y as PortalApprovalCall } from "./portal-core-Ckq-Mrzb.js";
|
|
3
3
|
import { McpPortalAgentConfig, McpPortalConfig, ResolvedMcpPortalProfile, SecretValue } from "@agent-vm/config-contracts";
|
|
4
4
|
import { Hono } from "hono";
|
|
5
5
|
|
|
@@ -78,4 +78,4 @@ declare function createPortalApprovalVerifier(props: {
|
|
|
78
78
|
};
|
|
79
79
|
//#endregion
|
|
80
80
|
export { createPortalApprovalVerifier as a, PortalAgentBearerAuth as c, PortalHttpAppOptions as d, PortalHttpAuditEvent as f, createPortalAgentRuntimeRecords as i, PortalHttpAgentIdentity as l, PortalApprovalAuditEvent as n, createPortalHttpAgentResolver as o, createPortalHttpApp as p, ResolveAgentHmacKeysProps as r, resolveAgentHmacKeys as s, PortalAgentRuntimeRecord as t, PortalHttpApp as u };
|
|
81
|
-
//# sourceMappingURL=resolve-agent-identity-
|
|
81
|
+
//# sourceMappingURL=resolve-agent-identity-C9Jc2NhJ.d.ts.map
|
package/dist/{resolve-agent-identity-FQL02YdW.d.ts.map → resolve-agent-identity-C9Jc2NhJ.d.ts.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-agent-identity-
|
|
1
|
+
{"version":3,"file":"resolve-agent-identity-C9Jc2NhJ.d.ts","names":[],"sources":["../src/mcp-proxy/portal-http-server.ts","../src/mcp-proxy/resolve-agent-identity.ts"],"mappings":";;;;;;UAWiB,uBAAA,SAAgC,mBAAA;AAAA,UAEhC,qBAAA;EAAA,SACP,uBAAA;EAAA,SACA,yBAAA,GAA4B,QAAA,CAAS,MAAA;EAAA,SACrC,SAAA,EAAW,MAAA;AAAA;AAAA,KAGT,oBAAA;EAAA,SACF,OAAA;EAAA,SACA,aAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,MAAA;EAAA,SAMA,MAAA;AAAA;AAAA,UAGO,oBAAA;EAAA,SACP,eAAA,EAAiB,qBAAA;EAAA,SACjB,cAAA,IAAkB,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,oBAAA,KAAyB,OAAA;EAAA,SAChE,SAAA,IAAa,KAAA,EAAO,oBAAA,KAAyB,OAAA;EAAA,SAC7C,gBAAA;IAAA,SACC,WAAA;IAAA,SACA,QAAA;EAAA;EAAA,SAED,IAAA,EAAM,UAAA;EAAA,SACN,eAAA,IAAmB,QAAA,EAAU,mBAAA,KAAwB,OAAA;EAAA,SACrD,mBAAA,IACR,KAAA,EAAO,KAAA,EACP,QAAA,EAAU,mBAAA,KACN,OAAA;EAAA,SACI,kBAAA;EAAA,SACA,oBAAA,IAAwB,OAAA,aAAoB,uBAAA;AAAA;AAAA,KAG1C,aAAA,GAAgB,IAAA;EAAA,SAClB,mBAAA,QAA2B,OAAA;AAAA;AAAA,iBAiDrB,mBAAA,CAAoB,OAAA,EAAS,oBAAA,GAAuB,aAAA;;;UCrFnD,yBAAA;EAAA,SACP,MAAA,EAAQ,QAAA,CAAS,MAAA,SAAe,oBAAA;EAAA,SAChC,OAAA,EAAS,WAAA,SAAoB,MAAA;EAAA,SAC7B,aAAA,GAAgB,MAAA,EAAQ,WAAA,KAAgB,OAAA;AAAA;AAAA,UAGjC,wBAAA;EAAA,SACP,OAAA;EAAA,SACA,OAAA,EAAS,MAAA;EAAA,SACT,OAAA,EAAS,wBAAA;EAAA,SACT,WAAA;AAAA;AAAA,UAGO,wBAAA;EAAA,SACP,OAAA;EAAA,SACA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,MAAA;EAAA,SACA,MAAA;EAAA,SACA,cAAA;AAAA;AAAA,iBAuBY,oBAAA,CACrB,KAAA,EAAO,yBAAA,GACL,OAAA,CAAQ,WAAA,SAAoB,MAAA;AAAA,iBAef,+BAAA,CAAgC,KAAA;EAAA,SACtC,QAAA,EAAU,WAAA,SAAoB,MAAA;EAAA,SAC9B,YAAA,EAAc,eAAA;AAAA,IACpB,WAAA,SAAoB,wBAAA;AAAA,iBAiBR,6BAAA,CACf,OAAA,EAAS,WAAA,SAAoB,wBAAA,KAC1B,OAAA,aAAoB,UAAA,QAAkB,yBAAA;AAAA,iBAsC1B,4BAAA,CAA6B,KAAA;EAAA,SACnC,6BAAA;EAAA,SACA,cAAA,IAAkB,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,wBAAA;EAAA,SACvC,SAAA,IAAa,KAAA,EAAO,wBAAA;EAAA,SACpB,OAAA,EAAS,WAAA,SAAoB,wBAAA;AAAA,KAEtC,KAAA,WAAgB,kBAAA,IAChB,OAAA,UACA,KAAA;EAAA,SAEa,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAAyC,MAAA;AAAA;EAAA,SACzC,IAAA;AAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as portalToolInputSchemas } from "./portal-tools-
|
|
1
|
+
import { _ as createPortalAgentIdentity, i as redactThrownError } from "./upstream-response-middleware-Cd1MxA6A.js";
|
|
2
|
+
import { n as portalToolInputSchemas } from "./portal-tools-DA7j2pyv.js";
|
|
3
3
|
import { i as verifyAgentBearerAuthorization } from "./agent-bearer-token-DCtpDPCZ.js";
|
|
4
4
|
import { r as verifyApprovalToken, t as hashCallArguments } from "./hmac-token-DBqWY3-w.js";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
@@ -547,4 +547,4 @@ function createPortalApprovalVerifier(props) {
|
|
|
547
547
|
//#endregion
|
|
548
548
|
export { createPortalHttpApp as a, listPortalMcpTools as c, resolveAgentHmacKeys as i, portalMcpToolNames as l, createPortalApprovalVerifier as n, createPortalMcpServer as o, createPortalHttpAgentResolver as r, emitMcpProgress as s, createPortalAgentRuntimeRecords as t };
|
|
549
549
|
|
|
550
|
-
//# sourceMappingURL=resolve-agent-identity-
|
|
550
|
+
//# sourceMappingURL=resolve-agent-identity-ZMMY2Wqm.js.map
|
package/dist/{resolve-agent-identity-DnC_Pmnh.js.map → resolve-agent-identity-ZMMY2Wqm.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-agent-identity-DnC_Pmnh.js","names":[],"sources":["../src/mcp-proxy/portal-mcp-server.ts","../src/mcp-proxy/portal-http-server.ts","../src/mcp-proxy/resolve-agent-identity.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\ttype CallToolResult,\n\ttype Tool,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport type {\n\tPortalAgentScope,\n\tPortalCore,\n\tPortalCoreEvent,\n\tPortalCoreToolDescriptor,\n\tPortalCoreResult,\n\tPortalCoreToolName,\n} from '../core/portal-core.js';\nimport { portalToolInputSchemas } from '../core/portal-tools.js';\nimport { redactThrownError } from '../upstream-response-middleware.js';\n\nexport const portalMcpToolNames = [\n\t'mcp_portal_list',\n\t'mcp_portal_search',\n\t'mcp_portal_describe',\n\t'mcp_portal_call',\n] as const;\n\nexport type PortalMcpToolName = (typeof portalMcpToolNames)[number];\n\nconst portalMcpToolNameSet = new Set<string>(portalMcpToolNames);\n\nfunction isPortalCoreToolName(value: string): value is PortalCoreToolName {\n\treturn portalMcpToolNameSet.has(value);\n}\n\nexport function listPortalMcpTools(\n\tdescriptors?: readonly PortalCoreToolDescriptor[],\n): readonly Tool[] {\n\treturn (\n\t\tdescriptors ?? [\n\t\t\t{\n\t\t\t\tdescription: 'List authorized MCP namespaces and compact tool summaries.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_list,\n\t\t\t\tname: 'mcp_portal_list',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescription: 'Search the caller scoped MCP Portal index.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_search,\n\t\t\t\tname: 'mcp_portal_search',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescription: 'Describe exact MCP tool schemas and optional TypeScript/Zod helpers.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_describe,\n\t\t\t\tname: 'mcp_portal_describe',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescription: 'Validate and call an authorized upstream MCP tool by namespace and toolName.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_call,\n\t\t\t\tname: 'mcp_portal_call',\n\t\t\t},\n\t\t]\n\t);\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction coreResultIsError(value: PortalCoreResult): boolean {\n\tif (value.items.some((item) => item.status === 'failed')) {\n\t\treturn true;\n\t}\n\tif (!isObjectRecord(value.structuredContent)) {\n\t\treturn false;\n\t}\n\treturn value.structuredContent.ok === false;\n}\n\nfunction jsonToolResult(value: PortalCoreResult): CallToolResult {\n\treturn {\n\t\tcontent: [{ text: JSON.stringify(value), type: 'text' }],\n\t\t...(coreResultIsError(value) ? { isError: true } : {}),\n\t};\n}\n\nfunction errorToolResult(error: unknown): CallToolResult {\n\tconst redactedError = redactThrownError(error);\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttext: redactedError.message,\n\t\t\t\ttype: 'text',\n\t\t\t},\n\t\t],\n\t\tisError: true,\n\t};\n}\n\nasync function sendBestEffortNotification(\n\tnotification: {\n\t\treadonly method: 'notifications/message' | 'notifications/progress';\n\t\treadonly params: Record<string, unknown>;\n\t},\n\tsendNotification: (notification: {\n\t\treadonly method: 'notifications/message' | 'notifications/progress';\n\t\treadonly params: Record<string, unknown>;\n\t}) => Promise<void>,\n): Promise<void> {\n\ttry {\n\t\tawait sendNotification(notification);\n\t} catch {\n\t\t// Progress is advisory; unsupported client notification channels must not fail the tool call.\n\t}\n}\n\nexport async function emitMcpProgress(props: {\n\treadonly event: PortalCoreEvent;\n\treadonly sendNotification: (notification: {\n\t\treadonly method: 'notifications/message' | 'notifications/progress';\n\t\treadonly params: Record<string, unknown>;\n\t}) => Promise<void>;\n\treadonly progressToken: number | string | undefined;\n}): Promise<void> {\n\tif (props.event.kind === 'upstream_notification') {\n\t\tif (!isObjectRecord(props.event.params)) {\n\t\t\treturn;\n\t\t}\n\t\tif (props.event.method === 'notifications/progress') {\n\t\t\tif (props.progressToken === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sendBestEffortNotification(\n\t\t\t\t{\n\t\t\t\t\tmethod: 'notifications/progress',\n\t\t\t\t\tparams: { ...props.event.params, progressToken: props.progressToken },\n\t\t\t\t},\n\t\t\t\tprops.sendNotification,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (props.event.method !== 'notifications/message') {\n\t\t\treturn;\n\t\t}\n\t\tawait sendBestEffortNotification(\n\t\t\t{\n\t\t\t\tmethod: 'notifications/message',\n\t\t\t\tparams: props.event.params,\n\t\t\t},\n\t\t\tprops.sendNotification,\n\t\t);\n\t\treturn;\n\t}\n\tif (props.event.kind !== 'progress' && props.event.kind !== 'partial_content') {\n\t\treturn;\n\t}\n\tconst message =\n\t\tprops.event.kind === 'progress'\n\t\t\t? props.event.message\n\t\t\t: props.event.content.type === 'text'\n\t\t\t\t? props.event.content.text\n\t\t\t\t: JSON.stringify(props.event.content.value);\n\tif (message === undefined || message.length === 0) {\n\t\treturn;\n\t}\n\tif (props.progressToken !== undefined) {\n\t\tawait sendBestEffortNotification(\n\t\t\t{\n\t\t\t\tmethod: 'notifications/progress',\n\t\t\t\tparams: {\n\t\t\t\t\tmessage,\n\t\t\t\t\tprogress: props.event.kind === 'progress' ? (props.event.progress ?? 0) : 0,\n\t\t\t\t\tprogressToken: props.progressToken,\n\t\t\t\t\t...(props.event.kind === 'progress' && props.event.total !== undefined\n\t\t\t\t\t\t? { total: props.event.total }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tprops.sendNotification,\n\t\t);\n\t\treturn;\n\t}\n\tawait sendBestEffortNotification(\n\t\t{\n\t\t\tmethod: 'notifications/message',\n\t\t\tparams: {\n\t\t\t\tdata: message,\n\t\t\t\tlevel: 'info',\n\t\t\t},\n\t\t},\n\t\tprops.sendNotification,\n\t);\n}\n\nexport function createPortalMcpServer(props: {\n\treadonly core: PortalCore;\n\treadonly scope: PortalAgentScope;\n}): Server {\n\tconst server = new Server(\n\t\t{ name: 'mcp-portal', version: '1.0.0' },\n\t\t{ capabilities: { tools: { listChanged: false } } },\n\t);\n\n\tserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n\t\ttools: listPortalMcpTools(props.core.describeTools(props.scope)),\n\t}));\n\n\tserver.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n\t\tif (!isPortalCoreToolName(request.params.name)) {\n\t\t\treturn {\n\t\t\t\tcontent: [{ text: `Unknown MCP Portal tool: ${request.params.name}`, type: 'text' }],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\tconst result = await props.core.collectPortalCoreResult(\n\t\t\t\tprops.core.callStream({\n\t\t\t\t\tinput: request.params.arguments ?? {},\n\t\t\t\t\tscope: props.scope,\n\t\t\t\t\tsignal: extra.signal,\n\t\t\t\t\ttoolName: request.params.name,\n\t\t\t\t}),\n\t\t\t\t{\n\t\t\t\t\tonEvent: async (event) => {\n\t\t\t\t\t\tawait emitMcpProgress({\n\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\tprogressToken: extra['_meta']?.progressToken,\n\t\t\t\t\t\t\tsendNotification: extra.sendNotification,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn jsonToolResult(result);\n\t\t} catch (error) {\n\t\t\treturn errorToolResult(error);\n\t\t}\n\t});\n\n\treturn server;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { StreamableHTTPTransport } from '@hono/mcp';\nimport { getConnInfo } from '@hono/node-server/conninfo';\nimport { Hono, type Context } from 'hono';\n\nimport type { PortalCore } from '../core/portal-core.js';\nimport { createPortalAgentIdentity, type PortalAgentIdentity } from '../portal-access-policy.js';\nimport { verifyAgentBearerAuthorization } from '../portal-auth/agent-bearer-token.js';\nimport { createPortalMcpServer } from './portal-mcp-server.js';\n\nexport interface PortalHttpAgentIdentity extends PortalAgentIdentity {}\n\nexport interface PortalAgentBearerAuth {\n\treadonly authorizationHeaderName: string;\n\treadonly credentialVersionsByAgent?: Readonly<Record<string, number>>;\n\treadonly masterKey: Buffer;\n}\n\nexport type PortalHttpAuditEvent = {\n\treadonly agentId: string;\n\treadonly clientAddress: string;\n\treadonly decision: 'allow' | 'deny';\n\treadonly kind: 'mcp_proxy_auth';\n\treadonly reason?:\n\t\t| 'malformed'\n\t\t| 'missing'\n\t\t| 'rate_limited'\n\t\t| 'signature-mismatch'\n\t\t| 'unknown_agent';\n\treadonly timeMs: number;\n};\n\nexport interface PortalHttpAppOptions {\n\treadonly agentBearerAuth: PortalAgentBearerAuth;\n\treadonly auditErrorSink?: (error: Error, event: PortalHttpAuditEvent) => Promise<void> | void;\n\treadonly auditSink?: (event: PortalHttpAuditEvent) => Promise<void> | void;\n\treadonly authFailureLimit?: {\n\t\treadonly maxFailures: number;\n\t\treadonly windowMs: number;\n\t};\n\treadonly core: PortalCore;\n\treadonly onSessionClosed?: (identity: PortalAgentIdentity) => Promise<void> | void;\n\treadonly onSessionCloseError?: (\n\t\terror: Error,\n\t\tidentity: PortalAgentIdentity,\n\t) => Promise<void> | void;\n\treadonly registeredAgentIds?: readonly string[];\n\treadonly resolveAgentIdentity?: (agentId: string) => PortalHttpAgentIdentity | null;\n}\n\nexport type PortalHttpApp = Hono & {\n\treadonly closePortalSessions: () => Promise<void>;\n};\n\nconst mcpSessionIdHeader = 'mcp-session-id';\nconst defaultAuthFailureLimit = { maxFailures: 60, windowMs: 60_000 } as const;\nconst authFailureBucketLimit = 1_024;\nconst directClientAddress = 'direct-client';\nconst unknownAgentCredentialVersionForOpaqueAuthTiming = 1;\n\ninterface ActivePortalMcpSession {\n\treadonly identity: PortalAgentIdentity;\n\treadonly server: ReturnType<typeof createPortalMcpServer>;\n\treadonly transport: StreamableHTTPTransport;\n}\n\ninterface AuthFailureBucket {\n\treadonly resetAtMs: number;\n\tfailures: number;\n}\n\nfunction activeSessionKey(scopeId: string, sessionId: string): string {\n\treturn `${scopeId}\\n${sessionId}`;\n}\n\nfunction unauthorizedResponse(): Response {\n\treturn Response.json({ error: { kind: 'unauthorized' }, ok: false }, { status: 401 });\n}\n\nfunction rateLimitedResponse(): Response {\n\treturn Response.json({ error: { kind: 'rate_limited' }, ok: false }, { status: 429 });\n}\n\nfunction unavailableResponse(): Response {\n\treturn Response.json({ error: { kind: 'shutting_down' }, ok: false }, { status: 503 });\n}\n\nfunction errorFromUnknown(error: unknown): Error {\n\treturn error instanceof Error ? error : new Error(String(error));\n}\n\nfunction clientAddressFromContext(context: Context): string {\n\ttry {\n\t\tconst address = getConnInfo(context).remote.address;\n\t\treturn address && address.length > 0 ? address : directClientAddress;\n\t} catch {\n\t\treturn directClientAddress;\n\t}\n}\n\nexport function createPortalHttpApp(options: PortalHttpAppOptions): PortalHttpApp {\n\tif (options.agentBearerAuth === undefined) {\n\t\tthrow new Error('MCP Portal HTTP app requires agent bearer auth.');\n\t}\n\tif (options.agentBearerAuth.authorizationHeaderName.length === 0) {\n\t\tthrow new Error('MCP Portal HTTP app requires agent bearer auth header name.');\n\t}\n\tconst app = new Hono();\n\tconst activeSessions = new Map<string, ActivePortalMcpSession>();\n\tconst authFailureBuckets = new Map<string, AuthFailureBucket>();\n\tconst pendingNewSessionRequests = new Set<Promise<void>>();\n\tconst authFailureLimit = options.authFailureLimit ?? defaultAuthFailureLimit;\n\tlet closing = false;\n\n\tasync function auditAuth(event: Omit<PortalHttpAuditEvent, 'kind' | 'timeMs'>): Promise<void> {\n\t\tconst auditEvent = { ...event, kind: 'mcp_proxy_auth', timeMs: Date.now() } as const;\n\t\ttry {\n\t\t\tawait options.auditSink?.(auditEvent);\n\t\t} catch (error) {\n\t\t\tawait options.auditErrorSink?.(errorFromUnknown(error), auditEvent);\n\t\t}\n\t}\n\n\tasync function reportSessionCloseError(\n\t\terror: unknown,\n\t\tidentity: PortalAgentIdentity,\n\t): Promise<void> {\n\t\tawait options.onSessionCloseError?.(errorFromUnknown(error), identity);\n\t}\n\n\tfunction pruneAuthFailureBuckets(nowMs: number): void {\n\t\tfor (const [key, bucket] of authFailureBuckets) {\n\t\t\tif (bucket.resetAtMs <= nowMs) {\n\t\t\t\tauthFailureBuckets.delete(key);\n\t\t\t}\n\t\t}\n\t\twhile (authFailureBuckets.size > authFailureBucketLimit) {\n\t\t\tconst firstKey = authFailureBuckets.keys().next().value;\n\t\t\tif (typeof firstKey !== 'string') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tauthFailureBuckets.delete(firstKey);\n\t\t}\n\t}\n\n\tfunction isAuthFailureRateLimited(clientAddress: string): boolean {\n\t\tconst nowMs = Date.now();\n\t\tpruneAuthFailureBuckets(nowMs);\n\t\tconst bucket = authFailureBuckets.get(clientAddress);\n\t\tif (bucket === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\tif (bucket.resetAtMs <= nowMs) {\n\t\t\tauthFailureBuckets.delete(clientAddress);\n\t\t\treturn false;\n\t\t}\n\t\treturn bucket.failures >= authFailureLimit.maxFailures;\n\t}\n\n\tfunction recordAuthFailure(clientAddress: string): void {\n\t\tconst nowMs = Date.now();\n\t\tpruneAuthFailureBuckets(nowMs);\n\t\tconst bucket = authFailureBuckets.get(clientAddress);\n\t\tif (bucket !== undefined && bucket.resetAtMs > nowMs) {\n\t\t\tbucket.failures += 1;\n\t\t\treturn;\n\t\t}\n\t\tauthFailureBuckets.set(clientAddress, {\n\t\t\tfailures: 1,\n\t\t\tresetAtMs: nowMs + authFailureLimit.windowMs,\n\t\t});\n\t\tpruneAuthFailureBuckets(nowMs);\n\t}\n\n\tfunction clearAuthFailures(clientAddress: string): void {\n\t\tauthFailureBuckets.delete(clientAddress);\n\t}\n\n\tasync function closeActiveSession(\n\t\tsessionKey: string,\n\t\tcloseOptions: { readonly closeTransport: boolean },\n\t): Promise<void> {\n\t\tconst activeSession = activeSessions.get(sessionKey);\n\t\tif (!activeSession) {\n\t\t\treturn;\n\t\t}\n\t\tactiveSessions.delete(sessionKey);\n\t\ttry {\n\t\t\tif (closeOptions.closeTransport) {\n\t\t\t\tawait activeSession.transport.close();\n\t\t\t}\n\t\t} finally {\n\t\t\tawait options.onSessionClosed?.(activeSession.identity);\n\t\t}\n\t}\n\n\tfunction trackPendingNewSessionRequest(): () => void {\n\t\tlet resolvePending: (() => void) | undefined;\n\t\tconst pendingRequest = new Promise<void>((resolve) => {\n\t\t\tresolvePending = resolve;\n\t\t});\n\t\tpendingNewSessionRequests.add(pendingRequest);\n\t\treturn () => {\n\t\t\tpendingNewSessionRequests.delete(pendingRequest);\n\t\t\tresolvePending?.();\n\t\t};\n\t}\n\n\tasync function createActiveSession(\n\t\tidentityBase: PortalAgentIdentity,\n\t): Promise<ActivePortalMcpSession> {\n\t\tconst sessionId = randomUUID();\n\t\tconst sessionKey = activeSessionKey(identityBase.agentScopeId, sessionId);\n\t\tlet server: ReturnType<typeof createPortalMcpServer> | null = null;\n\t\tconst identity = createPortalAgentIdentity({\n\t\t\tagentId: identityBase.agentId,\n\t\t\tagentScopeId: identityBase.agentScopeId,\n\t\t\tsessionId,\n\t\t\tsource: identityBase.source,\n\t\t});\n\t\tconst transport = new StreamableHTTPTransport({\n\t\t\tonsessionclosed: () => {\n\t\t\t\tvoid closeActiveSession(sessionKey, { closeTransport: false }).catch((error: unknown) =>\n\t\t\t\t\treportSessionCloseError(error, identity),\n\t\t\t\t);\n\t\t\t},\n\t\t\tonsessioninitialized: (initializedSessionId) => {\n\t\t\t\tif (!server) {\n\t\t\t\t\tthrow new Error('MCP Portal session initialized before server connection.');\n\t\t\t\t}\n\t\t\t\tactiveSessions.set(activeSessionKey(identityBase.agentScopeId, initializedSessionId), {\n\t\t\t\t\tidentity,\n\t\t\t\t\tserver,\n\t\t\t\t\ttransport,\n\t\t\t\t});\n\t\t\t},\n\t\t\tsessionIdGenerator: () => sessionId,\n\t\t});\n\t\tserver = createPortalMcpServer({\n\t\t\tcore: options.core,\n\t\t\tscope: identity,\n\t\t});\n\t\tawait server.connect(transport);\n\t\treturn { identity, server, transport };\n\t}\n\n\tasync function closePortalSessions(): Promise<void> {\n\t\tclosing = true;\n\t\tconst closeErrors: Error[] = [];\n\t\twhile (activeSessions.size > 0 || pendingNewSessionRequests.size > 0) {\n\t\t\tif (pendingNewSessionRequests.size > 0) {\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tawait Promise.allSettled(pendingNewSessionRequests);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Closing may trigger callbacks that mutate activeSessions, so drain snapshots until empty.\n\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\tconst closeResults = await Promise.allSettled(\n\t\t\t\t[...activeSessions.keys()].map((sessionKey) =>\n\t\t\t\t\tcloseActiveSession(sessionKey, { closeTransport: true }),\n\t\t\t\t),\n\t\t\t);\n\t\t\tcloseErrors.push(\n\t\t\t\t...closeResults\n\t\t\t\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t\t\t\t.map((result): Error => errorFromUnknown(result.reason)),\n\t\t\t);\n\t\t}\n\t\tif (closeErrors.length > 0) {\n\t\t\tthrow new AggregateError(closeErrors, 'Failed to close one or more MCP Portal sessions.');\n\t\t}\n\t}\n\n\tapp.get('/health', (context) =>\n\t\tcontext.json({ agents: [...(options.registeredAgentIds ?? [])].toSorted(), ok: true }),\n\t);\n\n\tapp.all('/agents/:agentId/mcp', async (context) => {\n\t\tconst agentId = context.req.param('agentId');\n\t\tconst clientAddress = clientAddressFromContext(context);\n\t\tif (closing) {\n\t\t\treturn unavailableResponse();\n\t\t}\n\t\tif (isAuthFailureRateLimited(clientAddress)) {\n\t\t\tawait auditAuth({\n\t\t\t\tagentId,\n\t\t\t\tclientAddress,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: 'rate_limited',\n\t\t\t});\n\t\t\treturn rateLimitedResponse();\n\t\t}\n\t\tconst agentBearerAuth = options.agentBearerAuth;\n\t\tconst credentialVersion = agentBearerAuth.credentialVersionsByAgent?.[agentId];\n\t\tconst verification = verifyAgentBearerAuthorization({\n\t\t\tagentId,\n\t\t\tauthorizationHeader: context.req.header(agentBearerAuth.authorizationHeaderName),\n\t\t\tcredentialVersion: credentialVersion ?? unknownAgentCredentialVersionForOpaqueAuthTiming,\n\t\t\tmasterKey: agentBearerAuth.masterKey,\n\t\t});\n\t\tconst agentIdentity = options.resolveAgentIdentity?.(agentId) ?? null;\n\t\tif (agentIdentity === null) {\n\t\t\trecordAuthFailure(clientAddress);\n\t\t\tawait auditAuth({\n\t\t\t\tagentId,\n\t\t\t\tclientAddress,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: 'unknown_agent',\n\t\t\t});\n\t\t\treturn unauthorizedResponse();\n\t\t}\n\t\tif (!verification.ok) {\n\t\t\trecordAuthFailure(clientAddress);\n\t\t\tawait auditAuth({\n\t\t\t\tagentId,\n\t\t\t\tclientAddress,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: verification.reason,\n\t\t\t});\n\t\t\treturn unauthorizedResponse();\n\t\t}\n\t\tclearAuthFailures(clientAddress);\n\t\tawait auditAuth({ agentId, clientAddress, decision: 'allow' });\n\n\t\tconst mcpSessionId = context.req.header(mcpSessionIdHeader);\n\t\tif (mcpSessionId) {\n\t\t\tconst activeSession = activeSessions.get(\n\t\t\t\tactiveSessionKey(agentIdentity.agentScopeId, mcpSessionId),\n\t\t\t);\n\t\t\tif (!activeSession) {\n\t\t\t\treturn new Response('Unknown MCP portal session', { status: 404 });\n\t\t\t}\n\t\t\treturn await activeSession.transport.handleRequest(context);\n\t\t}\n\n\t\tconst finishPendingRequest = trackPendingNewSessionRequest();\n\t\ttry {\n\t\t\tif (closing) {\n\t\t\t\treturn unavailableResponse();\n\t\t\t}\n\t\t\tconst activeSession = await createActiveSession(agentIdentity);\n\t\t\tif (closing) {\n\t\t\t\tawait activeSession.transport.close();\n\t\t\t\treturn unavailableResponse();\n\t\t\t}\n\t\t\treturn await activeSession.transport.handleRequest(context);\n\t\t} finally {\n\t\t\tfinishPendingRequest();\n\t\t}\n\t});\n\n\treturn Object.assign(app, { closePortalSessions });\n}\n","import {\n\tresolveMcpPortalProfile,\n\tmcpPortalCallRequiresApproval,\n\ttype McpPortalAgentConfig,\n\ttype McpPortalConfig,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\n\nimport type { PortalApprovalCall } from '../core/portal-tools.js';\nimport { createPortalAgentIdentity } from '../portal-access-policy.js';\nimport { hashCallArguments, verifyApprovalToken } from '../portal-auth/hmac-token.js';\n\nconst approvalTokenMaxLifetimeMs = 5 * 60_000;\nconst approvalTokenReplayCacheLimit = 4_096;\n\nexport interface ResolveAgentHmacKeysProps {\n\treadonly agents: Readonly<Record<string, McpPortalAgentConfig>>;\n\treadonly envKeys: ReadonlyMap<string, Buffer>;\n\treadonly resolveSecret: (secret: SecretValue) => Promise<string>;\n}\n\nexport interface PortalAgentRuntimeRecord {\n\treadonly agentId: string;\n\treadonly hmacKey: Buffer;\n\treadonly profile: ResolvedMcpPortalProfile;\n\treadonly profileName: string;\n}\n\nexport interface PortalApprovalAuditEvent {\n\treadonly agentId: string;\n\treadonly decision: 'allow' | 'deny';\n\treadonly kind: 'mcp_portal_approval';\n\treadonly reason?: 'approval_token_invalid' | 'approval_token_missing' | 'no_approval_required';\n\treadonly timeMs: number;\n\treadonly verifierReason?: string;\n}\n\nasync function resolveAgentHmacKeyEntry(props: {\n\treadonly agent: McpPortalAgentConfig;\n\treadonly agentId: string;\n\treadonly envKeys: ReadonlyMap<string, Buffer>;\n\treadonly resolveSecret: (secret: SecretValue) => Promise<string>;\n}): Promise<readonly [string, Buffer]> {\n\tconst envKey = props.envKeys.get(props.agentId);\n\tif (envKey !== undefined) {\n\t\treturn [props.agentId, envKey];\n\t}\n\tif (props.agent.hmacKey === undefined) {\n\t\tthrow new Error(`Missing HMAC key for MCP Portal agent \"${props.agentId}\".`);\n\t}\n\tconst secretValue = await props.resolveSecret(props.agent.hmacKey);\n\tif (!/^[0-9a-f]+$/u.test(secretValue) || secretValue.length !== 64) {\n\t\tthrow new Error(`MCP Portal agent \"${props.agentId}\" HMAC key must be 64 hex characters.`);\n\t}\n\treturn [props.agentId, Buffer.from(secretValue, 'hex')];\n}\n\nexport async function resolveAgentHmacKeys(\n\tprops: ResolveAgentHmacKeysProps,\n): Promise<ReadonlyMap<string, Buffer>> {\n\treturn new Map(\n\t\tawait Promise.all(\n\t\t\tObject.entries(props.agents).map(([agentId, agent]) =>\n\t\t\t\tresolveAgentHmacKeyEntry({\n\t\t\t\t\tagent,\n\t\t\t\t\tagentId,\n\t\t\t\t\tenvKeys: props.envKeys,\n\t\t\t\t\tresolveSecret: props.resolveSecret,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n}\n\nexport function createPortalAgentRuntimeRecords(props: {\n\treadonly hmacKeys: ReadonlyMap<string, Buffer>;\n\treadonly portalConfig: McpPortalConfig;\n}): ReadonlyMap<string, PortalAgentRuntimeRecord> {\n\tconst records = new Map<string, PortalAgentRuntimeRecord>();\n\tfor (const [agentId, agent] of Object.entries(props.portalConfig.agents)) {\n\t\tconst hmacKey = props.hmacKeys.get(agentId);\n\t\tif (hmacKey === undefined) {\n\t\t\tthrow new Error(`Missing HMAC key for MCP Portal agent \"${agentId}\".`);\n\t\t}\n\t\trecords.set(agentId, {\n\t\t\tagentId,\n\t\t\thmacKey,\n\t\t\tprofile: resolveMcpPortalProfile(props.portalConfig, agent.profile),\n\t\t\tprofileName: agent.profile,\n\t\t});\n\t}\n\treturn records;\n}\n\nexport function createPortalHttpAgentResolver(\n\trecords: ReadonlyMap<string, PortalAgentRuntimeRecord>,\n): (agentId: string) => ReturnType<typeof createPortalAgentIdentity> | null {\n\treturn (agentId) => {\n\t\tconst record = records.get(agentId);\n\t\tif (record === undefined) {\n\t\t\treturn null;\n\t\t}\n\t\treturn createPortalAgentIdentity({\n\t\t\tagentId,\n\t\t\tagentScopeId: agentId,\n\t\t\tsource: 'mcp-proxy-bearer',\n\t\t});\n\t};\n}\n\nfunction approvalRequiredByProfile(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: PortalApprovalCall,\n): boolean {\n\tconst annotations = call.tool.annotations;\n\treturn mcpPortalCallRequiresApproval(profile, {\n\t\t...(annotations === undefined ? {} : { annotations }),\n\t\tnamespace: call.namespace,\n\t\ttoolName: call.toolName,\n\t});\n}\n\nfunction approvalTokenCallDigests(calls: readonly PortalApprovalCall[]): readonly {\n\treadonly argumentsHash: string;\n\treadonly namespace: string;\n\treadonly toolName: string;\n}[] {\n\treturn calls.map((call) => ({\n\t\targumentsHash: hashCallArguments(call.arguments),\n\t\tnamespace: call.namespace,\n\t\ttoolName: call.toolName,\n\t}));\n}\n\nexport function createPortalApprovalVerifier(props: {\n\treadonly approvalTokenReplayCacheLimit?: number;\n\treadonly auditErrorSink?: (error: Error, event: PortalApprovalAuditEvent) => void;\n\treadonly auditSink?: (event: PortalApprovalAuditEvent) => void;\n\treadonly records: ReadonlyMap<string, PortalAgentRuntimeRecord>;\n}): (\n\tcalls: readonly PortalApprovalCall[],\n\tagentId: string,\n\ttoken: string | undefined,\n) =>\n\t| { readonly kind: 'allow' }\n\t| { readonly kind: 'approval_token_invalid'; readonly reason: string }\n\t| { readonly kind: 'approval_token_missing' } {\n\tfunction auditApproval(event: Omit<PortalApprovalAuditEvent, 'kind' | 'timeMs'>): void {\n\t\tconst auditEvent = { ...event, kind: 'mcp_portal_approval', timeMs: Date.now() } as const;\n\t\ttry {\n\t\t\tprops.auditSink?.(auditEvent);\n\t\t} catch (error) {\n\t\t\tprops.auditErrorSink?.(error instanceof Error ? error : new Error(String(error)), auditEvent);\n\t\t}\n\t}\n\n\tconst consumedApprovalTokenIds = new Map<string, number>();\n\tconst replayCacheLimit = props.approvalTokenReplayCacheLimit ?? approvalTokenReplayCacheLimit;\n\tconst consumeTokenId = (\n\t\tagentId: string,\n\t\tjti: string,\n\t\texpiresAtMs: number,\n\t):\n\t\t| { readonly ok: true }\n\t\t| { readonly ok: false; readonly reason: 'replay-cache-full' | 'replayed' } => {\n\t\tconst nowMs = Date.now();\n\t\tfor (const [tokenKey, tokenExpiresAtMs] of consumedApprovalTokenIds) {\n\t\t\tif (tokenExpiresAtMs <= nowMs) {\n\t\t\t\tconsumedApprovalTokenIds.delete(tokenKey);\n\t\t\t}\n\t\t}\n\t\tconst tokenKey = `${agentId}\\n${jti}`;\n\t\tif (consumedApprovalTokenIds.has(tokenKey)) {\n\t\t\treturn { ok: false, reason: 'replayed' };\n\t\t}\n\t\tif (consumedApprovalTokenIds.size >= replayCacheLimit) {\n\t\t\treturn { ok: false, reason: 'replay-cache-full' };\n\t\t}\n\t\tconsumedApprovalTokenIds.set(tokenKey, expiresAtMs);\n\t\treturn { ok: true };\n\t};\n\treturn (calls, agentId, token) => {\n\t\tconst record = props.records.get(agentId);\n\t\tif (record === undefined) {\n\t\t\tauditApproval({\n\t\t\t\tagentId,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: 'approval_token_invalid',\n\t\t\t\tverifierReason: 'unknown-agent',\n\t\t\t});\n\t\t\treturn { kind: 'approval_token_invalid', reason: 'unknown-agent' };\n\t\t}\n\t\tconst callsRequiringApproval = calls.filter((call) =>\n\t\t\tapprovalRequiredByProfile(record.profile, call),\n\t\t);\n\t\tif (callsRequiringApproval.length === 0) {\n\t\t\tauditApproval({ agentId, decision: 'allow', reason: 'no_approval_required' });\n\t\t\treturn { kind: 'allow' };\n\t\t}\n\t\tif (token === undefined) {\n\t\t\tauditApproval({ agentId, decision: 'deny', reason: 'approval_token_missing' });\n\t\t\treturn { kind: 'approval_token_missing' };\n\t\t}\n\t\tconst verificationProps = {\n\t\t\tagentId,\n\t\t\tcalls: approvalTokenCallDigests(callsRequiringApproval),\n\t\t\tconsumeTokenId: (jti: string, expiresAtMs: number) =>\n\t\t\t\tconsumeTokenId(agentId, jti, expiresAtMs),\n\t\t\tkey: record.hmacKey,\n\t\t\tmaxLifetimeMs: approvalTokenMaxLifetimeMs,\n\t\t\tnowMs: Date.now(),\n\t\t\ttoken,\n\t\t};\n\t\tconst verification = verifyApprovalToken(verificationProps);\n\t\tif (verification.ok) {\n\t\t\tauditApproval({ agentId, decision: 'allow' });\n\t\t\treturn { kind: 'allow' };\n\t\t}\n\t\tauditApproval({\n\t\t\tagentId,\n\t\t\tdecision: 'deny',\n\t\t\treason: 'approval_token_invalid',\n\t\t\tverifierReason: verification.reason,\n\t\t});\n\t\treturn { kind: 'approval_token_invalid', reason: verification.reason };\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resolve-agent-identity-ZMMY2Wqm.js","names":[],"sources":["../src/mcp-proxy/portal-mcp-server.ts","../src/mcp-proxy/portal-http-server.ts","../src/mcp-proxy/resolve-agent-identity.ts"],"sourcesContent":["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n\tCallToolRequestSchema,\n\tListToolsRequestSchema,\n\ttype CallToolResult,\n\ttype Tool,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport type {\n\tPortalAgentScope,\n\tPortalCore,\n\tPortalCoreEvent,\n\tPortalCoreToolDescriptor,\n\tPortalCoreResult,\n\tPortalCoreToolName,\n} from '../core/portal-core.js';\nimport { portalToolInputSchemas } from '../core/portal-tools.js';\nimport { redactThrownError } from '../upstream-response-middleware.js';\n\nexport const portalMcpToolNames = [\n\t'mcp_portal_list',\n\t'mcp_portal_search',\n\t'mcp_portal_describe',\n\t'mcp_portal_call',\n] as const;\n\nexport type PortalMcpToolName = (typeof portalMcpToolNames)[number];\n\nconst portalMcpToolNameSet = new Set<string>(portalMcpToolNames);\n\nfunction isPortalCoreToolName(value: string): value is PortalCoreToolName {\n\treturn portalMcpToolNameSet.has(value);\n}\n\nexport function listPortalMcpTools(\n\tdescriptors?: readonly PortalCoreToolDescriptor[],\n): readonly Tool[] {\n\treturn (\n\t\tdescriptors ?? [\n\t\t\t{\n\t\t\t\tdescription: 'List authorized MCP namespaces and compact tool summaries.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_list,\n\t\t\t\tname: 'mcp_portal_list',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescription: 'Search the caller scoped MCP Portal index.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_search,\n\t\t\t\tname: 'mcp_portal_search',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescription: 'Describe exact MCP tool schemas and optional TypeScript/Zod helpers.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_describe,\n\t\t\t\tname: 'mcp_portal_describe',\n\t\t\t},\n\t\t\t{\n\t\t\t\tdescription: 'Validate and call an authorized upstream MCP tool by namespace and toolName.',\n\t\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_call,\n\t\t\t\tname: 'mcp_portal_call',\n\t\t\t},\n\t\t]\n\t);\n}\n\nfunction isObjectRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction coreResultIsError(value: PortalCoreResult): boolean {\n\tif (value.items.some((item) => item.status === 'failed')) {\n\t\treturn true;\n\t}\n\tif (!isObjectRecord(value.structuredContent)) {\n\t\treturn false;\n\t}\n\treturn value.structuredContent.ok === false;\n}\n\nfunction jsonToolResult(value: PortalCoreResult): CallToolResult {\n\treturn {\n\t\tcontent: [{ text: JSON.stringify(value), type: 'text' }],\n\t\t...(coreResultIsError(value) ? { isError: true } : {}),\n\t};\n}\n\nfunction errorToolResult(error: unknown): CallToolResult {\n\tconst redactedError = redactThrownError(error);\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttext: redactedError.message,\n\t\t\t\ttype: 'text',\n\t\t\t},\n\t\t],\n\t\tisError: true,\n\t};\n}\n\nasync function sendBestEffortNotification(\n\tnotification: {\n\t\treadonly method: 'notifications/message' | 'notifications/progress';\n\t\treadonly params: Record<string, unknown>;\n\t},\n\tsendNotification: (notification: {\n\t\treadonly method: 'notifications/message' | 'notifications/progress';\n\t\treadonly params: Record<string, unknown>;\n\t}) => Promise<void>,\n): Promise<void> {\n\ttry {\n\t\tawait sendNotification(notification);\n\t} catch {\n\t\t// Progress is advisory; unsupported client notification channels must not fail the tool call.\n\t}\n}\n\nexport async function emitMcpProgress(props: {\n\treadonly event: PortalCoreEvent;\n\treadonly sendNotification: (notification: {\n\t\treadonly method: 'notifications/message' | 'notifications/progress';\n\t\treadonly params: Record<string, unknown>;\n\t}) => Promise<void>;\n\treadonly progressToken: number | string | undefined;\n}): Promise<void> {\n\tif (props.event.kind === 'upstream_notification') {\n\t\tif (!isObjectRecord(props.event.params)) {\n\t\t\treturn;\n\t\t}\n\t\tif (props.event.method === 'notifications/progress') {\n\t\t\tif (props.progressToken === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait sendBestEffortNotification(\n\t\t\t\t{\n\t\t\t\t\tmethod: 'notifications/progress',\n\t\t\t\t\tparams: { ...props.event.params, progressToken: props.progressToken },\n\t\t\t\t},\n\t\t\t\tprops.sendNotification,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tif (props.event.method !== 'notifications/message') {\n\t\t\treturn;\n\t\t}\n\t\tawait sendBestEffortNotification(\n\t\t\t{\n\t\t\t\tmethod: 'notifications/message',\n\t\t\t\tparams: props.event.params,\n\t\t\t},\n\t\t\tprops.sendNotification,\n\t\t);\n\t\treturn;\n\t}\n\tif (props.event.kind !== 'progress' && props.event.kind !== 'partial_content') {\n\t\treturn;\n\t}\n\tconst message =\n\t\tprops.event.kind === 'progress'\n\t\t\t? props.event.message\n\t\t\t: props.event.content.type === 'text'\n\t\t\t\t? props.event.content.text\n\t\t\t\t: JSON.stringify(props.event.content.value);\n\tif (message === undefined || message.length === 0) {\n\t\treturn;\n\t}\n\tif (props.progressToken !== undefined) {\n\t\tawait sendBestEffortNotification(\n\t\t\t{\n\t\t\t\tmethod: 'notifications/progress',\n\t\t\t\tparams: {\n\t\t\t\t\tmessage,\n\t\t\t\t\tprogress: props.event.kind === 'progress' ? (props.event.progress ?? 0) : 0,\n\t\t\t\t\tprogressToken: props.progressToken,\n\t\t\t\t\t...(props.event.kind === 'progress' && props.event.total !== undefined\n\t\t\t\t\t\t? { total: props.event.total }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t},\n\t\t\tprops.sendNotification,\n\t\t);\n\t\treturn;\n\t}\n\tawait sendBestEffortNotification(\n\t\t{\n\t\t\tmethod: 'notifications/message',\n\t\t\tparams: {\n\t\t\t\tdata: message,\n\t\t\t\tlevel: 'info',\n\t\t\t},\n\t\t},\n\t\tprops.sendNotification,\n\t);\n}\n\nexport function createPortalMcpServer(props: {\n\treadonly core: PortalCore;\n\treadonly scope: PortalAgentScope;\n}): Server {\n\tconst server = new Server(\n\t\t{ name: 'mcp-portal', version: '1.0.0' },\n\t\t{ capabilities: { tools: { listChanged: false } } },\n\t);\n\n\tserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n\t\ttools: listPortalMcpTools(props.core.describeTools(props.scope)),\n\t}));\n\n\tserver.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n\t\tif (!isPortalCoreToolName(request.params.name)) {\n\t\t\treturn {\n\t\t\t\tcontent: [{ text: `Unknown MCP Portal tool: ${request.params.name}`, type: 'text' }],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t\ttry {\n\t\t\tconst result = await props.core.collectPortalCoreResult(\n\t\t\t\tprops.core.callStream({\n\t\t\t\t\tinput: request.params.arguments ?? {},\n\t\t\t\t\tscope: props.scope,\n\t\t\t\t\tsignal: extra.signal,\n\t\t\t\t\ttoolName: request.params.name,\n\t\t\t\t}),\n\t\t\t\t{\n\t\t\t\t\tonEvent: async (event) => {\n\t\t\t\t\t\tawait emitMcpProgress({\n\t\t\t\t\t\t\tevent,\n\t\t\t\t\t\t\tprogressToken: extra['_meta']?.progressToken,\n\t\t\t\t\t\t\tsendNotification: extra.sendNotification,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn jsonToolResult(result);\n\t\t} catch (error) {\n\t\t\treturn errorToolResult(error);\n\t\t}\n\t});\n\n\treturn server;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport { StreamableHTTPTransport } from '@hono/mcp';\nimport { getConnInfo } from '@hono/node-server/conninfo';\nimport { Hono, type Context } from 'hono';\n\nimport type { PortalCore } from '../core/portal-core.js';\nimport { createPortalAgentIdentity, type PortalAgentIdentity } from '../portal-access-policy.js';\nimport { verifyAgentBearerAuthorization } from '../portal-auth/agent-bearer-token.js';\nimport { createPortalMcpServer } from './portal-mcp-server.js';\n\nexport interface PortalHttpAgentIdentity extends PortalAgentIdentity {}\n\nexport interface PortalAgentBearerAuth {\n\treadonly authorizationHeaderName: string;\n\treadonly credentialVersionsByAgent?: Readonly<Record<string, number>>;\n\treadonly masterKey: Buffer;\n}\n\nexport type PortalHttpAuditEvent = {\n\treadonly agentId: string;\n\treadonly clientAddress: string;\n\treadonly decision: 'allow' | 'deny';\n\treadonly kind: 'mcp_proxy_auth';\n\treadonly reason?:\n\t\t| 'malformed'\n\t\t| 'missing'\n\t\t| 'rate_limited'\n\t\t| 'signature-mismatch'\n\t\t| 'unknown_agent';\n\treadonly timeMs: number;\n};\n\nexport interface PortalHttpAppOptions {\n\treadonly agentBearerAuth: PortalAgentBearerAuth;\n\treadonly auditErrorSink?: (error: Error, event: PortalHttpAuditEvent) => Promise<void> | void;\n\treadonly auditSink?: (event: PortalHttpAuditEvent) => Promise<void> | void;\n\treadonly authFailureLimit?: {\n\t\treadonly maxFailures: number;\n\t\treadonly windowMs: number;\n\t};\n\treadonly core: PortalCore;\n\treadonly onSessionClosed?: (identity: PortalAgentIdentity) => Promise<void> | void;\n\treadonly onSessionCloseError?: (\n\t\terror: Error,\n\t\tidentity: PortalAgentIdentity,\n\t) => Promise<void> | void;\n\treadonly registeredAgentIds?: readonly string[];\n\treadonly resolveAgentIdentity?: (agentId: string) => PortalHttpAgentIdentity | null;\n}\n\nexport type PortalHttpApp = Hono & {\n\treadonly closePortalSessions: () => Promise<void>;\n};\n\nconst mcpSessionIdHeader = 'mcp-session-id';\nconst defaultAuthFailureLimit = { maxFailures: 60, windowMs: 60_000 } as const;\nconst authFailureBucketLimit = 1_024;\nconst directClientAddress = 'direct-client';\nconst unknownAgentCredentialVersionForOpaqueAuthTiming = 1;\n\ninterface ActivePortalMcpSession {\n\treadonly identity: PortalAgentIdentity;\n\treadonly server: ReturnType<typeof createPortalMcpServer>;\n\treadonly transport: StreamableHTTPTransport;\n}\n\ninterface AuthFailureBucket {\n\treadonly resetAtMs: number;\n\tfailures: number;\n}\n\nfunction activeSessionKey(scopeId: string, sessionId: string): string {\n\treturn `${scopeId}\\n${sessionId}`;\n}\n\nfunction unauthorizedResponse(): Response {\n\treturn Response.json({ error: { kind: 'unauthorized' }, ok: false }, { status: 401 });\n}\n\nfunction rateLimitedResponse(): Response {\n\treturn Response.json({ error: { kind: 'rate_limited' }, ok: false }, { status: 429 });\n}\n\nfunction unavailableResponse(): Response {\n\treturn Response.json({ error: { kind: 'shutting_down' }, ok: false }, { status: 503 });\n}\n\nfunction errorFromUnknown(error: unknown): Error {\n\treturn error instanceof Error ? error : new Error(String(error));\n}\n\nfunction clientAddressFromContext(context: Context): string {\n\ttry {\n\t\tconst address = getConnInfo(context).remote.address;\n\t\treturn address && address.length > 0 ? address : directClientAddress;\n\t} catch {\n\t\treturn directClientAddress;\n\t}\n}\n\nexport function createPortalHttpApp(options: PortalHttpAppOptions): PortalHttpApp {\n\tif (options.agentBearerAuth === undefined) {\n\t\tthrow new Error('MCP Portal HTTP app requires agent bearer auth.');\n\t}\n\tif (options.agentBearerAuth.authorizationHeaderName.length === 0) {\n\t\tthrow new Error('MCP Portal HTTP app requires agent bearer auth header name.');\n\t}\n\tconst app = new Hono();\n\tconst activeSessions = new Map<string, ActivePortalMcpSession>();\n\tconst authFailureBuckets = new Map<string, AuthFailureBucket>();\n\tconst pendingNewSessionRequests = new Set<Promise<void>>();\n\tconst authFailureLimit = options.authFailureLimit ?? defaultAuthFailureLimit;\n\tlet closing = false;\n\n\tasync function auditAuth(event: Omit<PortalHttpAuditEvent, 'kind' | 'timeMs'>): Promise<void> {\n\t\tconst auditEvent = { ...event, kind: 'mcp_proxy_auth', timeMs: Date.now() } as const;\n\t\ttry {\n\t\t\tawait options.auditSink?.(auditEvent);\n\t\t} catch (error) {\n\t\t\tawait options.auditErrorSink?.(errorFromUnknown(error), auditEvent);\n\t\t}\n\t}\n\n\tasync function reportSessionCloseError(\n\t\terror: unknown,\n\t\tidentity: PortalAgentIdentity,\n\t): Promise<void> {\n\t\tawait options.onSessionCloseError?.(errorFromUnknown(error), identity);\n\t}\n\n\tfunction pruneAuthFailureBuckets(nowMs: number): void {\n\t\tfor (const [key, bucket] of authFailureBuckets) {\n\t\t\tif (bucket.resetAtMs <= nowMs) {\n\t\t\t\tauthFailureBuckets.delete(key);\n\t\t\t}\n\t\t}\n\t\twhile (authFailureBuckets.size > authFailureBucketLimit) {\n\t\t\tconst firstKey = authFailureBuckets.keys().next().value;\n\t\t\tif (typeof firstKey !== 'string') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tauthFailureBuckets.delete(firstKey);\n\t\t}\n\t}\n\n\tfunction isAuthFailureRateLimited(clientAddress: string): boolean {\n\t\tconst nowMs = Date.now();\n\t\tpruneAuthFailureBuckets(nowMs);\n\t\tconst bucket = authFailureBuckets.get(clientAddress);\n\t\tif (bucket === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\tif (bucket.resetAtMs <= nowMs) {\n\t\t\tauthFailureBuckets.delete(clientAddress);\n\t\t\treturn false;\n\t\t}\n\t\treturn bucket.failures >= authFailureLimit.maxFailures;\n\t}\n\n\tfunction recordAuthFailure(clientAddress: string): void {\n\t\tconst nowMs = Date.now();\n\t\tpruneAuthFailureBuckets(nowMs);\n\t\tconst bucket = authFailureBuckets.get(clientAddress);\n\t\tif (bucket !== undefined && bucket.resetAtMs > nowMs) {\n\t\t\tbucket.failures += 1;\n\t\t\treturn;\n\t\t}\n\t\tauthFailureBuckets.set(clientAddress, {\n\t\t\tfailures: 1,\n\t\t\tresetAtMs: nowMs + authFailureLimit.windowMs,\n\t\t});\n\t\tpruneAuthFailureBuckets(nowMs);\n\t}\n\n\tfunction clearAuthFailures(clientAddress: string): void {\n\t\tauthFailureBuckets.delete(clientAddress);\n\t}\n\n\tasync function closeActiveSession(\n\t\tsessionKey: string,\n\t\tcloseOptions: { readonly closeTransport: boolean },\n\t): Promise<void> {\n\t\tconst activeSession = activeSessions.get(sessionKey);\n\t\tif (!activeSession) {\n\t\t\treturn;\n\t\t}\n\t\tactiveSessions.delete(sessionKey);\n\t\ttry {\n\t\t\tif (closeOptions.closeTransport) {\n\t\t\t\tawait activeSession.transport.close();\n\t\t\t}\n\t\t} finally {\n\t\t\tawait options.onSessionClosed?.(activeSession.identity);\n\t\t}\n\t}\n\n\tfunction trackPendingNewSessionRequest(): () => void {\n\t\tlet resolvePending: (() => void) | undefined;\n\t\tconst pendingRequest = new Promise<void>((resolve) => {\n\t\t\tresolvePending = resolve;\n\t\t});\n\t\tpendingNewSessionRequests.add(pendingRequest);\n\t\treturn () => {\n\t\t\tpendingNewSessionRequests.delete(pendingRequest);\n\t\t\tresolvePending?.();\n\t\t};\n\t}\n\n\tasync function createActiveSession(\n\t\tidentityBase: PortalAgentIdentity,\n\t): Promise<ActivePortalMcpSession> {\n\t\tconst sessionId = randomUUID();\n\t\tconst sessionKey = activeSessionKey(identityBase.agentScopeId, sessionId);\n\t\tlet server: ReturnType<typeof createPortalMcpServer> | null = null;\n\t\tconst identity = createPortalAgentIdentity({\n\t\t\tagentId: identityBase.agentId,\n\t\t\tagentScopeId: identityBase.agentScopeId,\n\t\t\tsessionId,\n\t\t\tsource: identityBase.source,\n\t\t});\n\t\tconst transport = new StreamableHTTPTransport({\n\t\t\tonsessionclosed: () => {\n\t\t\t\tvoid closeActiveSession(sessionKey, { closeTransport: false }).catch((error: unknown) =>\n\t\t\t\t\treportSessionCloseError(error, identity),\n\t\t\t\t);\n\t\t\t},\n\t\t\tonsessioninitialized: (initializedSessionId) => {\n\t\t\t\tif (!server) {\n\t\t\t\t\tthrow new Error('MCP Portal session initialized before server connection.');\n\t\t\t\t}\n\t\t\t\tactiveSessions.set(activeSessionKey(identityBase.agentScopeId, initializedSessionId), {\n\t\t\t\t\tidentity,\n\t\t\t\t\tserver,\n\t\t\t\t\ttransport,\n\t\t\t\t});\n\t\t\t},\n\t\t\tsessionIdGenerator: () => sessionId,\n\t\t});\n\t\tserver = createPortalMcpServer({\n\t\t\tcore: options.core,\n\t\t\tscope: identity,\n\t\t});\n\t\tawait server.connect(transport);\n\t\treturn { identity, server, transport };\n\t}\n\n\tasync function closePortalSessions(): Promise<void> {\n\t\tclosing = true;\n\t\tconst closeErrors: Error[] = [];\n\t\twhile (activeSessions.size > 0 || pendingNewSessionRequests.size > 0) {\n\t\t\tif (pendingNewSessionRequests.size > 0) {\n\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\tawait Promise.allSettled(pendingNewSessionRequests);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Closing may trigger callbacks that mutate activeSessions, so drain snapshots until empty.\n\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\tconst closeResults = await Promise.allSettled(\n\t\t\t\t[...activeSessions.keys()].map((sessionKey) =>\n\t\t\t\t\tcloseActiveSession(sessionKey, { closeTransport: true }),\n\t\t\t\t),\n\t\t\t);\n\t\t\tcloseErrors.push(\n\t\t\t\t...closeResults\n\t\t\t\t\t.filter((result): result is PromiseRejectedResult => result.status === 'rejected')\n\t\t\t\t\t.map((result): Error => errorFromUnknown(result.reason)),\n\t\t\t);\n\t\t}\n\t\tif (closeErrors.length > 0) {\n\t\t\tthrow new AggregateError(closeErrors, 'Failed to close one or more MCP Portal sessions.');\n\t\t}\n\t}\n\n\tapp.get('/health', (context) =>\n\t\tcontext.json({ agents: [...(options.registeredAgentIds ?? [])].toSorted(), ok: true }),\n\t);\n\n\tapp.all('/agents/:agentId/mcp', async (context) => {\n\t\tconst agentId = context.req.param('agentId');\n\t\tconst clientAddress = clientAddressFromContext(context);\n\t\tif (closing) {\n\t\t\treturn unavailableResponse();\n\t\t}\n\t\tif (isAuthFailureRateLimited(clientAddress)) {\n\t\t\tawait auditAuth({\n\t\t\t\tagentId,\n\t\t\t\tclientAddress,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: 'rate_limited',\n\t\t\t});\n\t\t\treturn rateLimitedResponse();\n\t\t}\n\t\tconst agentBearerAuth = options.agentBearerAuth;\n\t\tconst credentialVersion = agentBearerAuth.credentialVersionsByAgent?.[agentId];\n\t\tconst verification = verifyAgentBearerAuthorization({\n\t\t\tagentId,\n\t\t\tauthorizationHeader: context.req.header(agentBearerAuth.authorizationHeaderName),\n\t\t\tcredentialVersion: credentialVersion ?? unknownAgentCredentialVersionForOpaqueAuthTiming,\n\t\t\tmasterKey: agentBearerAuth.masterKey,\n\t\t});\n\t\tconst agentIdentity = options.resolveAgentIdentity?.(agentId) ?? null;\n\t\tif (agentIdentity === null) {\n\t\t\trecordAuthFailure(clientAddress);\n\t\t\tawait auditAuth({\n\t\t\t\tagentId,\n\t\t\t\tclientAddress,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: 'unknown_agent',\n\t\t\t});\n\t\t\treturn unauthorizedResponse();\n\t\t}\n\t\tif (!verification.ok) {\n\t\t\trecordAuthFailure(clientAddress);\n\t\t\tawait auditAuth({\n\t\t\t\tagentId,\n\t\t\t\tclientAddress,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: verification.reason,\n\t\t\t});\n\t\t\treturn unauthorizedResponse();\n\t\t}\n\t\tclearAuthFailures(clientAddress);\n\t\tawait auditAuth({ agentId, clientAddress, decision: 'allow' });\n\n\t\tconst mcpSessionId = context.req.header(mcpSessionIdHeader);\n\t\tif (mcpSessionId) {\n\t\t\tconst activeSession = activeSessions.get(\n\t\t\t\tactiveSessionKey(agentIdentity.agentScopeId, mcpSessionId),\n\t\t\t);\n\t\t\tif (!activeSession) {\n\t\t\t\treturn new Response('Unknown MCP portal session', { status: 404 });\n\t\t\t}\n\t\t\treturn await activeSession.transport.handleRequest(context);\n\t\t}\n\n\t\tconst finishPendingRequest = trackPendingNewSessionRequest();\n\t\ttry {\n\t\t\tif (closing) {\n\t\t\t\treturn unavailableResponse();\n\t\t\t}\n\t\t\tconst activeSession = await createActiveSession(agentIdentity);\n\t\t\tif (closing) {\n\t\t\t\tawait activeSession.transport.close();\n\t\t\t\treturn unavailableResponse();\n\t\t\t}\n\t\t\treturn await activeSession.transport.handleRequest(context);\n\t\t} finally {\n\t\t\tfinishPendingRequest();\n\t\t}\n\t});\n\n\treturn Object.assign(app, { closePortalSessions });\n}\n","import {\n\tresolveMcpPortalProfile,\n\tmcpPortalCallRequiresApproval,\n\ttype McpPortalAgentConfig,\n\ttype McpPortalConfig,\n\ttype ResolvedMcpPortalProfile,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\n\nimport type { PortalApprovalCall } from '../core/portal-tools.js';\nimport { createPortalAgentIdentity } from '../portal-access-policy.js';\nimport { hashCallArguments, verifyApprovalToken } from '../portal-auth/hmac-token.js';\n\nconst approvalTokenMaxLifetimeMs = 5 * 60_000;\nconst approvalTokenReplayCacheLimit = 4_096;\n\nexport interface ResolveAgentHmacKeysProps {\n\treadonly agents: Readonly<Record<string, McpPortalAgentConfig>>;\n\treadonly envKeys: ReadonlyMap<string, Buffer>;\n\treadonly resolveSecret: (secret: SecretValue) => Promise<string>;\n}\n\nexport interface PortalAgentRuntimeRecord {\n\treadonly agentId: string;\n\treadonly hmacKey: Buffer;\n\treadonly profile: ResolvedMcpPortalProfile;\n\treadonly profileName: string;\n}\n\nexport interface PortalApprovalAuditEvent {\n\treadonly agentId: string;\n\treadonly decision: 'allow' | 'deny';\n\treadonly kind: 'mcp_portal_approval';\n\treadonly reason?: 'approval_token_invalid' | 'approval_token_missing' | 'no_approval_required';\n\treadonly timeMs: number;\n\treadonly verifierReason?: string;\n}\n\nasync function resolveAgentHmacKeyEntry(props: {\n\treadonly agent: McpPortalAgentConfig;\n\treadonly agentId: string;\n\treadonly envKeys: ReadonlyMap<string, Buffer>;\n\treadonly resolveSecret: (secret: SecretValue) => Promise<string>;\n}): Promise<readonly [string, Buffer]> {\n\tconst envKey = props.envKeys.get(props.agentId);\n\tif (envKey !== undefined) {\n\t\treturn [props.agentId, envKey];\n\t}\n\tif (props.agent.hmacKey === undefined) {\n\t\tthrow new Error(`Missing HMAC key for MCP Portal agent \"${props.agentId}\".`);\n\t}\n\tconst secretValue = await props.resolveSecret(props.agent.hmacKey);\n\tif (!/^[0-9a-f]+$/u.test(secretValue) || secretValue.length !== 64) {\n\t\tthrow new Error(`MCP Portal agent \"${props.agentId}\" HMAC key must be 64 hex characters.`);\n\t}\n\treturn [props.agentId, Buffer.from(secretValue, 'hex')];\n}\n\nexport async function resolveAgentHmacKeys(\n\tprops: ResolveAgentHmacKeysProps,\n): Promise<ReadonlyMap<string, Buffer>> {\n\treturn new Map(\n\t\tawait Promise.all(\n\t\t\tObject.entries(props.agents).map(([agentId, agent]) =>\n\t\t\t\tresolveAgentHmacKeyEntry({\n\t\t\t\t\tagent,\n\t\t\t\t\tagentId,\n\t\t\t\t\tenvKeys: props.envKeys,\n\t\t\t\t\tresolveSecret: props.resolveSecret,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n}\n\nexport function createPortalAgentRuntimeRecords(props: {\n\treadonly hmacKeys: ReadonlyMap<string, Buffer>;\n\treadonly portalConfig: McpPortalConfig;\n}): ReadonlyMap<string, PortalAgentRuntimeRecord> {\n\tconst records = new Map<string, PortalAgentRuntimeRecord>();\n\tfor (const [agentId, agent] of Object.entries(props.portalConfig.agents)) {\n\t\tconst hmacKey = props.hmacKeys.get(agentId);\n\t\tif (hmacKey === undefined) {\n\t\t\tthrow new Error(`Missing HMAC key for MCP Portal agent \"${agentId}\".`);\n\t\t}\n\t\trecords.set(agentId, {\n\t\t\tagentId,\n\t\t\thmacKey,\n\t\t\tprofile: resolveMcpPortalProfile(props.portalConfig, agent.profile),\n\t\t\tprofileName: agent.profile,\n\t\t});\n\t}\n\treturn records;\n}\n\nexport function createPortalHttpAgentResolver(\n\trecords: ReadonlyMap<string, PortalAgentRuntimeRecord>,\n): (agentId: string) => ReturnType<typeof createPortalAgentIdentity> | null {\n\treturn (agentId) => {\n\t\tconst record = records.get(agentId);\n\t\tif (record === undefined) {\n\t\t\treturn null;\n\t\t}\n\t\treturn createPortalAgentIdentity({\n\t\t\tagentId,\n\t\t\tagentScopeId: agentId,\n\t\t\tsource: 'mcp-proxy-bearer',\n\t\t});\n\t};\n}\n\nfunction approvalRequiredByProfile(\n\tprofile: ResolvedMcpPortalProfile,\n\tcall: PortalApprovalCall,\n): boolean {\n\tconst annotations = call.tool.annotations;\n\treturn mcpPortalCallRequiresApproval(profile, {\n\t\t...(annotations === undefined ? {} : { annotations }),\n\t\tnamespace: call.namespace,\n\t\ttoolName: call.toolName,\n\t});\n}\n\nfunction approvalTokenCallDigests(calls: readonly PortalApprovalCall[]): readonly {\n\treadonly argumentsHash: string;\n\treadonly namespace: string;\n\treadonly toolName: string;\n}[] {\n\treturn calls.map((call) => ({\n\t\targumentsHash: hashCallArguments(call.arguments),\n\t\tnamespace: call.namespace,\n\t\ttoolName: call.toolName,\n\t}));\n}\n\nexport function createPortalApprovalVerifier(props: {\n\treadonly approvalTokenReplayCacheLimit?: number;\n\treadonly auditErrorSink?: (error: Error, event: PortalApprovalAuditEvent) => void;\n\treadonly auditSink?: (event: PortalApprovalAuditEvent) => void;\n\treadonly records: ReadonlyMap<string, PortalAgentRuntimeRecord>;\n}): (\n\tcalls: readonly PortalApprovalCall[],\n\tagentId: string,\n\ttoken: string | undefined,\n) =>\n\t| { readonly kind: 'allow' }\n\t| { readonly kind: 'approval_token_invalid'; readonly reason: string }\n\t| { readonly kind: 'approval_token_missing' } {\n\tfunction auditApproval(event: Omit<PortalApprovalAuditEvent, 'kind' | 'timeMs'>): void {\n\t\tconst auditEvent = { ...event, kind: 'mcp_portal_approval', timeMs: Date.now() } as const;\n\t\ttry {\n\t\t\tprops.auditSink?.(auditEvent);\n\t\t} catch (error) {\n\t\t\tprops.auditErrorSink?.(error instanceof Error ? error : new Error(String(error)), auditEvent);\n\t\t}\n\t}\n\n\tconst consumedApprovalTokenIds = new Map<string, number>();\n\tconst replayCacheLimit = props.approvalTokenReplayCacheLimit ?? approvalTokenReplayCacheLimit;\n\tconst consumeTokenId = (\n\t\tagentId: string,\n\t\tjti: string,\n\t\texpiresAtMs: number,\n\t):\n\t\t| { readonly ok: true }\n\t\t| { readonly ok: false; readonly reason: 'replay-cache-full' | 'replayed' } => {\n\t\tconst nowMs = Date.now();\n\t\tfor (const [tokenKey, tokenExpiresAtMs] of consumedApprovalTokenIds) {\n\t\t\tif (tokenExpiresAtMs <= nowMs) {\n\t\t\t\tconsumedApprovalTokenIds.delete(tokenKey);\n\t\t\t}\n\t\t}\n\t\tconst tokenKey = `${agentId}\\n${jti}`;\n\t\tif (consumedApprovalTokenIds.has(tokenKey)) {\n\t\t\treturn { ok: false, reason: 'replayed' };\n\t\t}\n\t\tif (consumedApprovalTokenIds.size >= replayCacheLimit) {\n\t\t\treturn { ok: false, reason: 'replay-cache-full' };\n\t\t}\n\t\tconsumedApprovalTokenIds.set(tokenKey, expiresAtMs);\n\t\treturn { ok: true };\n\t};\n\treturn (calls, agentId, token) => {\n\t\tconst record = props.records.get(agentId);\n\t\tif (record === undefined) {\n\t\t\tauditApproval({\n\t\t\t\tagentId,\n\t\t\t\tdecision: 'deny',\n\t\t\t\treason: 'approval_token_invalid',\n\t\t\t\tverifierReason: 'unknown-agent',\n\t\t\t});\n\t\t\treturn { kind: 'approval_token_invalid', reason: 'unknown-agent' };\n\t\t}\n\t\tconst callsRequiringApproval = calls.filter((call) =>\n\t\t\tapprovalRequiredByProfile(record.profile, call),\n\t\t);\n\t\tif (callsRequiringApproval.length === 0) {\n\t\t\tauditApproval({ agentId, decision: 'allow', reason: 'no_approval_required' });\n\t\t\treturn { kind: 'allow' };\n\t\t}\n\t\tif (token === undefined) {\n\t\t\tauditApproval({ agentId, decision: 'deny', reason: 'approval_token_missing' });\n\t\t\treturn { kind: 'approval_token_missing' };\n\t\t}\n\t\tconst verificationProps = {\n\t\t\tagentId,\n\t\t\tcalls: approvalTokenCallDigests(callsRequiringApproval),\n\t\t\tconsumeTokenId: (jti: string, expiresAtMs: number) =>\n\t\t\t\tconsumeTokenId(agentId, jti, expiresAtMs),\n\t\t\tkey: record.hmacKey,\n\t\t\tmaxLifetimeMs: approvalTokenMaxLifetimeMs,\n\t\t\tnowMs: Date.now(),\n\t\t\ttoken,\n\t\t};\n\t\tconst verification = verifyApprovalToken(verificationProps);\n\t\tif (verification.ok) {\n\t\t\tauditApproval({ agentId, decision: 'allow' });\n\t\t\treturn { kind: 'allow' };\n\t\t}\n\t\tauditApproval({\n\t\t\tagentId,\n\t\t\tdecision: 'deny',\n\t\t\treason: 'approval_token_invalid',\n\t\t\tverifierReason: verification.reason,\n\t\t});\n\t\treturn { kind: 'approval_token_invalid', reason: verification.reason };\n\t};\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,MAAa,qBAAqB;CACjC;CACA;CACA;CACA;CACA;AAID,MAAM,uBAAuB,IAAI,IAAY,mBAAmB;AAEhE,SAAS,qBAAqB,OAA4C;CACzE,OAAO,qBAAqB,IAAI,MAAM;;AAGvC,SAAgB,mBACf,aACkB;CAClB,OACC,eAAe;EACd;GACC,aAAa;GACb,aAAa,uBAAuB;GACpC,MAAM;GACN;EACD;GACC,aAAa;GACb,aAAa,uBAAuB;GACpC,MAAM;GACN;EACD;GACC,aAAa;GACb,aAAa,uBAAuB;GACpC,MAAM;GACN;EACD;GACC,aAAa;GACb,aAAa,uBAAuB;GACpC,MAAM;GACN;EACD;;AAIH,SAAS,eAAe,OAAkD;CACzE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,kBAAkB,OAAkC;CAC5D,IAAI,MAAM,MAAM,MAAM,SAAS,KAAK,WAAW,SAAS,EACvD,OAAO;CAER,IAAI,CAAC,eAAe,MAAM,kBAAkB,EAC3C,OAAO;CAER,OAAO,MAAM,kBAAkB,OAAO;;AAGvC,SAAS,eAAe,OAAyC;CAChE,OAAO;EACN,SAAS,CAAC;GAAE,MAAM,KAAK,UAAU,MAAM;GAAE,MAAM;GAAQ,CAAC;EACxD,GAAI,kBAAkB,MAAM,GAAG,EAAE,SAAS,MAAM,GAAG,EAAE;EACrD;;AAGF,SAAS,gBAAgB,OAAgC;CAExD,OAAO;EACN,SAAS,CACR;GACC,MAJmB,kBAAkB,MAIlB,CAAC;GACpB,MAAM;GACN,CACD;EACD,SAAS;EACT;;AAGF,eAAe,2BACd,cAIA,kBAIgB;CAChB,IAAI;EACH,MAAM,iBAAiB,aAAa;SAC7B;;AAKT,eAAsB,gBAAgB,OAOpB;CACjB,IAAI,MAAM,MAAM,SAAS,yBAAyB;EACjD,IAAI,CAAC,eAAe,MAAM,MAAM,OAAO,EACtC;EAED,IAAI,MAAM,MAAM,WAAW,0BAA0B;GACpD,IAAI,MAAM,kBAAkB,KAAA,GAC3B;GAED,MAAM,2BACL;IACC,QAAQ;IACR,QAAQ;KAAE,GAAG,MAAM,MAAM;KAAQ,eAAe,MAAM;KAAe;IACrE,EACD,MAAM,iBACN;GACD;;EAED,IAAI,MAAM,MAAM,WAAW,yBAC1B;EAED,MAAM,2BACL;GACC,QAAQ;GACR,QAAQ,MAAM,MAAM;GACpB,EACD,MAAM,iBACN;EACD;;CAED,IAAI,MAAM,MAAM,SAAS,cAAc,MAAM,MAAM,SAAS,mBAC3D;CAED,MAAM,UACL,MAAM,MAAM,SAAS,aAClB,MAAM,MAAM,UACZ,MAAM,MAAM,QAAQ,SAAS,SAC5B,MAAM,MAAM,QAAQ,OACpB,KAAK,UAAU,MAAM,MAAM,QAAQ,MAAM;CAC9C,IAAI,YAAY,KAAA,KAAa,QAAQ,WAAW,GAC/C;CAED,IAAI,MAAM,kBAAkB,KAAA,GAAW;EACtC,MAAM,2BACL;GACC,QAAQ;GACR,QAAQ;IACP;IACA,UAAU,MAAM,MAAM,SAAS,aAAc,MAAM,MAAM,YAAY,IAAK;IAC1E,eAAe,MAAM;IACrB,GAAI,MAAM,MAAM,SAAS,cAAc,MAAM,MAAM,UAAU,KAAA,IAC1D,EAAE,OAAO,MAAM,MAAM,OAAO,GAC5B,EAAE;IACL;GACD,EACD,MAAM,iBACN;EACD;;CAED,MAAM,2BACL;EACC,QAAQ;EACR,QAAQ;GACP,MAAM;GACN,OAAO;GACP;EACD,EACD,MAAM,iBACN;;AAGF,SAAgB,sBAAsB,OAG3B;CACV,MAAM,SAAS,IAAI,OAClB;EAAE,MAAM;EAAc,SAAS;EAAS,EACxC,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,OAAO,EAAE,EAAE,CACnD;CAED,OAAO,kBAAkB,wBAAwB,aAAa,EAC7D,OAAO,mBAAmB,MAAM,KAAK,cAAc,MAAM,MAAM,CAAC,EAChE,EAAE;CAEH,OAAO,kBAAkB,uBAAuB,OAAO,SAAS,UAAU;EACzE,IAAI,CAAC,qBAAqB,QAAQ,OAAO,KAAK,EAC7C,OAAO;GACN,SAAS,CAAC;IAAE,MAAM,4BAA4B,QAAQ,OAAO;IAAQ,MAAM;IAAQ,CAAC;GACpF,SAAS;GACT;EAEF,IAAI;GAkBH,OAAO,eAAe,MAjBD,MAAM,KAAK,wBAC/B,MAAM,KAAK,WAAW;IACrB,OAAO,QAAQ,OAAO,aAAa,EAAE;IACrC,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,UAAU,QAAQ,OAAO;IACzB,CAAC,EACF,EACC,SAAS,OAAO,UAAU;IACzB,MAAM,gBAAgB;KACrB;KACA,eAAe,MAAM,UAAU;KAC/B,kBAAkB,MAAM;KACxB,CAAC;MAEH,CACD,CAC4B;WACrB,OAAO;GACf,OAAO,gBAAgB,MAAM;;GAE7B;CAEF,OAAO;;;;ACrLR,MAAM,qBAAqB;AAC3B,MAAM,0BAA0B;CAAE,aAAa;CAAI,UAAU;CAAQ;AACrE,MAAM,yBAAyB;AAC/B,MAAM,sBAAsB;AAC5B,MAAM,mDAAmD;AAazD,SAAS,iBAAiB,SAAiB,WAA2B;CACrE,OAAO,GAAG,QAAQ,IAAI;;AAGvB,SAAS,uBAAiC;CACzC,OAAO,SAAS,KAAK;EAAE,OAAO,EAAE,MAAM,gBAAgB;EAAE,IAAI;EAAO,EAAE,EAAE,QAAQ,KAAK,CAAC;;AAGtF,SAAS,sBAAgC;CACxC,OAAO,SAAS,KAAK;EAAE,OAAO,EAAE,MAAM,gBAAgB;EAAE,IAAI;EAAO,EAAE,EAAE,QAAQ,KAAK,CAAC;;AAGtF,SAAS,sBAAgC;CACxC,OAAO,SAAS,KAAK;EAAE,OAAO,EAAE,MAAM,iBAAiB;EAAE,IAAI;EAAO,EAAE,EAAE,QAAQ,KAAK,CAAC;;AAGvF,SAAS,iBAAiB,OAAuB;CAChD,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC;;AAGjE,SAAS,yBAAyB,SAA0B;CAC3D,IAAI;EACH,MAAM,UAAU,YAAY,QAAQ,CAAC,OAAO;EAC5C,OAAO,WAAW,QAAQ,SAAS,IAAI,UAAU;SAC1C;EACP,OAAO;;;AAIT,SAAgB,oBAAoB,SAA8C;CACjF,IAAI,QAAQ,oBAAoB,KAAA,GAC/B,MAAM,IAAI,MAAM,kDAAkD;CAEnE,IAAI,QAAQ,gBAAgB,wBAAwB,WAAW,GAC9D,MAAM,IAAI,MAAM,8DAA8D;CAE/E,MAAM,MAAM,IAAI,MAAM;CACtB,MAAM,iCAAiB,IAAI,KAAqC;CAChE,MAAM,qCAAqB,IAAI,KAAgC;CAC/D,MAAM,4CAA4B,IAAI,KAAoB;CAC1D,MAAM,mBAAmB,QAAQ,oBAAoB;CACrD,IAAI,UAAU;CAEd,eAAe,UAAU,OAAqE;EAC7F,MAAM,aAAa;GAAE,GAAG;GAAO,MAAM;GAAkB,QAAQ,KAAK,KAAK;GAAE;EAC3E,IAAI;GACH,MAAM,QAAQ,YAAY,WAAW;WAC7B,OAAO;GACf,MAAM,QAAQ,iBAAiB,iBAAiB,MAAM,EAAE,WAAW;;;CAIrE,eAAe,wBACd,OACA,UACgB;EAChB,MAAM,QAAQ,sBAAsB,iBAAiB,MAAM,EAAE,SAAS;;CAGvE,SAAS,wBAAwB,OAAqB;EACrD,KAAK,MAAM,CAAC,KAAK,WAAW,oBAC3B,IAAI,OAAO,aAAa,OACvB,mBAAmB,OAAO,IAAI;EAGhC,OAAO,mBAAmB,OAAO,wBAAwB;GACxD,MAAM,WAAW,mBAAmB,MAAM,CAAC,MAAM,CAAC;GAClD,IAAI,OAAO,aAAa,UACvB;GAED,mBAAmB,OAAO,SAAS;;;CAIrC,SAAS,yBAAyB,eAAgC;EACjE,MAAM,QAAQ,KAAK,KAAK;EACxB,wBAAwB,MAAM;EAC9B,MAAM,SAAS,mBAAmB,IAAI,cAAc;EACpD,IAAI,WAAW,KAAA,GACd,OAAO;EAER,IAAI,OAAO,aAAa,OAAO;GAC9B,mBAAmB,OAAO,cAAc;GACxC,OAAO;;EAER,OAAO,OAAO,YAAY,iBAAiB;;CAG5C,SAAS,kBAAkB,eAA6B;EACvD,MAAM,QAAQ,KAAK,KAAK;EACxB,wBAAwB,MAAM;EAC9B,MAAM,SAAS,mBAAmB,IAAI,cAAc;EACpD,IAAI,WAAW,KAAA,KAAa,OAAO,YAAY,OAAO;GACrD,OAAO,YAAY;GACnB;;EAED,mBAAmB,IAAI,eAAe;GACrC,UAAU;GACV,WAAW,QAAQ,iBAAiB;GACpC,CAAC;EACF,wBAAwB,MAAM;;CAG/B,SAAS,kBAAkB,eAA6B;EACvD,mBAAmB,OAAO,cAAc;;CAGzC,eAAe,mBACd,YACA,cACgB;EAChB,MAAM,gBAAgB,eAAe,IAAI,WAAW;EACpD,IAAI,CAAC,eACJ;EAED,eAAe,OAAO,WAAW;EACjC,IAAI;GACH,IAAI,aAAa,gBAChB,MAAM,cAAc,UAAU,OAAO;YAE7B;GACT,MAAM,QAAQ,kBAAkB,cAAc,SAAS;;;CAIzD,SAAS,gCAA4C;EACpD,IAAI;EACJ,MAAM,iBAAiB,IAAI,SAAe,YAAY;GACrD,iBAAiB;IAChB;EACF,0BAA0B,IAAI,eAAe;EAC7C,aAAa;GACZ,0BAA0B,OAAO,eAAe;GAChD,kBAAkB;;;CAIpB,eAAe,oBACd,cACkC;EAClC,MAAM,YAAY,YAAY;EAC9B,MAAM,aAAa,iBAAiB,aAAa,cAAc,UAAU;EACzE,IAAI,SAA0D;EAC9D,MAAM,WAAW,0BAA0B;GAC1C,SAAS,aAAa;GACtB,cAAc,aAAa;GAC3B;GACA,QAAQ,aAAa;GACrB,CAAC;EACF,MAAM,YAAY,IAAI,wBAAwB;GAC7C,uBAAuB;IACtB,mBAAwB,YAAY,EAAE,gBAAgB,OAAO,CAAC,CAAC,OAAO,UACrE,wBAAwB,OAAO,SAAS,CACxC;;GAEF,uBAAuB,yBAAyB;IAC/C,IAAI,CAAC,QACJ,MAAM,IAAI,MAAM,2DAA2D;IAE5E,eAAe,IAAI,iBAAiB,aAAa,cAAc,qBAAqB,EAAE;KACrF;KACA;KACA;KACA,CAAC;;GAEH,0BAA0B;GAC1B,CAAC;EACF,SAAS,sBAAsB;GAC9B,MAAM,QAAQ;GACd,OAAO;GACP,CAAC;EACF,MAAM,OAAO,QAAQ,UAAU;EAC/B,OAAO;GAAE;GAAU;GAAQ;GAAW;;CAGvC,eAAe,sBAAqC;EACnD,UAAU;EACV,MAAM,cAAuB,EAAE;EAC/B,OAAO,eAAe,OAAO,KAAK,0BAA0B,OAAO,GAAG;GACrE,IAAI,0BAA0B,OAAO,GAAG;IAEvC,MAAM,QAAQ,WAAW,0BAA0B;IACnD;;GAID,MAAM,eAAe,MAAM,QAAQ,WAClC,CAAC,GAAG,eAAe,MAAM,CAAC,CAAC,KAAK,eAC/B,mBAAmB,YAAY,EAAE,gBAAgB,MAAM,CAAC,CACxD,CACD;GACD,YAAY,KACX,GAAG,aACD,QAAQ,WAA4C,OAAO,WAAW,WAAW,CACjF,KAAK,WAAkB,iBAAiB,OAAO,OAAO,CAAC,CACzD;;EAEF,IAAI,YAAY,SAAS,GACxB,MAAM,IAAI,eAAe,aAAa,mDAAmD;;CAI3F,IAAI,IAAI,YAAY,YACnB,QAAQ,KAAK;EAAE,QAAQ,CAAC,GAAI,QAAQ,sBAAsB,EAAE,CAAE,CAAC,UAAU;EAAE,IAAI;EAAM,CAAC,CACtF;CAED,IAAI,IAAI,wBAAwB,OAAO,YAAY;EAClD,MAAM,UAAU,QAAQ,IAAI,MAAM,UAAU;EAC5C,MAAM,gBAAgB,yBAAyB,QAAQ;EACvD,IAAI,SACH,OAAO,qBAAqB;EAE7B,IAAI,yBAAyB,cAAc,EAAE;GAC5C,MAAM,UAAU;IACf;IACA;IACA,UAAU;IACV,QAAQ;IACR,CAAC;GACF,OAAO,qBAAqB;;EAE7B,MAAM,kBAAkB,QAAQ;EAChC,MAAM,oBAAoB,gBAAgB,4BAA4B;EACtE,MAAM,eAAe,+BAA+B;GACnD;GACA,qBAAqB,QAAQ,IAAI,OAAO,gBAAgB,wBAAwB;GAChF,mBAAmB,qBAAqB;GACxC,WAAW,gBAAgB;GAC3B,CAAC;EACF,MAAM,gBAAgB,QAAQ,uBAAuB,QAAQ,IAAI;EACjE,IAAI,kBAAkB,MAAM;GAC3B,kBAAkB,cAAc;GAChC,MAAM,UAAU;IACf;IACA;IACA,UAAU;IACV,QAAQ;IACR,CAAC;GACF,OAAO,sBAAsB;;EAE9B,IAAI,CAAC,aAAa,IAAI;GACrB,kBAAkB,cAAc;GAChC,MAAM,UAAU;IACf;IACA;IACA,UAAU;IACV,QAAQ,aAAa;IACrB,CAAC;GACF,OAAO,sBAAsB;;EAE9B,kBAAkB,cAAc;EAChC,MAAM,UAAU;GAAE;GAAS;GAAe,UAAU;GAAS,CAAC;EAE9D,MAAM,eAAe,QAAQ,IAAI,OAAO,mBAAmB;EAC3D,IAAI,cAAc;GACjB,MAAM,gBAAgB,eAAe,IACpC,iBAAiB,cAAc,cAAc,aAAa,CAC1D;GACD,IAAI,CAAC,eACJ,OAAO,IAAI,SAAS,8BAA8B,EAAE,QAAQ,KAAK,CAAC;GAEnE,OAAO,MAAM,cAAc,UAAU,cAAc,QAAQ;;EAG5D,MAAM,uBAAuB,+BAA+B;EAC5D,IAAI;GACH,IAAI,SACH,OAAO,qBAAqB;GAE7B,MAAM,gBAAgB,MAAM,oBAAoB,cAAc;GAC9D,IAAI,SAAS;IACZ,MAAM,cAAc,UAAU,OAAO;IACrC,OAAO,qBAAqB;;GAE7B,OAAO,MAAM,cAAc,UAAU,cAAc,QAAQ;YAClD;GACT,sBAAsB;;GAEtB;CAEF,OAAO,OAAO,OAAO,KAAK,EAAE,qBAAqB,CAAC;;;;ACnVnD,MAAM,6BAA6B,IAAI;AACvC,MAAM,gCAAgC;AAwBtC,eAAe,yBAAyB,OAKD;CACtC,MAAM,SAAS,MAAM,QAAQ,IAAI,MAAM,QAAQ;CAC/C,IAAI,WAAW,KAAA,GACd,OAAO,CAAC,MAAM,SAAS,OAAO;CAE/B,IAAI,MAAM,MAAM,YAAY,KAAA,GAC3B,MAAM,IAAI,MAAM,0CAA0C,MAAM,QAAQ,IAAI;CAE7E,MAAM,cAAc,MAAM,MAAM,cAAc,MAAM,MAAM,QAAQ;CAClE,IAAI,CAAC,eAAe,KAAK,YAAY,IAAI,YAAY,WAAW,IAC/D,MAAM,IAAI,MAAM,qBAAqB,MAAM,QAAQ,uCAAuC;CAE3F,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,aAAa,MAAM,CAAC;;AAGxD,eAAsB,qBACrB,OACuC;CACvC,OAAO,IAAI,IACV,MAAM,QAAQ,IACb,OAAO,QAAQ,MAAM,OAAO,CAAC,KAAK,CAAC,SAAS,WAC3C,yBAAyB;EACxB;EACA;EACA,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,CAAC,CACF,CACD,CACD;;AAGF,SAAgB,gCAAgC,OAGE;CACjD,MAAM,0BAAU,IAAI,KAAuC;CAC3D,KAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,MAAM,aAAa,OAAO,EAAE;EACzE,MAAM,UAAU,MAAM,SAAS,IAAI,QAAQ;EAC3C,IAAI,YAAY,KAAA,GACf,MAAM,IAAI,MAAM,0CAA0C,QAAQ,IAAI;EAEvE,QAAQ,IAAI,SAAS;GACpB;GACA;GACA,SAAS,wBAAwB,MAAM,cAAc,MAAM,QAAQ;GACnE,aAAa,MAAM;GACnB,CAAC;;CAEH,OAAO;;AAGR,SAAgB,8BACf,SAC2E;CAC3E,QAAQ,YAAY;EAEnB,IADe,QAAQ,IAAI,QACjB,KAAK,KAAA,GACd,OAAO;EAER,OAAO,0BAA0B;GAChC;GACA,cAAc;GACd,QAAQ;GACR,CAAC;;;AAIJ,SAAS,0BACR,SACA,MACU;CACV,MAAM,cAAc,KAAK,KAAK;CAC9B,OAAO,8BAA8B,SAAS;EAC7C,GAAI,gBAAgB,KAAA,IAAY,EAAE,GAAG,EAAE,aAAa;EACpD,WAAW,KAAK;EAChB,UAAU,KAAK;EACf,CAAC;;AAGH,SAAS,yBAAyB,OAI9B;CACH,OAAO,MAAM,KAAK,UAAU;EAC3B,eAAe,kBAAkB,KAAK,UAAU;EAChD,WAAW,KAAK;EAChB,UAAU,KAAK;EACf,EAAE;;AAGJ,SAAgB,6BAA6B,OAYE;CAC9C,SAAS,cAAc,OAAgE;EACtF,MAAM,aAAa;GAAE,GAAG;GAAO,MAAM;GAAuB,QAAQ,KAAK,KAAK;GAAE;EAChF,IAAI;GACH,MAAM,YAAY,WAAW;WACrB,OAAO;GACf,MAAM,iBAAiB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EAAE,WAAW;;;CAI/F,MAAM,2CAA2B,IAAI,KAAqB;CAC1D,MAAM,mBAAmB,MAAM,iCAAiC;CAChE,MAAM,kBACL,SACA,KACA,gBAG+E;EAC/E,MAAM,QAAQ,KAAK,KAAK;EACxB,KAAK,MAAM,CAAC,UAAU,qBAAqB,0BAC1C,IAAI,oBAAoB,OACvB,yBAAyB,OAAO,SAAS;EAG3C,MAAM,WAAW,GAAG,QAAQ,IAAI;EAChC,IAAI,yBAAyB,IAAI,SAAS,EACzC,OAAO;GAAE,IAAI;GAAO,QAAQ;GAAY;EAEzC,IAAI,yBAAyB,QAAQ,kBACpC,OAAO;GAAE,IAAI;GAAO,QAAQ;GAAqB;EAElD,yBAAyB,IAAI,UAAU,YAAY;EACnD,OAAO,EAAE,IAAI,MAAM;;CAEpB,QAAQ,OAAO,SAAS,UAAU;EACjC,MAAM,SAAS,MAAM,QAAQ,IAAI,QAAQ;EACzC,IAAI,WAAW,KAAA,GAAW;GACzB,cAAc;IACb;IACA,UAAU;IACV,QAAQ;IACR,gBAAgB;IAChB,CAAC;GACF,OAAO;IAAE,MAAM;IAA0B,QAAQ;IAAiB;;EAEnE,MAAM,yBAAyB,MAAM,QAAQ,SAC5C,0BAA0B,OAAO,SAAS,KAAK,CAC/C;EACD,IAAI,uBAAuB,WAAW,GAAG;GACxC,cAAc;IAAE;IAAS,UAAU;IAAS,QAAQ;IAAwB,CAAC;GAC7E,OAAO,EAAE,MAAM,SAAS;;EAEzB,IAAI,UAAU,KAAA,GAAW;GACxB,cAAc;IAAE;IAAS,UAAU;IAAQ,QAAQ;IAA0B,CAAC;GAC9E,OAAO,EAAE,MAAM,0BAA0B;;EAY1C,MAAM,eAAe,oBAAoB;GATxC;GACA,OAAO,yBAAyB,uBAAuB;GACvD,iBAAiB,KAAa,gBAC7B,eAAe,SAAS,KAAK,YAAY;GAC1C,KAAK,OAAO;GACZ,eAAe;GACf,OAAO,KAAK,KAAK;GACjB;GAEyD,CAAC;EAC3D,IAAI,aAAa,IAAI;GACpB,cAAc;IAAE;IAAS,UAAU;IAAS,CAAC;GAC7C,OAAO,EAAE,MAAM,SAAS;;EAEzB,cAAc;GACb;GACA,UAAU;GACV,QAAQ;GACR,gBAAgB,aAAa;GAC7B,CAAC;EACF,OAAO;GAAE,MAAM;GAA0B,QAAQ,aAAa;GAAQ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { t as createUpstreamMcpClientRuntime } from "./upstream-mcp-client-runtime-
|
|
2
|
-
import { i as resolveUpstreamServers, n as createPortalCore } from "./portal-core-
|
|
1
|
+
import { t as createUpstreamMcpClientRuntime } from "./upstream-mcp-client-runtime-Be_cw6pV.js";
|
|
2
|
+
import { i as resolveUpstreamServers, n as createPortalCore } from "./portal-core-B5cRpZMG.js";
|
|
3
3
|
import { t as decodePortalMasterKey } from "./agent-bearer-token-DCtpDPCZ.js";
|
|
4
|
-
import { a as createPortalHttpApp, n as createPortalApprovalVerifier, r as createPortalHttpAgentResolver, t as createPortalAgentRuntimeRecords } from "./resolve-agent-identity-
|
|
4
|
+
import { a as createPortalHttpApp, n as createPortalApprovalVerifier, r as createPortalHttpAgentResolver, t as createPortalAgentRuntimeRecords } from "./resolve-agent-identity-ZMMY2Wqm.js";
|
|
5
5
|
import { createHmac } from "node:crypto";
|
|
6
6
|
import { loadMcpConfig, loadMcpPortalConfig, resolveMcpPortalProfile } from "@agent-vm/config-contracts";
|
|
7
7
|
import { join } from "node:path";
|
|
@@ -175,20 +175,20 @@ function selectorsFromNamespaceTools(namespaceTools) {
|
|
|
175
175
|
}
|
|
176
176
|
function buildProfilePolicyMaps(portalConfig) {
|
|
177
177
|
const enabledNamespacesByAgent = {};
|
|
178
|
-
const
|
|
178
|
+
const enabledToolsByNamespaceByAgent = {};
|
|
179
179
|
const hiddenToolsByAgent = {};
|
|
180
180
|
const profileTtls = [];
|
|
181
181
|
for (const [agentId, agent] of Object.entries(portalConfig.agents)) {
|
|
182
182
|
const profile = resolveMcpPortalProfile(portalConfig, agent.profile);
|
|
183
183
|
enabledNamespacesByAgent[agentId] = profile.enabledNamespaces;
|
|
184
|
-
|
|
184
|
+
enabledToolsByNamespaceByAgent[agentId] = profile.enabledToolsByNamespace;
|
|
185
185
|
hiddenToolsByAgent[agentId] = selectorsFromNamespaceTools(profile.hiddenToolsByNamespace);
|
|
186
186
|
profileTtls.push(profile.cache.catalogTtlMs);
|
|
187
187
|
}
|
|
188
188
|
return {
|
|
189
189
|
cacheTtlMs: profileTtls.length === 0 ? 6e4 : Math.min(...profileTtls),
|
|
190
190
|
enabledNamespacesByAgent,
|
|
191
|
-
|
|
191
|
+
enabledToolsByNamespaceByAgent,
|
|
192
192
|
hiddenToolsByAgent
|
|
193
193
|
};
|
|
194
194
|
}
|
|
@@ -279,7 +279,7 @@ async function startPortalServer(props) {
|
|
|
279
279
|
accessPolicy: {
|
|
280
280
|
defaultPolicy: "deny-all",
|
|
281
281
|
enabledNamespacesByAgent: profilePolicyMaps.enabledNamespacesByAgent,
|
|
282
|
-
|
|
282
|
+
enabledToolsByNamespaceByAgent: profilePolicyMaps.enabledToolsByNamespaceByAgent,
|
|
283
283
|
hiddenToolsByAgent: profilePolicyMaps.hiddenToolsByAgent
|
|
284
284
|
},
|
|
285
285
|
approval: (calls, identity, approvalToken) => verifyApproval(calls, identity.agentId, approvalToken),
|
|
@@ -355,4 +355,4 @@ async function startPortalServer(props) {
|
|
|
355
355
|
//#endregion
|
|
356
356
|
export { handlePortalServerError as a, resolveSecretValue as c, deriveApprovalHmacKeysFromMasterKey as i, buildProfilePolicyMaps as n, parsePortalServerCliArgs as o, createServeSecretResolver as r, startPortalServer as s, applyAgentOverrides as t };
|
|
357
357
|
|
|
358
|
-
//# sourceMappingURL=serve-command-
|
|
358
|
+
//# sourceMappingURL=serve-command-Dz6nvnzQ.js.map
|