@agent-vm/mcp-portal 0.0.80 → 0.0.81

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.
Files changed (53) hide show
  1. package/dist/{agent-bearer-token-DCtpDPCZ.js → agent-bearer-token-NtEqghPk.js} +1 -1
  2. package/dist/{agent-bearer-token-DCtpDPCZ.js.map → agent-bearer-token-NtEqghPk.js.map} +1 -1
  3. package/dist/bin/mcp-portal.js +7 -7
  4. package/dist/cli/index.d.ts +1 -1
  5. package/dist/cli/index.js +1 -1
  6. package/dist/core/index.d.ts +28 -10
  7. package/dist/core/index.d.ts.map +1 -1
  8. package/dist/core/index.js +5 -5
  9. package/dist/hmac-token-B3QdUvuG.d.ts +40 -0
  10. package/dist/hmac-token-B3QdUvuG.d.ts.map +1 -0
  11. package/dist/{hmac-token-DBqWY3-w.js → hmac-token-D3c9OUTE.js} +1 -1
  12. package/dist/{hmac-token-DBqWY3-w.js.map → hmac-token-D3c9OUTE.js.map} +1 -1
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +3 -3
  15. package/dist/mcp-proxy/index.d.ts +2 -2
  16. package/dist/mcp-proxy/index.js +1 -1
  17. package/dist/portal-auth/agent-bearer-token.js +1 -1
  18. package/dist/portal-auth/hmac-token.d.ts +2 -40
  19. package/dist/portal-auth/hmac-token.js +1 -1
  20. package/dist/portal-config/index.d.ts +1 -1
  21. package/dist/portal-config/index.js +2 -2
  22. package/dist/{portal-core-CatZlNq_.d.ts → portal-core-B7scBU6I.d.ts} +46 -22
  23. package/dist/portal-core-B7scBU6I.d.ts.map +1 -0
  24. package/dist/{portal-core-e-qajblz.js → portal-core-B8HZPw3z.js} +86 -10
  25. package/dist/portal-core-B8HZPw3z.js.map +1 -0
  26. package/dist/{portal-tools-Ct2GuFSc.js → portal-tools-fFyF72Nl.js} +174 -83
  27. package/dist/portal-tools-fFyF72Nl.js.map +1 -0
  28. package/dist/{resolve-agent-identity-Dnqv2hAW.js → resolve-agent-identity-BQNGUP66.js} +34 -78
  29. package/dist/resolve-agent-identity-BQNGUP66.js.map +1 -0
  30. package/dist/{resolve-agent-identity-C1xp9_2R.d.ts → resolve-agent-identity-BqYlDgBX.d.ts} +4 -13
  31. package/dist/{resolve-agent-identity-C1xp9_2R.d.ts.map → resolve-agent-identity-BqYlDgBX.d.ts.map} +1 -1
  32. package/dist/{serve-command-DHkYmO6n.js → serve-command-4BNOH14H.js} +5 -5
  33. package/dist/{serve-command-DHkYmO6n.js.map → serve-command-4BNOH14H.js.map} +1 -1
  34. package/dist/{typescript-artifact-BVLt3Ifd.js → typescript-artifact-EQH4tZ0C.js} +2 -2
  35. package/dist/{typescript-artifact-BVLt3Ifd.js.map → typescript-artifact-EQH4tZ0C.js.map} +1 -1
  36. package/dist/{upstream-mcp-client-runtime-Be_cw6pV.js → upstream-mcp-client-runtime-vu2TiTUw.js} +3 -3
  37. package/dist/{upstream-mcp-client-runtime-Be_cw6pV.js.map → upstream-mcp-client-runtime-vu2TiTUw.js.map} +1 -1
  38. package/dist/{upstream-response-middleware-1MZnAD9C.d.ts → upstream-response-middleware-CkV-rDNO.d.ts} +1 -1
  39. package/dist/{upstream-response-middleware-1MZnAD9C.d.ts.map → upstream-response-middleware-CkV-rDNO.d.ts.map} +1 -1
  40. package/dist/{upstream-response-middleware-Cd1MxA6A.js → upstream-response-middleware-_dthoE1r.js} +2 -2
  41. package/dist/{upstream-response-middleware-Cd1MxA6A.js.map → upstream-response-middleware-_dthoE1r.js.map} +1 -1
  42. package/dist/{zod-schema-loader-DLGQpYFD.d.ts → zod-schema-loader-BubVafy-.d.ts} +9 -2
  43. package/dist/zod-schema-loader-BubVafy-.d.ts.map +1 -0
  44. package/dist/{zod-schema-loader-yNekKNpm.js → zod-schema-loader-C3I-MnWq.js} +76 -5
  45. package/dist/zod-schema-loader-C3I-MnWq.js.map +1 -0
  46. package/package.json +3 -3
  47. package/dist/portal-auth/hmac-token.d.ts.map +0 -1
  48. package/dist/portal-core-CatZlNq_.d.ts.map +0 -1
  49. package/dist/portal-core-e-qajblz.js.map +0 -1
  50. package/dist/portal-tools-Ct2GuFSc.js.map +0 -1
  51. package/dist/resolve-agent-identity-Dnqv2hAW.js.map +0 -1
  52. package/dist/zod-schema-loader-DLGQpYFD.d.ts.map +0 -1
  53. package/dist/zod-schema-loader-yNekKNpm.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { l as jsonObjectSchema } from "./zod-schema-loader-yNekKNpm.js";
2
- import { _ as createPortalAgentIdentity, y as resolvePortalAccessPolicy } from "./upstream-response-middleware-Cd1MxA6A.js";
3
- import { n as createPortalSessionManager } from "./upstream-mcp-client-runtime-Be_cw6pV.js";
4
- import { n as portalToolInputSchemas, t as createPortalToolHandlers } from "./portal-tools-Ct2GuFSc.js";
1
+ import { l as jsonObjectSchema } from "./zod-schema-loader-C3I-MnWq.js";
2
+ import { _ as createPortalAgentIdentity, y as resolvePortalAccessPolicy } from "./upstream-response-middleware-_dthoE1r.js";
3
+ import { n as createPortalSessionManager } from "./upstream-mcp-client-runtime-vu2TiTUw.js";
4
+ import { n as portalToolInputSchemas, r as preparePortalApprovalCallDigests, t as createPortalToolHandlers } from "./portal-tools-fFyF72Nl.js";
5
5
  import { z } from "zod";
6
6
  import { mcpConfigToResolvedProviders } from "@agent-vm/config-contracts";
7
7
  //#region src/core/provider-runtime.ts
@@ -29,9 +29,24 @@ async function resolveUpstreamServers(props) {
29
29
  return await Promise.all(mcpConfigToResolvedProviders(props.config).map(async (provider) => resolveUpstreamServer(provider, props.resolveSecret)));
30
30
  }
31
31
  //#endregion
32
+ //#region src/core/portal-core-validation.ts
33
+ function isUnknownRecord$1(value) {
34
+ return typeof value === "object" && value !== null && !Array.isArray(value);
35
+ }
36
+ function isPortalCoreJsonValue(value, activeObjects = /* @__PURE__ */ new Set()) {
37
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") return true;
38
+ if (typeof value !== "object") return false;
39
+ if (activeObjects.has(value)) return false;
40
+ activeObjects.add(value);
41
+ const isValid = Array.isArray(value) && value.every((entry) => isPortalCoreJsonValue(entry, activeObjects)) || isUnknownRecord$1(value) && Object.values(value).every((entry) => isPortalCoreJsonValue(entry, activeObjects));
42
+ activeObjects.delete(value);
43
+ return isValid;
44
+ }
45
+ //#endregion
32
46
  //#region src/core/portal-core.ts
33
47
  const maxQueuedPortalCoreEvents = 1024;
34
48
  const maxPortalCoreEventBytes = 256 * 1024;
