@frontmcp/sdk 0.3.0 → 0.4.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 (169) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +192 -164
  3. package/package.json +7 -4
  4. package/src/__test-utils__/fixtures/hook.fixtures.d.ts +46 -0
  5. package/src/__test-utils__/fixtures/hook.fixtures.js +114 -0
  6. package/src/__test-utils__/fixtures/hook.fixtures.js.map +1 -0
  7. package/src/__test-utils__/fixtures/index.d.ts +7 -0
  8. package/src/__test-utils__/fixtures/index.js +11 -0
  9. package/src/__test-utils__/fixtures/index.js.map +1 -0
  10. package/src/__test-utils__/fixtures/plugin.fixtures.d.ts +46 -0
  11. package/src/__test-utils__/fixtures/plugin.fixtures.js +127 -0
  12. package/src/__test-utils__/fixtures/plugin.fixtures.js.map +1 -0
  13. package/src/__test-utils__/fixtures/provider.fixtures.d.ts +69 -0
  14. package/src/__test-utils__/fixtures/provider.fixtures.js +131 -0
  15. package/src/__test-utils__/fixtures/provider.fixtures.js.map +1 -0
  16. package/src/__test-utils__/fixtures/scope.fixtures.d.ts +14 -0
  17. package/src/__test-utils__/fixtures/scope.fixtures.js +59 -0
  18. package/src/__test-utils__/fixtures/scope.fixtures.js.map +1 -0
  19. package/src/__test-utils__/fixtures/tool.fixtures.d.ts +36 -0
  20. package/src/__test-utils__/fixtures/tool.fixtures.js +91 -0
  21. package/src/__test-utils__/fixtures/tool.fixtures.js.map +1 -0
  22. package/src/__test-utils__/helpers/assertion.helpers.d.ts +45 -0
  23. package/src/__test-utils__/helpers/assertion.helpers.js +153 -0
  24. package/src/__test-utils__/helpers/assertion.helpers.js.map +1 -0
  25. package/src/__test-utils__/helpers/async.helpers.d.ts +48 -0
  26. package/src/__test-utils__/helpers/async.helpers.js +112 -0
  27. package/src/__test-utils__/helpers/async.helpers.js.map +1 -0
  28. package/src/__test-utils__/helpers/index.d.ts +6 -0
  29. package/src/__test-utils__/helpers/index.js +10 -0
  30. package/src/__test-utils__/helpers/index.js.map +1 -0
  31. package/src/__test-utils__/helpers/setup.helpers.d.ts +54 -0
  32. package/src/__test-utils__/helpers/setup.helpers.js +106 -0
  33. package/src/__test-utils__/helpers/setup.helpers.js.map +1 -0
  34. package/src/__test-utils__/index.d.ts +9 -0
  35. package/src/__test-utils__/index.js +14 -0
  36. package/src/__test-utils__/index.js.map +1 -0
  37. package/src/__test-utils__/mocks/flow-instance.mock.d.ts +50 -0
  38. package/src/__test-utils__/mocks/flow-instance.mock.js +72 -0
  39. package/src/__test-utils__/mocks/flow-instance.mock.js.map +1 -0
  40. package/src/__test-utils__/mocks/hook-registry.mock.d.ts +25 -0
  41. package/src/__test-utils__/mocks/hook-registry.mock.js +65 -0
  42. package/src/__test-utils__/mocks/hook-registry.mock.js.map +1 -0
  43. package/src/__test-utils__/mocks/index.d.ts +8 -0
  44. package/src/__test-utils__/mocks/index.js +12 -0
  45. package/src/__test-utils__/mocks/index.js.map +1 -0
  46. package/src/__test-utils__/mocks/plugin-registry.mock.d.ts +43 -0
  47. package/src/__test-utils__/mocks/plugin-registry.mock.js +70 -0
  48. package/src/__test-utils__/mocks/plugin-registry.mock.js.map +1 -0
  49. package/src/__test-utils__/mocks/provider-registry.mock.d.ts +39 -0
  50. package/src/__test-utils__/mocks/provider-registry.mock.js +72 -0
  51. package/src/__test-utils__/mocks/provider-registry.mock.js.map +1 -0
  52. package/src/__test-utils__/mocks/tool-registry.mock.d.ts +43 -0
  53. package/src/__test-utils__/mocks/tool-registry.mock.js +79 -0
  54. package/src/__test-utils__/mocks/tool-registry.mock.js.map +1 -0
  55. package/src/app/app.utils.js.map +1 -1
  56. package/src/app/instances/app.local.instance.js +8 -11
  57. package/src/app/instances/app.local.instance.js.map +1 -1
  58. package/src/auth/auth.registry.d.ts +2 -2
  59. package/src/auth/auth.registry.js +3 -3
  60. package/src/auth/auth.registry.js.map +1 -1
  61. package/src/auth/flows/oauth.authorize.flow.d.ts +8 -8
  62. package/src/auth/flows/oauth.register.flow.d.ts +4 -4
  63. package/src/auth/flows/oauth.token.flow.d.ts +4 -4
  64. package/src/auth/flows/well-known.jwks.flow.d.ts +12 -12
  65. package/src/auth/flows/well-known.oauth-authorization-server.flow.d.ts +8 -8
  66. package/src/auth/flows/well-known.prm.flow.d.ts +4 -4
  67. package/src/auth/instances/instance.local-primary-auth.d.ts +3 -2
  68. package/src/auth/instances/instance.local-primary-auth.js +4 -2
  69. package/src/auth/instances/instance.local-primary-auth.js.map +1 -1
  70. package/src/auth/instances/instance.remote-primary-auth.d.ts +3 -2
  71. package/src/auth/instances/instance.remote-primary-auth.js +3 -1
  72. package/src/auth/instances/instance.remote-primary-auth.js.map +1 -1
  73. package/src/auth/jwks/jwks.service.js +0 -1
  74. package/src/auth/jwks/jwks.service.js.map +1 -1
  75. package/src/common/decorators/tool.decorator.d.ts +97 -36
  76. package/src/common/decorators/tool.decorator.js +0 -1
  77. package/src/common/decorators/tool.decorator.js.map +1 -1
  78. package/src/common/entries/scope.entry.d.ts +1 -0
  79. package/src/common/entries/scope.entry.js +6 -0
  80. package/src/common/entries/scope.entry.js.map +1 -1
  81. package/src/common/entries/tool.entry.d.ts +54 -11
  82. package/src/common/entries/tool.entry.js +19 -0
  83. package/src/common/entries/tool.entry.js.map +1 -1
  84. package/src/common/interfaces/internal/registry.interface.d.ts +10 -2
  85. package/src/common/interfaces/internal/registry.interface.js.map +1 -1
  86. package/src/common/interfaces/plugin.interface.d.ts +1 -1
  87. package/src/common/interfaces/plugin.interface.js.map +1 -1
  88. package/src/common/interfaces/tool.interface.d.ts +12 -7
  89. package/src/common/interfaces/tool.interface.js +1 -1
  90. package/src/common/interfaces/tool.interface.js.map +1 -1
  91. package/src/common/metadata/front-mcp.metadata.d.ts +145 -145
  92. package/src/common/metadata/hook.metadata.d.ts +4 -2
  93. package/src/common/metadata/hook.metadata.js.map +1 -1
  94. package/src/common/metadata/prompt.metadata.d.ts +28 -28
  95. package/src/common/metadata/prompt.metadata.js.map +1 -1
  96. package/src/common/metadata/resource.metadata.d.ts +54 -54
  97. package/src/common/metadata/tool.metadata.d.ts +190 -7
  98. package/src/common/metadata/tool.metadata.js +41 -6
  99. package/src/common/metadata/tool.metadata.js.map +1 -1
  100. package/src/common/records/scope.record.d.ts +2 -2
  101. package/src/common/records/scope.record.js.map +1 -1
  102. package/src/common/schemas/http-output.schema.d.ts +106 -106
  103. package/src/common/tokens/tool.tokens.js.map +1 -1
  104. package/src/common/types/options/logging.options.d.ts +1 -2
  105. package/src/common/types/options/logging.options.js +1 -9
  106. package/src/common/types/options/logging.options.js.map +1 -1
  107. package/src/common/types/options/server-info.options.d.ts +19 -19
  108. package/src/errors/error-handler.d.ts +65 -0
  109. package/src/errors/error-handler.js +107 -0
  110. package/src/errors/error-handler.js.map +1 -0
  111. package/src/errors/index.d.ts +2 -0
  112. package/src/errors/index.js +26 -0
  113. package/src/errors/index.js.map +1 -0
  114. package/src/errors/mcp.error.d.ts +156 -0
  115. package/src/errors/mcp.error.js +243 -0
  116. package/src/errors/mcp.error.js.map +1 -0
  117. package/src/flows/flow.instance.js +7 -6
  118. package/src/flows/flow.instance.js.map +1 -1
  119. package/src/flows/flow.registry.js +1 -1
  120. package/src/flows/flow.registry.js.map +1 -1
  121. package/src/front-mcp/front-mcp.providers.d.ts +20 -20
  122. package/src/hooks/hook.registry.d.ts +5 -3
  123. package/src/hooks/hook.registry.js +13 -1
  124. package/src/hooks/hook.registry.js.map +1 -1
  125. package/src/plugin/plugin.registry.d.ts +7 -2
  126. package/src/plugin/plugin.registry.js +23 -11
  127. package/src/plugin/plugin.registry.js.map +1 -1
  128. package/src/prompt/prompt.registry.js +1 -0
  129. package/src/prompt/prompt.registry.js.map +1 -1
  130. package/src/resource/resource.registry.js +1 -0
  131. package/src/resource/resource.registry.js.map +1 -1
  132. package/src/scope/scope.instance.js +8 -2
  133. package/src/scope/scope.instance.js.map +1 -1
  134. package/src/scope/scope.registry.js +3 -2
  135. package/src/scope/scope.registry.js.map +1 -1
  136. package/src/scope/scope.utils.js +6 -4
  137. package/src/scope/scope.utils.js.map +1 -1
  138. package/src/store/adapters/store.memory.adapter.js +3 -1
  139. package/src/store/adapters/store.memory.adapter.js.map +1 -1
  140. package/src/tool/flows/call-tool.flow.d.ts +1012 -676
  141. package/src/tool/flows/call-tool.flow.js +94 -61
  142. package/src/tool/flows/call-tool.flow.js.map +1 -1
  143. package/src/tool/flows/tools-list.flow.d.ts +347 -590
  144. package/src/tool/flows/tools-list.flow.js +76 -49
  145. package/src/tool/flows/tools-list.flow.js.map +1 -1
  146. package/src/tool/tool.instance.d.ts +27 -8
  147. package/src/tool/tool.instance.js +40 -5
  148. package/src/tool/tool.instance.js.map +1 -1
  149. package/src/tool/tool.registry.js +19 -21
  150. package/src/tool/tool.registry.js.map +1 -1
  151. package/src/tool/tool.utils.d.ts +3 -2
  152. package/src/tool/tool.utils.js +377 -14
  153. package/src/tool/tool.utils.js.map +1 -1
  154. package/src/transport/adapters/transport.sse.adapter.js +2 -1
  155. package/src/transport/adapters/transport.sse.adapter.js.map +1 -1
  156. package/src/transport/adapters/transport.streamable-http.adapter.js.map +1 -1
  157. package/src/transport/flows/handle.sse.flow.js +6 -13
  158. package/src/transport/flows/handle.sse.flow.js.map +1 -1
  159. package/src/transport/flows/handle.streamable-http.flow.js +1 -0
  160. package/src/transport/flows/handle.streamable-http.flow.js.map +1 -1
  161. package/src/transport/mcp-handlers/call-tool-request.handler.d.ts +1 -1
  162. package/src/transport/mcp-handlers/call-tool-request.handler.js +10 -5
  163. package/src/transport/mcp-handlers/call-tool-request.handler.js.map +1 -1
  164. package/src/transport/mcp-handlers/index.d.ts +151 -268
  165. package/src/transport/mcp-handlers/list-tools-request.handler.d.ts +124 -216
  166. package/src/transport/transport.local.js +1 -0
  167. package/src/transport/transport.local.js.map +1 -1
  168. package/src/utils/string.utils.js +1 -1
  169. package/src/utils/string.utils.js.map +1 -1
