@softure-ai/mcp-access 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +78 -0
  3. package/dist/index.d.ts +4 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/messages/en.d.ts +4 -0
  7. package/dist/messages/en.d.ts.map +1 -1
  8. package/dist/messages/en.js +4 -0
  9. package/dist/messages/en.js.map +1 -1
  10. package/dist/messages/index.d.ts +4 -0
  11. package/dist/messages/index.d.ts.map +1 -1
  12. package/dist/server/endpoint.d.ts +8 -1
  13. package/dist/server/endpoint.d.ts.map +1 -1
  14. package/dist/server/endpoint.js +54 -7
  15. package/dist/server/endpoint.js.map +1 -1
  16. package/dist/server/index.d.ts +2 -1
  17. package/dist/server/index.d.ts.map +1 -1
  18. package/dist/server/index.js +1 -0
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server/request-diagnostics.d.ts +59 -0
  21. package/dist/server/request-diagnostics.d.ts.map +1 -0
  22. package/dist/server/request-diagnostics.js +84 -0
  23. package/dist/server/request-diagnostics.js.map +1 -0
  24. package/dist/server/server-factory.d.ts +2 -1
  25. package/dist/server/server-factory.d.ts.map +1 -1
  26. package/dist/server/server-factory.js +16 -10
  27. package/dist/server/server-factory.js.map +1 -1
  28. package/dist/server/server-info.d.ts +30 -2
  29. package/dist/server/server-info.d.ts.map +1 -1
  30. package/dist/server/server-info.js +28 -6
  31. package/dist/server/server-info.js.map +1 -1
  32. package/dist/server/tool-list.d.ts +2 -0
  33. package/dist/server/tool-list.d.ts.map +1 -1
  34. package/dist/server/tool-list.js +6 -2
  35. package/dist/server/tool-list.js.map +1 -1
  36. package/module.json +1 -1
  37. package/package.json +1 -1
  38. package/src/index.ts +1 -1
  39. package/src/messages/en.ts +6 -0
  40. package/src/server/endpoint.ts +73 -6
  41. package/src/server/index.ts +3 -0
  42. package/src/server/request-diagnostics.ts +130 -0
  43. package/src/server/server-factory.ts +32 -12
  44. package/src/server/server-info.ts +60 -8
  45. package/src/server/tool-list.ts +7 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-diagnostics.js","sourceRoot":"","sources":["../../src/server/request-diagnostics.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,qHAAqH;AACrH,iHAAiH;AACjH,8GAA8G;AAC9G,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAiDjD,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AACvD,MAAM,aAAa,GAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;AAExG,qGAAqG;AACrG,MAAM,UAAU,sBAAsB,CAAC,KAAa;IAClD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3G,OAAO,KAAK,CAAC,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;AACxF,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,OAAgB,EAAE,QAAgB;IACzE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC9E,MAAM,UAAU,GAAG,EAAE,GAAG,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC;IACxE,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,CAAC;IACpE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,QAAQ;QAAE,OAAO,UAAU,CAAC;IACrE,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;QAC1C,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ;YAAE,OAAO,UAAU,CAAC;QAC9C,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,2FAA2F;QAC3F,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACnE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC;IAE1E,MAAM,MAAM,GAAG,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO,EAAE,GAAG,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACvH,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,EAAE,GAAG,UAAU,EAAE,MAAM,EAAE,CAAC;IACnE,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1E,MAAM,MAAM,GACV,UAAU,KAAK,IAAI;QACjB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC;YACE,IAAI,EAAE,OAAO,UAAU,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;YACxF,OAAO,EAAE,OAAO,UAAU,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;SAClG,CAAC;IACR,MAAM,eAAe,GAAG,OAAO,MAAM,CAAC,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,sBAAsB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;IACpI,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACzD,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,qBAAqB,CAAC,WAA8C;IAClF,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACzE,MAAM,KAAK,GAAG,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC;IACjE,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,IAAI,CAAC;YACH,KAAK,CAAC,KAAK,CAAC,CAAC;QACf,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,gEAAgE,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxG,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAA2B;IAChD,OAAO,CAAC,IAAI,CAAC,uCAAuC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED,uFAAuF;AACvF,SAAS,kBAAkB,CAAC,SAAiB;IAC3C,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