49
+ const maxAgentFacingValidationIssues = 5;
35
50
  const portalCallRequestSchema = z.object({
36
51
  arguments: jsonObjectSchema,
37
52
  id: z.string().min(1),
@@ -51,8 +66,59 @@ function isUnknownRecord(value) {
51
66
  function errorRecordFromUnknown(error) {
52
67
  return isUnknownRecord(error) ? error : {};
53
68
  }
69
+ function isStringArray(value) {
70
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
71
+ }
72
+ function isJsonValueArray(value) {
73
+ return Array.isArray(value) && value.every((entry) => isPortalCoreJsonValue(entry));
74
+ }
75
+ function isValidationIssueReceived(value) {
76
+ return isUnknownRecord(value) && typeof value.type === "string" && (value.preview === void 0 || typeof value.preview === "string");
77
+ }
78
+ function isValidationIssue(value) {
79
+ return isUnknownRecord(value) && typeof value.code === "string" && typeof value.message === "string" && Array.isArray(value.path) && value.path.every((pathPart) => typeof pathPart === "string" || typeof pathPart === "number") && (value.expected === void 0 || typeof value.expected === "string") && (value.keys === void 0 || isStringArray(value.keys)) && (value.received === void 0 || isValidationIssueReceived(value.received)) && (value.values === void 0 || isJsonValueArray(value.values));
80
+ }
81
+ function validationIssuesFromUnknown(error) {
82
+ const issues = errorRecordFromUnknown(error).issues;
83
+ if (!Array.isArray(issues)) return;
84
+ const validationIssues = issues.filter((issue) => isValidationIssue(issue));
85
+ return validationIssues.length > 0 ? validationIssues : void 0;
86
+ }
87
+ function validationIssuePathLabel(path) {
88
+ return path.length === 0 ? "(root)" : path.map((pathPart) => String(pathPart)).join(".");
89
+ }
90
+ function formattedJsonValue(value) {
91
+ return JSON.stringify(value) ?? "[unserializable-json-value]";
92
+ }
93
+ function receivedValueLabel(received) {
94
+ if (received === void 0) return;
95
+ if (received.preview === void 0) return received.type;
96
+ const preview = received.type === "string" ? JSON.stringify(received.preview) : received.preview;
97
+ return `${received.type} ${preview}`;
98
+ }
99
+ function validationIssueSummary(issue) {
100
+ const details = [
101
+ issue.expected === void 0 ? void 0 : `expected ${issue.expected}`,
102
+ issue.values === void 0 ? void 0 : `allowed values ${issue.values.map((value) => formattedJsonValue(value)).join(", ")}`,
103
+ issue.keys === void 0 ? void 0 : `unrecognized keys ${issue.keys.join(", ")}`,
104
+ receivedValueLabel(issue.received) === void 0 ? void 0 : `received ${receivedValueLabel(issue.received)}`,
105
+ issue.message
106
+ ].filter((detail) => detail !== void 0);
107
+ return `${validationIssuePathLabel(issue.path)}: ${details.join("; ")}`;
108
+ }
109
+ function agentFacingValidationIssues(issues) {
110
+ return issues.slice(0, maxAgentFacingValidationIssues);
111
+ }
112
+ function messageFromValidationIssues(issues) {
113
+ const shownIssues = agentFacingValidationIssues(issues);
114
+ const truncatedIssues = issues.length - shownIssues.length;
115
+ const suffix = truncatedIssues > 0 ? ` | ${String(truncatedIssues)} more validation issue(s) omitted; call describe for the exact schema.` : "";
116
+ return `Input validation failed: ${shownIssues.map((issue) => validationIssueSummary(issue)).join(" | ")}${suffix}`;
117
+ }
54
118
  function messageFromUnknown(error) {
55
119
  if (error instanceof Error) return error.message;
120
+ const validationIssues = validationIssuesFromUnknown(error);
121
+ if (validationIssues !== void 0) return messageFromValidationIssues(validationIssues);
56
122
  const message = errorRecordFromUnknown(error).message;
57
123
  return typeof message === "string" ? message : String(error);
58
124
  }
@@ -101,9 +167,17 @@ function itemErrorFromPortalResult(result) {
101
167
  const namespace = errorRecord.namespace;
102
168
  const toolName = errorRecord.toolName;
103
169
  const upstream = errorRecord.upstream;
170
+ const issues = validationIssuesFromUnknown(result.error);
171
+ const shownIssues = issues === void 0 ? void 0 : agentFacingValidationIssues(issues);
172
+ const issuesTruncated = issues === void 0 || shownIssues === void 0 ? void 0 : issues.length - shownIssues.length;
104
173
  return {
105
174
  code: typeof kind === "string" ? kind : "portal_item_failed",
106
175
  message: messageFromUnknown(result.error),
176
+ ...issues === void 0 || shownIssues === void 0 ? {} : {
177
+ issueCount: issues.length,
178
+ issues: shownIssues,
179
+ ...issuesTruncated === void 0 || issuesTruncated <= 0 ? {} : { issuesTruncated }
180
+ },
107
181
  ...typeof namespace === "string" ? { namespace } : {},
108
182
  ...typeof toolName === "string" ? { toolName } : {},
109
183
  ...upstream === void 0 ? {} : { upstream }
@@ -349,10 +423,7 @@ function createPortalCore(props) {
349
423
  upstreamNamespaces: props.upstreamNamespaces
350
424
  });
351
425
  const createdAgentScopeIds = /* @__PURE__ */ new Set();
352
- const approval = props.approval ?? (() => {
353
- if (props.approvalTrustBoundary === "openclaw-before-tool-call-hook") return { kind: "allow" };
354
- throw new Error("MCP Portal approval evaluation is not configured.");
355
- });
426
+ const approval = props.approval;
356
427
  const toolRuntime = {
357
428
  approval,
358
429
  callUpstreamTool: props.runtime.callUpstreamTool,
@@ -391,7 +462,12 @@ function createPortalCore(props) {
391
462
  }
392
463
  }
393
464
  return {
394
- approval: { evaluateCalls: (calls, scope, approvalToken) => approval(calls, scope, approvalToken) },
465
+ approval: {
466
+ evaluateCalls: (calls, scope, approvalToken) => approval(calls, scope, approvalToken),
467
+ prepareCallDigests: async ({ input, scope }) => {
468
+ return preparePortalApprovalCallDigests(await sessionManager.getSession(scope), input);
469
+ }
470
+ },
395
471
  callStream,
396
472
  close: async () => {
397
473
  await Promise.all([...createdAgentScopeIds].map((agentScopeId) => sessionManager.invalidateAgentScope(agentScopeId)));
@@ -422,4 +498,4 @@ function createPortalCore(props) {
422
498
  //#endregion
423
499
  export { resolveUpstreamServers as i, createPortalCore as n, listPortalCoreToolDescriptors as r, collectPortalCoreResult as t };
424
500
 
425
- //# sourceMappingURL=portal-core-e-qajblz.js.map
501
+ //# sourceMappingURL=portal-core-B8HZPw3z.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portal-core-B8HZPw3z.js","names":["isUnknownRecord"],"sources":["../src/core/provider-runtime.ts","../src/core/portal-core-validation.ts","../src/core/portal-core.ts"],"sourcesContent":["import {\n\tmcpConfigToResolvedProviders,\n\ttype McpConfig,\n\ttype ResolvedMcpProvider,\n\ttype SecretValue,\n} from '@agent-vm/config-contracts';\n\nimport type { NormalizedUpstreamMcpServer } from '../upstream-mcp-client-runtime.js';\n\nexport interface ResolveUpstreamServersProps {\n\treadonly config: McpConfig;\n\treadonly resolveSecret: (secret: SecretValue) => Promise<string>;\n}\n\nasync function resolveProviderSecretRecord(\n\tsecrets: Readonly<Record<string, SecretValue>>,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<Readonly<Record<string, string>>> {\n\tconst resolvedEntries = await Promise.all(\n\t\tObject.entries(secrets).map(\n\t\t\tasync ([name, secret]) => [name, await resolveSecret(secret)] as const,\n\t\t),\n\t);\n\treturn Object.fromEntries(resolvedEntries);\n}\n\nasync function resolveUpstreamServer(\n\tprovider: ResolvedMcpProvider,\n\tresolveSecret: (secret: SecretValue) => Promise<string>,\n): Promise<NormalizedUpstreamMcpServer> {\n\tif (provider.transport === 'stdio') {\n\t\treturn {\n\t\t\targs: provider.args,\n\t\t\tcommand: provider.command,\n\t\t\t...(provider.cwd === undefined ? {} : { cwd: provider.cwd }),\n\t\t\tenv: await resolveProviderSecretRecord(provider.env, resolveSecret),\n\t\t\tnamespace: provider.namespace,\n\t\t\ttransport: 'stdio',\n\t\t};\n\t}\n\n\treturn {\n\t\theaders: await resolveProviderSecretRecord(provider.headers, resolveSecret),\n\t\tnamespace: provider.namespace,\n\t\ttransport: provider.transport,\n\t\turl: provider.url,\n\t};\n}\n\nexport async function resolveUpstreamServers(\n\tprops: ResolveUpstreamServersProps,\n): Promise<readonly NormalizedUpstreamMcpServer[]> {\n\treturn await Promise.all(\n\t\tmcpConfigToResolvedProviders(props.config).map(async (provider) =>\n\t\t\tresolveUpstreamServer(provider, props.resolveSecret),\n\t\t),\n\t);\n}\n","import type { JsonValue } from '../json-schema.js';\n\nfunction isUnknownRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function isPortalCoreJsonValue(\n\tvalue: unknown,\n\tactiveObjects = new Set<object>(),\n): value is JsonValue {\n\tif (\n\t\tvalue === null ||\n\t\ttypeof value === 'string' ||\n\t\ttypeof value === 'number' ||\n\t\ttypeof value === 'boolean'\n\t) {\n\t\treturn true;\n\t}\n\tif (typeof value !== 'object') {\n\t\treturn false;\n\t}\n\tif (activeObjects.has(value)) {\n\t\treturn false;\n\t}\n\tactiveObjects.add(value);\n\tconst isValid =\n\t\t(Array.isArray(value) && value.every((entry) => isPortalCoreJsonValue(entry, activeObjects))) ||\n\t\t(isUnknownRecord(value) &&\n\t\t\tObject.values(value).every((entry) => isPortalCoreJsonValue(entry, activeObjects)));\n\tactiveObjects.delete(value);\n\treturn isValid;\n}\n","import type { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { z } from 'zod';\n\nimport { jsonObjectSchema, type JsonValue } from '../json-schema.js';\nimport {\n\tcreatePortalAgentIdentity,\n\tresolvePortalAccessPolicy,\n\ttype PortalAccessPolicyConfig,\n\ttype PortalAgentIdentity,\n\ttype PortalAgentScopeSource,\n} from '../portal-access-policy.js';\nimport {\n\tcreatePortalSessionManager,\n\ttype PortalSessionManager,\n\ttype PortalSessionRuntime,\n} from '../portal-session.js';\nimport type { SkillGraphInput } from '../tool-graph.js';\nimport { isPortalCoreJsonValue } from './portal-core-validation.js';\nimport {\n\tcreatePortalToolHandlers,\n\tportalToolInputSchemas,\n\tpreparePortalApprovalCallDigests,\n\ttype PortalApprovalCallDigestMap,\n\ttype PortalApprovalCall,\n\ttype PortalBatchDiagnostic,\n\ttype PortalBatchResult,\n\ttype PortalToolResult,\n\ttype PortalToolRuntime,\n} from './portal-tools.js';\n\nexport type PortalAgentScope = PortalAgentIdentity;\n\nexport type PortalCoreToolName =\n\t| 'mcp_portal_list'\n\t| 'mcp_portal_search'\n\t| 'mcp_portal_describe'\n\t| 'mcp_portal_call';\n\nexport interface PortalAuditEvent {\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 PortalCoreResult {\n\treadonly auditEvents?: readonly PortalAuditEvent[];\n\treadonly content: readonly PortalCoreContentBlock[];\n\treadonly items: readonly PortalCoreItemResult[];\n\treadonly structuredContent?: unknown;\n}\n\nexport type PortalCoreItemResult =\n\t| {\n\t\t\treadonly content: readonly PortalCoreContentBlock[];\n\t\t\treadonly requestId: string;\n\t\t\treadonly status: 'success';\n\t\t\treadonly structuredContent?: unknown;\n\t }\n\t| {\n\t\t\treadonly error: PortalCoreItemError;\n\t\t\treadonly requestId: string;\n\t\t\treadonly status: 'failed';\n\t };\n\nexport interface PortalCoreItemError {\n\treadonly code: string;\n\treadonly issues?: readonly PortalCoreValidationIssue[];\n\treadonly issueCount?: number;\n\treadonly issuesTruncated?: number;\n\treadonly message: string;\n\treadonly namespace?: string;\n\treadonly toolName?: string;\n\treadonly upstream?: unknown;\n}\n\nexport interface PortalCoreValidationIssue {\n\treadonly code: string;\n\treadonly expected?: string;\n\treadonly keys?: readonly string[];\n\treadonly message: string;\n\treadonly path: readonly (number | string)[];\n\treadonly received?: {\n\t\treadonly preview?: string;\n\t\treadonly type: string;\n\t};\n\treadonly values?: readonly JsonValue[];\n}\n\nexport type PortalCoreContentBlock =\n\t| { readonly text: string; readonly type: 'text' }\n\t| { readonly type: 'json'; readonly value: unknown };\n\nexport type PortalCoreEvent =\n\t| {\n\t\t\treadonly kind: 'started';\n\t\t\treadonly toolName: PortalCoreToolName;\n\t }\n\t| {\n\t\t\treadonly kind: 'item_started';\n\t\t\treadonly namespace?: string;\n\t\t\treadonly requestId: string;\n\t\t\treadonly toolName?: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'progress';\n\t\t\treadonly message?: string;\n\t\t\treadonly progress?: number;\n\t\t\treadonly requestId?: string;\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\t\treadonly requestId?: string;\n\t }\n\t| {\n\t\t\treadonly content: PortalCoreContentBlock;\n\t\t\treadonly kind: 'partial_content';\n\t\t\treadonly requestId?: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'item_completed';\n\t\t\treadonly requestId: string;\n\t\t\treadonly result: Extract<PortalCoreItemResult, { readonly status: 'success' }>;\n\t }\n\t| {\n\t\t\treadonly error: PortalCoreItemError;\n\t\t\treadonly kind: 'item_failed';\n\t\t\treadonly requestId: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'completed';\n\t\t\treadonly result: PortalCoreResult;\n\t }\n\t| {\n\t\t\treadonly error: unknown;\n\t\t\treadonly kind: 'failed';\n\t };\n\nexport interface PortalCoreStreamCall {\n\treadonly input: unknown;\n\treadonly scope: PortalAgentScope;\n\treadonly signal?: AbortSignal;\n\treadonly toolName: PortalCoreToolName;\n}\n\nconst maxQueuedPortalCoreEvents = 1_024;\nconst maxPortalCoreEventBytes = 256 * 1_024;\nconst maxAgentFacingValidationIssues = 5;\n\nexport interface PortalCoreCollectOptions {\n\treadonly onEvent?: (event: PortalCoreEvent) => Promise<void> | void;\n}\n\nexport interface PortalCoreRuntime extends PortalSessionRuntime {\n\treadonly callUpstreamTool: PortalToolRuntime['callUpstreamTool'];\n}\n\nexport type PortalApprovalEvaluator = NonNullable<PortalToolRuntime['approval']>;\n\ninterface CreatePortalCoreBaseProps {\n\treadonly accessPolicy: PortalAccessPolicyConfig;\n\treadonly catalogTtlMs: number;\n\treadonly runtime: PortalCoreRuntime;\n\treadonly skills?: readonly SkillGraphInput[];\n\treadonly upstreamNamespaces: readonly string[];\n}\n\nexport interface CreatePortalCoreProps extends CreatePortalCoreBaseProps {\n\treadonly approval: PortalApprovalEvaluator;\n}\n\nexport interface PortalCore {\n\treadonly approval: {\n\t\treadonly evaluateCalls: (\n\t\t\tcalls: readonly PortalApprovalCall[],\n\t\t\tscope: PortalAgentScope,\n\t\t\tapprovalToken: string | undefined,\n\t\t) => ReturnType<PortalApprovalEvaluator>;\n\t\treadonly prepareCallDigests: (props: {\n\t\t\treadonly input: unknown;\n\t\t\treadonly scope: PortalAgentScope;\n\t\t}) => Promise<PortalApprovalCallDigestMap | null>;\n\t};\n\treadonly callStream: (call: PortalCoreStreamCall) => AsyncIterable<PortalCoreEvent>;\n\treadonly close: () => Promise<void>;\n\treadonly collectPortalCoreResult: typeof collectPortalCoreResult;\n\treadonly createAgentScope: (input: {\n\t\treadonly agentId: string;\n\t\treadonly agentScopeId: string;\n\t\treadonly authSubject?: string;\n\t\treadonly sessionId?: string;\n\t\treadonly sessionKey?: string;\n\t\treadonly source: PortalAgentScopeSource;\n\t}) => PortalAgentScope;\n\treadonly describeTools: (scope: PortalAgentScope) => readonly PortalCoreToolDescriptor[];\n\treadonly invalidateAgentScope: (agentScopeId: string) => Promise<void>;\n\treadonly invalidateSession: (scope: PortalAgentScope) => Promise<void>;\n\treadonly upstreamNamespaces: readonly string[];\n}\n\nexport interface PortalCoreToolDescriptor {\n\treadonly description: string;\n\treadonly inputSchema: Tool['inputSchema'];\n\treadonly name: PortalCoreToolName;\n}\n\nconst portalCallRequestSchema = z\n\t.object({\n\t\targuments: jsonObjectSchema,\n\t\tid: z.string().min(1),\n\t\tnamespace: z.string().min(1),\n\t\ttoolName: z.string().min(1),\n\t})\n\t.strict();\nconst portalCallInputSchema = z\n\t.object({\n\t\tcalls: z.array(portalCallRequestSchema).min(1),\n\t\tportalApprovalToken: z.string().min(1).optional(),\n\t})\n\t.strict();\n\nfunction diagnosticsToAuditEvents(\n\tdiagnostics: readonly PortalBatchDiagnostic[],\n): readonly PortalAuditEvent[] {\n\treturn diagnostics.map((diagnostic) => ({ ...diagnostic }));\n}\n\nfunction isUnknownRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction errorRecordFromUnknown(error: unknown): Record<string, unknown> {\n\treturn isUnknownRecord(error) ? error : {};\n}\n\nfunction isStringArray(value: unknown): value is readonly string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === 'string');\n}\n\nfunction isJsonValueArray(value: unknown): value is readonly JsonValue[] {\n\treturn Array.isArray(value) && value.every((entry) => isPortalCoreJsonValue(entry));\n}\n\nfunction isValidationIssueReceived(\n\tvalue: unknown,\n): value is { readonly preview?: string; readonly type: string } {\n\treturn (\n\t\tisUnknownRecord(value) &&\n\t\ttypeof value.type === 'string' &&\n\t\t(value.preview === undefined || typeof value.preview === 'string')\n\t);\n}\n\nfunction isValidationIssue(value: unknown): value is PortalCoreValidationIssue {\n\treturn (\n\t\tisUnknownRecord(value) &&\n\t\ttypeof value.code === 'string' &&\n\t\ttypeof value.message === 'string' &&\n\t\tArray.isArray(value.path) &&\n\t\tvalue.path.every((pathPart) => typeof pathPart === 'string' || typeof pathPart === 'number') &&\n\t\t(value.expected === undefined || typeof value.expected === 'string') &&\n\t\t(value.keys === undefined || isStringArray(value.keys)) &&\n\t\t(value.received === undefined || isValidationIssueReceived(value.received)) &&\n\t\t(value.values === undefined || isJsonValueArray(value.values))\n\t);\n}\n\nfunction validationIssuesFromUnknown(\n\terror: unknown,\n): readonly PortalCoreValidationIssue[] | undefined {\n\tconst issues = errorRecordFromUnknown(error).issues;\n\tif (!Array.isArray(issues)) {\n\t\treturn undefined;\n\t}\n\tconst validationIssues = issues.filter((issue): issue is PortalCoreValidationIssue =>\n\t\tisValidationIssue(issue),\n\t);\n\treturn validationIssues.length > 0 ? validationIssues : undefined;\n}\n\nfunction validationIssuePathLabel(path: readonly (number | string)[]): string {\n\treturn path.length === 0 ? '(root)' : path.map((pathPart) => String(pathPart)).join('.');\n}\n\nfunction formattedJsonValue(value: JsonValue): string {\n\tconst serialized = JSON.stringify(value);\n\treturn serialized ?? '[unserializable-json-value]';\n}\n\nfunction receivedValueLabel(received: PortalCoreValidationIssue['received']): string | undefined {\n\tif (received === undefined) {\n\t\treturn undefined;\n\t}\n\tif (received.preview === undefined) {\n\t\treturn received.type;\n\t}\n\tconst preview = received.type === 'string' ? JSON.stringify(received.preview) : received.preview;\n\treturn `${received.type} ${preview}`;\n}\n\nfunction validationIssueSummary(issue: PortalCoreValidationIssue): string {\n\tconst details = [\n\t\tissue.expected === undefined ? undefined : `expected ${issue.expected}`,\n\t\tissue.values === undefined\n\t\t\t? undefined\n\t\t\t: `allowed values ${issue.values.map((value) => formattedJsonValue(value)).join(', ')}`,\n\t\tissue.keys === undefined ? undefined : `unrecognized keys ${issue.keys.join(', ')}`,\n\t\treceivedValueLabel(issue.received) === undefined\n\t\t\t? undefined\n\t\t\t: `received ${receivedValueLabel(issue.received)}`,\n\t\tissue.message,\n\t].filter((detail): detail is string => detail !== undefined);\n\treturn `${validationIssuePathLabel(issue.path)}: ${details.join('; ')}`;\n}\n\nfunction agentFacingValidationIssues(\n\tissues: readonly PortalCoreValidationIssue[],\n): readonly PortalCoreValidationIssue[] {\n\treturn issues.slice(0, maxAgentFacingValidationIssues);\n}\n\nfunction messageFromValidationIssues(issues: readonly PortalCoreValidationIssue[]): string {\n\tconst shownIssues = agentFacingValidationIssues(issues);\n\tconst truncatedIssues = issues.length - shownIssues.length;\n\tconst suffix =\n\t\ttruncatedIssues > 0\n\t\t\t? ` | ${String(truncatedIssues)} more validation issue(s) omitted; call describe for the exact schema.`\n\t\t\t: '';\n\treturn `Input validation failed: ${shownIssues\n\t\t.map((issue) => validationIssueSummary(issue))\n\t\t.join(' | ')}${suffix}`;\n}\n\nfunction messageFromUnknown(error: unknown): string {\n\tif (error instanceof Error) {\n\t\treturn error.message;\n\t}\n\tconst validationIssues = validationIssuesFromUnknown(error);\n\tif (validationIssues !== undefined) {\n\t\treturn messageFromValidationIssues(validationIssues);\n\t}\n\tconst record = errorRecordFromUnknown(error);\n\tconst message = record.message;\n\treturn typeof message === 'string' ? message : String(error);\n}\n\nfunction errorFromAbortSignal(signal: AbortSignal): Error {\n\tconst reason: unknown = signal.reason;\n\treturn reason instanceof Error ? reason : new Error('MCP Portal core stream aborted.');\n}\n\nfunction throwIfAborted(signal: AbortSignal | undefined): void {\n\tif (signal?.aborted) {\n\t\tthrow errorFromAbortSignal(signal);\n\t}\n}\n\nfunction assertPortalCoreEventSize(event: PortalCoreEvent): void {\n\tconst serialized = JSON.stringify(event);\n\tif (serialized === undefined) {\n\t\treturn;\n\t}\n\tconst byteLength = Buffer.byteLength(serialized, 'utf8');\n\tif (byteLength > maxPortalCoreEventBytes) {\n\t\tthrow new Error(\n\t\t\t`MCP Portal core event exceeded ${String(maxPortalCoreEventBytes)} bytes (${String(byteLength)} bytes).`,\n\t\t);\n\t}\n}\n\nfunction waitForQueuedCoreEvent(props: {\n\treadonly setNotifyQueuedEvent: (notify: (() => void) | undefined) => void;\n\treadonly signal?: AbortSignal;\n}): Promise<void> {\n\tif (props.signal === undefined) {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tprops.setNotifyQueuedEvent(resolve);\n\t\t});\n\t}\n\tconst signal = props.signal;\n\treturn new Promise<void>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst settle = (complete: () => void): void => {\n\t\t\tif (settled) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettled = true;\n\t\t\tsignal.removeEventListener('abort', onAbort);\n\t\t\tprops.setNotifyQueuedEvent(undefined);\n\t\t\tcomplete();\n\t\t};\n\t\tconst onNotify = (): void => {\n\t\t\tsettle(resolve);\n\t\t};\n\t\tconst onAbort = (): void => {\n\t\t\tsettle(() => reject(errorFromAbortSignal(signal)));\n\t\t};\n\t\tprops.setNotifyQueuedEvent(onNotify);\n\t\tsignal.addEventListener('abort', onAbort, { once: true });\n\t\tif (signal.aborted) {\n\t\t\tonAbort();\n\t\t}\n\t});\n}\n\nfunction itemErrorFromPortalResult(result: PortalToolResult): PortalCoreItemError {\n\tif (result.ok) {\n\t\tthrow new Error('Cannot convert successful portal result into an item error.');\n\t}\n\tconst errorRecord = errorRecordFromUnknown(result.error);\n\tconst kind = errorRecord.kind;\n\tconst namespace = errorRecord.namespace;\n\tconst toolName = errorRecord.toolName;\n\tconst upstream = errorRecord.upstream;\n\tconst issues = validationIssuesFromUnknown(result.error);\n\tconst shownIssues = issues === undefined ? undefined : agentFacingValidationIssues(issues);\n\tconst issuesTruncated =\n\t\tissues === undefined || shownIssues === undefined\n\t\t\t? undefined\n\t\t\t: issues.length - shownIssues.length;\n\n\treturn {\n\t\tcode: typeof kind === 'string' ? kind : 'portal_item_failed',\n\t\tmessage: messageFromUnknown(result.error),\n\t\t...(issues === undefined || shownIssues === undefined\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tissueCount: issues.length,\n\t\t\t\t\tissues: shownIssues,\n\t\t\t\t\t...(issuesTruncated === undefined || issuesTruncated <= 0 ? {} : { issuesTruncated }),\n\t\t\t\t}),\n\t\t...(typeof namespace === 'string' ? { namespace } : {}),\n\t\t...(typeof toolName === 'string' ? { toolName } : {}),\n\t\t...(upstream === undefined ? {} : { upstream }),\n\t};\n}\n\nfunction itemResultFromPortalToolResult(\n\trequestId: string,\n\tresult: PortalToolResult,\n): PortalCoreItemResult {\n\tif (!result.ok) {\n\t\treturn {\n\t\t\terror: itemErrorFromPortalResult(result),\n\t\t\trequestId,\n\t\t\tstatus: 'failed',\n\t\t};\n\t}\n\n\treturn {\n\t\tcontent: [{ type: 'json', value: result.output }],\n\t\trequestId,\n\t\tstatus: 'success',\n\t\tstructuredContent: result.output,\n\t};\n}\n\nfunction scalarBatchResultToCoreResult(batchResult: PortalBatchResult): PortalCoreResult {\n\treturn {\n\t\tauditEvents: diagnosticsToAuditEvents(batchResult.diagnostics),\n\t\tcontent: [{ type: 'json', value: batchResult }],\n\t\titems: [],\n\t\tstructuredContent: batchResult,\n\t};\n}\n\nfunction batchItemsToCoreResult(props: {\n\treadonly diagnostics: readonly PortalBatchDiagnostic[];\n\treadonly items: readonly PortalCoreItemResult[];\n}): PortalCoreResult {\n\treturn {\n\t\tauditEvents: diagnosticsToAuditEvents(props.diagnostics),\n\t\tcontent: [],\n\t\titems: props.items,\n\t};\n}\n\nfunction namespaceDescription(namespaces: readonly string[]): string {\n\treturn namespaces.length === 0\n\t\t? 'No upstream MCP namespaces are authorized for this agent scope.'\n\t\t: `Allowed namespaces for this agent: ${namespaces.join(', ')}.`;\n}\n\nfunction cloneJsonObject<TValue>(value: TValue): TValue {\n\treturn structuredClone(value);\n}\n\nfunction withListNamespaceSchemaDescription(\n\tinputSchema: Tool['inputSchema'],\n\tnamespaces: readonly string[],\n): Tool['inputSchema'] {\n\tconst clonedSchema = cloneJsonObject(inputSchema);\n\tconst requests = isUnknownRecord(clonedSchema.properties)\n\t\t? clonedSchema.properties.requests\n\t\t: undefined;\n\tconst requestItems = isUnknownRecord(requests) ? requests.items : undefined;\n\tconst requestProperties = isUnknownRecord(requestItems) ? requestItems.properties : undefined;\n\tconst namespaceProperty = isUnknownRecord(requestProperties)\n\t\t? requestProperties.namespaces\n\t\t: undefined;\n\tif (isUnknownRecord(namespaceProperty)) {\n\t\tnamespaceProperty.description =\n\t\t\tnamespaces.length === 0\n\t\t\t\t? 'Optional namespace filter. No upstream MCP namespaces are authorized for this agent. Omit to list all currently discovered authorized namespaces.'\n\t\t\t\t: `Optional namespace filter. Allowed namespaces for this agent: ${namespaces.join(', ')}. Omit to list all currently discovered authorized namespaces.`;\n\t}\n\treturn clonedSchema;\n}\n\nexport function listPortalCoreToolDescriptors(\n\tnamespaces: readonly string[] = [],\n): readonly PortalCoreToolDescriptor[] {\n\tconst scopeDescription = namespaceDescription(namespaces);\n\treturn [\n\t\t{\n\t\t\tdescription: `List authorized MCP namespaces and compact tool summaries. ${scopeDescription}`,\n\t\t\tinputSchema: withListNamespaceSchemaDescription(\n\t\t\t\tportalToolInputSchemas.mcp_portal_list,\n\t\t\t\tnamespaces,\n\t\t\t),\n\t\t\tname: 'mcp_portal_list',\n\t\t},\n\t\t{\n\t\t\tdescription: 'Search the caller scoped MCP Portal index.',\n\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_search,\n\t\t\tname: 'mcp_portal_search',\n\t\t},\n\t\t{\n\t\t\tdescription: 'Describe exact MCP tool schemas and optional TypeScript/Zod helpers.',\n\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_describe,\n\t\t\tname: 'mcp_portal_describe',\n\t\t},\n\t\t{\n\t\t\tdescription: 'Validate and call an authorized upstream MCP tool by namespace and toolName.',\n\t\t\tinputSchema: portalToolInputSchemas.mcp_portal_call,\n\t\t\tname: 'mcp_portal_call',\n\t\t},\n\t];\n}\n\nexport async function collectPortalCoreResult(\n\tevents: AsyncIterable<PortalCoreEvent>,\n\toptions: PortalCoreCollectOptions = {},\n): Promise<PortalCoreResult> {\n\tlet result: PortalCoreResult | undefined;\n\tfor await (const event of events) {\n\t\tawait options.onEvent?.(event);\n\t\tif (event.kind === 'completed') {\n\t\t\tresult = event.result;\n\t\t}\n\t\tif (event.kind === 'failed') {\n\t\t\tthrow event.error;\n\t\t}\n\t}\n\tif (result === undefined) {\n\t\tthrow new Error('MCP Portal core stream ended without a completed event.');\n\t}\n\treturn result;\n}\n\nasync function* scalarToolStream(props: {\n\treadonly input: unknown;\n\treadonly scope: PortalAgentScope;\n\treadonly signal?: AbortSignal;\n\treadonly sessionManager: PortalSessionManager;\n\treadonly toolName: Exclude<PortalCoreToolName, 'mcp_portal_call'>;\n\treadonly toolRuntime: PortalToolRuntime;\n}): AsyncIterable<PortalCoreEvent> {\n\tconst handlers = createPortalToolHandlers(props.toolRuntime);\n\tconst handler =\n\t\tprops.toolName === 'mcp_portal_list'\n\t\t\t? handlers.list\n\t\t\t: props.toolName === 'mcp_portal_search'\n\t\t\t\t? handlers.search\n\t\t\t\t: handlers.describe;\n\tthrowIfAborted(props.signal);\n\tconst batchResult = await handler({ identity: props.scope, input: props.input });\n\tthrowIfAborted(props.signal);\n\tyield { kind: 'completed', result: scalarBatchResultToCoreResult(batchResult) };\n}\n\nasync function* callToolStream(props: {\n\treadonly input: unknown;\n\treadonly scope: PortalAgentScope;\n\treadonly signal?: AbortSignal;\n\treadonly toolRuntime: PortalToolRuntime;\n}): AsyncIterable<PortalCoreEvent> {\n\tconst parsedInput = portalCallInputSchema.safeParse(props.input);\n\tconst queuedEvents: PortalCoreEvent[] = [];\n\tlet notifyQueuedEvent: (() => void) | undefined;\n\tlet executionDone = false;\n\tconst pushEvent = (event: PortalCoreEvent): void => {\n\t\tassertPortalCoreEventSize(event);\n\t\tif (queuedEvents.length >= maxQueuedPortalCoreEvents) {\n\t\t\tthrow new Error(`MCP Portal core event queue exceeded ${maxQueuedPortalCoreEvents} events.`);\n\t\t}\n\t\tqueuedEvents.push(event);\n\t\tnotifyQueuedEvent?.();\n\t\tnotifyQueuedEvent = undefined;\n\t};\n\tconst streamingToolRuntime: PortalToolRuntime = {\n\t\t...props.toolRuntime,\n\t\tcallUpstreamTool: async (call) => {\n\t\t\tthrowIfAborted(props.signal);\n\t\t\tpushEvent({\n\t\t\t\tkind: 'item_started',\n\t\t\t\tnamespace: call.namespace,\n\t\t\t\trequestId: call.requestId,\n\t\t\t\ttoolName: call.toolName,\n\t\t\t});\n\t\t\tpushEvent({\n\t\t\t\tkind: 'progress',\n\t\t\t\tmessage: `Calling upstream MCP tool ${call.namespace}.${call.toolName}.`,\n\t\t\t\trequestId: call.requestId,\n\t\t\t});\n\t\t\treturn await props.toolRuntime.callUpstreamTool({\n\t\t\t\t...call,\n\t\t\t\t...(props.signal !== undefined ? { signal: props.signal } : {}),\n\t\t\t\tonEvent: (event) => {\n\t\t\t\t\tif (event.kind === 'progress') {\n\t\t\t\t\t\tpushEvent({\n\t\t\t\t\t\t\tkind: 'progress',\n\t\t\t\t\t\t\t...(event.message !== undefined ? { message: event.message } : {}),\n\t\t\t\t\t\t\t...(event.progress !== undefined ? { progress: event.progress } : {}),\n\t\t\t\t\t\t\trequestId: call.requestId,\n\t\t\t\t\t\t\t...(event.total !== undefined ? { total: event.total } : {}),\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (event.kind === 'partial_content') {\n\t\t\t\t\t\tpushEvent({\n\t\t\t\t\t\t\tcontent: event.content,\n\t\t\t\t\t\t\tkind: 'partial_content',\n\t\t\t\t\t\t\trequestId: call.requestId,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tpushEvent({\n\t\t\t\t\t\tkind: 'upstream_notification',\n\t\t\t\t\t\tmethod: event.method,\n\t\t\t\t\t\tparams: event.params,\n\t\t\t\t\t\trequestId: call.requestId,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t};\n\tconst handlers = createPortalToolHandlers(streamingToolRuntime);\n\tif (!parsedInput.success) {\n\t\tconst batchResult = await handlers.call({ identity: props.scope, input: props.input });\n\t\tyield { kind: 'completed', result: scalarBatchResultToCoreResult(batchResult) };\n\t\treturn;\n\t}\n\n\tconst itemResults: PortalCoreItemResult[] = [];\n\tconst batchResultPromise = handlers\n\t\t.call({\n\t\t\tidentity: props.scope,\n\t\t\tinput: props.input,\n\t\t})\n\t\t.finally(() => {\n\t\t\texecutionDone = true;\n\t\t\tnotifyQueuedEvent?.();\n\t\t\tnotifyQueuedEvent = undefined;\n\t\t});\n\tconst hasPendingExecutionEvents = (): boolean => !executionDone || queuedEvents.length > 0;\n\twhile (hasPendingExecutionEvents()) {\n\t\tconst event = queuedEvents.shift();\n\t\tif (event !== undefined) {\n\t\t\tyield event;\n\t\t\tcontinue;\n\t\t}\n\t\tthrowIfAborted(props.signal);\n\t\t// Streaming consumes events as they arrive; there is no parallel work to collect here.\n\t\t// eslint-disable-next-line no-await-in-loop\n\t\tawait waitForQueuedCoreEvent({\n\t\t\tsetNotifyQueuedEvent: (notify) => {\n\t\t\t\tnotifyQueuedEvent = notify;\n\t\t\t},\n\t\t\t...(props.signal !== undefined ? { signal: props.signal } : {}),\n\t\t});\n\t}\n\tconst batchResult = await batchResultPromise;\n\tthrowIfAborted(props.signal);\n\tif (batchResult.errors.length > 0) {\n\t\tyield { kind: 'completed', result: scalarBatchResultToCoreResult(batchResult) };\n\t\treturn;\n\t}\n\tfor (const request of parsedInput.data.calls) {\n\t\tconst portalResult = batchResult.results[request.id];\n\t\tconst itemResult =\n\t\t\tportalResult === undefined\n\t\t\t\t? ({\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: 'portal_item_missing',\n\t\t\t\t\t\t\tmessage: `MCP Portal did not return a result for request \"${request.id}\".`,\n\t\t\t\t\t\t\tnamespace: request.namespace,\n\t\t\t\t\t\t\ttoolName: request.toolName,\n\t\t\t\t\t\t},\n\t\t\t\t\t\trequestId: request.id,\n\t\t\t\t\t\tstatus: 'failed',\n\t\t\t\t\t} satisfies PortalCoreItemResult)\n\t\t\t\t: itemResultFromPortalToolResult(request.id, portalResult);\n\t\titemResults.push(itemResult);\n\t\tif (itemResult.status === 'success') {\n\t\t\tyield { kind: 'item_completed', requestId: request.id, result: itemResult };\n\t\t} else {\n\t\t\tyield { error: itemResult.error, kind: 'item_failed', requestId: request.id };\n\t\t}\n\t}\n\n\tyield {\n\t\tkind: 'completed',\n\t\tresult: batchItemsToCoreResult({ diagnostics: batchResult.diagnostics, items: itemResults }),\n\t};\n}\n\nexport function createPortalCore(props: CreatePortalCoreProps): PortalCore {\n\tconst sessionManager = createPortalSessionManager({\n\t\taccessPolicy: props.accessPolicy,\n\t\tcatalogTtlMs: props.catalogTtlMs,\n\t\truntime: props.runtime,\n\t\t...(props.skills !== undefined ? { skills: props.skills } : {}),\n\t\tupstreamNamespaces: props.upstreamNamespaces,\n\t});\n\tconst createdAgentScopeIds = new Set<string>();\n\tconst approval = props.approval;\n\tconst toolRuntime: PortalToolRuntime = {\n\t\tapproval,\n\t\tcallUpstreamTool: props.runtime.callUpstreamTool,\n\t\tgetSession: sessionManager.getSession,\n\t};\n\n\tasync function* callStream(call: PortalCoreStreamCall): AsyncIterable<PortalCoreEvent> {\n\t\ttry {\n\t\t\tthrowIfAborted(call.signal);\n\t\t\tyield { kind: 'started', toolName: call.toolName };\n\t\t\tthrowIfAborted(call.signal);\n\t\t\tif (call.toolName === 'mcp_portal_call') {\n\t\t\t\tyield* callToolStream({\n\t\t\t\t\tinput: call.input,\n\t\t\t\t\tscope: call.scope,\n\t\t\t\t\t...(call.signal !== undefined ? { signal: call.signal } : {}),\n\t\t\t\t\ttoolRuntime,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tyield* scalarToolStream({\n\t\t\t\tinput: call.input,\n\t\t\t\tscope: call.scope,\n\t\t\t\t...(call.signal !== undefined ? { signal: call.signal } : {}),\n\t\t\t\tsessionManager,\n\t\t\t\ttoolName: call.toolName,\n\t\t\t\ttoolRuntime,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tyield { error, kind: 'failed' };\n\t\t}\n\t}\n\n\treturn {\n\t\tapproval: {\n\t\t\tevaluateCalls: (calls, scope, approvalToken) => approval(calls, scope, approvalToken),\n\t\t\tprepareCallDigests: async ({ input, scope }) => {\n\t\t\t\tconst session = await sessionManager.getSession(scope);\n\t\t\t\treturn preparePortalApprovalCallDigests(session, input);\n\t\t\t},\n\t\t},\n\t\tcallStream,\n\t\tclose: async () => {\n\t\t\tawait Promise.all(\n\t\t\t\t[...createdAgentScopeIds].map((agentScopeId) =>\n\t\t\t\t\tsessionManager.invalidateAgentScope(agentScopeId),\n\t\t\t\t),\n\t\t\t);\n\t\t},\n\t\tcollectPortalCoreResult,\n\t\tcreateAgentScope: (input) => {\n\t\t\tconst scope = createPortalAgentIdentity(input);\n\t\t\tcreatedAgentScopeIds.add(scope.agentScopeId);\n\t\t\treturn scope;\n\t\t},\n\t\tdescribeTools: (scope) => {\n\t\t\tconst policy = resolvePortalAccessPolicy({\n\t\t\t\tconfig: props.accessPolicy,\n\t\t\t\tidentity: scope,\n\t\t\t\tupstreamNamespaces: props.upstreamNamespaces,\n\t\t\t});\n\t\t\treturn listPortalCoreToolDescriptors(policy.allowedNamespaces);\n\t\t},\n\t\tinvalidateAgentScope: async (agentScopeId) => {\n\t\t\tcreatedAgentScopeIds.delete(agentScopeId);\n\t\t\tawait sessionManager.invalidateAgentScope(agentScopeId);\n\t\t},\n\t\tinvalidateSession: async (scope) => {\n\t\t\tawait sessionManager.invalidateSession(scope);\n\t\t},\n\t\tupstreamNamespaces: props.upstreamNamespaces,\n\t};\n}\n"],"mappings":"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"}
@@ -1,7 +1,79 @@
1
- import { l as jsonObjectSchema, n as decodeToolRef, t as buildZodValidatorFromJsonSchema } from "./zod-schema-loader-yNekKNpm.js";
2
- import { h as createToolSummary, m as upstreamMcpFailureDetailsFromUnknown, v as portalAgentScopeKey } from "./upstream-response-middleware-Cd1MxA6A.js";
3
- import { t as generateTypescriptCatalogArtifact } from "./typescript-artifact-BVLt3Ifd.js";
1
+ import { l as jsonObjectSchema, n as decodeToolRef, t as buildZodValidatorFromJsonSchema } from "./zod-schema-loader-C3I-MnWq.js";
2
+ import { h as createToolSummary, m as upstreamMcpFailureDetailsFromUnknown, v as portalAgentScopeKey } from "./upstream-response-middleware-_dthoE1r.js";
3
+ import { r as verifyApprovalToken, t as hashCallArguments } from "./hmac-token-D3c9OUTE.js";
4
+ import { t as generateTypescriptCatalogArtifact } from "./typescript-artifact-EQH4tZ0C.js";
4
5
  import { z } from "zod";
6
+ import { mcpPortalCallPolicyDecision } from "@agent-vm/config-contracts";
7
+ //#region src/core/portal-approval-evaluator.ts
8
+ function approvalTokenCallDigests(calls) {
9
+ return calls.map((call) => ({
10
+ argumentsHash: hashCallArguments(call.arguments),
11
+ namespace: call.namespace,
12
+ toolName: call.toolName
13
+ }));
14
+ }
15
+ function callDecisionFromVerifierReason(reason) {
16
+ return {
17
+ kind: "approval_token_invalid",
18
+ reason
19
+ };
20
+ }
21
+ function createPortalPolicyApprovalEvaluator(props) {
22
+ return (calls, identity, token) => {
23
+ const agentId = typeof identity === "string" ? identity : identity.agentId;
24
+ const record = props.resolveRecord(agentId);
25
+ if (record === void 0) {
26
+ const decisionsByCallId = {};
27
+ for (const call of calls) decisionsByCallId[call.id] = callDecisionFromVerifierReason("unknown-agent");
28
+ return { decisionsByCallId };
29
+ }
30
+ const decisionsByCallId = {};
31
+ const callsRequiringApproval = [];
32
+ for (const call of calls) {
33
+ const policyDecision = mcpPortalCallPolicyDecision(record.profile, {
34
+ ...call.tool.annotations === void 0 ? {} : { annotations: call.tool.annotations },
35
+ namespace: call.namespace,
36
+ toolName: call.toolName
37
+ });
38
+ if (policyDecision.kind === "allow_without_approval") {
39
+ decisionsByCallId[call.id] = { kind: "allow" };
40
+ continue;
41
+ }
42
+ if (policyDecision.kind === "requires_approval") {
43
+ callsRequiringApproval.push(call);
44
+ continue;
45
+ }
46
+ decisionsByCallId[call.id] = { kind: "call_blocked" };
47
+ }
48
+ if (callsRequiringApproval.length === 0) return { decisionsByCallId };
49
+ if (record.hmacKey === void 0) {
50
+ for (const call of callsRequiringApproval) decisionsByCallId[call.id] = callDecisionFromVerifierReason("missing-hmac-key");
51
+ return { decisionsByCallId };
52
+ }
53
+ if (token === void 0) {
54
+ const missingTokenDecision = props.missingApprovalTokenDecision ?? { kind: "approval_token_missing" };
55
+ for (const call of callsRequiringApproval) decisionsByCallId[call.id] = missingTokenDecision;
56
+ return { decisionsByCallId };
57
+ }
58
+ const consumeTokenId = props.consumeTokenId;
59
+ const verification = verifyApprovalToken({
60
+ agentId,
61
+ calls: approvalTokenCallDigests(callsRequiringApproval),
62
+ ...consumeTokenId === void 0 ? {} : { consumeTokenId: (jti, expiresAtMs) => consumeTokenId(agentId, jti, expiresAtMs) },
63
+ key: record.hmacKey,
64
+ ...props.maxLifetimeMs === void 0 ? {} : { maxLifetimeMs: props.maxLifetimeMs },
65
+ nowMs: props.nowMs?.() ?? Date.now(),
66
+ token
67
+ });
68
+ if (!verification.ok) {
69
+ for (const call of callsRequiringApproval) decisionsByCallId[call.id] = callDecisionFromVerifierReason(verification.reason);
70
+ return { decisionsByCallId };
71
+ }
72
+ for (const call of callsRequiringApproval) decisionsByCallId[call.id] = { kind: "allow" };
73
+ return { decisionsByCallId };
74
+ };
75
+ }
76
+ //#endregion
5
77
  //#region src/core/portal-call-validation.ts
6
78
  function validatePortalToolArguments(tool, argumentsValue) {
7
79
  const validator = buildZodValidatorFromJsonSchema(tool.inputSchema);
@@ -114,6 +186,9 @@ const portalToolInputSchemas = {
114
186
  function messageFromError(error) {
115
187
  return error instanceof Error ? error.message : String(error);
116
188
  }
189
+ function approvalEvaluationForAllCalls(calls, decision) {
190
+ return { decisionsByCallId: Object.fromEntries(calls.map((call) => [call.id, decision])) };
191
+ }
117
192
  function invalidPortalInput(error) {
118
193
  return {
119
194
  diagnostics: [],
@@ -408,6 +483,21 @@ async function executePreparedPortalCall(call, identity, runtime) {
408
483
  function isPreparedPortalCall(value) {
409
484
  return "validatedArguments" in value;
410
485
  }
486
+ function preparePortalApprovalCallDigests(session, input) {
487
+ const parsedInput = callExecutionInputSchema.safeParse(input);
488
+ if (!parsedInput.success || duplicateIdResult(parsedInput.data.calls)) return null;
489
+ const preparedResults = parsedInput.data.calls.map((request) => preparePortalCall(session, request));
490
+ const digests = {};
491
+ for (const preparedResult of preparedResults) {
492
+ if (!isPreparedPortalCall(preparedResult)) continue;
493
+ digests[preparedResult.input.id] = {
494
+ argumentsHash: hashCallArguments(preparedResult.validatedArguments),
495
+ namespace: preparedResult.tool.namespace,
496
+ toolName: preparedResult.tool.toolName
497
+ };
498
+ }
499
+ return digests;
500
+ }
411
501
  async function addExecutableCallResults(props) {
412
502
  await Promise.all(props.preparedCalls.map(async (preparedCall) => {
413
503
  props.results[preparedCall.input.id] = await executePreparedPortalCall(preparedCall, props.identity, props.runtime);
@@ -429,7 +519,7 @@ function createPortalToolHandlers(runtime) {
429
519
  tool: executableCall.tool,
430
520
  toolName: executableCall.tool.toolName
431
521
  }));
432
- const approval = approvalCalls.length === 0 ? { kind: "allow" } : runtime.approval?.(approvalCalls, call.identity, parsedInput.data.portalApprovalToken) ?? { kind: "approval_configuration_missing" };
522
+ const approval = approvalCalls.length === 0 ? approvalEvaluationForAllCalls(approvalCalls, { kind: "allow" }) : runtime.approval?.(approvalCalls, call.identity, parsedInput.data.portalApprovalToken) ?? approvalEvaluationForAllCalls(approvalCalls, { kind: "approval_configuration_missing" });
433
523
  const results = {};
434
524
  const callsToExecute = [];
435
525
  for (const preparedResult of preparedResults) {
@@ -441,84 +531,85 @@ function createPortalToolHandlers(runtime) {
441
531
  }
442
532
  continue;
443
533
  }
444
- if (approval.kind === "approval_required") {
445
- results[preparedResult.input.id] = itemError({
446
- error: {
447
- kind: "approval_required",
448
- level: approval.level,
449
- message: "Operator approval is required before this batch can run.",
450
- namespace: preparedResult.tool.namespace,
451
- toolName: preparedResult.tool.toolName
452
- },
453
- input: {
454
- ...preparedResult.input,
455
- arguments: preparedResult.validatedArguments
456
- }
457
- });
458
- continue;
459
- }
460
- if (approval.kind === "approval_token_missing") {
461
- results[preparedResult.input.id] = itemError({
462
- error: {
463
- kind: "approval_token_missing",
464
- message: "An MCP Portal approval token is required before this batch can run.",
465
- namespace: preparedResult.tool.namespace,
466
- toolName: preparedResult.tool.toolName
467
- },
468
- input: {
469
- ...preparedResult.input,
470
- arguments: preparedResult.validatedArguments
471
- }
472
- });
473
- continue;
474
- }
475
- if (approval.kind === "approval_token_invalid") {
476
- results[preparedResult.input.id] = itemError({
477
- error: {
478
- kind: "approval_token_invalid",
479
- message: `MCP Portal approval token is invalid: ${approval.reason}.`,
480
- namespace: preparedResult.tool.namespace,
481
- reason: approval.reason,
482
- toolName: preparedResult.tool.toolName
483
- },
484
- input: {
485
- ...preparedResult.input,
486
- arguments: preparedResult.validatedArguments
487
- }
488
- });
489
- continue;
490
- }
491
- if (approval.kind === "call_blocked") {
492
- results[preparedResult.input.id] = itemError({
493
- error: {
494
- kind: "call_blocked",
495
- message: "MCP Portal policy does not allow this tool call.",
496
- namespace: preparedResult.tool.namespace,
497
- toolName: preparedResult.tool.toolName
498
- },
499
- input: {
500
- ...preparedResult.input,
501
- arguments: preparedResult.validatedArguments
502
- }
503
- });
504
- continue;
505
- }
506
- if (approval.kind === "approval_configuration_missing") {
507
- results[preparedResult.input.id] = itemError({
508
- error: {
509
- kind: "approval_configuration_missing",
510
- message: "MCP Portal approval evaluation is not configured.",
511
- namespace: preparedResult.tool.namespace,
512
- toolName: preparedResult.tool.toolName
513
- },
514
- input: {
515
- ...preparedResult.input,
516
- arguments: preparedResult.validatedArguments
517
- }
518
- });
519
- continue;
534
+ const approvalDecision = approval.decisionsByCallId[preparedResult.input.id] ?? { kind: "approval_configuration_missing" };
535
+ switch (approvalDecision.kind) {
536
+ case "allow":
537
+ callsToExecute.push(preparedResult);
538
+ continue;
539
+ case "approval_required":
540
+ results[preparedResult.input.id] = itemError({
541
+ error: {
542
+ kind: "approval_required",
543
+ level: approvalDecision.level,
544
+ message: "Operator approval is required before this MCP Portal call can run.",
545
+ namespace: preparedResult.tool.namespace,
546
+ toolName: preparedResult.tool.toolName
547
+ },
548
+ input: {
549
+ ...preparedResult.input,
550
+ arguments: preparedResult.validatedArguments
551
+ }
552
+ });
553
+ continue;
554
+ case "approval_token_missing":
555
+ results[preparedResult.input.id] = itemError({
556
+ error: {
557
+ kind: "approval_token_missing",
558
+ message: "An MCP Portal approval token is required before this MCP Portal call can run.",
559
+ namespace: preparedResult.tool.namespace,
560
+ toolName: preparedResult.tool.toolName
561
+ },
562
+ input: {
563
+ ...preparedResult.input,
564
+ arguments: preparedResult.validatedArguments
565
+ }
566
+ });
567
+ continue;
568
+ case "approval_token_invalid":
569
+ results[preparedResult.input.id] = itemError({
570
+ error: {
571
+ kind: "approval_token_invalid",
572
+ message: `MCP Portal approval token is invalid: ${approvalDecision.reason}.`,
573
+ namespace: preparedResult.tool.namespace,
574
+ reason: approvalDecision.reason,
575
+ toolName: preparedResult.tool.toolName
576
+ },
577
+ input: {
578
+ ...preparedResult.input,
579
+ arguments: preparedResult.validatedArguments
580
+ }
581
+ });
582
+ continue;
583
+ case "call_blocked":
584
+ results[preparedResult.input.id] = itemError({
585
+ error: {
586
+ kind: "call_blocked",
587
+ message: "MCP Portal policy does not allow this tool call.",
588
+ namespace: preparedResult.tool.namespace,
589
+ toolName: preparedResult.tool.toolName
590
+ },
591
+ input: {
592
+ ...preparedResult.input,
593
+ arguments: preparedResult.validatedArguments
594
+ }
595
+ });
596
+ continue;
597
+ case "approval_configuration_missing":
598
+ results[preparedResult.input.id] = itemError({
599
+ error: {
600
+ kind: "approval_configuration_missing",
601
+ message: "MCP Portal approval evaluation is not configured.",
602
+ namespace: preparedResult.tool.namespace,
603
+ toolName: preparedResult.tool.toolName
604
+ },
605
+ input: {
606
+ ...preparedResult.input,
607
+ arguments: preparedResult.validatedArguments
608
+ }
609
+ });
610
+ continue;
611
+ default: throw new Error(`Unhandled MCP Portal approval decision: ${JSON.stringify(approvalDecision)}`);
520
612
  }
521
- callsToExecute.push(preparedResult);
522
613
  }
523
614
  await addExecutableCallResults({
524
615
  identity: call.identity,
@@ -555,6 +646,6 @@ function createPortalToolHandlers(runtime) {
555
646
  };
556
647
  }
557
648
  //#endregion
558
- export { portalToolInputSchemas as n, validatePortalToolArguments as r, createPortalToolHandlers as t };
649
+ export { createPortalPolicyApprovalEvaluator as a, validatePortalToolArguments as i, portalToolInputSchemas as n, preparePortalApprovalCallDigests as r, createPortalToolHandlers as t };
559
650
 
560
- //# sourceMappingURL=portal-tools-Ct2GuFSc.js.map
651
+ //# sourceMappingURL=portal-tools-fFyF72Nl.js.map