@ontrails/mcp 1.0.0-beta.23 → 1.0.0-beta.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @ontrails/mcp
2
2
 
3
+ ## 1.0.0-beta.29
4
+
5
+ ### Patch Changes
6
+
7
+ - @ontrails/core@1.0.0-beta.29
8
+
9
+ ## 1.0.0-beta.28
10
+
11
+ ### Patch Changes
12
+
13
+ - @ontrails/core@1.0.0-beta.28
14
+
15
+ ## 1.0.0-beta.27
16
+
17
+ ### Patch Changes
18
+
19
+ - @ontrails/core@1.0.0-beta.27
20
+
21
+ ## 1.0.0-beta.26
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [1307568]
26
+ - Updated dependencies [371d19e]
27
+ - @ontrails/core@1.0.0-beta.26
28
+
29
+ ## 1.0.0-beta.25
30
+
31
+ ### Patch Changes
32
+
33
+ - a9fdbc7: Clarify surface accommodation doctrine in MCP surface facet metadata and Warden trail-fork coaching guidance.
34
+ - 2c08afe: Expose MCP trail graph fact resources and enable them for the Trails operator MCP surface.
35
+ - f1e6efa: Document the Wayfinder MCP resource surface and polish Wayfinder filter dogfood coverage for unified navigation.
36
+ - df13faf: Tighten Wayfinder navigation review findings: carry adapter filters into included adapter facts, keep live-source outline off the operator MCP surface until host-root binding exists, make unknown MCP resources protocol errors, route secondary Wayfinder graph populations through unified flags, and keep undeclared string `ctx.compose()` calls as Warden errors.
37
+ - Updated dependencies [c36aca9]
38
+ - Updated dependencies [3befcf1]
39
+ - Updated dependencies [a4f9cf6]
40
+ - Updated dependencies [9bcf34e]
41
+ - @ontrails/core@1.0.0-beta.25
42
+
43
+ ## 1.0.0-beta.24
44
+
45
+ ### Patch Changes
46
+
47
+ - @ontrails/core@1.0.0-beta.24
48
+
3
49
  ## 1.0.0-beta.23
4
50
 
5
51
  ### Patch Changes
package/README.md CHANGED
@@ -86,6 +86,7 @@ Cold context is projected through MCP resources, not extra Trails resources. `su
86
86
 
87
87
  - `trails://surface-map` lists the resolved MCP tool projection, including ordinary tools, facet tools, schemas, versions, deferred hints, and member trail IDs.
88
88
  - `trails://examples/<trailId>` exposes structured examples for exposed trails that define examples.
89
+ - `trails://trail/<trailId>` exposes MCP-visible graph facts for an exposed trail when graph resources are enabled.
89
90
 
90
91
  Disable resource projection only when the host needs a minimal MCP capability surface:
91
92
 
@@ -97,10 +98,12 @@ Or choose a narrower resource set:
97
98
 
98
99
  ```typescript
99
100
  await surface(graph, {
100
- mcpResources: { examples: false, surfaceMap: true },
101
+ mcpResources: { examples: false, graph: true, surfaceMap: true },
101
102
  });
102
103
  ```
103
104
 
105
+ Graph resources are opt-in for general MCP hosts because they widen cold context for every exposed trail. The Trails operator enables them so agents can inspect high-signal graph facts without invoking another tool.
106
+
104
107
  Facet definitions may set `mcp: { loading: 'deferred' }`. In this release, deferred loading is a compatibility hint under `_meta["ontrails/deferred"]`; the MCP tool schema remains present so clients that do not understand deferred loading continue to work.
105
108
 
106
109
  ## Tool naming
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/mcp",
3
- "version": "1.0.0-beta.23",
3
+ "version": "1.0.0-beta.29",
4
4
  "files": [
5
5
  "src/**/*.ts",
6
6
  "!src/**/__tests__/**",
@@ -22,7 +22,7 @@
22
22
  "clean": "rm -rf dist *.tsbuildinfo"
23
23
  },
