@happyvertical/smrt-app-mcp 0.57.42 → 0.57.44

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/errors.d.ts CHANGED
@@ -21,4 +21,46 @@ export declare class McpAccessError extends Error {
21
21
  readonly metadata: McpAccessErrorMetadata;
22
22
  constructor(status: number, message: string, metadata?: McpAccessErrorMetadata);
23
23
  }
24
+ /** Stable code for a request naming a tool this server does not publish. */
25
+ export declare const MCP_TOOL_NOT_FOUND_CODE = "mcp_tool_not_found";
26
+ /** Stable code for a tool call that needs an authenticated principal. */
27
+ export declare const MCP_AUTHENTICATION_REQUIRED_CODE = "mcp_authentication_required";
28
+ /** Stable code for an unmapped handler failure; carries no internals. */
29
+ export declare const MCP_TOOL_EXECUTION_FAILED_CODE = "mcp_tool_execution_failed";
30
+ /** The generic message an unmapped handler failure returns. */
31
+ export declare const MCP_TOOL_EXECUTION_FAILED_MESSAGE = "Workflow execution failed.";
32
+ /** The agent-safe projection of a tool failure: a stable code and a message. */
33
+ export interface McpToolErrorInfo {
34
+ code: string;
35
+ message: string;
36
+ /** Optional JSON-safe, non-sensitive structured detail. */
37
+ details?: Record<string, unknown>;
38
+ }
39
+ /**
40
+ * Throw from a workflow tool handler to hand the calling agent a typed,
41
+ * authored failure. The `code` and `message` (and optional `details`) reach
42
+ * the agent verbatim, so they must be safe to disclose: never put records,
43
+ * credentials, stack traces, or other tenants' data in them. Any other
44
+ * thrown value stays behind the generic failure message.
45
+ */
46
+ export declare class McpToolError extends Error {
47
+ readonly code: string;
48
+ readonly details?: Record<string, unknown>;
49
+ constructor(code: string, message: string, details?: Record<string, unknown>);
50
+ }
51
+ /** Per-tool mapping of a handler failure to a safe code and message. */
52
+ export type McpToolErrorMapper = (error: unknown) => McpToolErrorInfo | null | undefined;
53
+ /**
54
+ * Resolve a thrown value to the information that may reach an agent. Never
55
+ * throws: a thrown {@link McpToolError} or a valid `mapError` result yields its
56
+ * safe code and message; anything else (including a throwing or malformed
57
+ * mapper) yields the generic failure.
58
+ */
59
+ export declare function safeMcpToolError(error: unknown, mapError?: McpToolErrorMapper): McpToolErrorInfo;
60
+ /**
61
+ * The authored (opt-in) safe error for a thrown value: a valid
62
+ * {@link McpToolError} or `mapError` result, else `undefined`. Only this form
63
+ * is typed on the MCP wire; an unmapped failure keeps the generic result.
64
+ */
65
+ export declare function authoredMcpToolError(error: unknown, mapError?: McpToolErrorMapper): McpToolErrorInfo | undefined;
24
66
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE,kFAAkF;AAClF,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAErC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAEvB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB;gBAFhC,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACN,QAAQ,GAAE,sBAA2B;CAKjD"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,2BAA2B,CAAC;AAEpE,kFAAkF;AAClF,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,KAAK;IAErC,QAAQ,CAAC,MAAM,EAAE,MAAM;IAEvB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB;gBAFhC,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACN,QAAQ,GAAE,sBAA2B;CAKjD;AAED,4EAA4E;AAC5E,eAAO,MAAM,uBAAuB,uBAAuB,CAAC;AAE5D,yEAAyE;AACzE,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAE9E,yEAAyE;AACzE,eAAO,MAAM,8BAA8B,8BAA8B,CAAC;AAE1E,+DAA+D;AAC/D,eAAO,MAAM,iCAAiC,+BAA+B,CAAC;AAE9E,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOpC;AAED,wEAAwE;AACxE,MAAM,MAAM,kBAAkB,GAAG,CAC/B,KAAK,EAAE,OAAO,KACX,gBAAgB,GAAG,IAAI,GAAG,SAAS,CAAC;AA0CzC;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,kBAAkB,GAC5B,gBAAgB,CAElB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,kBAAkB,GAC5B,gBAAgB,GAAG,SAAS,CAiB9B"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Host operation tools: one authored definition projected as an MCP workflow
3
+ * tool (server) and a WebMCP tool (browser) without drifting.
4
+ *
5
+ * Browser-safe and dependency-free (type-only imports): the `./host-operations`
6
+ * entry never pulls the MCP server, `jose` or jobs into a client bundle.
7
+ * `@happyvertical/smrt-web` owns `registerWebMcpBespokeTool`; the WebMCP spec
8
+ * built here is structurally identical to its `WebMcpBespokeToolSpec`, so
9
+ * there is no package dependency on it.
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ import type { ToolEffect, ToolJsonSchema } from '@happyvertical/smrt-core/generators/mcp';
14
+ import { type McpToolErrorInfo, type McpToolErrorMapper } from './errors.js';
15
+ import type { McpAppPrincipal } from './server.js';
16
+ import type { McpWorkflowToolDefinition } from './workflow-tools.js';
17
+ export { McpToolError, type McpToolErrorInfo, type McpToolErrorMapper, safeMcpToolError, } from './errors.js';
18
+ /** The part of an operation both projections share; safe for a browser bundle. */
19
+ export interface HostOperationDescriptor {
20
+ name: string;
21
+ description: string;
22
+ title?: string;
23
+ /** Required canonical classification; it drives both projections' hints. */
24
+ effect: ToolEffect;
25
+ idempotent: boolean;
26
+ openWorld: boolean;
27
+ inputSchema: ToolJsonSchema;
28
+ outputSchema: ToolJsonSchema;
29
+ }
30
+ /** Trusted context handed to a host operation handler. */
31
+ export interface HostOperationContext {
32
+ /** Tool arguments. Untrusted: validate; never read authority from them. */
33
+ arguments: Record<string, unknown>;
34
+ /** The server-authenticated caller. Tenant, role and user come only from here. */
35
+ principal: McpAppPrincipal | null;
36
+ }
37
+ /** A host operation: descriptor plus the server-side handler. */
38
+ export interface HostOperationToolDefinition<TOutput = unknown> extends HostOperationDescriptor {
39
+ handler(context: HostOperationContext): TOutput | Promise<TOutput>;
40
+ /** Map a handler failure to a safe code and message; see `McpToolError`. */
41
+ mapError?: McpToolErrorMapper;
42
+ }
43
+ /** Validate and freeze a host operation definition. */
44
+ export declare function defineHostOperationTool<TOutput>(definition: HostOperationToolDefinition<TOutput>): HostOperationToolDefinition<TOutput>;
45
+ /**
46
+ * Execute an operation and resolve a failure to its agent-safe form. Never
47
+ * throws; shared by the MCP projection's error path and by a host's own
48
+ * session endpoint so both surface identical codes.
49
+ */
50
+ export declare function executeHostOperation<TOutput>(definition: HostOperationToolDefinition<TOutput>, context: HostOperationContext): Promise<{
51
+ ok: true;
52
+ output: TOutput;
53
+ } | {
54
+ ok: false;
55
+ error: McpToolErrorInfo;
56
+ }>;
57
+ /** The definition `createMcpAppServer({ workflowTools })` accepts. */
58
+ export declare function toMcpWorkflowTool(definition: HostOperationToolDefinition): McpWorkflowToolDefinition;
59
+ /** The WebMCP `registerTool` shape (`WebMcpBespokeToolSpec`), structurally. */
60
+ export interface HostOperationWebMcpSpec {
61
+ name: string;
62
+ description: string;
63
+ inputSchema: Record<string, unknown>;
64
+ annotations: {
65
+ readOnlyHint: boolean;
66
+ destructiveHint: boolean;
67
+ idempotentHint: boolean;
68
+ openWorldHint: boolean;
69
+ };
70
+ execute: (args: Record<string, unknown>, options?: {
71
+ signal?: AbortSignal;
72
+ }) => Promise<string>;
73
+ }
74
+ /** Invokes a host operation with the signed-in user's own authority. */
75
+ export type HostOperationCaller = (operation: string, args: Record<string, unknown>, options?: {
76
+ signal?: AbortSignal;
77
+ }) => Promise<unknown>;
78
+ /**
79
+ * The WebMCP spec for an operation. Its `execute` calls `caller` (normally
80
+ * {@link createSameOriginSessionCaller}), so the server handler never runs in,
81
+ * or ships to, the browser; pass the descriptor, not the handler.
82
+ */
83
+ export declare function toWebMcpSpec(descriptor: HostOperationDescriptor, caller: HostOperationCaller): HostOperationWebMcpSpec;
84
+ /** A failure a host operation endpoint reported, or a transport failure. */
85
+ export declare class HostOperationError extends Error {
86
+ readonly code: string;
87
+ readonly status: number;
88
+ readonly details?: Record<string, unknown>;
89
+ constructor(code: string, message: string, status?: number, details?: Record<string, unknown>);
90
+ }
91
+ export interface SameOriginSessionCallerOptions {
92
+ /**
93
+ * The operation endpoint: a same-origin path prefix (`'/api/operations'`,
94
+ * called as `<prefix>/<operation name>`) or a function from the operation
95
+ * name to a same-origin path. No query string or fragment is accepted, so
96
+ * nothing secret travels in a URL.
97
+ */
98
+ url: string | ((operation: string) => string);
99
+ /**
100
+ * Extra request headers per call, e.g. the host's CSRF token header. The
101
+ * credential itself is the browser's session cookie, never a header here.
102
+ */
103
+ headers?: () => Record<string, string> | Promise<Record<string, string>>;
104
+ /** Defaults to the global `fetch`. */
105
+ fetch?: typeof fetch;
106
+ /** Defaults to `globalThis.location.origin`; only used to vet absolute URLs. */
107
+ origin?: string;
108
+ }
109
+ /**
110
+ * Browser-side caller that invokes the host's operation endpoint with the
111
+ * signed-in user's own session: `credentials: 'same-origin'`, JSON `POST`
112
+ * `{ arguments }`, optional host CSRF headers. A non-2xx response carrying
113
+ * `{ error: { code, message } }` (the shape `executeHostOperation` yields)
114
+ * is thrown as a {@link HostOperationError}; the success body is returned.
115
+ */
116
+ export declare function createSameOriginSessionCaller(options: SameOriginSessionCallerOptions): HostOperationCaller;
117
+ //# sourceMappingURL=host-operations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-operations.d.ts","sourceRoot":"","sources":["../src/host-operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,160 @@
1
+ import { l as safeMcpToolError, s as McpToolError } from "./chunks/errors-XG_zn1pP.js";
2
+ //#region src/host-operations.ts
3
+ function defineHostOperationTool(definition) {
4
+ if (typeof definition.handler !== "function") throw new TypeError("Host operation handler must be a function.");
5
+ if (![
6
+ "read",
7
+ "write",
8
+ "destructive"
9
+ ].includes(definition.effect)) throw new TypeError("Host operation effect must be read, write, or destructive.");
10
+ if (typeof definition.idempotent !== "boolean" || typeof definition.openWorld !== "boolean") throw new TypeError("Host operation idempotent and openWorld must be boolean.");
11
+ if (typeof definition.name !== "string" || !/^[a-z][a-z0-9_]{0,63}$/.test(definition.name)) throw new TypeError("Host operation name must be lowercase snake_case with at most 64 characters.");
12
+ return Object.freeze({ ...definition });
13
+ }
14
+ function hintsFor(descriptor) {
15
+ return {
16
+ readOnlyHint: descriptor.effect === "read",
17
+ destructiveHint: descriptor.effect === "destructive",
18
+ idempotentHint: descriptor.idempotent,
19
+ openWorldHint: descriptor.openWorld
20
+ };
21
+ }
22
+ async function executeHostOperation(definition, context) {
23
+ try {
24
+ return {
25
+ ok: true,
26
+ output: await definition.handler(context)
27
+ };
28
+ } catch (error) {
29
+ return {
30
+ ok: false,
31
+ error: safeMcpToolError(error, definition.mapError)
32
+ };
33
+ }
34
+ }
35
+ function toMcpResponse(output) {
36
+ return {
37
+ content: [{
38
+ type: "text",
39
+ text: JSON.stringify(output ?? null)
40
+ }],
41
+ structuredContent: output ?? null
42
+ };
43
+ }
44
+ function toMcpWorkflowTool(definition) {
45
+ return {
46
+ name: definition.name,
47
+ description: definition.description,
48
+ ...definition.title ? { title: definition.title } : {},
49
+ inputSchema: definition.inputSchema,
50
+ outputSchema: definition.outputSchema,
51
+ effect: definition.effect,
52
+ idempotent: definition.idempotent,
53
+ openWorld: definition.openWorld,
54
+ async execute(context) {
55
+ return toMcpResponse(await definition.handler(context));
56
+ },
57
+ ...definition.mapError ? { mapError: definition.mapError } : {}
58
+ };
59
+ }
60
+ function toWebMcpSpec(descriptor, caller) {
61
+ return {
62
+ name: descriptor.name,
63
+ description: descriptor.description,
64
+ inputSchema: descriptor.inputSchema,
65
+ annotations: hintsFor(descriptor),
66
+ async execute(args, options) {
67
+ const output = await caller(descriptor.name, args, options?.signal ? { signal: options.signal } : void 0);
68
+ return JSON.stringify(output ?? null);
69
+ }
70
+ };
71
+ }
72
+ var HostOperationError = class extends Error {
73
+ code;
74
+ status;
75
+ details;
76
+ constructor(code, message, status = 0, details) {
77
+ super(message);
78
+ this.name = "HostOperationError";
79
+ this.code = code;
80
+ this.status = status;
81
+ if (details !== void 0) this.details = details;
82
+ }
83
+ };
84
+ var AUTHORITY_KEYS = /* @__PURE__ */ new Set([
85
+ "tenantid",
86
+ "tenant_id",
87
+ "role",
88
+ "roles",
89
+ "userid",
90
+ "user_id",
91
+ "principal",
92
+ "identity",
93
+ "permissions",
94
+ "scopes"
95
+ ]);
96
+ function operationUrl(options, operation) {
97
+ const raw = typeof options.url === "function" ? options.url(operation) : `${options.url.replace(/\/+$/, "")}/${encodeURIComponent(operation)}`;
98
+ const origin = options.origin ?? globalThis.location?.origin;
99
+ let path = raw;
100
+ if (!raw.startsWith("/")) {
101
+ let parsed;
102
+ try {
103
+ parsed = new URL(raw);
104
+ } catch {
105
+ throw new TypeError("Host operation URL must be a same-origin path.");
106
+ }
107
+ if (!origin || parsed.origin !== origin || parsed.username || parsed.password) throw new TypeError("Host operation URL must be same-origin.");
108
+ path = `${parsed.pathname}${parsed.search}${parsed.hash}`;
109
+ }
110
+ if (path.startsWith("//") || path.includes("?") || path.includes("#") || path.includes("\\")) throw new TypeError("Host operation URL must be a same-origin path without query or fragment.");
111
+ return path;
112
+ }
113
+ async function failureFrom(response) {
114
+ let body;
115
+ try {
116
+ body = await response.json();
117
+ } catch {
118
+ body = void 0;
119
+ }
120
+ const error = body?.error;
121
+ if (error && typeof error.code === "string" && error.code && typeof error.message === "string") return new HostOperationError(error.code, error.message, response.status, error.details && typeof error.details === "object" && !Array.isArray(error.details) ? error.details : void 0);
122
+ return new HostOperationError(`host_operation_http_${response.status}`, "The operation failed.", response.status);
123
+ }
124
+ function createSameOriginSessionCaller(options) {
125
+ return async (operation, args, callOptions) => {
126
+ const url = operationUrl(options, operation);
127
+ const sent = {};
128
+ for (const [key, value] of Object.entries(args ?? {})) if (!AUTHORITY_KEYS.has(key.toLowerCase())) sent[key] = value;
129
+ const extra = await options.headers?.() ?? {};
130
+ const doFetch = options.fetch ?? globalThis.fetch;
131
+ let response;
132
+ try {
133
+ response = await doFetch(url, {
134
+ method: "POST",
135
+ credentials: "same-origin",
136
+ redirect: "error",
137
+ headers: {
138
+ ...extra,
139
+ accept: "application/json",
140
+ "content-type": "application/json"
141
+ },
142
+ body: JSON.stringify({ arguments: sent }),
143
+ ...callOptions?.signal ? { signal: callOptions.signal } : {}
144
+ });
145
+ } catch {
146
+ throw new HostOperationError("host_operation_network_error", "The operation could not be reached.");
147
+ }
148
+ if (!response.ok) throw await failureFrom(response);
149
+ if (response.status === 204) return void 0;
150
+ try {
151
+ return await response.json();
152
+ } catch {
153
+ throw new HostOperationError("host_operation_bad_response", "The operation returned an unreadable response.", response.status);
154
+ }
155
+ };
156
+ }
157
+ //#endregion
158
+ export { HostOperationError, McpToolError, createSameOriginSessionCaller, defineHostOperationTool, executeHostOperation, safeMcpToolError, toMcpWorkflowTool, toWebMcpSpec };
159
+
160
+ //# sourceMappingURL=host-operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-operations.js","names":[],"sources":["../src/host-operations.ts"],"sourcesContent":["/**\n * Host operation tools: one authored definition projected as an MCP workflow\n * tool (server) and a WebMCP tool (browser) without drifting.\n *\n * Browser-safe and dependency-free (type-only imports): the `./host-operations`\n * entry never pulls the MCP server, `jose` or jobs into a client bundle.\n * `@happyvertical/smrt-web` owns `registerWebMcpBespokeTool`; the WebMCP spec\n * built here is structurally identical to its `WebMcpBespokeToolSpec`, so\n * there is no package dependency on it.\n *\n * @packageDocumentation\n */\nimport type {\n MCPResponse,\n ToolEffect,\n ToolJsonSchema,\n} from '@happyvertical/smrt-core/generators/mcp';\nimport {\n type McpToolErrorInfo,\n type McpToolErrorMapper,\n safeMcpToolError,\n} from './errors.js';\nimport type { McpAppPrincipal } from './server.js';\nimport type { McpWorkflowToolDefinition } from './workflow-tools.js';\n\nexport {\n McpToolError,\n type McpToolErrorInfo,\n type McpToolErrorMapper,\n safeMcpToolError,\n} from './errors.js';\n\n/** The part of an operation both projections share; safe for a browser bundle. */\nexport interface HostOperationDescriptor {\n name: string;\n description: string;\n title?: string;\n /** Required canonical classification; it drives both projections' hints. */\n effect: ToolEffect;\n idempotent: boolean;\n openWorld: boolean;\n inputSchema: ToolJsonSchema;\n outputSchema: ToolJsonSchema;\n}\n\n/** Trusted context handed to a host operation handler. */\nexport interface HostOperationContext {\n /** Tool arguments. Untrusted: validate; never read authority from them. */\n arguments: Record<string, unknown>;\n /** The server-authenticated caller. Tenant, role and user come only from here. */\n principal: McpAppPrincipal | null;\n}\n\n/** A host operation: descriptor plus the server-side handler. */\nexport interface HostOperationToolDefinition<TOutput = unknown>\n extends HostOperationDescriptor {\n handler(context: HostOperationContext): TOutput | Promise<TOutput>;\n /** Map a handler failure to a safe code and message; see `McpToolError`. */\n mapError?: McpToolErrorMapper;\n}\n\n/** Validate and freeze a host operation definition. */\nexport function defineHostOperationTool<TOutput>(\n definition: HostOperationToolDefinition<TOutput>,\n): HostOperationToolDefinition<TOutput> {\n if (typeof definition.handler !== 'function') {\n throw new TypeError('Host operation handler must be a function.');\n }\n if (!['read', 'write', 'destructive'].includes(definition.effect)) {\n throw new TypeError(\n 'Host operation effect must be read, write, or destructive.',\n );\n }\n if (\n typeof definition.idempotent !== 'boolean' ||\n typeof definition.openWorld !== 'boolean'\n ) {\n throw new TypeError(\n 'Host operation idempotent and openWorld must be boolean.',\n );\n }\n if (\n typeof definition.name !== 'string' ||\n !/^[a-z][a-z0-9_]{0,63}$/.test(definition.name)\n ) {\n throw new TypeError(\n 'Host operation name must be lowercase snake_case with at most 64 characters.',\n );\n }\n return Object.freeze({ ...definition });\n}\n\nfunction hintsFor(descriptor: HostOperationDescriptor) {\n return {\n readOnlyHint: descriptor.effect === 'read',\n destructiveHint: descriptor.effect === 'destructive',\n idempotentHint: descriptor.idempotent,\n openWorldHint: descriptor.openWorld,\n };\n}\n\n/**\n * Execute an operation and resolve a failure to its agent-safe form. Never\n * throws; shared by the MCP projection's error path and by a host's own\n * session endpoint so both surface identical codes.\n */\nexport async function executeHostOperation<TOutput>(\n definition: HostOperationToolDefinition<TOutput>,\n context: HostOperationContext,\n): Promise<\n { ok: true; output: TOutput } | { ok: false; error: McpToolErrorInfo }\n> {\n try {\n return { ok: true, output: await definition.handler(context) };\n } catch (error) {\n return { ok: false, error: safeMcpToolError(error, definition.mapError) };\n }\n}\n\nfunction toMcpResponse(output: unknown): MCPResponse {\n const text = JSON.stringify(output ?? null);\n return {\n content: [{ type: 'text', text }],\n structuredContent: output ?? null,\n };\n}\n\n/** The definition `createMcpAppServer({ workflowTools })` accepts. */\nexport function toMcpWorkflowTool(\n definition: HostOperationToolDefinition,\n): McpWorkflowToolDefinition {\n return {\n name: definition.name,\n description: definition.description,\n ...(definition.title ? { title: definition.title } : {}),\n inputSchema: definition.inputSchema,\n outputSchema: definition.outputSchema,\n effect: definition.effect,\n idempotent: definition.idempotent,\n openWorld: definition.openWorld,\n async execute(context) {\n return toMcpResponse(await definition.handler(context));\n },\n ...(definition.mapError ? { mapError: definition.mapError } : {}),\n };\n}\n\n/** The WebMCP `registerTool` shape (`WebMcpBespokeToolSpec`), structurally. */\nexport interface HostOperationWebMcpSpec {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n annotations: {\n readOnlyHint: boolean;\n destructiveHint: boolean;\n idempotentHint: boolean;\n openWorldHint: boolean;\n };\n execute: (\n args: Record<string, unknown>,\n options?: { signal?: AbortSignal },\n ) => Promise<string>;\n}\n\n/** Invokes a host operation with the signed-in user's own authority. */\nexport type HostOperationCaller = (\n operation: string,\n args: Record<string, unknown>,\n options?: { signal?: AbortSignal },\n) => Promise<unknown>;\n\n/**\n * The WebMCP spec for an operation. Its `execute` calls `caller` (normally\n * {@link createSameOriginSessionCaller}), so the server handler never runs in,\n * or ships to, the browser; pass the descriptor, not the handler.\n */\nexport function toWebMcpSpec(\n descriptor: HostOperationDescriptor,\n caller: HostOperationCaller,\n): HostOperationWebMcpSpec {\n return {\n name: descriptor.name,\n description: descriptor.description,\n inputSchema: descriptor.inputSchema as Record<string, unknown>,\n annotations: hintsFor(descriptor),\n async execute(args, options) {\n const output = await caller(\n descriptor.name,\n args,\n options?.signal ? { signal: options.signal } : undefined,\n );\n return JSON.stringify(output ?? null);\n },\n };\n}\n\n/** A failure a host operation endpoint reported, or a transport failure. */\nexport class HostOperationError extends Error {\n readonly code: string;\n readonly status: number;\n readonly details?: Record<string, unknown>;\n constructor(\n code: string,\n message: string,\n status = 0,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'HostOperationError';\n this.code = code;\n this.status = status;\n if (details !== undefined) this.details = details;\n }\n}\n\n/**\n * Argument keys that name authority. They are never forwarded: tenant, role\n * and user come from the signed-in session on the server, so a model-supplied\n * value is dropped rather than trusted (the server must ignore them too).\n */\nconst AUTHORITY_KEYS = new Set([\n 'tenantid',\n 'tenant_id',\n 'role',\n 'roles',\n 'userid',\n 'user_id',\n 'principal',\n 'identity',\n 'permissions',\n 'scopes',\n]);\n\nexport interface SameOriginSessionCallerOptions {\n /**\n * The operation endpoint: a same-origin path prefix (`'/api/operations'`,\n * called as `<prefix>/<operation name>`) or a function from the operation\n * name to a same-origin path. No query string or fragment is accepted, so\n * nothing secret travels in a URL.\n */\n url: string | ((operation: string) => string);\n /**\n * Extra request headers per call, e.g. the host's CSRF token header. The\n * credential itself is the browser's session cookie, never a header here.\n */\n headers?: () => Record<string, string> | Promise<Record<string, string>>;\n /** Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Defaults to `globalThis.location.origin`; only used to vet absolute URLs. */\n origin?: string;\n}\n\nfunction operationUrl(\n options: SameOriginSessionCallerOptions,\n operation: string,\n): string {\n const raw =\n typeof options.url === 'function'\n ? options.url(operation)\n : `${options.url.replace(/\\/+$/, '')}/${encodeURIComponent(operation)}`;\n const origin =\n options.origin ??\n (globalThis as { location?: { origin?: string } }).location?.origin;\n let path = raw;\n if (!raw.startsWith('/')) {\n let parsed: URL;\n try {\n parsed = new URL(raw);\n } catch {\n throw new TypeError('Host operation URL must be a same-origin path.');\n }\n if (\n !origin ||\n parsed.origin !== origin ||\n parsed.username ||\n parsed.password\n ) {\n throw new TypeError('Host operation URL must be same-origin.');\n }\n path = `${parsed.pathname}${parsed.search}${parsed.hash}`;\n }\n if (\n path.startsWith('//') ||\n path.includes('?') ||\n path.includes('#') ||\n path.includes('\\\\')\n ) {\n throw new TypeError(\n 'Host operation URL must be a same-origin path without query or fragment.',\n );\n }\n return path;\n}\n\nasync function failureFrom(response: Response): Promise<HostOperationError> {\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n body = undefined;\n }\n const error = (body as { error?: unknown } | undefined)?.error as\n | { code?: unknown; message?: unknown; details?: unknown }\n | undefined;\n if (\n error &&\n typeof error.code === 'string' &&\n error.code &&\n typeof error.message === 'string'\n ) {\n return new HostOperationError(\n error.code,\n error.message,\n response.status,\n error.details &&\n typeof error.details === 'object' &&\n !Array.isArray(error.details)\n ? (error.details as Record<string, unknown>)\n : undefined,\n );\n }\n return new HostOperationError(\n `host_operation_http_${response.status}`,\n 'The operation failed.',\n response.status,\n );\n}\n\n/**\n * Browser-side caller that invokes the host's operation endpoint with the\n * signed-in user's own session: `credentials: 'same-origin'`, JSON `POST`\n * `{ arguments }`, optional host CSRF headers. A non-2xx response carrying\n * `{ error: { code, message } }` (the shape `executeHostOperation` yields)\n * is thrown as a {@link HostOperationError}; the success body is returned.\n */\nexport function createSameOriginSessionCaller(\n options: SameOriginSessionCallerOptions,\n): HostOperationCaller {\n return async (operation, args, callOptions) => {\n const url = operationUrl(options, operation);\n const sent: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(args ?? {})) {\n if (!AUTHORITY_KEYS.has(key.toLowerCase())) sent[key] = value;\n }\n const extra = (await options.headers?.()) ?? {};\n const doFetch = options.fetch ?? globalThis.fetch;\n let response: Response;\n try {\n response = await doFetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n redirect: 'error',\n headers: {\n ...extra,\n accept: 'application/json',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({ arguments: sent }),\n ...(callOptions?.signal ? { signal: callOptions.signal } : {}),\n });\n } catch {\n throw new HostOperationError(\n 'host_operation_network_error',\n 'The operation could not be reached.',\n );\n }\n if (!response.ok) throw await failureFrom(response);\n if (response.status === 204) return undefined;\n try {\n return await response.json();\n } catch {\n throw new HostOperationError(\n 'host_operation_bad_response',\n 'The operation returned an unreadable response.',\n response.status,\n );\n }\n };\n}\n"],"mappings":";;AA8DO,SAAS,wBACd,YACsC;CACtC,IAAI,OAAO,WAAW,YAAY,YAChC,MAAM,IAAI,UAAU,4CAA4C;CAElE,IAAI,CAAC;EAAC;EAAQ;EAAS;CAAa,CAAA,CAAE,SAAS,WAAW,MAAM,GAC9D,MAAM,IAAI,UACR,4DACF;CAEF,IACE,OAAO,WAAW,eAAe,aACjC,OAAO,WAAW,cAAc,WAEhC,MAAM,IAAI,UACR,0DACF;CAEF,IACE,OAAO,WAAW,SAAS,YAC3B,CAAC,yBAAyB,KAAK,WAAW,IAAI,GAE9C,MAAM,IAAI,UACR,8EACF;CAEF,OAAO,OAAO,OAAO,EAAE,GAAG,WAAW,CAAC;AACxC;AAEA,SAAS,SAAS,YAAqC;CACrD,OAAO;EACL,cAAc,WAAW,WAAW;EACpC,iBAAiB,WAAW,WAAW;EACvC,gBAAgB,WAAW;EAC3B,eAAe,WAAW;CAC5B;AACF;AAOA,eAAsB,qBACpB,YACA,SAGA;CACA,IAAI;EACF,OAAO;GAAE,IAAI;GAAM,QAAQ,MAAM,WAAW,QAAQ,OAAO;EAAE;CAC/D,SAAS,OAAO;EACd,OAAO;GAAE,IAAI;GAAO,OAAO,iBAAiB,OAAO,WAAW,QAAQ;EAAE;CAC1E;AACF;AAEA,SAAS,cAAc,QAA8B;CAEnD,OAAO;EACL,SAAS,CAAC;GAAE,MAAM;GAAQ,MAFf,KAAK,UAAU,UAAU,IAEV;EAAK,CAAC;EAChC,mBAAmB,UAAU;CAC/B;AACF;AAGO,SAAS,kBACd,YAC2B;CAC3B,OAAO;EACL,MAAM,WAAW;EACjB,aAAa,WAAW;EACxB,GAAI,WAAW,QAAQ,EAAE,OAAO,WAAW,MAAM,IAAI,CAAC;EACtD,aAAa,WAAW;EACxB,cAAc,WAAW;EACzB,QAAQ,WAAW;EACnB,YAAY,WAAW;EACvB,WAAW,WAAW;EACtB,MAAM,QAAQ,SAAS;GACrB,OAAO,cAAc,MAAM,WAAW,QAAQ,OAAO,CAAC;EACxD;EACA,GAAI,WAAW,WAAW,EAAE,UAAU,WAAW,SAAS,IAAI,CAAC;CACjE;AACF;AA+BO,SAAS,aACd,YACA,QACyB;CACzB,OAAO;EACL,MAAM,WAAW;EACjB,aAAa,WAAW;EACxB,aAAa,WAAW;EACxB,aAAa,SAAS,UAAU;EAChC,MAAM,QAAQ,MAAM,SAAS;GAC3B,MAAM,SAAS,MAAM,OACnB,WAAW,MACX,MACA,SAAS,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,KAAA,CACjD;GACA,OAAO,KAAK,UAAU,UAAU,IAAI;EACtC;CACF;AACF;AAGO,IAAM,qBAAN,cAAiC,MAAM;CACnC;CACA;CACA;CACT,YACE,MACA,SACA,SAAS,GACT,SACA;EACA,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,SAAS;EACd,IAAI,YAAY,KAAA,GAAW,KAAK,UAAU;CAC5C;AACF;AAOA,IAAM,iCAAiB,IAAI,IAAI;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAqBD,SAAS,aACP,SACA,WACQ;CACR,MAAM,MACJ,OAAO,QAAQ,QAAQ,aACnB,QAAQ,IAAI,SAAS,IACrB,GAAG,QAAQ,IAAI,QAAQ,QAAQ,EAAE,EAAC,GAAI,mBAAmB,SAAS;CACxE,MAAM,SACJ,QAAQ,UACP,WAAkD,UAAU;CAC/D,IAAI,OAAO;CACX,IAAI,CAAC,IAAI,WAAW,GAAG,GAAG;EACxB,IAAI;EACJ,IAAI;GACF,SAAS,IAAI,IAAI,GAAG;EACtB,QAAQ;GACN,MAAM,IAAI,UAAU,gDAAgD;EACtE;EACA,IACE,CAAC,UACD,OAAO,WAAW,UAClB,OAAO,YACP,OAAO,UAEP,MAAM,IAAI,UAAU,yCAAyC;EAE/D,OAAO,GAAG,OAAO,WAAW,OAAO,SAAS,OAAO;CACrD;CACA,IACE,KAAK,WAAW,IAAI,KACpB,KAAK,SAAS,GAAG,KACjB,KAAK,SAAS,GAAG,KACjB,KAAK,SAAS,IAAI,GAElB,MAAM,IAAI,UACR,0EACF;CAEF,OAAO;AACT;AAEA,eAAe,YAAY,UAAiD;CAC1E,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,SAAS,KAAK;CAC7B,QAAQ;EACN,OAAO,KAAA;CACT;CACA,MAAM,QAAS,MAA0C;CAGzD,IACE,SACA,OAAO,MAAM,SAAS,YACtB,MAAM,QACN,OAAO,MAAM,YAAY,UAEzB,OAAO,IAAI,mBACT,MAAM,MACN,MAAM,SACN,SAAS,QACT,MAAM,WACJ,OAAO,MAAM,YAAY,YACzB,CAAC,MAAM,QAAQ,MAAM,OAAO,IACzB,MAAM,UACP,KAAA,CACN;CAEF,OAAO,IAAI,mBACT,uBAAuB,SAAS,UAChC,yBACA,SAAS,MACX;AACF;AASO,SAAS,8BACd,SACqB;CACrB,OAAO,OAAO,WAAW,MAAM,gBAAgB;EAC7C,MAAM,MAAM,aAAa,SAAS,SAAS;EAC3C,MAAM,OAAgC,CAAC;EACvC,KAAA,MAAW,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,CAAC,CAAC,GAClD,IAAI,CAAC,eAAe,IAAI,IAAI,YAAY,CAAC,GAAG,KAAK,OAAO;EAE1D,MAAM,QAAS,MAAM,QAAQ,UAAU,KAAM,CAAC;EAC9C,MAAM,UAAU,QAAQ,SAAS,WAAW;EAC5C,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,QAAQ,KAAK;IAC5B,QAAQ;IACR,aAAa;IACb,UAAU;IACV,SAAS;KACP,GAAG;KACH,QAAQ;KACR,gBAAgB;IAClB;IACA,MAAM,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;IACxC,GAAI,aAAa,SAAS,EAAE,QAAQ,YAAY,OAAO,IAAI,CAAC;GAC9D,CAAC;EACH,QAAQ;GACN,MAAM,IAAI,mBACR,gCACA,qCACF;EACF;EACA,IAAI,CAAC,SAAS,IAAI,MAAM,MAAM,YAAY,QAAQ;EAClD,IAAI,SAAS,WAAW,KAAK,OAAO,KAAA;EACpC,IAAI;GACF,OAAO,MAAM,SAAS,KAAK;EAC7B,QAAQ;GACN,MAAM,IAAI,mBACR,+BACA,kDACA,SAAS,MACX;EACF;CACF;AACF"}
@@ -0,0 +1,11 @@
1
+ import type { McpPrincipalIdentity } from './server.js';
2
+ /**
3
+ * Attach the adapter-verified credential identity to a principal as a
4
+ * non-enumerable property: it never changes the principal's enumerable
5
+ * (deep-equal, serialized) shape, and an object spread drops it, so any
6
+ * code that rebuilds a principal must re-stamp it from the authenticated one.
7
+ *
8
+ * @internal
9
+ */
10
+ export declare function stampVerifiedIdentity<T extends object>(principal: T, identity: McpPrincipalIdentity | undefined): T;
11
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACpD,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GACzC,CAAC,CAUH"}
package/dist/index.d.ts CHANGED
@@ -23,10 +23,11 @@
23
23
  */