@@ -7,6 +7,7 @@ require("reflect-metadata");
7
7
  const zod_1 = require("zod");
8
8
  const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
9
9
  const zod_to_json_schema_1 = require("zod-to-json-schema");
10
+ const errors_1 = require("../../errors");
10
11
  const inputSchema = zod_1.z.object({
11
12
  request: types_js_1.ListToolsRequestSchema,
12
13
  ctx: zod_1.z.any(),
@@ -40,10 +41,19 @@ let ToolsListFlow = class ToolsListFlow extends common_1.FlowBase {
40
41
  }
41
42
  async parseInput() {
42
43
  this.logger.verbose('parseInput:start');
43
- const { request: { method, params }, } = inputSchema.parse(this.rawInput);
44
+ let method;
45
+ let params;
46
+ try {
47
+ const inputData = inputSchema.parse(this.rawInput);
48
+ method = inputData.request.method;
49
+ params = inputData.request.params;
50
+ }
51
+ catch (e) {
52
+ throw new errors_1.InvalidInputError('Invalid request format', e instanceof zod_1.z.ZodError ? e.errors : undefined);
53
+ }
44
54
  if (method !== 'tools/list') {
45
55
  this.logger.warn(`parseInput: invalid method "${method}"`);
46
- throw new Error('Invalid method');
56
+ throw new errors_1.InvalidMethodError(method, 'tools/list');
47
57
  }
48
58
  const cursor = params?.cursor;
49
59
  if (cursor)
@@ -53,63 +63,80 @@ let ToolsListFlow = class ToolsListFlow extends common_1.FlowBase {
53
63
  }
54
64
  async findTools() {
55
65
  this.logger.info('findTools:start');
56
- const apps = this.scope.apps.getApps();
57
- this.logger.info(`findTools: discovered ${apps.length} app(s)`);
58
- const tools = [];
59
- const scopeTools = this.scope.tools.getTools();
60
- this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);
61
- for (const tool of scopeTools) {
62
- tools.push({ appName: tool.owner.id, tool });
66
+ try {
67
+ const apps = this.scope.apps.getApps();
68
+ this.logger.info(`findTools: discovered ${apps.length} app(s)`);
69
+ const tools = [];
70
+ const scopeTools = this.scope.tools.getTools();
71
+ this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);
72
+ for (const tool of scopeTools) {
73
+ tools.push({ appName: tool.owner.id, tool });
74
+ }
75
+ this.logger.info(`findTools: total tools collected=${tools.length}`);
76
+ if (tools.length === 0) {
77
+ this.logger.warn('findTools: no tools found across apps');
78
+ }
79
+ this.state.set('tools', tools);
80
+ this.logger.verbose('findTools:done');
63
81
  }
64
- this.logger.info(`findTools: total tools collected=${tools.length}`);
65
- if (tools.length === 0) {
66
- this.logger.warn('findTools: no tools found across apps');
82
+ catch (error) {
83
+ this.logger.error('findTools: failed to collect tools', error);
84
+ throw error;
67
85
  }
68
- this.state.set('tools', tools);
69
- this.logger.verbose('findTools:done');
70
86
  }
71
87
  async resolveConflicts() {
72
88
  this.logger.verbose('resolveConflicts:start');
73
- const found = this.state.required.tools;
74
- const counts = new Map();
75
- for (const { tool } of found) {
76
- const baseName = tool.metadata.id ?? tool.metadata.name;
77
- counts.set(baseName, (counts.get(baseName) ?? 0) + 1);
78
- }
79
- const conflicts = new Set([...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k));
80
- if (conflicts.size > 0) {
81
- const preview = this.sample(Array.from(conflicts)).join(', ');
82
- const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';
83
- this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);
89
+ try {
90
+ const found = this.state.required.tools;
91
+ const counts = new Map();
92
+ for (const { tool } of found) {
93
+ const baseName = tool.metadata.id ?? tool.metadata.name;
94
+ counts.set(baseName, (counts.get(baseName) ?? 0) + 1);
95
+ }
96
+ const conflicts = new Set([...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k));
97
+ if (conflicts.size > 0) {
98
+ const preview = this.sample(Array.from(conflicts)).join(', ');
99
+ const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';
100
+ this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);
101
+ }
102
+ else {
103
+ this.logger.info('resolveConflicts: no name conflicts detected');
104
+ }
105
+ const resolved = found.map(({ appName, tool }) => {
106
+ const baseName = tool.metadata.id ?? tool.metadata.name;
107
+ const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;
108
+ return { appName, tool, finalName };
109
+ });
110
+ this.state.set('resolvedTools', resolved);
111
+ this.logger.verbose('resolveConflicts:done');
84
112
  }
85
- else {
86
- this.logger.info('resolveConflicts: no name conflicts detected');
113
+ catch (error) {
114
+ this.logger.error('resolveConflicts: failed to resolve conflicts', error);
115
+ throw error;
87
116
  }
88
- const resolved = found.map(({ appName, tool }) => {
89
- const baseName = tool.metadata.id ?? tool.metadata.name;
90
- const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;
91
- return { appName, tool, finalName };
92
- });
93
- this.state.set('resolvedTools', resolved);
94
- this.logger.verbose('resolveConflicts:done');
95
117
  }
96
118
  async parseTools() {
97
119
  this.logger.verbose('parseTools:start');
98
- const resolved = this.state.required.resolvedTools;
99
- const tools = resolved.map(({ finalName, tool }) => ({
100
- name: finalName,
101
- title: tool.metadata.name,
102
- description: tool.metadata.description,
103
- annotations: tool.metadata.annotations,
104
- inputSchema: tool.metadata.rawInputSchema ??
105
- (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object(tool.metadata.inputSchema)),
106
- }));
107
- const preview = this.sample(tools.map(t => t.name)).join(', ');
108
- const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';
109
- this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);
110
- this.respond({ tools });
111
- this.logger.info('parseTools: response sent');
112
- this.logger.verbose('parseTools:done');
120
+ try {
121
+ const resolved = this.state.required.resolvedTools;
122
+ const tools = resolved.map(({ finalName, tool }) => ({
123
+ name: finalName,
124
+ title: tool.metadata.name,
125
+ description: tool.metadata.description,
126
+ annotations: tool.metadata.annotations,
127
+ inputSchema: tool.metadata.rawInputSchema ?? (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object(tool.metadata.inputSchema)),
128
+ }));
129
+ const preview = this.sample(tools.map((t) => t.name)).join(', ');
130
+ const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';
131
+ this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);
132
+ this.respond({ tools });
133
+ this.logger.info('parseTools: response sent');
134
+ this.logger.verbose('parseTools:done');
135
+ }
136
+ catch (error) {
137
+ this.logger.error('parseTools: failed to parse tools', error);
138
+ throw error;
139
+ }
113
140
  }
114
141
  };
