@ontrails/mcp 1.0.0-beta.12 → 1.0.0-beta.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/build.ts CHANGED
@@ -2,22 +2,23 @@
2
2
  * Build MCP tool definitions from a Trails App.
3
3
  *
4
4
  * Iterates the topo, generates McpToolDefinition[] with handlers that
5
- * validate input, compose layers, execute the implementation, and map
5
+ * validate input, compose gates, execute the implementation, and map
6
6
  * Results to MCP responses.
7
7
  */
8
8
 
9
9
  import {
10
10
  Result,
11
- SURFACE_KEY,
11
+ TRAILHEAD_KEY,
12
12
  ValidationError,
13
13
  executeTrail,
14
14
  isBlobRef,
15
+ validateEstablishedTopo,
15
16
  zodToJsonSchema,
16
17
  } from '@ontrails/core';
17
18
  import type {
18
19
  BlobRef,
19
- Layer,
20
- ServiceOverrideMap,
20
+ Gate,
21
+ ProvisionOverrideMap,
21
22
  Topo,
22
23
  Trail,
23
24
  TrailContextInit,
@@ -33,7 +34,7 @@ import { deriveToolName } from './tool-name.js';
33
34
  // ---------------------------------------------------------------------------
34
35
 
35
36
  export interface BuildMcpToolsOptions {
36
- /** Config values for services that declare a `config` schema, keyed by service ID. */
37
+ /** Config values for provisions that declare a `config` schema, keyed by provision ID. */
37
38
  readonly configValues?:
38
39
  | Readonly<Record<string, Record<string, unknown>>>
39
40
  | undefined;
@@ -42,8 +43,10 @@ export interface BuildMcpToolsOptions {
42
43
  | undefined;
43
44
  readonly excludeTrails?: readonly string[] | undefined;
44
45
  readonly includeTrails?: readonly string[] | undefined;
45
- readonly layers?: readonly Layer[] | undefined;
46
- readonly services?: ServiceOverrideMap | undefined;
46
+ readonly gates?: readonly Gate[] | undefined;
47
+ readonly provisions?: ProvisionOverrideMap | undefined;
48
+ /** Set to `false` to skip topo validation while building tools. */
49
+ readonly validate?: boolean | undefined;
47
50
  }
48
51
 
49
52
  export interface McpToolDefinition {
@@ -64,7 +67,7 @@ export interface McpExtra {
64
67
  readonly sendProgress?:
65
68
  | ((current: number, total: number) => Promise<void>)
66
69
  | undefined;
67
- readonly signal?: AbortSignal | undefined;
70
+ readonly abortSignal?: AbortSignal | undefined;
68
71
  }
69
72
 
70
73
  export interface McpToolResult {
@@ -212,20 +215,20 @@ const mcpError = (message: string): McpToolResult => ({
212
215
  isError: true,
213
216
  });
214
217
 
215
- /** Add the MCP surface marker while preserving any existing context extras. */
216
- const withMcpSurface = (
218
+ /** Add the MCP trailhead marker while preserving any existing context extras. */
219
+ const withMcpTrailhead = (
217
220
  progressCb: TrailContextInit['progress']
218
221
  ): Partial<TrailContextInit> => ({
219
222
  ...(progressCb === undefined ? {} : { progress: progressCb }),
220
223
  extensions: {
221
- [SURFACE_KEY]: 'mcp' as const,
224
+ [TRAILHEAD_KEY]: 'mcp' as const,
222
225
  },
223
226
  });
224
227
 
225
228
  const createHandler =
226
229
  (
227
230
  t: Trail<unknown, unknown>,
228
- layers: readonly Layer[],
231
+ gates: readonly Gate[],
229
232
  options: BuildMcpToolsOptions
230
233
  ): ((
231
234
  args: Record<string, unknown>,
@@ -234,12 +237,12 @@ const createHandler =
234
237
  async (args, extra): Promise<McpToolResult> => {
235
238
  const progressCb = createMcpProgressCallback(extra);
236
239
  const result = await executeTrail(t, args, {
240
+ abortSignal: extra.abortSignal,
237
241
  configValues: options.configValues,
238
242
  createContext: options.createContext,
239
- ctx: withMcpSurface(progressCb),
240
- layers,
241
- services: options.services,
242
- signal: extra.signal,
243
+ ctx: withMcpTrailhead(progressCb),
244
+ gates,
245
+ provisions: options.provisions,
243
246
  });
244
247
  if (result.isOk()) {
245
248
  return { content: await serializeOutput(result.value) };
@@ -257,15 +260,15 @@ const createHandler =
257
260
  * Each trail in the topo becomes an McpToolDefinition with:
258
261
  * - A derived tool name (app-prefixed, underscore-delimited)
259
262
  * - JSON Schema input from zodToJsonSchema
260
- * - MCP annotations from trail metadata
261
- * - A handler that validates, composes layers, executes, and maps results
263
+ * - MCP annotations from trail meta
264
+ * - A handler that validates, composes gates, executes, and maps results
262
265
  */
263
- /** Check if a trail should be included based on metadata and filters. */
266
+ /** Check if a trail should be included based on meta and filters. */
264
267
  const shouldInclude = (
265
268
  trail: Trail<unknown, unknown>,
266
269
  options: BuildMcpToolsOptions
267
270
  ): boolean => {
268
- if (trail.metadata?.['internal'] === true) {
271
+ if (trail.meta?.['internal'] === true) {
269
272
  return false;
270
273
  }
271
274
  if (options.includeTrails !== undefined && options.includeTrails.length > 0) {
@@ -302,7 +305,7 @@ const buildDescription = (
302
305
  const buildToolDefinition = (
303
306
  app: Topo,
304
307
  trail: Trail<unknown, unknown>,
305
- layers: readonly Layer[],
308
+ gates: readonly Gate[],
306
309
  options: BuildMcpToolsOptions
307
310
  ): McpToolDefinition => {
308
311
  const rawAnnotations = deriveAnnotations(trail);
@@ -311,7 +314,7 @@ const buildToolDefinition = (
311
314
  return {
312
315
  annotations,
313
316
  description: buildDescription(trail),
314
- handler: createHandler(trail, layers, options),
317
+ handler: createHandler(trail, gates, options),
315
318
  inputSchema: zodToJsonSchema(trail.input),
316
319
  name: deriveToolName(app.name, trail.id),
317
320
  trailId: trail.id,
@@ -322,7 +325,7 @@ const buildToolDefinition = (
322
325
  const registerTool = (
323
326
  app: Topo,
324
327
  trailItem: Trail<unknown, unknown>,
325
- layers: readonly Layer[],
328
+ gates: readonly Gate[],
326
329
  options: BuildMcpToolsOptions,
327
330
  nameToTrailId: Map<string, string>,
328
331
  tools: McpToolDefinition[]
@@ -337,7 +340,7 @@ const registerTool = (
337
340
  );
338
341
  }
339
342
  nameToTrailId.set(toolName, trailItem.id);
340
- tools.push(buildToolDefinition(app, trailItem, layers, options));
343
+ tools.push(buildToolDefinition(app, trailItem, gates, options));
341
344
  return Result.ok();
342
345
  };
343
346
 
@@ -348,11 +351,23 @@ const eligibleTrails = (
348
351
  ): Trail<unknown, unknown>[] =>
349
352
  app.list().filter((trail) => shouldInclude(trail, options));
350
353
 
351
- export const buildMcpTools = (
354
+ const validateToolBuild = (
352
355
  app: Topo,
353
- options: BuildMcpToolsOptions = {}
356
+ options: BuildMcpToolsOptions
357
+ ): Result<void, Error> => {
358
+ if (options.validate === false) {
359
+ return Result.ok();
360
+ }
361
+
362
+ const validated = validateEstablishedTopo(app);
363
+ return validated.isErr() ? Result.err(validated.error) : Result.ok();
364
+ };
365
+
366
+ const registerTools = (
367
+ app: Topo,
368
+ options: BuildMcpToolsOptions,
369
+ gates: readonly Gate[]
354
370
  ): Result<McpToolDefinition[], Error> => {
355
- const layers = options.layers ?? [];
356
371
  const tools: McpToolDefinition[] = [];
357
372
  const nameToTrailId = new Map<string, string>();
358
373
 
@@ -360,7 +375,7 @@ export const buildMcpTools = (
360
375
  const registered = registerTool(
361
376
  app,
362
377
  trailItem,
363
- layers,
378
+ gates,
364
379
  options,
365
380
  nameToTrailId,
366
381
  tools
@@ -372,3 +387,15 @@ export const buildMcpTools = (
372
387
 
373
388
  return Result.ok(tools);
374
389
  };
390
+
391
+ export const buildMcpTools = (
392
+ app: Topo,
393
+ options: BuildMcpToolsOptions = {}
394
+ ): Result<McpToolDefinition[], Error> => {
395
+ const validation = validateToolBuild(app, options);
396
+ if (validation.isErr()) {
397
+ return validation;
398
+ }
399
+
400
+ return registerTools(app, options, options.gates ?? []);
401
+ };
package/src/index.ts CHANGED
@@ -17,8 +17,8 @@ export { deriveAnnotations, type McpAnnotations } from './annotations.js';
17
17
  // Progress
18
18
  export { createMcpProgressCallback } from './progress.js';
19
19
 
20
- // Blaze
21
- export { blaze, type BlazeMcpOptions } from './blaze.js';
20
+ // Trailhead
21
+ export { trailhead, type TrailheadMcpOptions } from './trailhead.js';
22
22
 
23
23
  // Transport
24
24
  export { connectStdio } from './stdio.js';
package/src/stdio.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Thin wrapper around MCP SDK's StdioServerTransport.
3
3
  *
4
4
  * Exists as a separate function so it can be swapped for other transports
5
- * (SSE, streamable HTTP) without changing blaze().
5
+ * (SSE, streamable HTTP) without changing trailhead().
6
6
  */
7
7
 
8
8
  import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
@@ -1,11 +1,11 @@
1
1
  /**
2
- * blaze() -- the one-liner MCP server launcher.
2
+ * trailhead() -- the one-liner MCP server launcher.
3
3
  *
4
4
  * Three lines to expose trails as MCP tools:
5
5
  *
6
6
  * ```ts
7
7
  * const app = topo("myapp", entity);
8
- * await blaze(app);
8
+ * await trailhead(app);
9
9
  * ```
10
10
  */
11
11
 
@@ -15,12 +15,12 @@ import {
15
15
  ListToolsRequestSchema,
16
16
  } from '@modelcontextprotocol/sdk/types.js';
17
17
  import type {
18
- Layer,
19
- ServiceOverrideMap,
18
+ Gate,
19
+ ProvisionOverrideMap,
20
20
  Topo,
21
21
  TrailContextInit,
22
22
  } from '@ontrails/core';
23
- import { validateTopo } from '@ontrails/core';
23
+ import { validateEstablishedTopo } from '@ontrails/core';
24
24
 
25
25
  import type { McpToolDefinition } from './build.js';
26
26
  import { buildMcpTools } from './build.js';
@@ -30,8 +30,8 @@ import { connectStdio } from './stdio.js';
30
30
  // Options
31
31
  // ---------------------------------------------------------------------------
32
32
 
33
- export interface BlazeMcpOptions {
34
- /** Config values for services that declare a `config` schema, keyed by service ID. */
33
+ export interface TrailheadMcpOptions {
34
+ /** Config values for provisions that declare a `config` schema, keyed by provision ID. */
35
35
  readonly configValues?:
36
36
  | Readonly<Record<string, Record<string, unknown>>>
37
37
  | undefined;
@@ -40,7 +40,8 @@ export interface BlazeMcpOptions {
40
40
  | undefined;
41
41
  readonly excludeTrails?: readonly string[] | undefined;
42
42
  readonly includeTrails?: readonly string[] | undefined;
43
- readonly layers?: readonly Layer[] | undefined;
43
+ readonly gates?: readonly Gate[] | undefined;
44
+ readonly provisions?: ProvisionOverrideMap | undefined;
44
45
  readonly serverInfo?:
45
46
  | {
46
47
  readonly name?: string | undefined;
@@ -48,7 +49,6 @@ export interface BlazeMcpOptions {
48
49
  }
49
50
  | undefined;
50
51
  readonly transport?: 'stdio' | undefined;
51
- readonly services?: ServiceOverrideMap | undefined;
52
52
  /** Set to `false` to skip topo validation at startup. Defaults to `true`. */
53
53
  readonly validate?: boolean | undefined;
54
54
  }
@@ -119,9 +119,9 @@ export const createMcpServer = (
119
119
  };
120
120
 
121
121
  const extra = {
122
+ abortSignal: undefined as AbortSignal | undefined,
122
123
  progressToken,
123
124
  sendProgress,
124
- signal: undefined as AbortSignal | undefined,
125
125
  };
126
126
 
127
127
  const result = await tool.handler(args, extra);
@@ -133,18 +133,18 @@ export const createMcpServer = (
133
133
  };
134
134
 
135
135
  // ---------------------------------------------------------------------------
136
- // blaze
136
+ // trailhead
137
137
  // ---------------------------------------------------------------------------
138
138
 
139
139
  /**
140
140
  * Build MCP tools from an App, create a server, and connect via stdio.
141
141
  */
142
- export const blaze = async (
142
+ export const trailhead = async (
143
143
  app: Topo,
144
- options: BlazeMcpOptions = {}
144
+ options: TrailheadMcpOptions = {}
145
145
  ): Promise<void> => {
146
146
  if (options.validate !== false) {
147
- const validated = validateTopo(app);
147
+ const validated = validateEstablishedTopo(app);
148
148
  if (validated.isErr()) {
149
149
  throw validated.error;
150
150
  }
@@ -154,9 +154,10 @@ export const blaze = async (
154
154
  configValues: options.configValues,
155
155
  createContext: options.createContext,
156
156
  excludeTrails: options.excludeTrails,
157
+ gates: options.gates,
157
158
  includeTrails: options.includeTrails,
158
- layers: options.layers,
159
- services: options.services,
159
+ provisions: options.provisions,
160
+ validate: options.validate,
160
161
  });
161
162
 
162
163
  if (toolsResult.isErr()) {
@@ -1 +1 @@
1
- {"root":["./src/annotations.ts","./src/blaze.ts","./src/build.ts","./src/index.ts","./src/progress.ts","./src/stdio.ts","./src/tool-name.ts"],"version":"5.9.3"}
1
+ {"root":["./src/annotations.ts","./src/build.ts","./src/index.ts","./src/progress.ts","./src/stdio.ts","./src/tool-name.ts","./src/trailhead.ts"],"version":"5.9.3"}