24
24
  export { continueMcpWorkflow, createMcpContinuationTool, type McpWorkflowContinuation, } from './continuation.js';
25
25
  export { type CreateDefaultMcpAppServerOptions, createDefaultMcpAppServer, DEFAULT_MCP_APP_SERVER_INFO, type McpAppModel, type McpPrincipalScopePolicyOptions, mcpAllowedClassNames, mcpPrincipalScopePolicy, } from './defaults.js';
26
- export { MCP_ORIGIN_DENIED_CODE, MCP_TOOL_ACCESS_DENIED_CODE, McpAccessError, type McpAccessErrorMetadata, } from './errors.js';
26
+ export { MCP_AUTHENTICATION_REQUIRED_CODE, MCP_ORIGIN_DENIED_CODE, MCP_TOOL_ACCESS_DENIED_CODE, MCP_TOOL_EXECUTION_FAILED_CODE, MCP_TOOL_NOT_FOUND_CODE, McpAccessError, type McpAccessErrorMetadata, McpToolError, type McpToolErrorInfo, type McpToolErrorMapper, safeMcpToolError, } from './errors.js';
27
+ export { createSameOriginSessionCaller, defineHostOperationTool, executeHostOperation, type HostOperationCaller, type HostOperationContext, type HostOperationDescriptor, HostOperationError, type HostOperationToolDefinition, type HostOperationWebMcpSpec, type SameOriginSessionCallerOptions, toMcpWorkflowTool, toWebMcpSpec, } from './host-operations.js';
27
28
  export { createMcpProtocolServer, createMcpProtocolServerForRequest, type McpProtocolRequestOptions, type McpProtocolServerOptions, } from './protocol.js';
