@ontrails/mcp 1.0.0-beta.8 → 1.0.0-beta.9

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.
@@ -1,3 +1,3 @@
1
1
  $ oxlint ./src
2
2
  Found 0 warnings and 0 errors.
3
- Finished in 26ms on 12 files with 93 rules using 24 threads.
3
+ Finished in 76ms on 12 files with 93 rules using 24 threads.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @ontrails/mcp
2
2
 
3
+ ## 1.0.0-beta.9
4
+
5
+ ### Minor Changes
6
+
7
+ - Consolidated improvements across all surface packages.
8
+
9
+ **core**: Add `TrailResult<T>` utility type, `topo.ids()` and `topo.count` accessors, `dispatch()` for headless trail execution, and extract shared `executeTrail` pipeline used by CLI/MCP/HTTP.
10
+
11
+ **http**: Detect route path collisions and return `Result` from `buildHttpRoutes()`, wire request `AbortSignal` through to trail context, and make write → POST mapping explicit in intent-to-method lookup.
12
+
13
+ **mcp**: Return `Result` from `buildMcpTools()` on collision instead of throwing.
14
+
15
+ **cli**: Verify exception catching via centralized `executeTrail`.
16
+
17
+ **testing**: Follow context awareness improvements.
18
+
19
+ **warden**: Refactor rules as composable trails with examples.
20
+
21
+ **schema**: Error code and empty body fixes.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies
26
+ - @ontrails/core@1.0.0-beta.9
27
+
3
28
  ## 1.0.0-beta.8
4
29
 
5
30
  ### Patch Changes
package/README.md CHANGED
@@ -26,8 +26,9 @@ For more control, build the tools yourself:
26
26
  ```typescript
27
27
  import { buildMcpTools } from '@ontrails/mcp';
28
28
 
29
- const tools = buildMcpTools(app);
30
- for (const tool of tools) {
29
+ const result = buildMcpTools(app);
30
+ if (result.isErr()) throw result.error; // ValidationError on tool-name collision
31
+ for (const tool of result.value) {
31
32
  server.registerTool(tool.name, tool.handler, {
32
33
  inputSchema: tool.inputSchema,
33
34
  annotations: tool.annotations,
@@ -35,6 +36,8 @@ for (const tool of tools) {
35
36
  }
36
37
  ```
37
38
 
39
+ `buildMcpTools` returns `Result<McpToolDefinition[], Error>` rather than a bare array. It returns `Result.err(ValidationError)` if two trails derive the same MCP tool name. Each `McpToolDefinition` includes a `trailId` field that records which trail the tool was derived from.
40
+
38
41
  ## API
39
42
 
40
43
  | Export | What it does |