@@ -22,7 +22,8 @@ export interface McpServerFactoryOptions {
22
22
  readonly strictToolInput?: boolean | StrictToolInputOptions;
23
23
  /**
24
24
  * Adds the read-only `get_server_info` tool for every access level: the build info (pass `readBuildInfo` of
25
- * `@softure-ai/ops/server`) with the served name and version. Off by default.
25
+ * `@softure-ai/ops/server`) with the served name and version. Off by default. With `tools: true` it also answers the
26
+ * served tool contract of the caller's access level, taken from the measured list (#1078).
26
27
  */
27
28
  readonly serverInfoTool?: ServerInfoToolOptions;
28
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server-factory.d.ts","sourceRoot":"","sources":["../../src/server/server-factory.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAA0B,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGtF,MAAM,WAAW,uBAAuB;IACtC,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACpF,yGAAyG;IACzG,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC5D;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACjD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,yBAAyB,CAqClG"}
1
+ {"version":3,"file":"server-factory.d.ts","sourceRoot":"","sources":["../../src/server/server-factory.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAA0B,KAAK,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAGtF,MAAM,WAAW,uBAAuB;IACtC,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC;IACpF,yGAAyG;IACzG,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;IAC5D;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,qBAAqB,CAAC;CACjD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,yBAAyB,CA4ClG"}
@@ -11,7 +11,7 @@
11
11
  import { McpServer } from "@modelcontextprotocol/server";
12
12
  import { withStrictToolInput } from "./strict-input.js";
13
13
  import { registerServerInfoTool } from "./server-info.js";
14
- import { measureToolList } from "./tool-list.js";
14
+ import { describeToolList, listRecordedTools } from "./tool-list.js";
15
15
  /**
16
16
  * An `McpServerFactory` whose servers carry the tool list's version for the identity's access level. Its
17
17
  * `toolListVersion(identity)` reads that version without building a server, so `createMcpEndpoint` ties each session
@@ -19,13 +19,18 @@ import { measureToolList } from "./tool-list.js";
19
19
  */
20
20
  export function createMcpServerFactory(options) {
21
21
  const strictOptions = options.strictToolInput === true ? {} : options.strictToolInput === false ? undefined : options.strictToolInput;
22
- // The served version reaches `get_server_info` here; the recording server registers it with a placeholder, since
23
- // its handler never runs there and the version is not part of the listed tool.
24
- const registerTools = async (server, identity, version = "") => {
22
+ // The served version and the measured tools reach `get_server_info` here; the recording server registers it with a
23
+ // placeholder version and no tools, since its handler never runs there and neither is part of the listed tool.
24
+ const registerTools = async (server, identity, served) => {
25
25
  const target = strictOptions === undefined ? server : withStrictToolInput(server, strictOptions);
26
26
  await options.registerTools(target, identity);
27
- if (options.serverInfoTool !== undefined)
28
- registerServerInfoTool(target, { ...options.serverInfoTool, server: { name: options.name, version } });
27
+ if (options.serverInfoTool !== undefined) {
28
+ registerServerInfoTool(target, {
29
+ ...options.serverInfoTool,
30
+ server: { name: options.name, version: served?.version ?? "" },
31
+ servedTools: async () => (served === undefined ? [] : (await served.measure()).tools),
32
+ });
33
+ }
29
34
  };
30
35
  const measurements = new Map();
31
36
  // The promise is cached, so parallel first requests measure once; a failed measurement is dropped so
@@ -34,11 +39,12 @@ export function createMcpServerFactory(options) {
34
39
  const cached = measurements.get(identity.canWrite);
35
40
  if (cached !== undefined)
36
41
  return cached;
37
- const measurement = measureToolList((server) => registerTools(server, identity), {
38
- ...(options.release === undefined ? {} : { release: options.release }),
42
+ const release = options.release;
43
+ const measurement = listRecordedTools((server) => registerTools(server, identity), {
44
+ ...(release === undefined ? {} : { release }),
39
45
  name: options.name,
40
46
  ...(options.serverOptions === undefined ? {} : { serverOptions: options.serverOptions }),
41
- });
47
+ }).then((tools) => ({ ...describeToolList(tools, release), tools }));
42
48
  measurements.set(identity.canWrite, measurement);
43
49
  void measurement.catch(() => measurements.delete(identity.canWrite));
44
50
  return measurement;
@@ -47,7 +53,7 @@ export function createMcpServerFactory(options) {
47
53
  const factory = async (identity) => {
48
54
  const version = await toolListVersion(identity);
49
55
  const server = new McpServer({ name: options.name, version, ...(options.title === undefined ? {} : { title: options.title }) }, options.serverOptions);
50
- await registerTools(server, identity, version);
56
+ await registerTools(server, identity, { version, measure: () => measure(identity) });
51
57
  return server;
52
58
  };
53
59
  return Object.assign(factory, { toolListVersion });
@@ -1 +1 @@
1
- {"version":3,"file":"server-factory.js","sourceRoot":"","sources":["../../src/server/server-factory.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server-factory.js","sourceRoot":"","sources":["../../src/server/server-factory.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { McpServer } from "@modelcontextprotocol/server";
2
+ import type { ServedTool } from "./tool-list.js";
2
3
  export declare const SERVER_INFO_TOOL_NAME = "get_server_info";
3
4
  /** The build info of `@softure-ai/ops` (`readBuildInfo()`), typed by shape so mcp-access does not import ops. */
4
5
  export interface McpBuildInfo {
@@ -12,9 +13,20 @@ export interface ServerInfoToolOptions {
12
13
  readonly buildInfo: () => McpBuildInfo | Promise<McpBuildInfo>;
13
14
  /** The changelog the build info route answers, when the app passes one there. Only what is public. */
14
15
  readonly changelog?: () => unknown;
16
+ /**
17
+ * Also answers the served tool contract (`tools`), with an optional `name` input that narrows it to one tool. Turning
18
+ * it on changes the tool's input schema, so the version changes once. Default: off.
19
+ */
20
+ readonly tools?: boolean;
15
21
  /** Default: `serverInfoTool.description` of the module dictionary. */
16
22
  readonly description?: string;
17
23
  }
24
+ /** One served tool's contract, exactly as `tools/list` answers it. */
25
+ export interface ServedToolContract {
26
+ readonly name: string;
27
+ readonly description?: unknown;
28
+ readonly inputSchema: unknown;
29
+ }
18
30
  /** What `initialize` answers as `serverInfo`. */
19
31
  export interface ServedServerInfo {
20
32
  readonly name: string;
@@ -23,12 +35,28 @@ export interface ServedServerInfo {
23
35
  export interface RegisterServerInfoToolOptions extends ServerInfoToolOptions {
24
36
  /** The name and version the server answers at `initialize`; `createMcpServerFactory` passes them in. */
25
37
  readonly server: ServedServerInfo;
38
+ /**
39
+ * The tools the caller's `tools/list` answers, read when `tools` is on. `createMcpServerFactory` passes its measured
40
+ * list; a hand-built server passes `() => listServedTools(createServer)` for the caller's access level.
41
+ */
42
+ readonly servedTools?: () => readonly ServedTool[] | Promise<readonly ServedTool[]>;
43
+ }
44
+ /** The contract part of the answer, with `tools` on. */
45
+ export interface ServerInfoToolsAnswer {
46
+ /** Tells the model that the server's contract wins over its own copy. */
47
+ readonly toolsHint: string;
48
+ readonly tools: readonly ServedToolContract[];
49
+ /** Every served tool's name, when `name` matched none. */
50
+ readonly toolNames?: readonly string[];
26
51
  }
27
52
  /** The tool's answer: the served name and version, the build info and, with a provider, the changelog. */
28
53
  export type ServerInfoAnswer = McpBuildInfo & {
29
54
  readonly server: ServedServerInfo;
30
55
  readonly changelog?: unknown;
31
- };
32
- /** Registers `get_server_info`: no input fields, read only. A failing `buildInfo` reaches the SDK, which answers a tool error. */
56
+ } & Partial<ServerInfoToolsAnswer>;
57
+ /**
58
+ * Registers `get_server_info`, read only: no input fields, or an optional `name` with `tools` on. A failing `buildInfo`
59
+ * reaches the SDK, which answers a tool error.
60
+ */
33
61
  export declare function registerServerInfoTool(server: McpServer, options: RegisterServerInfoToolOptions): void;
34
62
  //# sourceMappingURL=server-info.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-info.d.ts","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAM9D,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD,iHAAiH;AACjH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,2GAA2G;IAC3G,QAAQ,CAAC,SAAS,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,sGAAsG;IACtG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IAC1E,wGAAwG;IACxG,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;CACnC;AAED,0GAA0G;AAC1G,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAElH,kIAAkI;AAClI,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAWtG"}
1
+ {"version":3,"file":"server-info.d.ts","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAI9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AAEvD,iHAAiH;AACjH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,qBAAqB;IACpC,2GAA2G;IAC3G,QAAQ,CAAC,SAAS,EAAE,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC/D,sGAAsG;IACtG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,sEAAsE;AACtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IAC1E,wGAAwG;IACxG,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;CACrF;AAED,wDAAwD;AACxD,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC9C,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,0GAA0G;AAC1G,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AAEnJ;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,6BAA6B,GAAG,IAAI,CAoBtG"}
@@ -3,20 +3,42 @@ import { z } from "zod";
3
3
  import { en } from "../messages/en.js";
4
4
  import { toolResult } from "./tools.js";
5
5
  export const SERVER_INFO_TOOL_NAME = "get_server_info";
6
- /** Registers `get_server_info`: no input fields, read only. A failing `buildInfo` reaches the SDK, which answers a tool error. */
6
+ /**
7
+ * Registers `get_server_info`, read only: no input fields, or an optional `name` with `tools` on. A failing `buildInfo`
8
+ * reaches the SDK, which answers a tool error.
9
+ */
7
10
  export function registerServerInfoTool(server, options) {
8
- server.registerTool(SERVER_INFO_TOOL_NAME, {
9
- description: options.description ?? en.serverInfoTool.description,
11
+ const annotations = { readOnlyHint: true, idempotentHint: true, openWorldHint: false };
12
+ const description = options.description ?? (options.tools === true ? en.serverInfoTool.descriptionWithTools : en.serverInfoTool.description);
13
+ if (options.tools !== true) {
10
14
  // An empty object rather than no schema, so strict input refuses a field sent to it.
11
- inputSchema: z.object({}),
12
- annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
13
- }, async () => toolResult(await readServerInfo(options)));
15
+ server.registerTool(SERVER_INFO_TOOL_NAME, { description, inputSchema: z.object({}), annotations }, async () => toolResult(await readServerInfo(options)));
16
+ return;
17
+ }
18
+ const readServedTools = options.servedTools;
19
+ if (readServedTools === undefined) {
20
+ throw new Error("@softure-ai/mcp-access: get_server_info with tools: true needs servedTools, e.g. () => listServedTools(createServer)");
21
+ }
22
+ server.registerTool(SERVER_INFO_TOOL_NAME, { description, inputSchema: z.object({ name: z.string().optional().describe(en.serverInfoTool.nameInputDescription) }), annotations }, async ({ name }) => {
23
+ const answer = await readServerInfo(options);
24
+ return toolResult({ ...answer, ...describeToolContract(await readServedTools(), name) });
25
+ });
14
26
  }
15
27
  async function readServerInfo(options) {
16
28
  const { release, commit, builtAt, startedAt } = await options.buildInfo();
17
29
  const answer = { server: { name: options.server.name, version: options.server.version }, release, commit, builtAt, startedAt };
18
30
  return options.changelog === undefined ? answer : { ...answer, changelog: await readChangelog(options.changelog) };
19
31
  }
32
+ /** The contract of every served tool, or of the one named; an unknown name answers no tool and every name. */
33
+ function describeToolContract(served, name) {
34
+ const tools = served.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema }));
35
+ if (name === undefined)
36
+ return { toolsHint: en.serverInfoTool.toolsHint, tools };
37
+ const named = tools.filter((tool) => tool.name === name);
38
+ if (named.length > 0)
39
+ return { toolsHint: en.serverInfoTool.toolsHint, tools: named };
40
+ return { toolsHint: en.serverInfoTool.unknownToolHint, tools: [], toolNames: tools.map((tool) => tool.name).sort() };
41
+ }
20
42
  /** As the build info route: a failing provider answers `null` and logs the error class, so the build info still answers. */
21
43
  async function readChangelog(provider) {
22
44
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"server-info.js","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,EAAE,EAAE,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,iBAAiB,CAAC;AAiCvD,kIAAkI;AAClI,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,OAAsC;IAC9F,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,cAAc,CAAC,WAAW;QACjE,qFAAqF;QACrF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAChF,EACD,KAAK,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC,CACtD,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,OAAsC;IAClE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;IAC1E,MAAM,MAAM,GAAqB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IACjJ,OAAO,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;AACrH,CAAC;AAED,4HAA4H;AAC5H,KAAK,UAAU,aAAa,CAAC,QAAuB;IAClD,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,QAAQ,EAAE,CAAC,IAAI,IAAI,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mDAAmD,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"server-info.js","sourceRoot":"","sources":["../../src/server/server-info.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,8 @@ export interface MeasureToolListOptions {
26
26
  * description, annotations or input or output schema changes the version; the order of registration does not.
27
27
  */
28
28
  export declare function measureToolList(registerTools: RegisterTools, options?: MeasureToolListOptions): Promise<ToolListMeasurement>;
29
+ /** The tools as `tools/list` answers them, registered on a recording server shaped like the served one. */
30
+ export declare function listRecordedTools(registerTools: RegisterTools, options?: MeasureToolListOptions): Promise<ServedTool[]>;
29
31
  /** The version and count for a listed tool set. */
30
32
  export declare function describeToolList(tools: readonly ServedTool[], release?: string): ToolListMeasurement;
31
33
  /** The first 12 hex digits of a sha256 over the tools in name order, each as canonical JSON (keys sorted at every level). */
@@ -1 +1 @@
1
- {"version":3,"file":"tool-list.d.ts","sourceRoot":"","sources":["../../src/server/tool-list.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,SAAS,EAAoB,KAAK,gBAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEjI,2CAA2C;AAC3C,eAAO,MAAM,yBAAyB,UAAU,CAAC;AAMjD,0EAA0E;AAC1E,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,mHAAmH;AACnH,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAMtI;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,GAAE,MAAkC,GAAG,mBAAmB,CAG/H;AAED,6HAA6H;AAC7H,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAGxE;AAED,wJAAwJ;AACxJ,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAgBjI"}
1
+ {"version":3,"file":"tool-list.d.ts","sourceRoot":"","sources":["../../src/server/tool-list.ts"],"names":[],"mappings":"AAMA,OAAO,EAAoB,SAAS,EAAoB,KAAK,gBAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAEjI,2CAA2C;AAC3C,eAAO,MAAM,yBAAyB,UAAU,CAAC;AAMjD,0EAA0E;AAC1E,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,mHAAmH;AACnH,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,QAAQ,CAAC,aAAa,CAAC,EAAE,gBAAgB,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAItI;AAED,2GAA2G;AAC3G,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAIjI;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,OAAO,GAAE,MAAkC,GAAG,mBAAmB,CAG/H;AAED,6HAA6H;AAC7H,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAGxE;AAED,wJAAwJ;AACxJ,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAgBjI"}
@@ -18,9 +18,13 @@ const RELEASE_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
18
18
  export async function measureToolList(registerTools, options = {}) {
19
19
  const release = options.release ?? DEFAULT_TOOL_LIST_RELEASE;
20
20
  assertRelease(release);
21
- const server = new McpServer({ name: options.name ?? "tool-list", version: release }, options.serverOptions);
21
+ return describeToolList(await listRecordedTools(registerTools, options), release);
22
+ }
23
+ /** The tools as `tools/list` answers them, registered on a recording server shaped like the served one. */
24
+ export async function listRecordedTools(registerTools, options = {}) {
25
+ const server = new McpServer({ name: options.name ?? "tool-list", version: options.release ?? DEFAULT_TOOL_LIST_RELEASE }, options.serverOptions);
22
26
  await registerTools(server);
23
- return describeToolList(await listServedTools(() => server), release);
27
+ return listServedTools(() => server);
24
28
  }
25
29
  /** The version and count for a listed tool set. */
26
30
  export function describeToolList(tools, release = DEFAULT_TOOL_LIST_RELEASE) {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-list.js","sourceRoot":"","sources":["../../src/server/tool-list.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-list.js","sourceRoot":"","sources":["../../src/server/tool-list.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.5.0",
3
+ "version": "0.7.0",
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", "used_confirmations", "operation_tasks"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softure-ai/mcp-access",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
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
@@ -51,7 +51,7 @@ export const API_TOKEN_RATE_LIMIT_BUCKETS = {
51
51
  export const mcpAccess = defineModule({
52
52
  manifest: {
53
53
  id: MODULE_ID,
54
- version: "0.5.0",
54
+ version: "0.7.0",
55
55
  dependsOn: { security: "^0.2.0", auth: "^0.2.0", jobs: "^0.1.1?", ops: "^0.2.0?" },
56
56
  dbSchema: "mcp",
57
57
  tables: ["access_tokens", "oauth_clients", "oauth_authorization_codes", "oauth_grants", "oauth_registration_window", "used_confirmations", "operation_tasks"],
@@ -129,6 +129,12 @@ export const en = {
129
129
  serverInfoTool: {
130
130
  description:
131
131
  "Tells which build of this server answers: its name and version (the version changes whenever a tool changes), the release, the commit, when it was built and started, and the changelog when the app publishes one. Use it to check that a change is live.",
132
+ descriptionWithTools:
133
+ "Tells which build of this server answers (its name and version, the release, the commit, when it was built and started, the changelog when the app publishes one) and the current description and input schema of every tool it serves you. Use it to check that a change is live, and read a tool's contract here when a call is refused or your copy may be out of date.",
134
+ nameInputDescription: "Optional: one tool's name, to answer only that tool's current description and input schema.",
135
+ toolsHint:
136
+ "If your copy of a tool's schema or description differs from `tools` here, the server's is current: build calls from it.",
137
+ unknownToolHint: "No served tool has that name; `toolNames` lists every tool this server serves to you.",
132
138
  },
133
139
  operations: {
134
140
  statusToolDescription:
@@ -25,9 +25,19 @@ import {
25
25
  isInitializeRequest,
26
26
  isToolListSessionCurrent,
27
27
  MCP_SESSION_ID_HEADER,
28
+ readToolListSessionVersion,
28
29
  rewriteInitializeAnswer,
29
30
  } from "./tool-list-session.js";
30
31
  import { isWritingEnabled } from "./writes-switch.js";
32
+ import {
33
+ createDiagnosticsSink,
34
+ readJsonRpcSummary,
35
+ sanitizeDiagnosticText,
36
+ type JsonRpcSummary,
37
+ type McpRequestDiagnostic,
38
+ type McpRequestDiagnostics,
39
+ type McpSessionState,
40
+ } from "./request-diagnostics.js";
31
41
 
32
42
  export { MCP_READ_SCOPE, MCP_WRITE_SCOPE };
33
43
 
@@ -60,6 +70,20 @@ export interface McpEndpointOptions {
60
70
  * `toolListVersion` (`createMcpServerFactory`). Without either, the endpoint issues no session id.
61
71
  */
62
72
  readonly toolListVersion?: ToolListVersionReader;
73
+ /**
74
+ * Request diagnostics (#1066), off by default: `true` logs one `console.info` line per request, a function receives
75
+ * each entry. An entry holds the JSON-RPC method, the tool name, the session state, the served tool list version,
76
+ * the status and the client's `clientInfo` on `initialize`; never a token, body, argument value or identity.
77
+ */
78
+ readonly diagnostics?: McpRequestDiagnostics;
79
+ }
80
+
81
+ /** What serving a request found out, for the diagnostics. */
82
+ interface SessionTrace {
83
+ session: McpSessionState;
84
+ sessionVersion: string | null;
85
+ toolListVersion: string | null;
86
+ sessionIssued: boolean;
63
87
  }
64
88
 
65
89
  /** Serves one request to the MCP endpoint. */
@@ -71,8 +95,9 @@ export type McpEndpoint = (ctx: McpAccessContext, request: Request) => Promise<R
71
95
  * (`responseMode: "json"`): a stream would add proxy buffering and timeouts for no tool that needs
72
96
  * it, and mid-call notifications are dropped.
73
97
  */
74
- export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpointOptions): McpEndpoint {
98
+ export function createMcpEndpoint({ createServer, toolListVersion, diagnostics }: McpEndpointOptions): McpEndpoint {
75
99
  const readToolListVersion = toolListVersion ?? getFactoryToolListVersion(createServer);
100
+ const report = createDiagnosticsSink(diagnostics);
76
101
  const handler = createMcpHandler(
77
102
  (requestContext) => createServer(readIdentity(requestContext.authInfo)),
78
103
  {
@@ -83,6 +108,17 @@ export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpoint
83
108
  );
84
109
 
85
110
  return async (ctx, request) => {
111
+ if (report === undefined) return serve(ctx, request, null);
112
+ const trace: SessionTrace = { session: "unchecked", sessionVersion: null, toolListVersion: null, sessionIssued: false };
113
+ // Read before serving: the SDK consumes the body. Only the method, tool name and clientInfo are kept.
114
+ const summary = await readJsonRpcSummary(request, MAX_MCP_REQUEST_BYTES);
115
+ const response = await serve(ctx, request, trace);
116
+ report(createDiagnostic(request, summary, trace, response.status));
117
+ return response;
118
+ };
119
+
120
+ async function serve(ctx: McpAccessContext, request: Request, trace: SessionTrace | null): Promise<Response> {
121
+ if (trace !== null && !request.headers.has(MCP_SESSION_ID_HEADER)) trace.session = "none";
86
122
  assertRateLimitBucket(ctx);
87
123
  const client = identifyClient(ctx, request.headers);
88
124
  if (!client.ok) return Response.json({ error: "client_unidentified" }, { status: 400, headers: NO_STORE });
@@ -105,15 +141,15 @@ export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpoint
105
141
 
106
142
  const authInfo = await authenticate(ctx, request);
107
143
  if (authInfo instanceof Response) return authInfo;
108
- return serveInSession(request, authInfo);
109
- };
144
+ return serveInSession(request, authInfo, trace);
145
+ }
110
146
 
111
147
  /**
112
148
  * Sessions tied to the tool list version (#1055): a session from another version (a release changed a tool, or the
113
149
  * access level changed) answers 404, so the client initializes again and lists the tools again; `initialize` gets a
114
150
  * new session id. A request without a session id is served as it always was.
115
151
  */
116
- async function serveInSession(request: Request, authInfo: AuthInfo): Promise<Response> {
152
+ async function serveInSession(request: Request, authInfo: AuthInfo, trace: SessionTrace | null): Promise<Response> {
117
153
  const sessionId = request.headers.get(MCP_SESSION_ID_HEADER);
118
154
  const isInitialize = sessionId === null && (await isInitializeRequest(request, MAX_MCP_REQUEST_BYTES));
119
155
  if (readToolListVersion === undefined || (sessionId === null && !isInitialize)) {
@@ -129,13 +165,44 @@ export function createMcpEndpoint({ createServer, toolListVersion }: McpEndpoint
129
165
  const response = await handler.fetch(request, { authInfo });
130
166
  return isInitialize ? rewriteInitializeAnswer(response, null) : response;
131
167
  }
168
+ if (trace !== null) trace.toolListVersion = version;
132
169
  if (sessionId !== null) {
133
- return isToolListSessionCurrent(sessionId, version) ? handler.fetch(request, { authInfo }) : createSessionRenewalResponse();
170
+ if (isToolListSessionCurrent(sessionId, version)) {
171
+ if (trace !== null) trace.session = "current";
172
+ return handler.fetch(request, { authInfo });
173
+ }
174
+ if (trace !== null) recordRenewedSession(trace, sessionId);
175
+ return createSessionRenewalResponse();
134
176
  }
135
- return rewriteInitializeAnswer(await handler.fetch(request, { authInfo }), createToolListSessionId(version));
177
+ const response = await rewriteInitializeAnswer(await handler.fetch(request, { authInfo }), createToolListSessionId(version));
178
+ if (trace !== null) trace.sessionIssued = response.headers.has(MCP_SESSION_ID_HEADER);
179
+ return response;
136
180
  }
137
181
  }
138
182
 
183
+ /** A session answered 404: stale when the id carries a version, not issued by the endpoint otherwise. */
184
+ function recordRenewedSession(trace: SessionTrace, sessionId: string): void {
185
+ const sessionVersion = readToolListSessionVersion(sessionId);
186
+ trace.session = sessionVersion === null ? "not_issued" : "stale";
187
+ trace.sessionVersion = sessionVersion === null ? null : sanitizeDiagnosticText(sessionVersion);
188
+ }
189
+
190
+ /** The diagnostics entry of one served request. */
191
+ function createDiagnostic(request: Request, summary: JsonRpcSummary, trace: SessionTrace, status: number): McpRequestDiagnostic {
192
+ return {
193
+ httpMethod: request.method,
194
+ method: summary.method,
195
+ tool: summary.tool,
196
+ session: trace.session,
197
+ sessionVersion: trace.sessionVersion,
198
+ toolListVersion: trace.toolListVersion,
199
+ sessionIssued: trace.sessionIssued,
200
+ status,
201
+ client: summary.client,
202
+ protocolVersion: summary.protocolVersion,
203
+ };
204
+ }
205
+
139
206
  /** The factory's own version reader, when it has one (`createMcpServerFactory`). */
140
207
  function getFactoryToolListVersion(factory: McpServerFactory | VersionedMcpServerFactory): ToolListVersionReader | undefined {
141
208
  return "toolListVersion" in factory && typeof factory.toolListVersion === "function" ? factory.toolListVersion : undefined;
@@ -143,6 +143,8 @@ export {
143
143
  type RegisterServerInfoToolOptions,
144
144
  type ServedServerInfo,
145
145
  type ServerInfoAnswer,
146
+ type ServerInfoToolsAnswer,
147
+ type ServedToolContract,
146
148
  type ServerInfoToolOptions,
147
149
  } from "./server-info.js";
148
150
  export { toStrictToolInput, withStrictToolInput, type RenamedFields, type StrictToolInputMessages, type StrictToolInputOptions } from "./strict-input.js";
@@ -163,6 +165,7 @@ export {
163
165
  MCP_SESSION_ID_HEADER,
164
166
  readToolListSessionVersion,
165
167
  } from "./tool-list-session.js";
168
+ export { type McpRequestDiagnostic, type McpRequestDiagnostics, type McpSessionState } from "./request-diagnostics.js";
166
169
  export {
167
170
  toolError,
168
171
  toolResult,
@@ -0,0 +1,130 @@
1
+ // Opt-in request diagnostics for the MCP endpoint (#1066). A hosted client can keep a stale tool list although the
2
+ // server serves the current one, and nothing showed what the client actually sends. One entry per request says which
3
+ // JSON-RPC method came, in which session state, with which answer. No token, body, argument value, session id or
4
+ // user identity is ever part of an entry; client-supplied strings are cut and stripped of control characters.
5
+ import { errorLogLabel } from "@softure-ai/core";
6
+
7
+ /** How a request's `Mcp-Session-Id` relates to the tool list version (#1055). */
8
+ export type McpSessionState =
9
+ /** No session id came with the request. */
10
+ | "none"
11
+ /** The session carries the current version and was served. */
12
+ | "current"
13
+ /** The session carries another version and was answered 404, so the client should initialize again. */
14
+ | "stale"
15
+ /** The session id is not one the endpoint issues; answered 404 like a stale one. */
16
+ | "not_issued"
17
+ /** A session id came, but it was not checked (refused before authentication, or no version to check against). */
18
+ | "unchecked";
19
+
20
+ /** One request as the diagnostics see it. */
21
+ export interface McpRequestDiagnostic {
22
+ /** The HTTP method. */
23
+ readonly httpMethod: string;
24
+ /** The JSON-RPC method, `"batch"` for an array, `null` when the body was not read or is not JSON-RPC. */
25
+ readonly method: string | null;
26
+ /** The tool name of a `tools/call`, otherwise `null`. */
27
+ readonly tool: string | null;
28
+ readonly session: McpSessionState;
29
+ /** The version a stale session carries, otherwise `null`. */
30
+ readonly sessionVersion: string | null;
31
+ /** The tool list version served to the identity, `null` when unknown (refused before authentication, no reader). */
32
+ readonly toolListVersion: string | null;
33
+ /** Whether the answer issued a new session id (a successful `initialize`). */
34
+ readonly sessionIssued: boolean;
35
+ /** The HTTP status of the answer. */
36
+ readonly status: number;
37
+ /** The client's `clientInfo` on `initialize`, otherwise `null`. */
38
+ readonly client: { readonly name: string; readonly version: string } | null;
39
+ /** The protocol version the client asked for on `initialize`, otherwise the `MCP-Protocol-Version` header, or `null`. */
40
+ readonly protocolVersion: string | null;
41
+ }
42
+
43
+ /** `true` logs one `console.info` line per request; a function receives each entry instead. */
44
+ export type McpRequestDiagnostics = boolean | ((entry: McpRequestDiagnostic) => void);
45
+
46
+ /** What the diagnostics read from a request body. */
47
+ export interface JsonRpcSummary {
48
+ readonly method: string | null;
49
+ readonly tool: string | null;
50
+ readonly client: { readonly name: string; readonly version: string } | null;
51
+ readonly protocolVersion: string | null;
52
+ }
53
+
54
+ const MAX_TEXT_LENGTH = 128;
55
+ const PROTOCOL_VERSION_HEADER = "mcp-protocol-version";
56
+ const EMPTY_SUMMARY: JsonRpcSummary = { method: null, tool: null, client: null, protocolVersion: null };
57
+
58
+ /** Client-supplied text as it may be logged: control characters replaced, at most 128 characters. */
59
+ export function sanitizeDiagnosticText(value: string): string {
60
+ const clean = Array.from(value, (character) => (isControlCharacter(character) ? "?" : character)).join("");
61
+ return clean.length > MAX_TEXT_LENGTH ? `${clean.slice(0, MAX_TEXT_LENGTH)}…` : clean;
62
+ }
63
+
64
+ /**
65
+ * The method, tool name, `clientInfo` and protocol version of a request, read from a clone of its body. A body over
66
+ * `maxBytes` or one that is not JSON gives no method (the SDK answers it itself). Nothing else of the body is kept.
67
+ */
68
+ export async function readJsonRpcSummary(request: Request, maxBytes: number): Promise<JsonRpcSummary> {
69
+ const header = request.headers.get(PROTOCOL_VERSION_HEADER);
70
+ const headerVersion = header === null ? null : sanitizeDiagnosticText(header);
71
+ const withHeader = { ...EMPTY_SUMMARY, protocolVersion: headerVersion };
72
+ if (request.method !== "POST") return withHeader;
73
+ const length = Number(request.headers.get("content-length") ?? "0");
74
+ if (!Number.isFinite(length) || length > maxBytes) return withHeader;
75
+ let body: unknown;
76
+ try {
77
+ const text = await request.clone().text();
78
+ if (text.length > maxBytes) return withHeader;
79
+ body = JSON.parse(text);
80
+ } catch {
81
+ // Not JSON or no readable body: the SDK answers that itself; the entry just has no method.
82
+ return withHeader;
83
+ }
84
+ if (Array.isArray(body)) return { ...withHeader, method: "batch" };
85
+ if (!isRecord(body) || typeof body.method !== "string") return withHeader;
86
+
87
+ const method = sanitizeDiagnosticText(body.method);
88
+ const params = isRecord(body.params) ? body.params : {};
89
+ if (body.method === "tools/call") {
90
+ return { ...withHeader, method, tool: typeof params.name === "string" ? sanitizeDiagnosticText(params.name) : null };
91
+ }
92
+ if (body.method !== "initialize") return { ...withHeader, method };
93
+ const clientInfo = isRecord(params.clientInfo) ? params.clientInfo : null;
94
+ const client =
95
+ clientInfo === null
96
+ ? null
97
+ : {
98
+ name: typeof clientInfo.name === "string" ? sanitizeDiagnosticText(clientInfo.name) : "",
99
+ version: typeof clientInfo.version === "string" ? sanitizeDiagnosticText(clientInfo.version) : "",
100
+ };
101
+ const protocolVersion = typeof params.protocolVersion === "string" ? sanitizeDiagnosticText(params.protocolVersion) : headerVersion;
102
+ return { method, tool: null, client, protocolVersion };
103
+ }
104
+
105
+ /** The sink for the option, or `undefined` when diagnostics are off. A throwing sink is logged, never rethrown. */
106
+ export function createDiagnosticsSink(diagnostics: McpRequestDiagnostics | undefined): ((entry: McpRequestDiagnostic) => void) | undefined {
107
+ if (diagnostics === undefined || diagnostics === false) return undefined;
108
+ const write = diagnostics === true ? logDiagnostic : diagnostics;
109
+ return (entry) => {
110
+ try {
111
+ write(entry);
112
+ } catch (error) {
113
+ console.error(`@softure-ai/mcp-access: the request diagnostics sink failed: ${errorLogLabel(error)}`);
114
+ }
115
+ };
116
+ }
117
+
118
+ function logDiagnostic(entry: McpRequestDiagnostic): void {
119
+ console.info(`@softure-ai/mcp-access: mcp request ${JSON.stringify(entry)}`);
120
+ }
121
+
122
+ /** C0 controls, DEL and C1 controls: anything that could break or forge a log line. */
123
+ function isControlCharacter(character: string): boolean {
124
+ const code = character.codePointAt(0) ?? 0;
125
+ return code < 0x20 || (code >= 0x7f && code <= 0x9f);
126
+ }
127
+
128
+ function isRecord(value: unknown): value is Record<string, unknown> {
129
+ return typeof value === "object" && value !== null && !Array.isArray(value);
130
+ }