28
29
  export { MCP_APP_RESOURCE_MAX_BYTES, MCP_APP_RESOURCE_MIME, type McpAppResource, type McpAppResourceContent, type McpAppResourceCsp, type McpAppResourceDefinition, type McpResourcePolicy, prepareMcpAppResource, } from './resources.js';
29
- export { type CallToolInput, type CreateMcpAppServerOptions, createMcpAppServer, type ListToolsInput, type McpAppPrincipal, type McpAppServer, type McpAppUser, type McpPublicToolPatternsThunk, type McpSmrtOptionsThunk, type McpTaskPrincipalPolicy, type McpTenantBinding, type McpToolListCacheHint, type McpToolListCacheOptions, type McpToolPolicy, type McpToolPolicyContext, type McpWorkflowAssertion, } from './server.js';
30
+ export { type CallToolInput, type CreateMcpAppServerOptions, createMcpAppServer, type ListToolsInput, type McpAppPrincipal, type McpAppServer, type McpAppUser, type McpPrincipalIdentity, type McpPublicToolPatternsThunk, type McpSmrtOptionsThunk, type McpTaskPrincipalPolicy, type McpTenantBinding, type McpToolCallAuditEvent, type McpToolCallOutcome, type McpToolListCacheHint, type McpToolListCacheOptions, type McpToolPolicy, type McpToolPolicyContext, type McpWorkflowAssertion, } from './server.js';
30
31
  export { classNamePrefixes, isAllowedCoreTool, isPublicMcpTool, isPublicToolName, isReadOnlyToolName, MCP_TOOL_EFFECTS, type McpToolEffect, matchesToolPattern, mcpToolEffect, } from './tools.js';