24
24
  "dependencies": {
25
- "@ontrails/core": "^1.0.0-beta.23"
25
+ "@ontrails/core": "^1.0.0-beta.29"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@modelcontextprotocol/sdk": "^1.28.0",
package/src/build.ts CHANGED
@@ -73,6 +73,10 @@ export const MCP_TOOL_ERROR_META_KEY = 'ontrails/error';
73
73
  /**
74
74
  * Metadata key used to identify MCP tools derived from surface facets.
75
75
  *
76
+ * Surface facets preserve member trail identity rather than merging member
77
+ * contracts. The metadata names the facet and its member trail IDs so clients
78
+ * can inspect the grouped entry before choosing a selected trail.
79
+ *
76
80
  * @example
77
81
  * ```ts
78
82
  * import { MCP_TOOL_FACET_META_KEY } from '@ontrails/mcp';
@@ -111,6 +115,7 @@ export interface DeriveMcpToolsOptions extends BaseSurfaceOptions {
111
115
 
112
116
  export type McpSurfaceFacetTrailSelector = string | readonly string[];
113
117
 
118
+ /** Surface-side grouped entry over existing trails. */
114
119
  export interface McpSurfaceFacetDefinition {
115
120
  readonly trails: McpSurfaceFacetTrailSelector;
116
121
  readonly description: string;
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ export {
22
22
  export {
23
23
  MCP_EXAMPLES_RESOURCE_PREFIX,
24
24
  MCP_SURFACE_MAP_RESOURCE_URI,
25
+ MCP_TRAIL_RESOURCE_PREFIX,
25
26
  buildMcpResources,
26
27
  isMcpFacetTool,
27
28
  type BuiltMcpResources,
package/src/resources.ts CHANGED
@@ -35,6 +35,18 @@ export const MCP_SURFACE_MAP_RESOURCE_URI = 'trails://surface-map';
35
35
  */
36
36
  export const MCP_EXAMPLES_RESOURCE_PREFIX = 'trails://examples/';
37
37
 
38
+ /**
39
+ * Prefix used for trail graph fact resources exposed through MCP.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * import { MCP_TRAIL_RESOURCE_PREFIX } from '@ontrails/mcp';
44
+ *
45
+ * const uri = `${MCP_TRAIL_RESOURCE_PREFIX}${encodeURIComponent('tasks.create')}`;
46
+ * ```
47
+ */
48
+ export const MCP_TRAIL_RESOURCE_PREFIX = 'trails://trail/';
49
+
38
50
  export interface McpResourceDefinition {
39
51
  readonly uri: string;
40
52
  readonly mimeType: string;
@@ -51,6 +63,7 @@ export interface McpResourceContent {
51
63
  export interface McpResourcesConfig {
52
64
  readonly surfaceMap?: boolean | undefined;
53
65
  readonly examples?: boolean | undefined;
66
+ readonly graph?: boolean | undefined;
54
67
  }
55
68
 
56
69
  export interface BuiltMcpResources {
@@ -76,6 +89,21 @@ interface McpSurfaceMap {
76
89
  readonly tools: readonly McpSurfaceMapTool[];
77
90
  }
78
91
 
92
+ interface McpTrailResource {
93
+ readonly trailId: string;
94
+ readonly description?: string | undefined;
95
+ readonly intent: Trail<unknown, unknown, unknown>['intent'];
96
+ readonly visibility: Trail<unknown, unknown, unknown>['visibility'];
97
+ readonly composes: readonly string[];
98
+ readonly resources: readonly string[];
99
+ readonly signals: {
100
+ readonly fires: readonly string[];
101
+ readonly on: readonly string[];
102
+ };
103
+ readonly surface: 'mcp';
104
+ readonly tools: readonly McpSurfaceMapTool[];
105
+ }
106
+
79
107
  const asJson = (value: unknown): string =>
80
108
  `${JSON.stringify(value, null, 2)}\n`;
81
109
 
@@ -118,6 +146,9 @@ const exposedTrailIds = (
118
146
  const examplesUriForTrail = (trailId: string): string =>
119
147
  `${MCP_EXAMPLES_RESOURCE_PREFIX}${encodeURIComponent(trailId)}`;
120
148
 
149
+ const trailUriForTrail = (trailId: string): string =>
150
+ `${MCP_TRAIL_RESOURCE_PREFIX}${encodeURIComponent(trailId)}`;
151
+
121
152
  const buildExampleResource = (
122
153
  trailItem: Trail<unknown, unknown, unknown>
123
154
  ):
@@ -167,6 +198,76 @@ const buildExampleResources = (
167
198
  .filter((resource) => resource !== undefined);
168
199
  };
169
200
 
201
+ const resourceId = (
202
+ resource: Trail<unknown, unknown, unknown>['resources'][number]
203
+ ) => resource.id;
204
+
205
+ const buildTrailGraphResource = (
206
+ trailItem: Trail<unknown, unknown, unknown>,
207
+ tools: readonly McpToolDefinition[]
208
+ ): {
209
+ readonly content: McpResourceContent;
210
+ readonly listing: McpResourceDefinition;
211
+ } => {
212
+ const uri = trailUriForTrail(trailItem.id);
213
+ const surfaceTools = tools
214
+ .filter(
215
+ (tool) =>
216
+ tool.trailId === trailItem.id ||
217
+ tool.memberTrailIds?.includes(trailItem.id) === true
218
+ )
219
+ .map(projectSurfaceMapTool);
220
+ const payload: McpTrailResource = {
221
+ composes: trailItem.composes,
222
+ ...(trailItem.description === undefined
223
+ ? {}
224
+ : { description: trailItem.description }),
225
+ intent: trailItem.intent,
226
+ resources: trailItem.resources.map(resourceId),
227
+ signals: {
228
+ fires: trailItem.fires,
229
+ on: trailItem.on,
230
+ },
231
+ surface: 'mcp',
232
+ tools: surfaceTools,
233
+ trailId: trailItem.id,
234
+ visibility: trailItem.visibility,
235
+ };
236
+
237
+ return {
238
+ content: {
239
+ mimeType: 'application/json',
240
+ text: asJson(payload),
241
+ uri,
242
+ },
243
+ listing: {
244
+ description: `MCP-visible graph facts for trail "${trailItem.id}".`,
245
+ mimeType: 'application/json',
246
+ name: `Trail graph fact: ${trailItem.id}`,
247
+ uri,
248
+ },
249
+ };
250
+ };
251
+
252
+ const buildTrailGraphResources = (
253
+ graph: Topo,
254
+ tools: readonly McpToolDefinition[]
255
+ ): readonly {
256
+ readonly content: McpResourceContent;
257
+ readonly listing: McpResourceDefinition;
258
+ }[] => {
259
+ const visibleTrailIds = exposedTrailIds(tools);
260
+ return graph
261
+ .list()
262
+ .filter((trailItem) => visibleTrailIds.has(trailItem.id))
263
+ .map((trailItem) =>
264
+ buildTrailGraphResource(
265
+ trailItem as Trail<unknown, unknown, unknown>,
266
+ tools
267
+ )
268
+ );
269
+ };
270
+
170
271
  /**
171
272
  * Build the cold-context MCP resources for a Trails graph and tool set.
172
273
  *
@@ -208,6 +309,13 @@ export const buildMcpResources = (
208
309
  }
209
310
  }
210
311
 
312
+ if (config.graph === true) {
313
+ for (const resource of buildTrailGraphResources(graph, tools)) {
314
+ listings.push(resource.listing);
315
+ contents.set(resource.content.uri, resource.content);
316
+ }
317
+ }
318
+
211
319
  return {
212
320
  list: listings,
213
321
  read: (uri) => contents.get(uri),
package/src/surface.ts CHANGED
@@ -5,8 +5,10 @@
5
5
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
6
  import {
7
7
  CallToolRequestSchema,
8
+ ErrorCode,
8
9
  ListResourcesRequestSchema,
9
10
  ListToolsRequestSchema,
11
+ McpError,
10
12
  ReadResourceRequestSchema,
11
13
  } from '@modelcontextprotocol/sdk/types.js';
12
14
  import type {
@@ -176,14 +178,14 @@ const createMcpServer = (
176
178
 
177
179
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
178
180
  const content = mcpResources.read(request.params.uri);
181
+ if (content === undefined) {
182
+ throw new McpError(
183
+ ErrorCode.InvalidParams,
184
+ `Resource ${request.params.uri} not found`
185
+ );
186
+ }
179
187
  return {
180
- contents: [
181
- content ?? {
182
- mimeType: 'text/plain',
183
- text: `Unknown MCP resource: ${request.params.uri}`,
184
- uri: request.params.uri,
185
- },
186
- ],
188
+ contents: [content],
187
189
  };
188
190
  });
189
191
  }