@softure-ai/mcp-access 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ Newest first. Each version lists what changed for an app that uses `@softure-ai/
4
4
  production, the version gets a line `verified in: <app>@<commit>` ([docs/05](../../docs/05-adoption-playbook.md),
5
5
  "Definition of done"). Versions before the first one below are described in their GitHub Releases (`mcp-access@x.y.z`).
6
6
 
7
+ ## 0.2.6
8
+
9
+ - A hook around each tool call (#804): `withToolErrors` and `actionTool` take optional `onToolCall`, `caller`
10
+ (`{ tokenId, clientName }`) and, for `withToolErrors`, `args`. The hook gets one `ToolCallRecord` per call: tool
11
+ name, token id, client name, argument names (never values), outcome (`succeeded` with an item count, `failed` with
12
+ the error code, `thrown` with the `safeError` code), start and duration. A failing hook is logged by kind and never
13
+ changes the answer. `findTokenClientName(ctx, tokenId)` (`/server`) gives the token's name. Migrate: an app that
14
+ wraps each tool's work inside `withToolErrors` to read the raw result and time it, and looks up
15
+ `mcp.access_tokens.name` itself, drops both and passes `{ caller, args, onToolCall }` instead. `actionTool` now
16
+ answers an error state through `withToolErrors`'s result path; the answer is the same.
17
+
7
18
  ## 0.2.5
8
19
 
9
20
  - `TokenManager` keeps keyboard focus (#590): when the issued token appears, focus moves to its heading
package/README.md CHANGED
@@ -177,6 +177,25 @@ if (canWrite) {
177
177
  `{ status: "error", error }` state is a tool error through the hints; otherwise the answer is `message` (text or
178
178
  `(state) => text`), else the state as JSON.
179
179
 
180
+ To keep a record of tool calls (a calls panel, usage figures), pass `onToolCall` with a `caller` built once per
181
+ request in the factory. The hook runs after each call with one record: `tool` (the `label`, else `"call"`),
182
+ `tokenId`, `clientName`, `argumentNames` (names only, never values), `outcome` (`succeeded` with `itemCount` for an
183
+ array value, `failed` with the result's error code, `thrown` with the `safeError` code, `null` for a
184
+ `PublicError`), `startedAt` and `durationMs`. The hook is awaited; when it throws, the failure is logged by kind and
185
+ the assistant gets the same answer. `findTokenClientName(ctx, tokenId)` gives the token's name (`null` for the stdio
186
+ id or a token that is gone).
187
+
188
+ ```ts
189
+ export async function createServer({ userId, canWrite, tokenId }: McpServerIdentity) {
190
+ const caller = { tokenId, clientName: await findTokenClientName(ctx, tokenId) };
191
+ const onToolCall = (record: ToolCallRecord) => saveToolCall(db, userId, record);
192
+ server.registerTool("list_orders", { inputSchema: { status: z.string() } }, (args) =>
193
+ withToolErrors(() => findOrders(db, userId, args), { label: "list_orders", caller, args, onToolCall }),
194
+ );
195
+ // actionTool(handler, { label: "place_order", caller, onToolCall }) passes its arguments itself.
196
+ }
197
+ ```
198
+
180
199
  ### Stdio
181
200
 
182
201
  A local assistant on the machine that holds the database can run the same factory over stdio, without a token:
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ export const MCP_RATE_LIMIT_BUCKETS = {
30
30
  export const mcpAccess = defineModule({
31
31
  manifest: {
32
32
  id: MODULE_ID,
33
- version: "0.2.5",
33
+ version: "0.2.6",
34
34
  dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
35
35
  dbSchema: "mcp",
36
36
  tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window"],
@@ -1,5 +1,5 @@
1
1
  import type { CallToolResult } from "@modelcontextprotocol/server";
2
- import { type ToolErrorHints } from "./tools.js";
2
+ import { type ToolCaller, type ToolCallHook, type ToolErrorHints } from "./tools.js";
3
3
  /** The action, called with the form. A `useActionState` action is passed as `(form) => action(INITIAL, form)`. */
4
4
  export type FormActionHandler = (formData: FormData) => unknown;
5
5
  export interface ActionToolOptions {
@@ -7,8 +7,12 @@ export interface ActionToolOptions {
7
7
  readonly message?: string | ((state: unknown) => string);
8
8
  /** Texts per error code, as in `withToolErrors`. */
9
9
  readonly hints?: ToolErrorHints;
10
- /** The tool's name in the log line. */
10
+ /** The tool's name in the log line and in the `onToolCall` record. */
11
11
  readonly label?: string;
12
+ /** Called once after each call with its record, as in `withToolErrors`. */
13
+ readonly onToolCall?: ToolCallHook;
14
+ /** Who called, for the record, as in `withToolErrors`. */
15
+ readonly caller?: ToolCaller;
12
16
  }
13
17
  /** The tool callback for `server.registerTool(name, { inputSchema }, actionTool(handler))`. */
14
18
  export declare function actionTool(handler: FormActionHandler, options?: ActionToolOptions): (args: Readonly<Record<string, unknown>>) => Promise<CallToolResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"action-tool.d.ts","sourceRoot":"","sources":["../../src/server/action-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAuD,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAEtG,kHAAkH;AAClH,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,0GAA0G;IAC1G,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC;IACzD,oDAAoD;IACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,GAAE,iBAAsB,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAa5J;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,QAAQ,CAS5E"}
1
+ {"version":3,"file":"action-tool.d.ts","sourceRoot":"","sources":["../../src/server/action-tool.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAA8B,KAAK,UAAU,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjH,kHAAkH;AAClH,MAAM,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC;AAEhE,MAAM,WAAW,iBAAiB;IAChC,0GAA0G;IAC1G,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,CAAC;IACzD,oDAAoD;IACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC;IACnC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;CAC9B;AAED,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,GAAE,iBAAsB,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,OAAO,CAAC,cAAc,CAAC,CAoB5J;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,QAAQ,CAS5E"}
@@ -1,16 +1,23 @@
1
- import { describeCode, toolError, toolResult, withToolErrors } from "./tools.js";
1
+ import { toolResult, withToolErrors } from "./tools.js";
2
2
  /** The tool callback for `server.registerTool(name, { inputSchema }, actionTool(handler))`. */
3
3
  export function actionTool(handler, options = {}) {
4
4
  const hints = options.hints ?? {};
5
5
  return (args) => withToolErrors(async () => {
6
6
  const state = await handler(toFormData(args));
7
7
  const error = readErrorCode(state);
8
+ // As a core result, so withToolErrors answers it through the hints and records its code.
8
9
  if (error !== null)
9
- return toolError(describeCode(error, hints));
10
+ return { ok: false, error };
10
11
  if (options.message === undefined)
11
12
  return toolResult(state);
12
13
  return toolResult(typeof options.message === "string" ? options.message : options.message(state));
13
- }, { hints, ...(options.label === undefined ? {} : { label: options.label }) });
14
+ }, {
15
+ hints,
16
+ args,
17
+ ...(options.label === undefined ? {} : { label: options.label }),
18
+ ...(options.onToolCall === undefined ? {} : { onToolCall: options.onToolCall }),
19
+ ...(options.caller === undefined ? {} : { caller: options.caller }),
20
+ });
14
21
  }
15
22
  /**
16
23
  * Arguments as a submitted form: strings as they are, numbers as text, `true` as `"on"` (a checked
@@ -1 +1 @@
1
- {"version":3,"file":"action-tool.js","sourceRoot":"","sources":["../../src/server/action-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action-tool.js","sourceRoot":"","sources":["../../src/server/action-tool.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,6 @@ export { getCodeChallenge, isPkceVerifierValid, isValidCodeChallenge, PKCE_METHO
13
13
  export { getMcpAccessMessages, getMcpAccessOptions, getMcpAccessRoutes, getMcpEndpointUrl, type McpAccessRoutes } from "./options.js";
14
14
  export { pruneMcpAccess, type PrunedMcpAccessRecords } from "./prune.js";
15
15
  export { deleteMcpAccessUserData, exportMcpAccessUserData, mcpAccessPrivacyContributor, type McpAccessUserData, } from "./privacy.js";
16
- export { ACCESS_TOKEN_PREFIX, hashAccessToken, isAccessTokenShape, issueAccessToken, listAccessTokens, pruneAccessTokens, revokeAccessToken, verifyAccessToken, type IssueAccessTokenInput, type IssueAccessTokenResult, type IssuedAccessToken, type McpAccessContext, type RevokeAccessTokenInput, type VerifiedAccessToken, } from "./tokens.js";
17
- export { toolError, toolResult, withToolErrors, type ToolErrorHints, type ToolErrorOptions } from "./tools.js";
16
+ export { ACCESS_TOKEN_PREFIX, hashAccessToken, isAccessTokenShape, issueAccessToken, listAccessTokens, pruneAccessTokens, findTokenClientName, revokeAccessToken, verifyAccessToken, type IssueAccessTokenInput, type IssueAccessTokenResult, type IssuedAccessToken, type McpAccessContext, type RevokeAccessTokenInput, type VerifiedAccessToken, } from "./tokens.js";
17
+ export { toolError, toolResult, withToolErrors, type ToolCaller, type ToolCallHook, type ToolCallOutcome, type ToolCallRecord, type ToolErrorHints, type ToolErrorOptions, } from "./tools.js";
18
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,6 @@ export { getCodeChallenge, isPkceVerifierValid, isValidCodeChallenge, PKCE_METHO
14
14
  export { getMcpAccessMessages, getMcpAccessOptions, getMcpAccessRoutes, getMcpEndpointUrl } from "./options.js";
15
15
  export { pruneMcpAccess } from "./prune.js";
16
16
  export { deleteMcpAccessUserData, exportMcpAccessUserData, mcpAccessPrivacyContributor, } from "./privacy.js";
17
- export { ACCESS_TOKEN_PREFIX, hashAccessToken, isAccessTokenShape, issueAccessToken, listAccessTokens, pruneAccessTokens, revokeAccessToken, verifyAccessToken, } from "./tokens.js";
18
- export { toolError, toolResult, withToolErrors } from "./tools.js";
17
+ export { ACCESS_TOKEN_PREFIX, hashAccessToken, isAccessTokenShape, issueAccessToken, listAccessTokens, pruneAccessTokens, findTokenClientName, revokeAccessToken, verifyAccessToken, } from "./tokens.js";
18
+ export { toolError, toolResult, withToolErrors, } from "./tools.js";
19
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,+FAA+F;AAC/F,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,eAAe,GAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkD,MAAM,kBAAkB,CAAC;AAC1G,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,wBAAwB,EACxB,+BAA+B,EAC/B,sBAAsB,GAGvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GASjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,kCAAkC,EAClC,mBAAmB,EACnB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,4BAA4B,EAC5B,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,2BAA2B,EAC3B,YAAY,EACZ,gCAAgC,EAChC,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,GAK7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,iBAAiB,EAA0C,MAAM,eAAe,CAAC;AACrI,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,uBAAuB,EAAyD,MAAM,uBAAuB,CAAC;AAC1L,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACrG,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAwB,MAAM,cAAc,CAAC;AACtI,OAAO,EAAE,cAAc,EAA+B,MAAM,YAAY,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,2BAA2B,GAE5B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAOlB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAA8C,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,+FAA+F;AAC/F,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,eAAe,GAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkD,MAAM,kBAAkB,CAAC;AAC1G,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,wBAAwB,EACxB,+BAA+B,EAC/B,sBAAsB,GAGvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,GASjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,kCAAkC,EAClC,mBAAmB,EACnB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,4BAA4B,EAC5B,+BAA+B,EAC/B,gCAAgC,EAChC,2BAA2B,EAC3B,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,2BAA2B,EAC3B,YAAY,EACZ,gCAAgC,EAChC,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,GAK7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,iBAAiB,EAA0C,MAAM,eAAe,CAAC;AACrI,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,uBAAuB,EAAyD,MAAM,uBAAuB,CAAC;AAC1L,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACrG,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,iBAAiB,EAAwB,MAAM,cAAc,CAAC;AACtI,OAAO,EAAE,cAAc,EAA+B,MAAM,YAAY,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,2BAA2B,GAE5B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAOlB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,SAAS,EACT,UAAU,EACV,cAAc,GAOf,MAAM,YAAY,CAAC"}
@@ -62,6 +62,11 @@ export interface VerifiedAccessToken {
62
62
  /** The OAuth grant the token was issued from; null for a hand-issued token. */
63
63
  readonly grantId: string | null;
64
64
  }
65
+ /**
66
+ * A token's name, the client it was issued for ("Laptop", an OAuth client's name), for a record of tool calls:
67
+ * `null` for an id that is not a stored token's (the stdio id, a pruned or unknown token).
68
+ */
69
+ export declare function findTokenClientName(ctx: McpAccessContext, tokenId: string): Promise<string | null>;
65
70
  /**
66
71
  * The identity behind a token, or null for anything unknown, revoked or expired: the caller cannot
67
72
  * tell which, so a guess learns nothing. The expiry sits in the query, so no code path can forget
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/server/tokens.ts"],"names":[],"mappings":"AAIA,OAAO,EAA0B,KAAK,GAAG,EAAE,KAAK,aAAa,EAAE,KAAK,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKtD,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;AAExD,0EAA0E;AAC1E,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAU7C,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEzD;AAYD,qGAAqG;AACrG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAGrG;AAED,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CAC1B;AAED,MAAM,MAAM,sBAAsB,GAC9B,EAAE,CAAC,iBAAiB,CAAC,GACrB,GAAG,CAAC,0BAA0B,GAAG,0BAA0B,GAAG,gCAAgC,CAAC,CAAC;AAEpG;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA4B3H;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAaxG;AAED,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAO5D;AAED,yCAAyC;AACzC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAwBjH;AAsBD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAM9E"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/server/tokens.ts"],"names":[],"mappings":"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"}
@@ -106,6 +106,16 @@ export async function revokeAccessToken(ctx, input) {
106
106
  .returning();
107
107
  return removed.length > 0 ? ok() : err("mcp-access.token_not_found");
108
108
  }
109
+ /**
110
+ * A token's name, the client it was issued for ("Laptop", an OAuth client's name), for a record of tool calls:
111
+ * `null` for an id that is not a stored token's (the stdio id, a pruned or unknown token).
112
+ */
113
+ export async function findTokenClientName(ctx, tokenId) {
114
+ if (!UUID_SHAPE.test(tokenId))
115
+ return null;
116
+ const [row] = await ctx.db.select({ name: accessTokens.name }).from(accessTokens).where(eq(accessTokens.id, tokenId));
117
+ return row?.name ?? null;
118
+ }
109
119
  /**
110
120
  * The identity behind a token, or null for anything unknown, revoked or expired: the caller cannot
111
121
  * tell which, so a guess learns nothing. The expiry sits in the query, so no code path can forget
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/server/tokens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/server/tokens.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,51 @@
1
1
  import { type CallToolResult } from "@modelcontextprotocol/server";
2
+ import { type CoreErrorCode } from "@softure-ai/core";
2
3
  /** What the assistant reads for an error code: the app's own text per code, e.g. `{ "orders.not_found": "No order with that number." }`. */
3
4
  export type ToolErrorHints = Readonly<Record<string, string>>;
4
5
  export interface ToolErrorOptions {
5
6
  /** Texts per error code; a code without one is answered as the code itself. */
6
7
  readonly hints?: ToolErrorHints;
7
- /** The tool's name in the log line. */
8
+ /** The tool's name in the log line and in the `onToolCall` record. */
8
9
  readonly label?: string;
10
+ /** Called once after each call with its record. Its failure is logged by kind and never changes the answer. */
11
+ readonly onToolCall?: ToolCallHook;
12
+ /** Who called, for the record: built once per request in the app's server factory. */
13
+ readonly caller?: ToolCaller;
14
+ /** The tool's arguments, for the record: only their names are read, never their values. */
15
+ readonly args?: Readonly<Record<string, unknown>>;
9
16
  }
17
+ /** The client behind a call: the token's id (`McpServerIdentity.tokenId`) and its name (`findTokenClientName`). */
18
+ export interface ToolCaller {
19
+ readonly tokenId: string;
20
+ readonly clientName: string | null;
21
+ }
22
+ /**
23
+ * How a call ended. `succeeded`: `itemCount` is the length of an array value, else `null`. `failed`: the
24
+ * result's error code, `null` for a `CallToolResult` the tool marked `isError` itself. `thrown`: the
25
+ * `safeError` code, `null` for a `PublicError` (a deliberate message, no code).
26
+ */
27
+ export type ToolCallOutcome = {
28
+ readonly kind: "succeeded";
29
+ readonly itemCount: number | null;
30
+ } | {
31
+ readonly kind: "failed";
32
+ readonly code: string | null;
33
+ } | {
34
+ readonly kind: "thrown";
35
+ readonly code: CoreErrorCode | null;
36
+ };
37
+ /** One tool call as the `onToolCall` hook sees it. */
38
+ export interface ToolCallRecord {
39
+ /** The tool's `label`, else `"call"`. */
40
+ readonly tool: string;
41
+ readonly tokenId: string | null;
42
+ readonly clientName: string | null;
43
+ readonly argumentNames: readonly string[];
44
+ readonly outcome: ToolCallOutcome;
45
+ readonly startedAt: Date;
46
+ readonly durationMs: number;
47
+ }
48
+ export type ToolCallHook = (record: ToolCallRecord) => unknown;
10
49
  /** A successful tool answer: a string as text, anything else as JSON text. */
11
50
  export declare function toolResult(value: unknown): CallToolResult;
12
51
  /** A failed tool answer the assistant reads and may act on. */
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAGrF,4IAA4I;AAC5I,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,uCAAuC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAQD,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAEzD;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAEzD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAMjH;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAE,cAAmB,GAAG,cAAc,CAItF;AAUD,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAExE"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAA8C,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElG,4IAA4I;AAC5I,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;IAChC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+GAA+G;IAC/G,QAAQ,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC;IACnC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAC7B,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD;AAED,mHAAmH;AACnH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACjE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,CAAC;AAErE,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC;AAQ/D,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAEzD;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAEzD;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAcjH;AA8BD,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,GAAE,cAAmB,GAAG,cAAc,CAItF;AAUD,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAExE"}
@@ -1,6 +1,7 @@
1
1
  // Tool results for the app's MCP server and the boundary that keeps failures safe: the assistant gets
2
2
  // a value, a `PublicError`'s message or a hint, never a thrown error's text (a failed query carries
3
- // its SQL and parameters). The log gets the error's kind only (`errorLogLabel`).
3
+ // its SQL and parameters). The log gets the error's kind only (`errorLogLabel`). An optional hook sees
4
+ // each call as a whole: which tool, which client, the outcome with its code, and how long it took.
4
5
  import { isCallToolResult } from "@modelcontextprotocol/server";
5
6
  import { errorLogLabel, getPublicMessage, safeError } from "@softure-ai/core";
6
7
  /** For failures the tool did not expect: what `safeError` makes of them, unless a hint replaces it. */
@@ -23,12 +24,49 @@ export function toolError(message) {
23
24
  * anything else is logged by kind and answered with the hint for its `safeError` code, else a fixed text.
24
25
  */
25
26
  export async function withToolErrors(work, options = {}) {
27
+ const startedAt = Date.now();
28
+ let answer;
29
+ let outcome;
26
30
  try {
27
- return answerValue(await work(), options.hints);
31
+ const value = await work();
32
+ answer = answerValue(value, options.hints);
33
+ outcome = describeValueOutcome(value);
28
34
  }
29
35
  catch (error) {
30
- return answerFailure(error, options);
36
+ answer = answerFailure(error, options);
37
+ outcome = { kind: "thrown", code: getPublicMessage(error) === null ? safeError(error).error : null };
31
38
  }
39
+ if (options.onToolCall !== undefined)
40
+ await reportToolCall(options, outcome, startedAt);
41
+ return answer;
42
+ }
43
+ async function reportToolCall(options, outcome, startedAt) {
44
+ const tool = options.label ?? "call";
45
+ const record = {
46
+ tool,
47
+ tokenId: options.caller?.tokenId ?? null,
48
+ clientName: options.caller?.clientName ?? null,
49
+ argumentNames: Object.keys(options.args ?? {}),
50
+ outcome,
51
+ startedAt: new Date(startedAt),
52
+ durationMs: Date.now() - startedAt,
53
+ };
54
+ try {
55
+ await options.onToolCall?.(record);
56
+ }
57
+ catch (error) {
58
+ console.error(`@softure-ai/mcp-access: the onToolCall hook failed for tool ${tool}: ${errorLogLabel(error)}`);
59
+ }
60
+ }
61
+ function describeValueOutcome(value) {
62
+ if (isCallToolResult(value))
63
+ return value.isError === true ? { kind: "failed", code: null } : { kind: "succeeded", itemCount: null };
64
+ if (isResult(value))
65
+ return value.ok ? countItems(value.value) : { kind: "failed", code: value.error };
66
+ return countItems(value);
67
+ }
68
+ function countItems(value) {
69
+ return { kind: "succeeded", itemCount: Array.isArray(value) ? value.length : null };
32
70
  }
33
71
  /** The answer for a value a tool or an action returned. */
34
72
  export function answerValue(value, hints = {}) {
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/server/tools.ts"],"names":[],"mappings":"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"}
package/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "mcp-access",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "dependsOn": { "security": "^0.2.0", "auth": "^0.2.0", "jobs": "^0.1.1?", "ops": "^0.2.0?" },
5
5
  "dbSchema": "mcp",
6
6
  "tables": ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softure-ai/mcp-access",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "SOFTURE AI MCP access module: hashed, scoped, expiring access tokens, a rate-limited Bearer endpoint around the app's MCP server factory, and a token page with client setup instructions for Next.js; tool result helpers with a safe error boundary, a stdio entry, a catalog parity check and the softure-mcp prune command.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -34,7 +34,7 @@ export const MCP_RATE_LIMIT_BUCKETS = {
34
34
  export const mcpAccess = defineModule({
35
35
  manifest: {
36
36
  id: MODULE_ID,
37
- version: "0.2.5",
37
+ version: "0.2.6",
38
38
  dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
39
39
  dbSchema: "mcp",
40
40
  tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window"],
@@ -1,7 +1,7 @@
1
1
  // A server action as a write tool: the tool's arguments become the form the action reads, so the tool
2
2
  // and the form share one validation path, and the action's error state becomes a tool error.
3
3
  import type { CallToolResult } from "@modelcontextprotocol/server";
4
- import { describeCode, toolError, toolResult, withToolErrors, type ToolErrorHints } from "./tools.js";
4
+ import { toolResult, withToolErrors, type ToolCaller, type ToolCallHook, type ToolErrorHints } from "./tools.js";
5
5
 
6
6
  /** The action, called with the form. A `useActionState` action is passed as `(form) => action(INITIAL, form)`. */
7
7
  export type FormActionHandler = (formData: FormData) => unknown;
@@ -11,8 +11,12 @@ export interface ActionToolOptions {
11
11
  readonly message?: string | ((state: unknown) => string);
12
12
  /** Texts per error code, as in `withToolErrors`. */
13
13
  readonly hints?: ToolErrorHints;
14
- /** The tool's name in the log line. */
14
+ /** The tool's name in the log line and in the `onToolCall` record. */
15
15
  readonly label?: string;
16
+ /** Called once after each call with its record, as in `withToolErrors`. */
17
+ readonly onToolCall?: ToolCallHook;
18
+ /** Who called, for the record, as in `withToolErrors`. */
19
+ readonly caller?: ToolCaller;
16
20
  }
17
21
 
18
22
  /** The tool callback for `server.registerTool(name, { inputSchema }, actionTool(handler))`. */
@@ -23,11 +27,18 @@ export function actionTool(handler: FormActionHandler, options: ActionToolOption
23
27
  async () => {
24
28
  const state = await handler(toFormData(args));
25
29
  const error = readErrorCode(state);
26
- if (error !== null) return toolError(describeCode(error, hints));
30
+ // As a core result, so withToolErrors answers it through the hints and records its code.
31
+ if (error !== null) return { ok: false, error };
27
32
  if (options.message === undefined) return toolResult(state);
28
33
  return toolResult(typeof options.message === "string" ? options.message : options.message(state));
29
34
  },
30
- { hints, ...(options.label === undefined ? {} : { label: options.label }) },
35
+ {
36
+ hints,
37
+ args,
38
+ ...(options.label === undefined ? {} : { label: options.label }),
39
+ ...(options.onToolCall === undefined ? {} : { onToolCall: options.onToolCall }),
40
+ ...(options.caller === undefined ? {} : { caller: options.caller }),
41
+ },
31
42
  );
32
43
  }
33
44
 
@@ -92,6 +92,7 @@ export {
92
92
  issueAccessToken,
93
93
  listAccessTokens,
94
94
  pruneAccessTokens,
95
+ findTokenClientName,
95
96
  revokeAccessToken,
96
97
  verifyAccessToken,
97
98
  type IssueAccessTokenInput,
@@ -101,4 +102,14 @@ export {
101
102
  type RevokeAccessTokenInput,
102
103
  type VerifiedAccessToken,
103
104
  } from "./tokens.js";
104
- export { toolError, toolResult, withToolErrors, type ToolErrorHints, type ToolErrorOptions } from "./tools.js";
105
+ export {
106
+ toolError,
107
+ toolResult,
108
+ withToolErrors,
109
+ type ToolCaller,
110
+ type ToolCallHook,
111
+ type ToolCallOutcome,
112
+ type ToolCallRecord,
113
+ type ToolErrorHints,
114
+ type ToolErrorOptions,
115
+ } from "./tools.js";
@@ -159,6 +159,16 @@ export interface VerifiedAccessToken {
159
159
  readonly grantId: string | null;
160
160
  }
161
161
 
162
+ /**
163
+ * A token's name, the client it was issued for ("Laptop", an OAuth client's name), for a record of tool calls:
164
+ * `null` for an id that is not a stored token's (the stdio id, a pruned or unknown token).
165
+ */
166
+ export async function findTokenClientName(ctx: McpAccessContext, tokenId: string): Promise<string | null> {
167
+ if (!UUID_SHAPE.test(tokenId)) return null;
168
+ const [row] = await ctx.db.select({ name: accessTokens.name }).from(accessTokens).where(eq(accessTokens.id, tokenId));
169
+ return row?.name ?? null;
170
+ }
171
+
162
172
  /**
163
173
  * The identity behind a token, or null for anything unknown, revoked or expired: the caller cannot
164
174
  * tell which, so a guess learns nothing. The expiry sits in the query, so no code path can forget
@@ -1,8 +1,9 @@
1
1
  // Tool results for the app's MCP server and the boundary that keeps failures safe: the assistant gets
2
2
  // a value, a `PublicError`'s message or a hint, never a thrown error's text (a failed query carries
3
- // its SQL and parameters). The log gets the error's kind only (`errorLogLabel`).
3
+ // its SQL and parameters). The log gets the error's kind only (`errorLogLabel`). An optional hook sees
4
+ // each call as a whole: which tool, which client, the outcome with its code, and how long it took.
4
5
  import { isCallToolResult, type CallToolResult } from "@modelcontextprotocol/server";
5
- import { errorLogLabel, getPublicMessage, safeError } from "@softure-ai/core";
6
+ import { errorLogLabel, getPublicMessage, safeError, type CoreErrorCode } from "@softure-ai/core";
6
7
 
7
8
  /** What the assistant reads for an error code: the app's own text per code, e.g. `{ "orders.not_found": "No order with that number." }`. */
8
9
  export type ToolErrorHints = Readonly<Record<string, string>>;
@@ -10,10 +11,46 @@ export type ToolErrorHints = Readonly<Record<string, string>>;
10
11
  export interface ToolErrorOptions {
11
12
  /** Texts per error code; a code without one is answered as the code itself. */
12
13
  readonly hints?: ToolErrorHints;
13
- /** The tool's name in the log line. */
14
+ /** The tool's name in the log line and in the `onToolCall` record. */
14
15
  readonly label?: string;
16
+ /** Called once after each call with its record. Its failure is logged by kind and never changes the answer. */
17
+ readonly onToolCall?: ToolCallHook;
18
+ /** Who called, for the record: built once per request in the app's server factory. */
19
+ readonly caller?: ToolCaller;
20
+ /** The tool's arguments, for the record: only their names are read, never their values. */
21
+ readonly args?: Readonly<Record<string, unknown>>;
15
22
  }
16
23
 
24
+ /** The client behind a call: the token's id (`McpServerIdentity.tokenId`) and its name (`findTokenClientName`). */
25
+ export interface ToolCaller {
26
+ readonly tokenId: string;
27
+ readonly clientName: string | null;
28
+ }
29
+
30
+ /**
31
+ * How a call ended. `succeeded`: `itemCount` is the length of an array value, else `null`. `failed`: the
32
+ * result's error code, `null` for a `CallToolResult` the tool marked `isError` itself. `thrown`: the
33
+ * `safeError` code, `null` for a `PublicError` (a deliberate message, no code).
34
+ */
35
+ export type ToolCallOutcome =
36
+ | { readonly kind: "succeeded"; readonly itemCount: number | null }
37
+ | { readonly kind: "failed"; readonly code: string | null }
38
+ | { readonly kind: "thrown"; readonly code: CoreErrorCode | null };
39
+
40
+ /** One tool call as the `onToolCall` hook sees it. */
41
+ export interface ToolCallRecord {
42
+ /** The tool's `label`, else `"call"`. */
43
+ readonly tool: string;
44
+ readonly tokenId: string | null;
45
+ readonly clientName: string | null;
46
+ readonly argumentNames: readonly string[];
47
+ readonly outcome: ToolCallOutcome;
48
+ readonly startedAt: Date;
49
+ readonly durationMs: number;
50
+ }
51
+
52
+ export type ToolCallHook = (record: ToolCallRecord) => unknown;
53
+
17
54
  /** For failures the tool did not expect: what `safeError` makes of them, unless a hint replaces it. */
18
55
  const DEFAULT_FAILURE_TEXT: ToolErrorHints = {
19
56
  "core.database_failed": "The database could not answer; try again later.",
@@ -37,11 +74,47 @@ export function toolError(message: string): CallToolResult {
37
74
  * anything else is logged by kind and answered with the hint for its `safeError` code, else a fixed text.
38
75
  */
39
76
  export async function withToolErrors(work: () => unknown, options: ToolErrorOptions = {}): Promise<CallToolResult> {
77
+ const startedAt = Date.now();
78
+ let answer: CallToolResult;
79
+ let outcome: ToolCallOutcome;
40
80
  try {
41
- return answerValue(await work(), options.hints);
81
+ const value = await work();
82
+ answer = answerValue(value, options.hints);
83
+ outcome = describeValueOutcome(value);
42
84
  } catch (error) {
43
- return answerFailure(error, options);
85
+ answer = answerFailure(error, options);
86
+ outcome = { kind: "thrown", code: getPublicMessage(error) === null ? safeError(error).error : null };
44
87
  }
88
+ if (options.onToolCall !== undefined) await reportToolCall(options, outcome, startedAt);
89
+ return answer;
90
+ }
91
+
92
+ async function reportToolCall(options: ToolErrorOptions, outcome: ToolCallOutcome, startedAt: number): Promise<void> {
93
+ const tool = options.label ?? "call";
94
+ const record: ToolCallRecord = {
95
+ tool,
96
+ tokenId: options.caller?.tokenId ?? null,
97
+ clientName: options.caller?.clientName ?? null,
98
+ argumentNames: Object.keys(options.args ?? {}),
99
+ outcome,
100
+ startedAt: new Date(startedAt),
101
+ durationMs: Date.now() - startedAt,
102
+ };
103
+ try {
104
+ await options.onToolCall?.(record);
105
+ } catch (error) {
106
+ console.error(`@softure-ai/mcp-access: the onToolCall hook failed for tool ${tool}: ${errorLogLabel(error)}`);
107
+ }
108
+ }
109
+
110
+ function describeValueOutcome(value: unknown): ToolCallOutcome {
111
+ if (isCallToolResult(value)) return value.isError === true ? { kind: "failed", code: null } : { kind: "succeeded", itemCount: null };
112
+ if (isResult(value)) return value.ok ? countItems(value.value) : { kind: "failed", code: value.error };
113
+ return countItems(value);
114
+ }
115
+
116
+ function countItems(value: unknown): ToolCallOutcome {
117
+ return { kind: "succeeded", itemCount: Array.isArray(value) ? value.length : null };
45
118
  }
46
119
 
47
120
  /** The answer for a value a tool or an action returned. */