31
32
  export { createMcpWorkflowTool, type McpWorkflowTool, type McpWorkflowToolContext, type McpWorkflowToolDefinition, type McpWorkflowToolVisibility, } from './workflow-tools.js';
32
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,uBAAuB,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,2BAA2B,EAC3B,KAAK,WAAW,EAChB,KAAK,8BAA8B,EACnC,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,cAAc,EACd,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC9B,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,aAAa,EAClB,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,uBAAuB,GAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,2BAA2B,EAC3B,KAAK,WAAW,EAChB,KAAK,8BAA8B,EACnC,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gCAAgC,EAChC,sBAAsB,EACtB,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,cAAc,EACd,KAAK,sBAAsB,EAC3B,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,6BAA6B,EAC7B,uBAAuB,EACvB,oBAAoB,EACpB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,kBAAkB,EAClB,KAAK,2BAA2B,EAChC,KAAK,uBAAuB,EAC5B,KAAK,8BAA8B,EACnC,iBAAiB,EACjB,YAAY,GACb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,yBAAyB,EAC9B,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,aAAa,EAClB,kBAAkB,EAClB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
- import { C as McpAccessError, S as MCP_TOOL_ACCESS_DENIED_CODE, _ as MCP_APP_RESOURCE_MAX_BYTES, a as createDefaultMcpAppServer, b as createMcpWorkflowTool, c as createMcpAppServer, d as isAllowedCoreTool, f as isPublicMcpTool, g as mcpToolEffect, h as matchesToolPattern, i as DEFAULT_MCP_APP_SERVER_INFO, l as MCP_TOOL_EFFECTS, m as isReadOnlyToolName, n as createMcpProtocolServer, o as mcpAllowedClassNames, p as isPublicToolName, r as createMcpProtocolServerForRequest, s as mcpPrincipalScopePolicy, u as classNamePrefixes, v as MCP_APP_RESOURCE_MIME, x as MCP_ORIGIN_DENIED_CODE, y as prepareMcpAppResource } from "./chunks/protocol-CoCuR_w7.js";
1
+ import { a as MCP_TOOL_NOT_FOUND_CODE, i as MCP_TOOL_EXECUTION_FAILED_CODE, l as safeMcpToolError, n as MCP_ORIGIN_DENIED_CODE, o as McpAccessError, r as MCP_TOOL_ACCESS_DENIED_CODE, s as McpToolError, t as MCP_AUTHENTICATION_REQUIRED_CODE } from "./chunks/errors-XG_zn1pP.js";
2
+ import { _ as MCP_APP_RESOURCE_MAX_BYTES, a as createDefaultMcpAppServer, b as createMcpWorkflowTool, c as createMcpAppServer, d as isAllowedCoreTool, f as isPublicMcpTool, g as mcpToolEffect, h as matchesToolPattern, i as DEFAULT_MCP_APP_SERVER_INFO, l as MCP_TOOL_EFFECTS, m as isReadOnlyToolName, n as createMcpProtocolServer, o as mcpAllowedClassNames, p as isPublicToolName, r as createMcpProtocolServerForRequest, s as mcpPrincipalScopePolicy, u as classNamePrefixes, v as MCP_APP_RESOURCE_MIME, y as prepareMcpAppResource } from "./chunks/protocol-BRQji5k_.js";
3
+ import { HostOperationError, createSameOriginSessionCaller, defineHostOperationTool, executeHostOperation, toMcpWorkflowTool, toWebMcpSpec } from "./host-operations.js";
2
4
  import { getActiveJobExecutionContext, isRunnerExecutionContext } from "@happyvertical/smrt-jobs";