@@ -1 +1 @@
1
- {"version":3,"file":"blaze.d.ts","sourceRoot":"","sources":["../src/blaze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAQpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,CAAC,EACnB,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,GAC5C,SAAS,CAAC;IACd,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAChB;QACE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACvC,GACD,SAAS,CAAC;IACd,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1C;AAMD;;GAEG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,iBAAiB,EAAE,EAC1B,MAAM;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KACxD,MAmEF,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,KAAK,GAChB,KAAK,IAAI,EACT,UAAS,eAAoB,KAC5B,OAAO,CAAC,IAAI,CAcd,CAAC"}
1
+ {"version":3,"file":"blaze.d.ts","sourceRoot":"","sources":["../src/blaze.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAQpD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,aAAa,CAAC,EACnB,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,GAC5C,SAAS,CAAC;IACd,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAChB;QACE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACvC,GACD,SAAS,CAAC;IACd,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC1C;AAMD;;GAEG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,iBAAiB,EAAE,EAC1B,MAAM;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,KACxD,MAmEF,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,KAAK,GAChB,KAAK,IAAI,EACT,UAAS,eAAoB,KAC5B,OAAO,CAAC,IAAI,CAkBd,CAAC"}
package/dist/blaze.js CHANGED
@@ -81,13 +81,16 @@ export const createMcpServer = (tools, info) => {
81
81
  * Build MCP tools from an App, create a server, and connect via stdio.
82
82
  */
83
83
  export const blaze = async (app, options = {}) => {
84
- const tools = buildMcpTools(app, {
84
+ const toolsResult = buildMcpTools(app, {
85
85
  createContext: options.createContext,
86
86
  excludeTrails: options.excludeTrails,
87
87
  includeTrails: options.includeTrails,
88
88
  layers: options.layers,
89
89
  });
90
- const server = createMcpServer(tools, {
90
+ if (toolsResult.isErr()) {
91
+ throw toolsResult.error;
92
+ }
93
+ const server = createMcpServer(toolsResult.value, {
91
94
  name: options.serverInfo?.name ?? app.name,
92
95
  version: options.serverInfo?.version ?? '0.1.0',
93
96
  });
package/dist/blaze.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"blaze.js","sourceRoot":"","sources":["../src/blaze.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"blaze.js","sourceRoot":"","sources":["../src/blaze.ts"],"names":[],"mappings":"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"}
package/dist/build.d.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  * validate input, compose layers, execute the implementation, and map
6
6
  * Results to MCP responses.
7
7
  */
8
+ import { Result } from '@ontrails/core';
8
9
  import type { Layer, Topo, TrailContext } from '@ontrails/core';
9
10
  import type { McpAnnotations } from './annotations.js';
10
11
  export interface BuildMcpToolsOptions {
@@ -19,6 +20,8 @@ export interface McpToolDefinition {
19
20
  readonly handler: (args: Record<string, unknown>, extra: McpExtra) => Promise<McpToolResult>;
20
21
  readonly inputSchema: Record<string, unknown>;
21
22
  readonly name: string;
23
+ /** The trail ID this tool was derived from. */
24
+ readonly trailId: string;
22
25
  }
23
26
  export interface McpExtra {
24
27
  readonly progressToken?: string | number | undefined;
@@ -36,5 +39,5 @@ export interface McpContent {
36
39
  readonly type: 'text' | 'image' | 'resource';
37
40
  readonly uri?: string | undefined;
38
41
  }
39
- export declare const buildMcpTools: (app: Topo, options?: BuildMcpToolsOptions) => McpToolDefinition[];
42
+ export declare const buildMcpTools: (app: Topo, options?: BuildMcpToolsOptions) => Result<McpToolDefinition[], Error>;
40
43
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAW,KAAK,EAAE,IAAI,EAAS,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASvD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,CAAC,EACnB,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,GAC5C,SAAS,CAAC;IACd,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,WAAW,EAAE,cAAc,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,CAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,QAAQ,KACZ,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,YAAY,CAAC,EAClB,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GACnD,SAAS,CAAC;IACd,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAsSD,eAAO,MAAM,aAAa,GACxB,KAAK,IAAI,EACT,UAAS,oBAAyB,KACjC,iBAAiB,EAUnB,CAAC"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,MAAM,EAKP,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAW,KAAK,EAAE,IAAI,EAAS,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AASvD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,CAAC,EACnB,CAAC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,GAC5C,SAAS,CAAC;IACd,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;CAChD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,WAAW,EAAE,cAAc,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,CAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,KAAK,EAAE,QAAQ,KACZ,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,YAAY,CAAC,EAClB,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GACnD,SAAS,CAAC;IACd,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAwQD,eAAO,MAAM,aAAa,GACxB,KAAK,IAAI,EACT,UAAS,oBAAyB,KACjC,MAAM,CAAC,iBAAiB,EAAE,EAAE,KAAK,CAoBnC,CAAC"}
package/dist/build.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * validate input, compose layers, execute the implementation, and map
6
6
  * Results to MCP responses.
7
7
  */
8
- import { composeLayers, createTrailContext, isBlobRef, validateInput, zodToJsonSchema, } from '@ontrails/core';
8
+ import { Result, ValidationError, executeTrail, isBlobRef, zodToJsonSchema, } from '@ontrails/core';
9
9
  import { deriveAnnotations } from './annotations.js';
10
10
  import { createMcpProgressCallback } from './progress.js';
11
11
  import { deriveToolName } from './tool-name.js';
@@ -114,40 +114,18 @@ const mcpError = (message) => ({
114
114
  content: [{ text: message, type: 'text' }],
115
115
  isError: true,
116
116
  });
117
- /** Build a TrailContext from options and MCP extra. */
118
- const buildTrailContext = async (options, extra) => {
119
- const baseContext = options.createContext !== undefined && options.createContext !== null
120
- ? await options.createContext()
121
- : createTrailContext();
122
- const signal = extra.signal ?? baseContext.signal;
117
+ const createHandler = (t, layers, options) => async (args, extra) => {
123
118
  const progressCb = createMcpProgressCallback(extra);
124
- return {
125
- ...baseContext,
126
- signal,
127
- ...(progressCb === undefined ? {} : { progress: progressCb }),
128
- };
129
- };
130
- /** Execute a trail and map the result to an MCP response. */
131
- const executeAndMap = async (trail, validatedInput, ctx, layers) => {
132
- const impl = composeLayers([...layers], trail, trail.run);
133
- try {
134
- const result = await impl(validatedInput, ctx);
135
- if (result.isOk()) {
136
- return { content: await serializeOutput(result.value) };
137
- }
138
- return mcpError(result.error.message);
119
+ const result = await executeTrail(t, args, {
120
+ createContext: options.createContext,
121
+ ctx: progressCb === undefined ? undefined : { progress: progressCb },
122
+ layers,
123
+ signal: extra.signal,
124
+ });
125
+ if (result.isOk()) {
126
+ return { content: await serializeOutput(result.value) };
139
127
  }
140
- catch (error) {
141
- return mcpError(error instanceof Error ? error.message : String(error));
142
- }
143
- };
144
- const createHandler = (trail, layers, options) => async (args, extra) => {
145
- const validated = validateInput(trail.input, args);
146
- if (validated.isErr()) {
147
- return mcpError(validated.error.message);
148
- }
149
- const ctx = await buildTrailContext(options, extra);
150
- return executeAndMap(trail, validated.value, ctx, layers);
128
+ return mcpError(result.error.message);
151
129
  };
152
130
  // ---------------------------------------------------------------------------
153
131
  // Builder
@@ -198,6 +176,7 @@ const buildToolDefinition = (app, trail, layers, options) => {
198
176
  handler: createHandler(trail, layers, options),
199
177
  inputSchema: zodToJsonSchema(trail.input),
200
178
  name: deriveToolName(app.name, trail.id),
179
+ trailId: trail.id,
201
180
  };
202
181
  };
203
182
  /** Register a trail as an MCP tool, checking for name collisions. */
@@ -205,10 +184,11 @@ const registerTool = (app, trailItem, layers, options, nameToTrailId, tools) =>
205
184
  const toolName = deriveToolName(app.name, trailItem.id);
206
185
  const existingId = nameToTrailId.get(toolName);
207
186
  if (existingId !== undefined) {
208
- throw new Error(`MCP tool-name collision: trails "${existingId}" and "${trailItem.id}" both derive the tool name "${toolName}"`);
187
+ return Result.err(new ValidationError(`MCP tool-name collision: trails "${existingId}" and "${trailItem.id}" both derive the tool name "${toolName}"`));
209
188
  }
210
189
  nameToTrailId.set(toolName, trailItem.id);
211
190
  tools.push(buildToolDefinition(app, trailItem, layers, options));
191
+ return Result.ok();
212
192
  };
213
193
  /** Filter topo items to eligible trails. */
214
194
  const eligibleTrails = (app, options) => app
@@ -220,8 +200,11 @@ export const buildMcpTools = (app, options = {}) => {
220
200
  const tools = [];
221
201
  const nameToTrailId = new Map();
222
202
  for (const trailItem of eligibleTrails(app, options)) {
223
- registerTool(app, trailItem, layers, options, nameToTrailId, tools);
203
+ const registered = registerTool(app, trailItem, layers, options, nameToTrailId, tools);
204
+ if (registered.isErr()) {
205
+ return registered;
206
+ }
224
207
  }
225
- return tools;
208
+ return Result.ok(tools);
226
209
  };
227
210
  //# sourceMappingURL=build.js.map
package/dist/build.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAIxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA+ChD,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAE9E,0EAA0E;AAC1E,MAAM,YAAY,GAAG,CACnB,MAAoB,EACpB,WAAmB,EACP,EAAE;IACd,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,yDAAyD;AACzD,MAAM,aAAa,GAAG,KAAK,EACzB,MAAkC,EACb,EAAE;IACvB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAClC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,SAAS,CAAC;QACR,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5C,IAAI,IAAI,EAAE,CAAC;YACT,MAAM;QACR,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;IAC9B,CAAC;IACD,OAAO,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,mEAAmE;AACnE,MAAM,eAAe,GAAG,CAAC,IAAa,EAAoC,EAAE;IAC1E,IAAI,IAAI,CAAC,IAAI,YAAY,cAAc,EAAE,CAAC;QACxC,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,KAAiB,EAAU,EAAE;IACvD,8DAA8D;IAC9D,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,KAAK,EAAE,IAAa,EAAuB,EAAE;IACjE,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,OAAO;YACL,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC;YAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,OAAO;SACd,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,UAAU;QAChB,GAAG,EAAE,UAAU,IAAI,CAAC,IAAI,EAAE;KAC3B,CAAC;AACJ,CAAC,CAAC;AAEF,8DAA8D;AAC9D,MAAM,kBAAkB,GAAG,KAAK,EAC9B,GAA4B,EAK3B,EAAE;IACH,MAAM,YAAY,GAAiB,EAAE,CAAC;IACtC,MAAM,UAAU,GAA4B,EAAE,CAAC;IAC/C,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,aAAa,GAAG,IAAI,CAAC;YACrB,YAAY,CAAC,IAAI,CAAC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACxB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;AACrD,CAAC,CAAC;AAEF,yDAAyD;AACzD,MAAM,oBAAoB,GAAG,KAAK,EAChC,GAA4B,EACgB,EAAE;IAC9C,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,GAC/C,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,YAAY,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,KAAK,EAC3B,KAAc,EACkB,EAAE;IAClC,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzE,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,KAAgC,CAAC,CAAC;QAC3E,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,gDAAgD;AAChD,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAiB,EAAE,CAAC,CAAC;IACpD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1C,OAAO,EAAE,IAAI;CACd,CAAC,CAAC;AAEH,uDAAuD;AACvD,MAAM,iBAAiB,GAAG,KAAK,EAC7B,OAA6B,EAC7B,KAAe,EACQ,EAAE;IACzB,MAAM,WAAW,GACf,OAAO,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI;QACnE,CAAC,CAAC,MAAM,OAAO,CAAC,aAAa,EAAE;QAC/B,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAE3B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,WAAW,CAAC,MAAM,CAAC;IAClD,MAAM,UAAU,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAEpD,OAAO;QACL,GAAG,WAAW;QACd,MAAM;QACN,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;KAC9D,CAAC;AACJ,CAAC,CAAC;AAEF,6DAA6D;AAC7D,MAAM,aAAa,GAAG,KAAK,EACzB,KAA8B,EAC9B,cAAuB,EACvB,GAAiB,EACjB,MAAwB,EACA,EAAE;IAC1B,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,CAAC;QACD,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,OAAO,QAAQ,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,aAAa,GACjB,CACE,KAA8B,EAC9B,MAAwB,EACxB,OAA6B,EAIF,EAAE,CAC/B,KAAK,EAAE,IAAI,EAAE,KAAK,EAA0B,EAAE;IAC5C,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACpD,OAAO,aAAa,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEJ,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,yEAAyE;AACzE,MAAM,aAAa,GAAG,CACpB,KAA8B,EAC9B,OAA6B,EACpB,EAAE;IACX,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5E,OAAO,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,IACE,OAAO,CAAC,aAAa,KAAK,SAAS;QACnC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EACxC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,gEAAgE;AAChE,MAAM,gBAAgB,GAAG,CACvB,KAA8B,EACV,EAAE;IACtB,IAAI,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAC5B,IACE,WAAW,KAAK,SAAS;QACzB,KAAK,CAAC,QAAQ,KAAK,SAAS;QAC5B,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EACzB,CAAC;QACD,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC;QACtC,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,WAAW,GAAG,GAAG,WAAW,sBAAsB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACzF,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF,uDAAuD;AACvD,MAAM,mBAAmB,GAAG,CAC1B,GAAS,EACT,KAA8B,EAC9B,MAAwB,EACxB,OAA6B,EACV,EAAE;IACrB,MAAM,cAAc,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,WAAW,GACf,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,OAAO;QACL,WAAW;QACX,WAAW,EAAE,gBAAgB,CAAC,KAAK,CAAC;QACpC,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC;QAC9C,WAAW,EAAE,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;QACzC,IAAI,EAAE,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;KACzC,CAAC;AACJ,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,YAAY,GAAG,CACnB,GAAS,EACT,SAAkC,EAClC,MAAwB,EACxB,OAA6B,EAC7B,aAAkC,EAClC,KAA0B,EACpB,EAAE;IACR,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CACb,oCAAoC,UAAU,UAAU,SAAS,CAAC,EAAE,gCAAgC,QAAQ,GAAG,CAChH,CAAC;IACJ,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AACnE,CAAC,CAAC;AAEF,4CAA4C;AAC5C,MAAM,cAAc,GAAG,CACrB,GAAS,EACT,OAA6B,EACF,EAAE,CAC7B,GAAG;KACA,IAAI,EAAE;KACN,MAAM,CACL,CAAC,IAAI,EAAmC,EAAE,CACxC,IAAI,CAAC,IAAI,KAAK,OAAO;IACrB,aAAa,CAAC,IAA+B,EAAE,OAAO,CAAC,CAC1D,CAAC;AAEN,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAAS,EACT,UAAgC,EAAE,EACb,EAAE;IACvB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACpC,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEhD,KAAK,MAAM,SAAS,IAAI,cAAc,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC;QACrD,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/mcp",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0-beta.9",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
@@ -14,7 +14,7 @@
14
14
  "clean": "rm -rf dist *.tsbuildinfo"
15
15
  },
16
16
  "dependencies": {
17
- "@ontrails/core": "^1.0.0-beta.6"
17
+ "@ontrails/core": "^1.0.0-beta.8"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@modelcontextprotocol/sdk": "^1.12.0",
@@ -5,12 +5,13 @@ import { z } from 'zod';
5
5
 
6
6
  import { createMcpServer } from '../blaze.js';
7
7
  import { buildMcpTools } from '../build.js';
8
+ import type { McpToolDefinition } from '../build.js';
8
9
 
9
10
  // ---------------------------------------------------------------------------
10
11
  // Tests
11
12
  // ---------------------------------------------------------------------------
12
13
 
13
- const requireTool = (tools: ReturnType<typeof buildMcpTools>, name: string) => {
14
+ const requireTool = (tools: McpToolDefinition[], name: string) => {
14
15
  const tool = tools.find((entry) => entry.name === name);
15
16
  expect(tool).toBeDefined();
16
17
  if (!tool) {
@@ -19,6 +20,19 @@ const requireTool = (tools: ReturnType<typeof buildMcpTools>, name: string) => {
19
20
  return tool;
20
21
  };
21
22
 
23
+ /**
24
+ * Unwrap buildMcpTools result, throwing on error so test failures surface clearly.
25
+ */
26
+ const buildTools = (
27
+ ...args: Parameters<typeof buildMcpTools>
28
+ ): McpToolDefinition[] => {
29
+ const result = buildMcpTools(...args);
30
+ if (result.isErr()) {
31
+ throw result.error;
32
+ }
33
+ return result.value;
34
+ };
35
+
22
36
  const createIntegrationTools = () => {
23
37
  const greetTrail = trail('greet', {
24
38
  description: 'Greet someone',
@@ -34,7 +48,7 @@ const createIntegrationTools = () => {
34
48
  run: (_input) => Result.ok({ deleted: true }),
35
49
  });
36
50
 
37
- return buildMcpTools(topo('myapp', { deleteTrail, greetTrail }));
51
+ return buildTools(topo('myapp', { deleteTrail, greetTrail }));
38
52
  };
39
53
 
40
54
  describe('blaze', () => {
@@ -47,7 +61,7 @@ describe('blaze', () => {
47
61
  });
48
62
 
49
63
  const app = topo('testapp', { echoTrail });
50
- const tools = buildMcpTools(app);
64
+ const tools = buildTools(app);
51
65
  const server = createMcpServer(tools, {
52
66
  name: 'testapp',
53
67
  version: '0.1.0',
@@ -72,7 +86,7 @@ describe('blaze', () => {
72
86
  });
73
87
 
74
88
  const app = topo('testapp', { echoTrail, searchTrail });
75
- const tools = buildMcpTools(app);
89
+ const tools = buildTools(app);
76
90
 
77
91
  expect(tools).toHaveLength(2);
78
92
 
@@ -5,7 +5,7 @@ import type { Layer } from '@ontrails/core';
5
5
  import { z } from 'zod';
6
6
 
7
7
  import { buildMcpTools } from '../build.js';
8
- import type { McpExtra } from '../build.js';
8
+ import type { McpExtra, McpToolDefinition } from '../build.js';
9
9
 
10
10
  // ---------------------------------------------------------------------------
11
11
  // Helpers
@@ -47,7 +47,7 @@ const exampleTrail = trail('with.examples', {
47
47
 
48
48
  const noExtra: McpExtra = {};
49
49
 
50
- const requireTool = (tools: ReturnType<typeof buildMcpTools>, name: string) => {
50
+ const requireTool = (tools: McpToolDefinition[], name: string) => {
51
51
  const tool = tools.find((entry) => entry.name === name);
52
52
  expect(tool).toBeDefined();
53
53
  if (!tool) {
@@ -56,7 +56,7 @@ const requireTool = (tools: ReturnType<typeof buildMcpTools>, name: string) => {
56
56
  return tool;
57
57
  };
58
58
 
59
- const requireOnlyTool = (tools: ReturnType<typeof buildMcpTools>) => {
59
+ const requireOnlyTool = (tools: McpToolDefinition[]) => {
60
60
  expect(tools).toHaveLength(1);
61
61
  const [tool] = tools;
62
62
  expect(tool).toBeDefined();
@@ -66,6 +66,20 @@ const requireOnlyTool = (tools: ReturnType<typeof buildMcpTools>) => {
66
66
  return tool;
67
67
  };
68
68
 
69
+ /**
70
+ * Unwrap buildMcpTools result for success-path tests.
71
+ * Throws if the result is an error so test failures surface clearly.
72
+ */
73
+ const buildTools = (
74
+ ...args: Parameters<typeof buildMcpTools>
75
+ ): McpToolDefinition[] => {
76
+ const result = buildMcpTools(...args);
77
+ if (result.isErr()) {
78
+ throw result.error;
79
+ }
80
+ return result.value;
81
+ };
82
+
69
83
  const parseJsonContent = (
70
84
  content: { readonly text?: string | undefined } | undefined
71
85
  ): unknown => {
@@ -81,7 +95,7 @@ describe('buildMcpTools', () => {
81
95
  describe('discovery', () => {
82
96
  test('builds tools from a single-trail app', () => {
83
97
  const app = topo('myapp', { echoTrail });
84
- const tools = buildMcpTools(app);
98
+ const tools = buildTools(app);
85
99
 
86
100
  expect(tools).toHaveLength(1);
87
101
  expect(requireOnlyTool(tools).name).toBe('myapp_echo');
@@ -89,7 +103,7 @@ describe('buildMcpTools', () => {
89
103
 
90
104
  test('builds tools from a multi-trail app', () => {
91
105
  const app = topo('myapp', { deleteTrail, echoTrail, failTrail });
92
- const tools = buildMcpTools(app);
106
+ const tools = buildTools(app);
93
107
 
94
108
  expect(tools).toHaveLength(3);
95
109
  const names = tools.map((t) => t.name);
@@ -100,14 +114,14 @@ describe('buildMcpTools', () => {
100
114
 
101
115
  test('tool names follow derivation rules', () => {
102
116
  const app = topo('myapp', { deleteTrail });
103
- const tools = buildMcpTools(app);
117
+ const tools = buildTools(app);
104
118
 
105
119
  expect(requireOnlyTool(tools).name).toBe('myapp_item_delete');
106
120
  });
107
121
 
108
122
  test('input schema is valid JSON Schema', () => {
109
123
  const app = topo('myapp', { echoTrail });
110
- const schema = requireOnlyTool(buildMcpTools(app)).inputSchema;
124
+ const schema = requireOnlyTool(buildTools(app)).inputSchema;
111
125
 
112
126
  expect(schema['type']).toBe('object');
113
127
  expect(schema['properties']).toBeDefined();
@@ -117,7 +131,7 @@ describe('buildMcpTools', () => {
117
131
 
118
132
  test('annotations are correctly derived', () => {
119
133
  const app = topo('myapp', { deleteTrail, echoTrail });
120
- const tools = buildMcpTools(app);
134
+ const tools = buildTools(app);
121
135
 
122
136
  expect(requireTool(tools, 'myapp_echo').annotations?.readOnlyHint).toBe(
123
137
  true
@@ -129,12 +143,22 @@ describe('buildMcpTools', () => {
129
143
  requireTool(tools, 'myapp_item_delete').annotations?.destructiveHint
130
144
  ).toBe(true);
131
145
  });
146
+
147
+ test('trailId identifies the source trail', () => {
148
+ const app = topo('myapp', { deleteTrail, echoTrail });
149
+ const tools = buildTools(app);
150
+
151
+ expect(requireTool(tools, 'myapp_echo').trailId).toBe('echo');
152
+ expect(requireTool(tools, 'myapp_item_delete').trailId).toBe(
153
+ 'item.delete'
154
+ );
155
+ });
132
156
  });
133
157
 
134
158
  describe('handler execution', () => {
135
159
  test('handler validates input and returns isError on invalid', async () => {
136
160
  const app = topo('myapp', { echoTrail });
137
- const tool = requireOnlyTool(buildMcpTools(app));
161
+ const tool = requireOnlyTool(buildTools(app));
138
162
 
139
163
  const result = await tool.handler({ notMessage: 123 }, noExtra);
140
164
  expect(result?.isError).toBe(true);
@@ -144,7 +168,7 @@ describe('buildMcpTools', () => {
144
168
 
145
169
  test('handler calls implementation and returns result as text content', async () => {
146
170
  const app = topo('myapp', { echoTrail });
147
- const tool = requireOnlyTool(buildMcpTools(app));
171
+ const tool = requireOnlyTool(buildTools(app));
148
172
 
149
173
  const result = await tool.handler({ message: 'hello' }, noExtra);
150
174
  expect(result?.isError).toBeUndefined();
@@ -156,7 +180,7 @@ describe('buildMcpTools', () => {
156
180
 
157
181
  test('handler maps errors to isError content', async () => {
158
182
  const app = topo('myapp', { failTrail });
159
- const tool = requireOnlyTool(buildMcpTools(app));
183
+ const tool = requireOnlyTool(buildTools(app));
160
184
 
161
185
  const result = await tool.handler({ reason: 'broken' }, noExtra);
162
186
  expect(result?.isError).toBe(true);
@@ -171,9 +195,7 @@ describe('buildMcpTools', () => {
171
195
  },
172
196
  });
173
197
 
174
- const tool = requireOnlyTool(
175
- buildMcpTools(topo('myapp', { throwTrail }))
176
- );
198
+ const tool = requireOnlyTool(buildTools(topo('myapp', { throwTrail })));
177
199
  const result = await tool.handler({}, noExtra);
178
200
 
179
201
  expect(result?.isError).toBe(true);
@@ -184,7 +206,7 @@ describe('buildMcpTools', () => {
184
206
  describe('filters', () => {
185
207
  test('include filter limits which trails become tools', () => {
186
208
  const app = topo('myapp', { deleteTrail, echoTrail, failTrail });
187
- const tools = buildMcpTools(app, {
209
+ const tools = buildTools(app, {
188
210
  includeTrails: ['echo'],
189
211
  });
190
212
 
@@ -194,7 +216,7 @@ describe('buildMcpTools', () => {
194
216
 
195
217
  test('exclude filter removes specific trails', () => {
196
218
  const app = topo('myapp', { deleteTrail, echoTrail, failTrail });
197
- const tools = buildMcpTools(app, {
219
+ const tools = buildTools(app, {
198
220
  excludeTrails: ['fail'],
199
221
  });
200
222
 
@@ -205,7 +227,7 @@ describe('buildMcpTools', () => {
205
227
 
206
228
  test('include takes precedence over exclude', () => {
207
229
  const app = topo('myapp', { deleteTrail, echoTrail, failTrail });
208
- const tools = buildMcpTools(app, {
230
+ const tools = buildTools(app, {
209
231
  excludeTrails: ['fail'],
210
232
  includeTrails: ['echo', 'fail'],
211
233
  });
@@ -234,7 +256,7 @@ describe('buildMcpTools', () => {
234
256
  };
235
257
 
236
258
  const app = topo('myapp', { echoTrail });
237
- const tool = requireOnlyTool(buildMcpTools(app, { layers: [testLayer] }));
259
+ const tool = requireOnlyTool(buildTools(app, { layers: [testLayer] }));
238
260
 
239
261
  await tool.handler({ message: 'hi' }, noExtra);
240
262
  expect(calls).toEqual(['before', 'after']);
@@ -252,9 +274,7 @@ describe('buildMcpTools', () => {
252
274
  });
253
275
 
254
276
  const controller = new AbortController();
255
- const tool = requireOnlyTool(
256
- buildMcpTools(topo('myapp', { signalTrail }))
257
- );
277
+ const tool = requireOnlyTool(buildTools(topo('myapp', { signalTrail })));
258
278
 
259
279
  await tool.handler({}, { signal: controller.signal });
260
280
  expect(capturedSignal).toBe(controller.signal);
@@ -262,7 +282,7 @@ describe('buildMcpTools', () => {
262
282
 
263
283
  test('description includes first example input when present', () => {
264
284
  const app = topo('myapp', { exampleTrail });
265
- const tool = requireOnlyTool(buildMcpTools(app));
285
+ const tool = requireOnlyTool(buildTools(app));
266
286
 
267
287
  expect(tool.description).toContain('A trail with examples');
268
288
  expect(tool.description).toContain('"name":"world"');
@@ -282,7 +302,7 @@ describe('buildMcpTools', () => {
282
302
 
283
303
  const app = topo('myapp', { ctxTrail });
284
304
  const tool = requireOnlyTool(
285
- buildMcpTools(app, {
305
+ buildTools(app, {
286
306
  createContext: () => ({
287
307
  custom: true,
288
308
  requestId: 'test-id',
@@ -311,7 +331,7 @@ describe('buildMcpTools', () => {
311
331
  ),
312
332
  });
313
333
 
314
- const tool = requireOnlyTool(buildMcpTools(topo('myapp', { blobTrail })));
334
+ const tool = requireOnlyTool(buildTools(topo('myapp', { blobTrail })));
315
335
  const result = await tool.handler({}, noExtra);
316
336
 
317
337
  expect(result?.content[0]?.type).toBe('image');
@@ -333,7 +353,7 @@ describe('buildMcpTools', () => {
333
353
  ),
334
354
  });
335
355
 
336
- const tool = requireOnlyTool(buildMcpTools(topo('myapp', { blobTrail })));
356
+ const tool = requireOnlyTool(buildTools(topo('myapp', { blobTrail })));
337
357
  const result = await tool.handler({}, noExtra);
338
358
 
339
359
  expect(result?.content[0]?.type).toBe('resource');
@@ -362,7 +382,7 @@ describe('buildMcpTools', () => {
362
382
  ),
363
383
  });
364
384
 
365
- const tool = requireOnlyTool(buildMcpTools(topo('myapp', { blobTrail })));
385
+ const tool = requireOnlyTool(buildTools(topo('myapp', { blobTrail })));
366
386
  const result = await tool.handler({}, noExtra);
367
387
 
368
388
  expect(result?.content[0]?.type).toBe('image');
@@ -372,7 +392,7 @@ describe('buildMcpTools', () => {
372
392
  });
373
393
 
374
394
  describe('tool-name collision detection', () => {
375
- test('throws on trails that produce the same derived tool name', () => {
395
+ test('returns Err on trails that produce the same derived tool name', () => {
376
396
  const dotTrail = trail('foo.bar', {
377
397
  input: z.object({}),
378
398
  run: () => Result.ok({ ok: true }),
@@ -383,10 +403,12 @@ describe('buildMcpTools', () => {
383
403
  });
384
404
 
385
405
  const app = topo('myapp', { dotTrail, underscoreTrail });
386
- expect(() => buildMcpTools(app)).toThrow(/tool-name collision/i);
406
+ const result = buildMcpTools(app);
407
+ expect(result.isErr()).toBe(true);
408
+ expect(result.error?.message).toMatch(/tool-name collision/i);
387
409
  });
388
410
 
389
- test('throws on trails where hyphen and underscore collide', () => {
411
+ test('returns Err on trails where hyphen and underscore collide', () => {
390
412
  const hyphenTrail = trail('foo-bar', {
391
413
  input: z.object({}),
392
414
  run: () => Result.ok({ ok: true }),
@@ -397,10 +419,12 @@ describe('buildMcpTools', () => {
397
419
  });
398
420
 
399
421
  const app = topo('myapp', { hyphenTrail, underscoreTrail });
400
- expect(() => buildMcpTools(app)).toThrow(/tool-name collision/i);
422
+ const result = buildMcpTools(app);
423
+ expect(result.isErr()).toBe(true);
424
+ expect(result.error?.message).toMatch(/tool-name collision/i);
401
425
  });
402
426
 
403
- test('does not throw when trail names are distinct after normalization', () => {
427
+ test('returns Ok when trail names are distinct after normalization', () => {
404
428
  const fooTrail = trail('foo', {
405
429
  input: z.object({}),
406
430
  run: () => Result.ok({ ok: true }),
@@ -411,7 +435,8 @@ describe('buildMcpTools', () => {
411
435
  });
412
436
 
413
437
  const app = topo('myapp', { barTrail, fooTrail });
414
- expect(() => buildMcpTools(app)).not.toThrow();
438
+ const result = buildMcpTools(app);
439
+ expect(result.isOk()).toBe(true);
415
440
  });
416
441
  });
417
442
 
@@ -426,9 +451,7 @@ describe('buildMcpTools', () => {
426
451
  run: (input) => Result.ok({ greeting: `Hello, ${input.name}!` }),
427
452
  });
428
453
 
429
- const tool = requireOnlyTool(
430
- buildMcpTools(topo('testapp', { greetTrail }))
431
- );
454
+ const tool = requireOnlyTool(buildTools(topo('testapp', { greetTrail })));
432
455
 
433
456
  expect(tool).toMatchObject({
434
457
  annotations: {
package/src/blaze.ts CHANGED
@@ -130,14 +130,18 @@ export const blaze = async (
130
130
  app: Topo,
131
131
  options: BlazeMcpOptions = {}
132
132
  ): Promise<void> => {
133
- const tools = buildMcpTools(app, {
133
+ const toolsResult = buildMcpTools(app, {
134
134
  createContext: options.createContext,
135
135
  excludeTrails: options.excludeTrails,
136
136
  includeTrails: options.includeTrails,
137
137
  layers: options.layers,
138
138
  });
139
139
 
140
- const server = createMcpServer(tools, {
140
+ if (toolsResult.isErr()) {
141
+ throw toolsResult.error;
142
+ }
143
+
144
+ const server = createMcpServer(toolsResult.value, {
141
145
  name: options.serverInfo?.name ?? app.name,
142
146
  version: options.serverInfo?.version ?? '0.1.0',
143
147
  });
package/src/build.ts CHANGED
@@ -7,10 +7,10 @@
7
7
  */
8
8
 
9
9
  import {
10
- composeLayers,
11
- createTrailContext,
10
+ Result,
11
+ ValidationError,
12
+ executeTrail,
12
13
  isBlobRef,
13
- validateInput,
14
14
  zodToJsonSchema,
15
15
  } from '@ontrails/core';
16
16
  import type { BlobRef, Layer, Topo, Trail, TrailContext } from '@ontrails/core';
@@ -42,6 +42,8 @@ export interface McpToolDefinition {
42
42
  ) => Promise<McpToolResult>;
43
43
  readonly inputSchema: Record<string, unknown>;
44
44
  readonly name: string;
45
+ /** The trail ID this tool was derived from. */
46
+ readonly trailId: string;
45
47
  }
46
48
 
47
49
  export interface McpExtra {
@@ -197,48 +199,9 @@ const mcpError = (message: string): McpToolResult => ({
197
199
  isError: true,
198
200
  });
199
201
 
200
- /** Build a TrailContext from options and MCP extra. */
201
- const buildTrailContext = async (
202
- options: BuildMcpToolsOptions,
203
- extra: McpExtra
204
- ): Promise<TrailContext> => {
205
- const baseContext =
206
- options.createContext !== undefined && options.createContext !== null
207
- ? await options.createContext()
208
- : createTrailContext();
209
-
210
- const signal = extra.signal ?? baseContext.signal;
211
- const progressCb = createMcpProgressCallback(extra);
212
-
213
- return {
214
- ...baseContext,
215
- signal,
216
- ...(progressCb === undefined ? {} : { progress: progressCb }),
217
- };
218
- };
219
-
220
- /** Execute a trail and map the result to an MCP response. */
221
- const executeAndMap = async (
222
- trail: Trail<unknown, unknown>,
223
- validatedInput: unknown,
224
- ctx: TrailContext,
225
- layers: readonly Layer[]
226
- ): Promise<McpToolResult> => {
227
- const impl = composeLayers([...layers], trail, trail.run);
228
- try {
229
- const result = await impl(validatedInput, ctx);
230
- if (result.isOk()) {
231
- return { content: await serializeOutput(result.value) };
232
- }
233
- return mcpError(result.error.message);
234
- } catch (error: unknown) {
235
- return mcpError(error instanceof Error ? error.message : String(error));
236
- }
237
- };
238
-
239
202
  const createHandler =
240
203
  (
241
- trail: Trail<unknown, unknown>,
204
+ t: Trail<unknown, unknown>,
242
205
  layers: readonly Layer[],
243
206
  options: BuildMcpToolsOptions
244
207
  ): ((
@@ -246,12 +209,17 @@ const createHandler =
246
209
  extra: McpExtra
247
210
  ) => Promise<McpToolResult>) =>
248
211
  async (args, extra): Promise<McpToolResult> => {
249
- const validated = validateInput(trail.input, args);
250
- if (validated.isErr()) {
251
- return mcpError(validated.error.message);
212
+ const progressCb = createMcpProgressCallback(extra);
213
+ const result = await executeTrail(t, args, {
214
+ createContext: options.createContext,
215
+ ctx: progressCb === undefined ? undefined : { progress: progressCb },
216
+ layers,
217
+ signal: extra.signal,
218
+ });
219
+ if (result.isOk()) {
220
+ return { content: await serializeOutput(result.value) };
252
221
  }
253
- const ctx = await buildTrailContext(options, extra);
254
- return executeAndMap(trail, validated.value, ctx, layers);
222
+ return mcpError(result.error.message);
255
223
  };
256
224
 
257
225
  // ---------------------------------------------------------------------------
@@ -321,6 +289,7 @@ const buildToolDefinition = (
321
289
  handler: createHandler(trail, layers, options),
322
290
  inputSchema: zodToJsonSchema(trail.input),
323
291
  name: deriveToolName(app.name, trail.id),
292
+ trailId: trail.id,
324
293
  };
325
294
  };
326
295
 
@@ -332,16 +301,19 @@ const registerTool = (
332
301
  options: BuildMcpToolsOptions,
333
302
  nameToTrailId: Map<string, string>,
334
303
  tools: McpToolDefinition[]
335
- ): void => {
304
+ ): Result<void, Error> => {
336
305
  const toolName = deriveToolName(app.name, trailItem.id);
337
306
  const existingId = nameToTrailId.get(toolName);
338
307
  if (existingId !== undefined) {
339
- throw new Error(
340
- `MCP tool-name collision: trails "${existingId}" and "${trailItem.id}" both derive the tool name "${toolName}"`
308
+ return Result.err(
309
+ new ValidationError(
310
+ `MCP tool-name collision: trails "${existingId}" and "${trailItem.id}" both derive the tool name "${toolName}"`
311
+ )
341
312
  );
342
313
  }
343
314
  nameToTrailId.set(toolName, trailItem.id);
344
315
  tools.push(buildToolDefinition(app, trailItem, layers, options));
316
+ return Result.ok();
345
317
  };
346
318
 
347
319
  /** Filter topo items to eligible trails. */
@@ -360,14 +332,24 @@ const eligibleTrails = (
360
332
  export const buildMcpTools = (
361
333
  app: Topo,
362
334
  options: BuildMcpToolsOptions = {}
363
- ): McpToolDefinition[] => {
335
+ ): Result<McpToolDefinition[], Error> => {
364
336
  const layers = options.layers ?? [];
365
337
  const tools: McpToolDefinition[] = [];
366
338
  const nameToTrailId = new Map<string, string>();
367
339
 
368
340
  for (const trailItem of eligibleTrails(app, options)) {
369
- registerTool(app, trailItem, layers, options, nameToTrailId, tools);
341
+ const registered = registerTool(
342
+ app,
343
+ trailItem,
344
+ layers,
345
+ options,
346
+ nameToTrailId,
347
+ tools
348
+ );
349
+ if (registered.isErr()) {
350
+ return registered;
351
+ }
370
352
  }
371
353
 
372
- return tools;
354
+ return Result.ok(tools);
373
355
  };