115
142
  tslib_1.__decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"tools-list.flow.js","sourceRoot":"","sources":["../../../../src/tool/flows/tools-list.flow.ts"],"names":[],"mappings":"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","sourcesContent":["// tools/flows/list-tools.flow.ts\nimport {Flow, FlowBase, FlowHooksOf, FlowPlan, FlowRunOptions, ToolEntry} from '../../common';\nimport 'reflect-metadata';\nimport {z} from 'zod';\nimport {ListToolsRequestSchema, ListToolsResultSchema} from '@modelcontextprotocol/sdk/types.js';\nimport {zodToJsonSchema} from 'zod-to-json-schema';\n\nconst inputSchema = z.object({\n request: ListToolsRequestSchema,\n ctx: z.any(),\n});\n\nconst outputSchema = ListToolsResultSchema;\n\nconst stateSchema = z.object({\n cursor: z.string().optional(),\n tools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n })\n ),\n resolvedTools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n finalName: z.string(),\n })\n ),\n});\n\ntype ResponseToolItem = z.infer<typeof outputSchema>['tools'][number];\n\n// TODO: add support for pagination\n// TODO: add support for session based tools\nconst plan = {\n pre: ['parseInput'],\n execute: ['findTools', 'resolveConflicts'],\n post: ['parseTools'],\n} as const satisfies FlowPlan<string>;\n\ndeclare global {\n interface ExtendFlows {\n 'tools:list-tools': FlowRunOptions<\n ToolsListFlow,\n typeof plan,\n typeof inputSchema,\n typeof outputSchema,\n typeof stateSchema\n >;\n }\n}\n\nconst name = 'tools:list-tools' as const;\nconst {Stage} = FlowHooksOf('tools:list-tools');\n\n@Flow({\n name,\n plan,\n inputSchema,\n outputSchema,\n access: 'authorized',\n})\nexport default class ToolsListFlow extends FlowBase<typeof name> {\n logger = this.scopeLogger.child('ToolsListFlow');\n\n private sample<T>(arr: T[], n = 5): T[] {\n return arr.slice(0, n);\n }\n\n @Stage('parseInput')\n async parseInput() {\n this.logger.verbose('parseInput:start');\n const {\n request: {method, params},\n } = inputSchema.parse(this.rawInput);\n\n if (method !== 'tools/list') {\n this.logger.warn(`parseInput: invalid method \"${method}\"`);\n throw new Error('Invalid method');\n }\n\n const cursor = params?.cursor;\n if (cursor) this.logger.verbose(`parseInput: cursor=${cursor}`);\n this.state.set('cursor', cursor);\n this.logger.verbose('parseInput:done');\n }\n\n @Stage('findTools')\n async findTools() {\n this.logger.info('findTools:start');\n const apps = this.scope.apps.getApps();\n this.logger.info(`findTools: discovered ${apps.length} app(s)`);\n\n const tools: Array<{ appName: string; tool: ToolEntry }> = [];\n\n const scopeTools = this.scope.tools.getTools();\n this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);\n\n for (const tool of scopeTools) {\n tools.push({appName: tool.owner.id, tool});\n }\n this.logger.info(`findTools: total tools collected=${tools.length}`);\n if (tools.length === 0) {\n this.logger.warn('findTools: no tools found across apps');\n }\n\n this.state.set('tools', tools);\n this.logger.verbose('findTools:done');\n }\n\n @Stage('resolveConflicts')\n async resolveConflicts() {\n this.logger.verbose('resolveConflicts:start');\n const found = this.state.required.tools;\n\n const counts = new Map<string, number>();\n for (const {tool} of found) {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n counts.set(baseName, (counts.get(baseName) ?? 0) + 1);\n }\n\n const conflicts = new Set<string>(\n [...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k)\n );\n\n if (conflicts.size > 0) {\n const preview = this.sample(Array.from(conflicts)).join(', ');\n const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';\n this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);\n } else {\n this.logger.info('resolveConflicts: no name conflicts detected');\n }\n\n const resolved = found.map(({appName, tool}) => {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;\n return {appName, tool, finalName};\n });\n\n this.state.set('resolvedTools', resolved);\n this.logger.verbose('resolveConflicts:done');\n }\n\n @Stage('parseTools')\n async parseTools() {\n this.logger.verbose('parseTools:start');\n const resolved = this.state.required.resolvedTools;\n\n const tools: ResponseToolItem[] = resolved.map(({finalName, tool}) => ({\n name: finalName,\n title: tool.metadata.name,\n description: tool.metadata.description,\n annotations: tool.metadata.annotations,\n inputSchema:\n (tool.metadata as any).rawInputSchema ??\n (zodToJsonSchema(z.object(tool.metadata.inputSchema) as any) as any),\n }));\n\n const preview = this.sample(tools.map(t => t.name)).join(', ');\n const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';\n this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);\n\n this.respond({tools});\n this.logger.info('parseTools: response sent');\n this.logger.verbose('parseTools:done');\n\n }\n}\n"]}