3
5
  //#region src/continuation.ts
4
6
  async function continueMcpWorkflow(options) {
@@ -69,6 +71,6 @@ function createMcpContinuationTool(options) {
69
71
  return definition;
70
72
  }
71
73
  //#endregion
72
- export { DEFAULT_MCP_APP_SERVER_INFO, MCP_APP_RESOURCE_MAX_BYTES, MCP_APP_RESOURCE_MIME, MCP_ORIGIN_DENIED_CODE, MCP_TOOL_ACCESS_DENIED_CODE, MCP_TOOL_EFFECTS, McpAccessError, classNamePrefixes, continueMcpWorkflow, createDefaultMcpAppServer, createMcpAppServer, createMcpContinuationTool, createMcpProtocolServer, createMcpProtocolServerForRequest, createMcpWorkflowTool, isAllowedCoreTool, isPublicMcpTool, isPublicToolName, isReadOnlyToolName, matchesToolPattern, mcpAllowedClassNames, mcpPrincipalScopePolicy, mcpToolEffect, prepareMcpAppResource };
74
+ export { DEFAULT_MCP_APP_SERVER_INFO, HostOperationError, MCP_APP_RESOURCE_MAX_BYTES, MCP_APP_RESOURCE_MIME, MCP_AUTHENTICATION_REQUIRED_CODE, MCP_ORIGIN_DENIED_CODE, MCP_TOOL_ACCESS_DENIED_CODE, MCP_TOOL_EFFECTS, MCP_TOOL_EXECUTION_FAILED_CODE, MCP_TOOL_NOT_FOUND_CODE, McpAccessError, McpToolError, classNamePrefixes, continueMcpWorkflow, createDefaultMcpAppServer, createMcpAppServer, createMcpContinuationTool, createMcpProtocolServer, createMcpProtocolServerForRequest, createMcpWorkflowTool, createSameOriginSessionCaller, defineHostOperationTool, executeHostOperation, isAllowedCoreTool, isPublicMcpTool, isPublicToolName, isReadOnlyToolName, matchesToolPattern, mcpAllowedClassNames, mcpPrincipalScopePolicy, mcpToolEffect, prepareMcpAppResource, safeMcpToolError, toMcpWorkflowTool, toWebMcpSpec };
73
75
 
74
76
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/continuation.ts"],"sourcesContent":["import {\n getActiveJobExecutionContext,\n isRunnerExecutionContext,\n type McpTaskContinuation,\n type McpTaskStore,\n} from '@happyvertical/smrt-jobs';\nimport { McpAccessError } from './errors.js';\nimport type { McpAppPrincipal } from './server.js';\nimport {\n createMcpWorkflowTool,\n type McpWorkflowToolDefinition,\n} from './workflow-tools.js';\n\n/** Server-owned immutable review reference; contains no permission snapshot. */\nexport interface McpWorkflowContinuation extends McpTaskContinuation {\n /** Application review page, including the application's own authentication. */\n reviewUrl: string;\n}\n\n/**\n * Compose a durable job with its owning workflow. The host answer is only an\n * input hint. `applyReviewed` must call the owning immutable review/revision and\n * idempotency API, rechecking domain approval inside that transaction.\n * No host callback or server session survives suspension.\n */\nexport async function continueMcpWorkflow<T>(options: {\n binding: McpWorkflowContinuation;\n inputSchema: Record<string, unknown>;\n applyReviewed: (\n input: unknown,\n binding: Readonly<McpTaskContinuation>,\n ) => Promise<T>;\n}): Promise<T> {\n const context = getActiveJobExecutionContext();\n if (!context || !isRunnerExecutionContext(context) || !context.task) {\n throw new Error('Durable workflow requires an active MCP task');\n }\n const url = new URL(options.binding.reviewUrl);\n const loopback =\n url.protocol === 'http:' &&\n ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password\n ) {\n throw new Error('Workflow review URL must use HTTPS without credentials');\n }\n await context.task.assertAuthorized();\n const binding = Object.freeze({\n recordId: options.binding.recordId,\n revision: options.binding.revision,\n inputKey: options.binding.inputKey,\n });\n const input = await context.task.requestContinuation(binding, {\n schema: options.inputSchema,\n reviewUrl: url.href,\n });\n await context.task.assertAuthorized();\n return options.applyReviewed(input, binding);\n}\n\n/**\n * Declare the ordinary tool fallback for hosts without elicitation. `storeFor`\n * must return a store bound to the supplied verified actor and active tenant;\n * the application policy callback resolves current read authority.\n */\nexport function createMcpContinuationTool(options: {\n name: string;\n storeFor: (\n principal: McpAppPrincipal,\n ) => Promise<Pick<McpTaskStore, 'getContinuation'>>;\n authorize: (principal: McpAppPrincipal, taskId: string) => Promise<boolean>;\n}): McpWorkflowToolDefinition {\n const definition: McpWorkflowToolDefinition = {\n name: options.name,\n description:\n 'Read the current input form or human review URL for your waiting workflow task.',\n effect: 'read',\n idempotent: true,\n openWorld: false,\n inputSchema: {\n type: 'object',\n properties: { taskId: { type: 'string', minLength: 1, maxLength: 256 } },\n required: ['taskId'],\n additionalProperties: false,\n },\n outputSchema: {\n type: 'object',\n properties: {\n continuation: { anyOf: [{ type: 'object' }, { type: 'null' }] },\n },\n required: ['continuation'],\n additionalProperties: false,\n },\n async execute(context) {\n const taskId = context.arguments.taskId;\n const principal = context.principal;\n try {\n if (\n !principal ||\n typeof taskId !== 'string' ||\n !taskId ||\n taskId.length > 256 ||\n !(await options.authorize(principal, taskId))\n )\n throw new Error('Denied');\n const store = await options.storeFor(principal);\n const data = { continuation: await store.getContinuation(taskId) };\n return {\n content: [{ type: 'text', text: JSON.stringify(data) }],\n structuredContent: data,\n };\n } catch {\n throw new McpAccessError(403, 'Tool access denied');\n }\n },\n };\n createMcpWorkflowTool(definition);\n return definition;\n}\n"],"mappings":";;;AAyBA,eAAsB,oBAAuB,SAO9B;CACb,MAAM,UAAU,6BAA6B;CAC7C,IAAI,CAAC,WAAW,CAAC,yBAAyB,OAAO,KAAK,CAAC,QAAQ,MAC7D,MAAM,IAAI,MAAM,8CAA8C;CAEhE,MAAM,MAAM,IAAI,IAAI,QAAQ,QAAQ,SAAS;CAC7C,MAAM,WACJ,IAAI,aAAa,WACjB;EAAC;EAAa;EAAa;CAAO,CAAA,CAAE,SAAS,IAAI,QAAQ;CAC3D,IACG,IAAI,aAAa,YAAY,CAAC,YAC/B,IAAI,YACJ,IAAI,UAEJ,MAAM,IAAI,MAAM,wDAAwD;CAE1E,MAAM,QAAQ,KAAK,iBAAiB;CACpC,MAAM,UAAU,OAAO,OAAO;EAC5B,UAAU,QAAQ,QAAQ;EAC1B,UAAU,QAAQ,QAAQ;EAC1B,UAAU,QAAQ,QAAQ;CAC5B,CAAC;CACD,MAAM,QAAQ,MAAM,QAAQ,KAAK,oBAAoB,SAAS;EAC5D,QAAQ,QAAQ;EAChB,WAAW,IAAI;CACjB,CAAC;CACD,MAAM,QAAQ,KAAK,iBAAiB;CACpC,OAAO,QAAQ,cAAc,OAAO,OAAO;AAC7C;AAOO,SAAS,0BAA0B,SAMZ;CAC5B,MAAM,aAAwC;EAC5C,MAAM,QAAQ;EACd,aACE;EACF,QAAQ;EACR,YAAY;EACZ,WAAW;EACX,aAAa;GACX,MAAM;GACN,YAAY,EAAE,QAAQ;IAAE,MAAM;IAAU,WAAW;IAAG,WAAW;GAAI,EAAE;GACvE,UAAU,CAAC,QAAQ;GACnB,sBAAsB;EACxB;EACA,cAAc;GACZ,MAAM;GACN,YAAY,EACV,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,SAAS,GAAG,EAAE,MAAM,OAAO,CAAC,EAAE,EAChE;GACA,UAAU,CAAC,cAAc;GACzB,sBAAsB;EACxB;EACA,MAAM,QAAQ,SAAS;GACrB,MAAM,SAAS,QAAQ,UAAU;GACjC,MAAM,YAAY,QAAQ;GAC1B,IAAI;IACF,IACE,CAAC,aACD,OAAO,WAAW,YAClB,CAAC,UACD,OAAO,SAAS,OAChB,CAAE,MAAM,QAAQ,UAAU,WAAW,MAAM,GAE3C,MAAM,IAAI,MAAM,QAAQ;IAE1B,MAAM,OAAO,EAAE,cAAc,OAAM,MADf,QAAQ,SAAS,SAAS,EAAA,CACL,gBAAgB,MAAM,EAAE;IACjE,OAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,KAAK,UAAU,IAAI;KAAE,CAAC;KACtD,mBAAmB;IACrB;GACF,QAAQ;IACN,MAAM,IAAI,eAAe,KAAK,oBAAoB;GACpD;EACF;CACF;CACA,sBAAsB,UAAU;CAChC,OAAO;AACT"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/continuation.ts"],"sourcesContent":["import {\n getActiveJobExecutionContext,\n isRunnerExecutionContext,\n type McpTaskContinuation,\n type McpTaskStore,\n} from '@happyvertical/smrt-jobs';\nimport { McpAccessError } from './errors.js';\nimport type { McpAppPrincipal } from './server.js';\nimport {\n createMcpWorkflowTool,\n type McpWorkflowToolDefinition,\n} from './workflow-tools.js';\n\n/** Server-owned immutable review reference; contains no permission snapshot. */\nexport interface McpWorkflowContinuation extends McpTaskContinuation {\n /** Application review page, including the application's own authentication. */\n reviewUrl: string;\n}\n\n/**\n * Compose a durable job with its owning workflow. The host answer is only an\n * input hint. `applyReviewed` must call the owning immutable review/revision and\n * idempotency API, rechecking domain approval inside that transaction.\n * No host callback or server session survives suspension.\n */\nexport async function continueMcpWorkflow<T>(options: {\n binding: McpWorkflowContinuation;\n inputSchema: Record<string, unknown>;\n applyReviewed: (\n input: unknown,\n binding: Readonly<McpTaskContinuation>,\n ) => Promise<T>;\n}): Promise<T> {\n const context = getActiveJobExecutionContext();\n if (!context || !isRunnerExecutionContext(context) || !context.task) {\n throw new Error('Durable workflow requires an active MCP task');\n }\n const url = new URL(options.binding.reviewUrl);\n const loopback =\n url.protocol === 'http:' &&\n ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password\n ) {\n throw new Error('Workflow review URL must use HTTPS without credentials');\n }\n await context.task.assertAuthorized();\n const binding = Object.freeze({\n recordId: options.binding.recordId,\n revision: options.binding.revision,\n inputKey: options.binding.inputKey,\n });\n const input = await context.task.requestContinuation(binding, {\n schema: options.inputSchema,\n reviewUrl: url.href,\n });\n await context.task.assertAuthorized();\n return options.applyReviewed(input, binding);\n}\n\n/**\n * Declare the ordinary tool fallback for hosts without elicitation. `storeFor`\n * must return a store bound to the supplied verified actor and active tenant;\n * the application policy callback resolves current read authority.\n */\nexport function createMcpContinuationTool(options: {\n name: string;\n storeFor: (\n principal: McpAppPrincipal,\n ) => Promise<Pick<McpTaskStore, 'getContinuation'>>;\n authorize: (principal: McpAppPrincipal, taskId: string) => Promise<boolean>;\n}): McpWorkflowToolDefinition {\n const definition: McpWorkflowToolDefinition = {\n name: options.name,\n description:\n 'Read the current input form or human review URL for your waiting workflow task.',\n effect: 'read',\n idempotent: true,\n openWorld: false,\n inputSchema: {\n type: 'object',\n properties: { taskId: { type: 'string', minLength: 1, maxLength: 256 } },\n required: ['taskId'],\n additionalProperties: false,\n },\n outputSchema: {\n type: 'object',\n properties: {\n continuation: { anyOf: [{ type: 'object' }, { type: 'null' }] },\n },\n required: ['continuation'],\n additionalProperties: false,\n },\n async execute(context) {\n const taskId = context.arguments.taskId;\n const principal = context.principal;\n try {\n if (\n !principal ||\n typeof taskId !== 'string' ||\n !taskId ||\n taskId.length > 256 ||\n !(await options.authorize(principal, taskId))\n )\n throw new Error('Denied');\n const store = await options.storeFor(principal);\n const data = { continuation: await store.getContinuation(taskId) };\n return {\n content: [{ type: 'text', text: JSON.stringify(data) }],\n structuredContent: data,\n };\n } catch {\n throw new McpAccessError(403, 'Tool access denied');\n }\n },\n };\n createMcpWorkflowTool(definition);\n return definition;\n}\n"],"mappings":";;;;;AAyBA,eAAsB,oBAAuB,SAO9B;CACb,MAAM,UAAU,6BAA6B;CAC7C,IAAI,CAAC,WAAW,CAAC,yBAAyB,OAAO,KAAK,CAAC,QAAQ,MAC7D,MAAM,IAAI,MAAM,8CAA8C;CAEhE,MAAM,MAAM,IAAI,IAAI,QAAQ,QAAQ,SAAS;CAC7C,MAAM,WACJ,IAAI,aAAa,WACjB;EAAC;EAAa;EAAa;CAAO,CAAA,CAAE,SAAS,IAAI,QAAQ;CAC3D,IACG,IAAI,aAAa,YAAY,CAAC,YAC/B,IAAI,YACJ,IAAI,UAEJ,MAAM,IAAI,MAAM,wDAAwD;CAE1E,MAAM,QAAQ,KAAK,iBAAiB;CACpC,MAAM,UAAU,OAAO,OAAO;EAC5B,UAAU,QAAQ,QAAQ;EAC1B,UAAU,QAAQ,QAAQ;EAC1B,UAAU,QAAQ,QAAQ;CAC5B,CAAC;CACD,MAAM,QAAQ,MAAM,QAAQ,KAAK,oBAAoB,SAAS;EAC5D,QAAQ,QAAQ;EAChB,WAAW,IAAI;CACjB,CAAC;CACD,MAAM,QAAQ,KAAK,iBAAiB;CACpC,OAAO,QAAQ,cAAc,OAAO,OAAO;AAC7C;AAOO,SAAS,0BAA0B,SAMZ;CAC5B,MAAM,aAAwC;EAC5C,MAAM,QAAQ;EACd,aACE;EACF,QAAQ;EACR,YAAY;EACZ,WAAW;EACX,aAAa;GACX,MAAM;GACN,YAAY,EAAE,QAAQ;IAAE,MAAM;IAAU,WAAW;IAAG,WAAW;GAAI,EAAE;GACvE,UAAU,CAAC,QAAQ;GACnB,sBAAsB;EACxB;EACA,cAAc;GACZ,MAAM;GACN,YAAY,EACV,cAAc,EAAE,OAAO,CAAC,EAAE,MAAM,SAAS,GAAG,EAAE,MAAM,OAAO,CAAC,EAAE,EAChE;GACA,UAAU,CAAC,cAAc;GACzB,sBAAsB;EACxB;EACA,MAAM,QAAQ,SAAS;GACrB,MAAM,SAAS,QAAQ,UAAU;GACjC,MAAM,YAAY,QAAQ;GAC1B,IAAI;IACF,IACE,CAAC,aACD,OAAO,WAAW,YAClB,CAAC,UACD,OAAO,SAAS,OAChB,CAAE,MAAM,QAAQ,UAAU,WAAW,MAAM,GAE3C,MAAM,IAAI,MAAM,QAAQ;IAE1B,MAAM,OAAO,EAAE,cAAc,OAAM,MADf,QAAQ,SAAS,SAAS,EAAA,CACL,gBAAgB,MAAM,EAAE;IACjE,OAAO;KACL,SAAS,CAAC;MAAE,MAAM;MAAQ,MAAM,KAAK,UAAU,IAAI;KAAE,CAAC;KACtD,mBAAmB;IACrB;GACF,QAAQ;IACN,MAAM,IAAI,eAAe,KAAK,oBAAoB;GACpD;EACF;CACF;CACA,sBAAsB,UAAU;CAChC,OAAO;AACT"}
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-app-mcp",
5
- "packageVersion": "0.57.42",
5
+ "packageVersion": "0.57.44",
6
6
  "objects": {},
7
7
  "moduleType": "smrt",
8
8
  "smrtDependencies": [
package/dist/server.d.ts CHANGED
@@ -17,6 +17,7 @@
17
17
  */
18
18
  import type { MCPConfig, MCPResponse, MCPTool } from '@happyvertical/smrt-core/generators/mcp';
19
19
  import { type McpTask } from '@happyvertical/smrt-jobs';
20
+ import { type McpToolErrorInfo } from './errors.js';
20
21
  import { type McpAppResource, type McpAppResourceContent, type McpAppResourceDefinition, type McpResourcePolicy } from './resources.js';
21
22
  import { type McpToolEffect } from './tools.js';
22
23
  import { type McpWorkflowToolDefinition } from './workflow-tools.js';
@@ -35,8 +36,21 @@ import { type McpWorkflowToolDefinition } from './workflow-tools.js';
35
36
  * authority inherited from an active inheritable ancestor membership.
36
37
  */
37
38
  export type McpTenantBinding = 'direct' | 'direct-or-inherited';
39
+ /**
40
+ * The verified credential identity behind a principal, stamped only by the
41
+ * authentication adapters (never request input, never a principal mapper):
42
+ * the token `issuer`, `subject` and OAuth `clientId` the server itself
43
+ * validated. Surfaced to {@link McpToolCallAuditEvent} for audit.
44
+ */
45
+ export interface McpPrincipalIdentity {
46
+ issuer: string;
47
+ subject: string;
48
+ clientId?: string;
49
+ }
38
50
  export interface McpAppPrincipal {
39
51
  id?: string;
52
+ /** Adapter-stamped verified credential identity; see {@link McpPrincipalIdentity}. */
53
+ identity?: McpPrincipalIdentity;
40
54
  /** Tenant boundary for task ownership and generated tenant-scoped actions. */
41
55
  tenantId?: string;
42
56
  /** Trusted operator override for generated tenant-scoped actions. */
@@ -55,6 +69,29 @@ export interface McpAppPrincipal {
55
69
  export interface McpAppUser extends McpAppPrincipal {
56
70
  id: string;
57
71
  }
72
+ /** How a call ended, as reported to {@link CreateMcpAppServerOptions.onToolCall}. */
73
+ export type McpToolCallOutcome = 'ok' | 'denied' | 'error';
74
+ /**
75
+ * One audited tool call. Every `tools/call` and task-creating call produces
76
+ * exactly one event, including calls refused before any handler ran
77
+ * (unknown or filtered tool, authentication, `toolPolicy`, workflow
78
+ * assertion denials).
79
+ *
80
+ * `principal` and `identity` are what this server authenticated for the
81
+ * request (adapter-derived), never anything the client claimed; they are
82
+ * `null` for an unauthenticated call or one whose adapter stamps no
83
+ * credential identity (session principals). `tool` is the name the caller
84
+ * requested (truncated), which is client-supplied for an unknown tool.
85
+ * `error` is only the safe `{ code, message }` an agent could see, never a
86
+ * stack or raw error.
87
+ */
88
+ export interface McpToolCallAuditEvent {
89
+ tool: string;
90
+ principal: Readonly<McpAppPrincipal> | null;
91
+ identity: Readonly<McpPrincipalIdentity> | null;
92
+ outcome: McpToolCallOutcome;
93
+ error?: Readonly<McpToolErrorInfo>;
94
+ }
58
95
  /** Context supplied to the optional per-tool principal policy. */
59
96
  export interface McpToolPolicyContext {
60
97
  principal: McpAppPrincipal | null;
@@ -151,6 +188,15 @@ export interface CreateMcpAppServerOptions {
151
188
  * assertion gates before the handler runs.
152
189
  */
153
190
  workflowTools?: readonly McpWorkflowToolDefinition[];
191
+ /**
192
+ * Audit hook, awaited once per tool call after its outcome is known. A
193
+ * hook that throws or rejects never changes the tool result and never
194
+ * escapes; the failure is passed to `onToolCallHookError` when set. Keep it
195
+ * fast: a call returns after the hook settles.
196
+ */
197
+ onToolCall?: (event: McpToolCallAuditEvent) => void | Promise<void>;
198
+ /** Receives (never rethrown) failures of {@link onToolCall}. */
199
+ onToolCallHookError?: (error: unknown) => void;
154
200
  /**
155
201
  * Restrict the catalog to tools whose effect (see `mcpToolEffect`) is
156
202
  * listed, for example `['read']` until per-operation authorization exists.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}