1
+ {"version":3,"file":"tools-list.flow.js","sourceRoot":"","sources":["../../../../src/tool/flows/tools-list.flow.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AACjC,yCAAgG;AAChG,4BAA0B;AAC1B,6BAAwB;AACxB,iEAAmG;AACnG,2DAAqD;AACrD,yCAAqE;AAErE,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,iCAAsB;IAC/B,GAAG,EAAE,OAAC,CAAC,GAAG,EAAE;CACb,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,gCAAqB,CAAC;AAE3C,MAAM,WAAW,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3B,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,KAAK,EAAE,OAAC,CAAC,KAAK,CACZ,OAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,OAAC,CAAC,UAAU,CAAC,kBAAS,CAAC;KAC9B,CAAC,CACH;IACD,aAAa,EAAE,OAAC,CAAC,KAAK,CACpB,OAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE;QACnB,IAAI,EAAE,OAAC,CAAC,UAAU,CAAC,kBAAS,CAAC;QAC7B,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;KACtB,CAAC,CACH;CACF,CAAC,CAAC;AAIH,mCAAmC;AACnC,4CAA4C;AAC5C,MAAM,IAAI,GAAG;IACX,GAAG,EAAE,CAAC,YAAY,CAAC;IACnB,OAAO,EAAE,CAAC,WAAW,EAAE,kBAAkB,CAAC;IAC1C,IAAI,EAAE,CAAC,YAAY,CAAC;CACe,CAAC;AActC,MAAM,IAAI,GAAG,kBAA2B,CAAC;AACzC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAA,oBAAW,EAAC,kBAAkB,CAAC,CAAC;AASnC,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,iBAAqB;IAC9D,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAEzC,MAAM,CAAI,GAAQ,EAAE,CAAC,GAAG,CAAC;QAC/B,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACzB,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAExC,IAAI,MAAe,CAAC;QACpB,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;YAClC,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;QACpC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,0BAAiB,CAAC,wBAAwB,EAAE,CAAC,YAAY,OAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACxG,CAAC;QAED,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,+BAA+B,MAAM,GAAG,CAAC,CAAC;YAC3D,MAAM,IAAI,2BAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC;QAC9B,IAAI,MAAM;YAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACzC,CAAC;IAGK,AAAN,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAEpC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;YAEhE,MAAM,KAAK,GAAgD,EAAE,CAAC;YAE9D,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,0BAA0B,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;YAEnE,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oCAAoC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;YACrE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;YAC5D,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;YAC/D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAGK,AAAN,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;YAExC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;YACzC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC;gBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACxD,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACxD,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAElG,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACvB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9D,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,SAAS,CAAC,IAAI,+BAA+B,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC;YACxG,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;YACnE,CAAC;YAED,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;gBAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACxD,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAChF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;YACtC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;QAC/C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,EAAE,KAAK,CAAC,CAAC;YAC1E,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU;QACd,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAExC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;YAEnD,MAAM,KAAK,GAAuB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBACvE,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBACzB,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;gBACtC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;gBACtC,WAAW,EACR,IAAI,CAAC,QAAgB,CAAC,cAAc,IAAK,IAAA,oCAAe,EAAC,OAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAQ,CAAS;aAChH,CAAC,CAAC,CAAC;YAEJ,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjE,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YACpE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,KAAK,CAAC,MAAM,wBAAwB,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC;YAEhG,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF,CAAA;AAvHO;IADL,KAAK,CAAC,YAAY,CAAC;;;;+CAuBnB;AAGK;IADL,KAAK,CAAC,WAAW,CAAC;;;;8CA4BlB;AAGK;IADL,KAAK,CAAC,kBAAkB,CAAC;;;;qDAmCzB;AAGK;IADL,KAAK,CAAC,YAAY,CAAC;;;;+CA2BnB;AA9HkB,aAAa;IAPjC,IAAA,aAAI,EAAC;QACJ,IAAI;QACJ,IAAI;QACJ,WAAW;QACX,YAAY;QACZ,MAAM,EAAE,YAAY;KACrB,CAAC;GACmB,aAAa,CA+HjC;kBA/HoB,aAAa","sourcesContent":["// tools/flows/list-tools.flow.ts\nimport { Flow, FlowBase, FlowHooksOf, FlowPlan, FlowRunOptions, ToolEntry } from '../../common';\nimport 'reflect-metadata';\nimport { z } from 'zod';\nimport { ListToolsRequestSchema, ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport { InvalidMethodError, InvalidInputError } from '../../errors';\n\nconst inputSchema = z.object({\n request: ListToolsRequestSchema,\n ctx: z.any(),\n});\n\nconst outputSchema = ListToolsResultSchema;\n\nconst stateSchema = z.object({\n cursor: z.string().optional(),\n tools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n }),\n ),\n resolvedTools: z.array(\n z.object({\n appName: z.string(),\n tool: z.instanceof(ToolEntry),\n finalName: z.string(),\n }),\n ),\n});\n\ntype ResponseToolItem = z.infer<typeof outputSchema>['tools'][number];\n\n// TODO: add support for pagination\n// TODO: add support for session based tools\nconst plan = {\n pre: ['parseInput'],\n execute: ['findTools', 'resolveConflicts'],\n post: ['parseTools'],\n} as const satisfies FlowPlan<string>;\n\ndeclare global {\n interface ExtendFlows {\n 'tools:list-tools': FlowRunOptions<\n ToolsListFlow,\n typeof plan,\n typeof inputSchema,\n typeof outputSchema,\n typeof stateSchema\n >;\n }\n}\n\nconst name = 'tools:list-tools' as const;\nconst { Stage } = FlowHooksOf('tools:list-tools');\n\n@Flow({\n name,\n plan,\n inputSchema,\n outputSchema,\n access: 'authorized',\n})\nexport default class ToolsListFlow extends FlowBase<typeof name> {\n logger = this.scopeLogger.child('ToolsListFlow');\n\n private sample<T>(arr: T[], n = 5): T[] {\n return arr.slice(0, n);\n }\n\n @Stage('parseInput')\n async parseInput() {\n this.logger.verbose('parseInput:start');\n\n let method!: string;\n let params: any;\n try {\n const inputData = inputSchema.parse(this.rawInput);\n method = inputData.request.method;\n params = inputData.request.params;\n } catch (e) {\n throw new InvalidInputError('Invalid request format', e instanceof z.ZodError ? e.errors : undefined);\n }\n\n if (method !== 'tools/list') {\n this.logger.warn(`parseInput: invalid method \"${method}\"`);\n throw new InvalidMethodError(method, 'tools/list');\n }\n\n const cursor = params?.cursor;\n if (cursor) this.logger.verbose(`parseInput: cursor=${cursor}`);\n this.state.set('cursor', cursor);\n this.logger.verbose('parseInput:done');\n }\n\n @Stage('findTools')\n async findTools() {\n this.logger.info('findTools:start');\n\n try {\n const apps = this.scope.apps.getApps();\n this.logger.info(`findTools: discovered ${apps.length} app(s)`);\n\n const tools: Array<{ appName: string; tool: ToolEntry }> = [];\n\n const scopeTools = this.scope.tools.getTools();\n this.logger.verbose(`findTools: scope tools=${scopeTools.length}`);\n\n for (const tool of scopeTools) {\n tools.push({ appName: tool.owner.id, tool });\n }\n\n this.logger.info(`findTools: total tools collected=${tools.length}`);\n if (tools.length === 0) {\n this.logger.warn('findTools: no tools found across apps');\n }\n\n this.state.set('tools', tools);\n this.logger.verbose('findTools:done');\n } catch (error) {\n this.logger.error('findTools: failed to collect tools', error);\n throw error;\n }\n }\n\n @Stage('resolveConflicts')\n async resolveConflicts() {\n this.logger.verbose('resolveConflicts:start');\n\n try {\n const found = this.state.required.tools;\n\n const counts = new Map<string, number>();\n for (const { tool } of found) {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n counts.set(baseName, (counts.get(baseName) ?? 0) + 1);\n }\n\n const conflicts = new Set<string>([...counts.entries()].filter(([, n]) => n > 1).map(([k]) => k));\n\n if (conflicts.size > 0) {\n const preview = this.sample(Array.from(conflicts)).join(', ');\n const extra = conflicts.size > 5 ? `, +${conflicts.size - 5} more` : '';\n this.logger.warn(`resolveConflicts: ${conflicts.size} name conflict(s) detected: ${preview}${extra}`);\n } else {\n this.logger.info('resolveConflicts: no name conflicts detected');\n }\n\n const resolved = found.map(({ appName, tool }) => {\n const baseName = tool.metadata.id ?? tool.metadata.name;\n const finalName = conflicts.has(baseName) ? `${appName}:${baseName}` : baseName;\n return { appName, tool, finalName };\n });\n\n this.state.set('resolvedTools', resolved);\n this.logger.verbose('resolveConflicts:done');\n } catch (error) {\n this.logger.error('resolveConflicts: failed to resolve conflicts', error);\n throw error;\n }\n }\n\n @Stage('parseTools')\n async parseTools() {\n this.logger.verbose('parseTools:start');\n\n try {\n const resolved = this.state.required.resolvedTools;\n\n const tools: ResponseToolItem[] = resolved.map(({ finalName, tool }) => ({\n name: finalName,\n title: tool.metadata.name,\n description: tool.metadata.description,\n annotations: tool.metadata.annotations,\n inputSchema:\n (tool.metadata as any).rawInputSchema ?? (zodToJsonSchema(z.object(tool.metadata.inputSchema) as any) as any),\n }));\n\n const preview = this.sample(tools.map((t) => t.name)).join(', ');\n const extra = tools.length > 5 ? `, +${tools.length - 5} more` : '';\n this.logger.info(`parseTools: prepared ${tools.length} tool descriptor(s): ${preview}${extra}`);\n\n this.respond({ tools });\n this.logger.info('parseTools: response sent');\n this.logger.verbose('parseTools:done');\n } catch (error) {\n this.logger.error('parseTools: failed to parse tools', error);\n throw error;\n }\n }\n}\n"]}
@@ -1,15 +1,34 @@
1
- import { EntryOwnerRef, ToolCallArgs, ToolCallExtra, ToolContext, ToolEntry, ToolRecord } from '../common';
1
+ import { EntryOwnerRef, ToolCallArgs, ToolCallExtra, ToolContext, ToolEntry, ToolInputType, ToolOutputType, ToolRecord, ParsedToolResult, ToolInputOf, ToolOutputOf, SafeTransformResult } from '../common';
2
2
  import ProviderRegistry from '../provider/provider.registry';
3
- import { z } from "zod";
4
- import HookRegistry from "../hooks/hook.registry";
5
- import { Scope } from "../scope";
6
- export declare class ToolInstance<In extends object = any, Out extends object = any> extends ToolEntry<In, Out> {
3
+ import { z } from 'zod';
4
+ import HookRegistry from '../hooks/hook.registry';
5
+ import { Scope } from '../scope';
6
+ import type { CallToolRequest } from '@modelcontextprotocol/sdk/types.js';
7
+ export declare class ToolInstance<InSchema extends ToolInputType = ToolInputType, OutSchema extends ToolOutputType = ToolOutputType, In = ToolInputOf<{
8
+ inputSchema: InSchema;
9
+ }>, Out = ToolOutputOf<{
10
+ outputSchema: OutSchema;
11
+ }>> extends ToolEntry<InSchema, OutSchema, In, Out> {
7
12
  private readonly providers;
8
- readonly name: string;
9
13
  readonly scope: Scope;
10
14
  readonly hooks: HookRegistry;
11
15
  constructor(record: ToolRecord, providers: ProviderRegistry, owner: EntryOwnerRef);
12
16
  protected initialize(): Promise<void>;
13
- getMetadata(): import("../common").ToolMetadata<z.ZodRawShape, z.ZodRawShape>;
14
- create(input: ToolCallArgs, ctx: ToolCallExtra): ToolContext<In, Out>;
17
+ getMetadata(): import("../common").ToolMetadata<z.ZodRawShape, ToolOutputType>;
18
+ getOutputSchema(): OutSchema | undefined;
19
+ create(input: ToolCallArgs, ctx: ToolCallExtra): ToolContext<InSchema, OutSchema, In, Out>;
20
+ parseInput(input: CallToolRequest['params']): CallToolRequest['params']['arguments'];
21
+ /**
22
+ * Turn the raw tool function result into an MCP-compliant CallToolResult:
23
+ * - `content`: list of ContentBlocks (text / image / audio / resource / resource_link)
24
+ * - `structuredContent`: sanitized JSON when outputSchema is "json-like"
25
+ *
26
+ * Rules:
27
+ * - If outputSchema is a JS array → multiple content items, each with its own type.
28
+ * - Primitive → stringifies into a TextContent block.
29
+ * - image/audio/resource/resource_link → passed through as-is.
30
+ * - JSON / structured → JSON.stringify for text, and full sanitized JSON in structuredContent.
31
+ */
32
+ parseOutput(raw: Out | Partial<Out> | any): ParsedToolResult;
33
+ safeParseOutput(raw: Out | Partial<Out> | any): SafeTransformResult<ParsedToolResult>;
15
34
  }
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
+ // file: libs/sdk/src/tool/tool.instance.ts
2
3
  Object.defineProperty(exports, "__esModule", { value: true });
3
4
  exports.ToolInstance = void 0;
4
5
  const common_1 = require("../common");
5
6
  const zod_1 = require("zod");
6
7
  const hooks_utils_1 = require("../hooks/hooks.utils");
8
+ const tool_utils_1 = require("./tool.utils");
7
9
  class ToolInstance extends common_1.ToolEntry {
8
10
  providers;
9
- name;
10
11
  scope;
11
12
  hooks;
12
13
  constructor(record, providers, owner) {
@@ -14,17 +15,20 @@ class ToolInstance extends common_1.ToolEntry {
14
15
  this.owner = owner;
15
16
  this.providers = providers;
16
17
  this.name = record.metadata.id || record.metadata.name;
18
+ this.fullName = this.owner.id + ':' + this.name;
17
19
  this.scope = this.providers.getActiveScope();
18
20
  this.hooks = this.scope.providers.getHooksRegistry();
19
21
  const schema = record.metadata.inputSchema;
20
- this.inputSchema = typeof schema.parse === 'function' ? schema : zod_1.z.object(schema);
22
+ // Support both Zod objects and raw ZodRawShape
23
+ this.inputSchema = schema instanceof zod_1.z.ZodObject ? schema.shape : schema ?? {};
24
+ // Whatever JSON schema representation you’re storing for inputs
21
25
  this.rawInputSchema = record.metadata.rawInputSchema;
22
- this.outputSchema = record.metadata.outputSchema ? zod_1.z.object(record.metadata.outputSchema) : zod_1.z.object({}).passthrough();
26
+ // IMPORTANT: keep the *raw* outputSchema (string literal, zod, raw shape, or array)
27
+ this.outputSchema = record.metadata.outputSchema;
23
28
  this.ready = this.initialize();
24
29
  }
25
30
  async initialize() {
26
- const hooks = (0, hooks_utils_1.normalizeHooksFromCls)(this.record.provide)
27
- .filter(hook => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools');
31
+ const hooks = (0, hooks_utils_1.normalizeHooksFromCls)(this.record.provide).filter((hook) => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools');
28
32
  if (hooks.length > 0) {
29
33
  await this.hooks.registerHooks(true, ...hooks);
30
34
  }
@@ -33,6 +37,9 @@ class ToolInstance extends common_1.ToolEntry {
33
37
  getMetadata() {
34
38
  return this.record.metadata;
35
39
  }
40
+ getOutputSchema() {
41
+ return this.outputSchema;
42
+ }
36
43
  create(input, ctx) {
37
44
  const metadata = this.metadata;
38
45
  const providers = this.providers;
@@ -53,6 +60,34 @@ class ToolInstance extends common_1.ToolEntry {
53
60
  return new FunctionToolContext(this.record, toolCtorArgs);
54
61
  }
55
62
  }
63
+ parseInput(input) {
64
+ const inputSchema = zod_1.z.object(this.inputSchema);
65
+ return inputSchema.parse(input.arguments);
66
+ }
67
+ /**
68
+ * Turn the raw tool function result into an MCP-compliant CallToolResult:
69
+ * - `content`: list of ContentBlocks (text / image / audio / resource / resource_link)
70
+ * - `structuredContent`: sanitized JSON when outputSchema is "json-like"
71
+ *
72
+ * Rules:
73
+ * - If outputSchema is a JS array → multiple content items, each with its own type.
74
+ * - Primitive → stringifies into a TextContent block.
75
+ * - image/audio/resource/resource_link → passed through as-is.
76
+ * - JSON / structured → JSON.stringify for text, and full sanitized JSON in structuredContent.
77
+ */
78
+ parseOutput(raw) {
79
+ const descriptor = this.outputSchema;
80
+ return (0, tool_utils_1.buildParsedToolResult)(descriptor, raw);
81
+ }
82
+ safeParseOutput(raw) {
83
+ const descriptor = this.outputSchema;
84
+ try {
85
+ return { success: true, data: (0, tool_utils_1.buildParsedToolResult)(descriptor, raw) };
86
+ }
87
+ catch (error) {
88
+ return { success: false, error };
89
+ }
90
+ }
56
91
  }
57
92
  exports.ToolInstance = ToolInstance;
58
93
  class FunctionToolContext extends common_1.ToolContext {
@@ -1 +1 @@
1
- {"version":3,"file":"tool.instance.js","sourceRoot":"","sources":["../../../src/tool/tool.instance.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n EntryOwnerRef, ToolCallArgs, ToolCallExtra, ToolContext,\n ToolCtorArgs, ToolEntry, ToolFunctionTokenRecord, ToolKind, ToolRecord\n} from '../common';\nimport ProviderRegistry from '../provider/provider.registry';\nimport {z} from \"zod\";\nimport HookRegistry from \"../hooks/hook.registry\";\nimport {Scope} from \"../scope\";\nimport {normalizeHooksFromCls} from \"../hooks/hooks.utils\";\n\n\nexport class ToolInstance<In extends object = any, Out extends object = any> extends ToolEntry<In, Out> {\n private readonly providers: ProviderRegistry;\n readonly name: string;\n readonly scope: Scope;\n readonly hooks: HookRegistry;\n\n constructor(record: ToolRecord, providers: ProviderRegistry, owner: EntryOwnerRef) {\n super(record);\n this.owner = owner;\n this.providers = providers;\n this.name = record.metadata.id || record.metadata.name;\n this.scope = this.providers.getActiveScope()\n this.hooks = this.scope.providers.getHooksRegistry();\n\n const schema: any = record.metadata.inputSchema\n this.inputSchema = typeof schema.parse === 'function' ? schema : z.object(schema);\n this.rawInputSchema = record.metadata.rawInputSchema as any;\n this.outputSchema = record.metadata.outputSchema ? z.object(record.metadata.outputSchema) : z.object({}).passthrough();\n this.ready = this.initialize();\n }\n\n protected async initialize() {\n const hooks = normalizeHooksFromCls(this.record.provide)\n .filter(hook => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools')\n if (hooks.length > 0) {\n await this.hooks.registerHooks(true, ...hooks)\n }\n return Promise.resolve();\n }\n\n getMetadata() {\n return this.record.metadata;\n }\n\n override create(input: ToolCallArgs, ctx: ToolCallExtra): ToolContext<In, Out> {\n const metadata = this.metadata;\n const providers = this.providers;\n const scope = this.providers.getActiveScope();\n const logger = scope.logger;\n const authInfo = ctx.authInfo;\n\n const toolCtorArgs: ToolCtorArgs<In> = {\n metadata,\n input: input as In,\n providers,\n logger,\n authInfo,\n }\n switch (this.record.kind) {\n case ToolKind.CLASS_TOKEN:\n return new this.record.provide(toolCtorArgs);\n case ToolKind.FUNCTION:\n return new FunctionToolContext<In, Out>(this.record, toolCtorArgs);\n }\n }\n}\n\nclass FunctionToolContext<In extends object = any, Out extends object = any> extends ToolContext<In, Out> {\n constructor(\n private readonly record: ToolFunctionTokenRecord,\n args: ToolCtorArgs<In>\n ) {\n super(args);\n }\n\n execute(input: In): Promise<Out> {\n return this.record.provide(input, this);\n }\n}\n\n"]}
1
+ {"version":3,"file":"tool.instance.js","sourceRoot":"","sources":["../../../src/tool/tool.instance.ts"],"names":[],"mappings":"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","sourcesContent":["// file: libs/sdk/src/tool/tool.instance.ts\n\nimport {\n EntryOwnerRef,\n ToolCallArgs,\n ToolCallExtra,\n ToolContext,\n ToolCtorArgs,\n ToolEntry,\n ToolFunctionTokenRecord,\n ToolInputType,\n ToolKind,\n ToolOutputType,\n ToolRecord,\n ParsedToolResult,\n ToolInputOf,\n ToolOutputOf,\n SafeTransformResult,\n} from '../common';\nimport ProviderRegistry from '../provider/provider.registry';\nimport { z } from 'zod';\nimport HookRegistry from '../hooks/hook.registry';\nimport { Scope } from '../scope';\nimport { normalizeHooksFromCls } from '../hooks/hooks.utils';\nimport type { CallToolRequest } from '@modelcontextprotocol/sdk/types.js';\nimport { buildParsedToolResult } from './tool.utils';\n\nexport class ToolInstance<\n InSchema extends ToolInputType = ToolInputType,\n OutSchema extends ToolOutputType = ToolOutputType,\n In = ToolInputOf<{ inputSchema: InSchema }>,\n Out = ToolOutputOf<{ outputSchema: OutSchema }>,\n> extends ToolEntry<InSchema, OutSchema, In, Out> {\n private readonly providers: ProviderRegistry;\n readonly scope: Scope;\n readonly hooks: HookRegistry;\n\n constructor(record: ToolRecord, providers: ProviderRegistry, owner: EntryOwnerRef) {\n super(record);\n this.owner = owner;\n this.providers = providers;\n this.name = record.metadata.id || record.metadata.name;\n this.fullName = this.owner.id + ':' + this.name;\n this.scope = this.providers.getActiveScope();\n this.hooks = this.scope.providers.getHooksRegistry();\n\n const schema: any = record.metadata.inputSchema;\n // Support both Zod objects and raw ZodRawShape\n this.inputSchema = schema instanceof z.ZodObject ? schema.shape : schema ?? {};\n\n // Whatever JSON schema representation you’re storing for inputs\n this.rawInputSchema = record.metadata.rawInputSchema;\n\n // IMPORTANT: keep the *raw* outputSchema (string literal, zod, raw shape, or array)\n this.outputSchema = record.metadata.outputSchema as OutSchema;\n\n this.ready = this.initialize();\n }\n\n protected async initialize() {\n const hooks = normalizeHooksFromCls(this.record.provide).filter(\n (hook) => hook.metadata.flow === 'tools:call-tool' || hook.metadata.flow === 'tools:list-tools',\n );\n if (hooks.length > 0) {\n await this.hooks.registerHooks(true, ...hooks);\n }\n return Promise.resolve();\n }\n\n getMetadata() {\n return this.record.metadata;\n }\n\n override getOutputSchema() {\n return this.outputSchema;\n }\n\n override create(input: ToolCallArgs, ctx: ToolCallExtra): ToolContext<InSchema, OutSchema, In, Out> {\n const metadata = this.metadata;\n const providers = this.providers;\n const scope = this.providers.getActiveScope();\n const logger = scope.logger;\n const authInfo = ctx.authInfo;\n\n const toolCtorArgs: ToolCtorArgs<In> = {\n metadata,\n input: input as In,\n providers,\n logger,\n authInfo,\n };\n switch (this.record.kind) {\n case ToolKind.CLASS_TOKEN:\n return new this.record.provide(toolCtorArgs) as ToolContext<InSchema, OutSchema, In, Out>;\n case ToolKind.FUNCTION:\n return new FunctionToolContext<InSchema, OutSchema, In, Out>(this.record, toolCtorArgs);\n }\n }\n\n override parseInput(input: CallToolRequest['params']): CallToolRequest['params']['arguments'] {\n const inputSchema = z.object(this.inputSchema);\n return inputSchema.parse(input.arguments);\n }\n /**\n * Turn the raw tool function result into an MCP-compliant CallToolResult:\n * - `content`: list of ContentBlocks (text / image / audio / resource / resource_link)\n * - `structuredContent`: sanitized JSON when outputSchema is \"json-like\"\n *\n * Rules:\n * - If outputSchema is a JS array → multiple content items, each with its own type.\n * - Primitive → stringifies into a TextContent block.\n * - image/audio/resource/resource_link → passed through as-is.\n * - JSON / structured → JSON.stringify for text, and full sanitized JSON in structuredContent.\n */\n override parseOutput(raw: Out | Partial<Out> | any): ParsedToolResult {\n const descriptor = this.outputSchema as any;\n\n return buildParsedToolResult(descriptor, raw);\n }\n\n override safeParseOutput(raw: Out | Partial<Out> | any): SafeTransformResult<ParsedToolResult> {\n const descriptor = this.outputSchema as any;\n try {\n return { success: true, data: buildParsedToolResult(descriptor, raw) };\n } catch (error: any) {\n return { success: false, error };\n }\n }\n}\n\nclass FunctionToolContext<\n InSchema extends ToolInputType,\n OutSchema extends ToolOutputType,\n In = ToolInputOf<{ inputSchema: InSchema }>,\n Out = ToolOutputOf<{ outputSchema: OutSchema }>,\n> extends ToolContext<InSchema, OutSchema, In, Out> {\n constructor(private readonly record: ToolFunctionTokenRecord, args: ToolCtorArgs<In>) {\n super(args);\n }\n\n execute(input: In): Promise<Out> {\n return this.record.provide(input, this);\n }\n}\n"]}
@@ -74,17 +74,21 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
74
74
  this.localRows.push(row);
75
75
  }
76
76
  const childAppRegistries = this.providers.getRegistries('AppRegistry');
77
- childAppRegistries.forEach(appRegistry => {
77
+ childAppRegistries.forEach((appRegistry) => {
78
78
  const apps = appRegistry.getApps();
79
79
  for (const app of apps) {
80
80
  const appToolsRegistries = app.providers.getRegistries('ToolRegistry');
81
- appToolsRegistries.filter(t => t.owner.kind === 'app').forEach(appToolRegistry => {
81
+ appToolsRegistries
82
+ .filter((t) => t.owner.kind === 'app')
83
+ .forEach((appToolRegistry) => {
82
84
  this.adoptFromChild(appToolRegistry, appToolRegistry.owner);
83
85
  });
84
86
  }
85
87
  });
86
88
  const childToolRegistries = this.providers.getRegistries('ToolRegistry');
87
- childToolRegistries.filter(t => t != this).forEach(toolRegistry => {
89
+ childToolRegistries
90
+ .filter((t) => t != this)
91
+ .forEach((toolRegistry) => {
88
92
  this.adoptFromChild(toolRegistry, toolRegistry.owner);
89
93
  });
90
94
  // Build effective indexes from (locals + already adopted children)
@@ -107,12 +111,12 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
107
111
  return;
108
112
  const childRows = child.listAllIndexed(); // includes child's lineage
109
113
  const prepend = this.owner ? [this.owner] : [];
110
- const adoptedRows = childRows.map(r => this.relineage(r, prepend));
114
+ const adoptedRows = childRows.map((r) => this.relineage(r, prepend));
111
115
  this.adopted.set(child, adoptedRows);
112
116
  this.children.add(child);
113
117
  // keep live if child changes
114
118
  child.subscribe({ immediate: false }, () => {
115
- const latest = child.listAllIndexed().map(r => this.relineage(r, prepend));
119
+ const latest = child.listAllIndexed().map((r) => this.relineage(r, prepend));
116
120
  this.adopted.set(child, latest);
117
121
  this.reindex();
118
122
  this.bump('reset');
@@ -161,11 +165,11 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
161
165
  }
162
166
  /** List all instances (locals + adopted). */
163
167
  listAllInstances() {
164
- return this.listAllIndexed().map(r => r.instance);
168
+ return this.listAllIndexed().map((r) => r.instance);
165
169
  }
166
170
  /** List instances by owner path (e.g. "app:Portal/plugin:Okta") */
167
171
  listByOwner(ownerPath) {
168
- return (this.byOwner.get(ownerPath) ?? []).map(r => r.instance);
172
+ return (this.byOwner.get(ownerPath) ?? []).map((r) => r.instance);
169
173
  }
170
174
  /* -------------------- Conflict-aware exported names -------------------- */
171
175
  /**
@@ -177,7 +181,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
177
181
  */
178
182
  exportResolvedNames(opts) {
179
183
  const cfg = { ...tool_types_1.DEFAULT_EXPORT_OPTS, ...(opts ?? {}) };
180
- const rows = this.listAllIndexed().map(r => {
184
+ const rows = this.listAllIndexed().map((r) => {
181
185
  const base = (0, tool_utils_1.normalizeSegment)(r.baseName, cfg.case);
182
186
  const isLocal = r.source === this;
183
187
  const provider = (0, tool_utils_1.normalizeProviderId)(this.providerIdOf(r.instance), cfg.case);
@@ -198,8 +202,8 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
198
202
  out.set((0, tool_utils_1.ensureMaxLen)(base, cfg.maxLen), g.row.instance);
199
203
  continue;
200
204
  }
201
- const locals = group.filter(g => g.isLocal);
202
- const children = group.filter(g => !g.isLocal);
205
+ const locals = group.filter((g) => g.isLocal);
206
+ const children = group.filter((g) => !g.isLocal);
203
207
  if (cfg.prefixChildrenOnConflict && locals.length > 0) {
204
208
  // Locals
205
209
  if (locals.length === 1) {
@@ -215,9 +219,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
215
219
  }
216
220
  // Children
217
221
  for (const c of children) {
218
- const pre = cfg.prefixSource === 'provider'
219
- ? (c.provider ?? c.ownerPath)
220
- : c.ownerPath;
222
+ const pre = cfg.prefixSource === 'provider' ? c.provider ?? c.ownerPath : c.ownerPath;
221
223
  const name = (0, tool_utils_1.ensureMaxLen)(`${pre}${(0, tool_utils_1.sepFor)(cfg.case)}${base}`, cfg.maxLen);
222
224
  out.set(disambiguate(name, out, cfg), c.row.instance);
223
225
  }
@@ -225,17 +227,13 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
225
227
  else {
226
228
  // Prefix everyone by source
227
229
  for (const r of group) {
228
- const pre = cfg.prefixSource === 'provider'
229
- ? (r.provider ?? r.ownerPath)
230
- : r.ownerPath;
230
+ const pre = cfg.prefixSource === 'provider' ? r.provider ?? r.ownerPath : r.ownerPath;
231
231
  const name = (0, tool_utils_1.ensureMaxLen)(`${pre}${(0, tool_utils_1.sepFor)(cfg.case)}${base}`, cfg.maxLen);
232
232
  out.set(disambiguate(name, out, cfg), r.row.instance);
233
233
  }
234
234
  }
235
235
  }
236
- return [...out.entries()]
237
- .sort((a, b) => a[0].localeCompare(b[0]))
238
- .map(([name, instance]) => ({ name, instance }));
236
+ return [...out.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([name, instance]) => ({ name, instance }));
239
237
  function disambiguate(candidate, pool, cfg) {
240
238
  if (!pool.has(candidate))
241
239
  return candidate;
@@ -251,7 +249,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
251
249
  /** Lookup by the exported (resolved) name. */
252
250
  getExported(name, opts) {
253
251
  const pairs = this.exportResolvedNames(opts);
254
- return pairs.find(p => p.name === name)?.instance;
252
+ return pairs.find((p) => p.name === name)?.instance;
255
253
  }
256
254
  /* -------------------- Subscriptions -------------------- */
257
255
  subscribe(opts, cb) {
@@ -305,7 +303,7 @@ class ToolRegistry extends regsitry_1.RegistryAbstract {
305
303
  const maybe = meta?.providerId ?? meta?.provider ?? meta?.ownerId ?? undefined;
306
304
  if (typeof maybe === 'string' && maybe.length)
307
305
  return maybe;
308
- const cls = (meta && meta.cls) ? meta.cls : undefined;
306
+ const cls = meta && meta.cls ? meta.cls : undefined;
309
307
  if (cls) {
310
308
  const id = (0, metadata_utils_1.getMetadata)('id', cls);
311
309
  if (typeof id === 'string' && id.length)