@ontrails/mcp 1.0.0-beta.2 → 1.0.0-beta.21

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 (49) hide show
  1. package/CHANGELOG.md +300 -5
  2. package/README.md +70 -21
  3. package/package.json +11 -3
  4. package/src/annotations.ts +32 -9
  5. package/src/build.ts +1236 -137
  6. package/src/index.ts +31 -4
  7. package/src/progress.ts +22 -0
  8. package/src/resources.ts +228 -0
  9. package/src/stdio.ts +9 -1
  10. package/src/surface.ts +279 -0
  11. package/.turbo/turbo-build.log +0 -1
  12. package/.turbo/turbo-lint.log +0 -3
  13. package/.turbo/turbo-typecheck.log +0 -1
  14. package/dist/annotations.d.ts +0 -19
  15. package/dist/annotations.d.ts.map +0 -1
  16. package/dist/annotations.js +0 -29
  17. package/dist/annotations.js.map +0 -1
  18. package/dist/blaze.d.ts +0 -36
  19. package/dist/blaze.d.ts.map +0 -1
  20. package/dist/blaze.js +0 -96
  21. package/dist/blaze.js.map +0 -1
  22. package/dist/build.d.ts +0 -40
  23. package/dist/build.d.ts.map +0 -1
  24. package/dist/build.js +0 -190
  25. package/dist/build.js.map +0 -1
  26. package/dist/index.d.ts +0 -7
  27. package/dist/index.d.ts.map +0 -1
  28. package/dist/index.js +0 -13
  29. package/dist/index.js.map +0 -1
  30. package/dist/progress.d.ts +0 -13
  31. package/dist/progress.d.ts.map +0 -1
  32. package/dist/progress.js +0 -51
  33. package/dist/progress.js.map +0 -1
  34. package/dist/stdio.d.ts +0 -12
  35. package/dist/stdio.d.ts.map +0 -1
  36. package/dist/stdio.js +0 -15
  37. package/dist/stdio.js.map +0 -1
  38. package/dist/tool-name.d.ts +0 -15
  39. package/dist/tool-name.d.ts.map +0 -1
  40. package/dist/tool-name.js +0 -19
  41. package/dist/tool-name.js.map +0 -1
  42. package/src/__tests__/annotations.test.ts +0 -70
  43. package/src/__tests__/blaze.test.ts +0 -105
  44. package/src/__tests__/build.test.ts +0 -377
  45. package/src/__tests__/progress.test.ts +0 -136
  46. package/src/__tests__/tool-name.test.ts +0 -46
  47. package/src/blaze.ts +0 -146
  48. package/tsconfig.json +0 -9
  49. package/tsconfig.tsbuildinfo +0 -1
package/src/index.ts CHANGED
@@ -1,13 +1,35 @@
1
1
  // Build
2
2
  export {
3
- buildMcpTools,
4
- type BuildMcpToolsOptions,
3
+ MCP_TOOL_ERROR_META_KEY,
4
+ MCP_TOOL_EXAMPLES_META_KEY,
5
+ MCP_TOOL_DEFERRED_META_KEY,
6
+ MCP_TOOL_FACET_META_KEY,
7
+ deriveMcpTools,
8
+ type DeriveMcpToolsOptions,
9
+ type McpSurfaceFacetDefinition,
10
+ type McpSurfaceFacetMap,
11
+ type McpSurfaceFacetTrailSelector,
5
12
  type McpToolDefinition,
6
13
  type McpToolResult,
14
+ type McpToolErrorMeta,
7
15
  type McpContent,
8
16
  type McpExtra,
17
+ type ResolveMcpPermit,
18
+ type ResolveMcpPermitInput,
9
19
  } from './build.js';
10
20
 
21
+ // MCP resources
22
+ export {
23
+ MCP_EXAMPLES_RESOURCE_PREFIX,
24
+ MCP_SURFACE_MAP_RESOURCE_URI,
25
+ buildMcpResources,
26
+ isMcpFacetTool,
27
+ type BuiltMcpResources,
28
+ type McpResourceContent,
29
+ type McpResourceDefinition,
30
+ type McpResourcesConfig,
31
+ } from './resources.js';
32
+
11
33
  // Tool naming
12
34
  export { deriveToolName } from './tool-name.js';
13
35
 
@@ -17,8 +39,13 @@ export { deriveAnnotations, type McpAnnotations } from './annotations.js';
17
39
  // Progress
18
40
  export { createMcpProgressCallback } from './progress.js';
19
41
 
20
- // Blaze
21
- export { blaze, type BlazeMcpOptions } from './blaze.js';
42
+ // Surface
43
+ export {
44
+ createServer,
45
+ surface,
46
+ type CreateServerOptions,
47
+ type SurfaceMcpResult,
48
+ } from './surface.js';
22
49
 
23
50
  // Transport
24
51
  export { connectStdio } from './stdio.js';
package/src/progress.ts CHANGED
@@ -54,6 +54,28 @@ const progressHandlers: Record<
54
54
  *
55
55
  * Returns `undefined` if the MCP client did not provide a progressToken
56
56
  * (meaning no progress reporting was requested).
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * import { createMcpProgressCallback, type McpExtra } from '@ontrails/mcp';
61
+ *
62
+ * const extra: McpExtra = {
63
+ * progressToken: 'token-123',
64
+ * sendProgress: async (current, total) => {
65
+ * console.log(`progress ${current}/${total}`);
66
+ * },
67
+ * };
68
+ *
69
+ * const progress = createMcpProgressCallback(extra);
70
+ * if (progress !== undefined) {
71
+ * progress({
72
+ * current: 0,
73
+ * ts: new Date().toISOString(),
74
+ * total: 1,
75
+ * type: 'start',
76
+ * });
77
+ * }
78
+ * ```
57
79
  */
58
80
  export const createMcpProgressCallback = (
59
81
  extra: McpExtra
@@ -0,0 +1,228 @@
1
+ /**
2
+ * MCP resource projection for cold Trails context.
3
+ */
4
+
5
+ import { deriveStructuredTrailExamples } from '@ontrails/core';
6
+ import type { Topo, Trail } from '@ontrails/core';
7
+
8
+ import {
9
+ MCP_TOOL_DEFERRED_META_KEY,
10
+ MCP_TOOL_FACET_META_KEY,
11
+ } from './build.js';
12
+ import type { McpToolDefinition } from './build.js';
13
+
14
+ /**
15
+ * Resource URI used for the resolved MCP surface map.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { MCP_SURFACE_MAP_RESOURCE_URI } from '@ontrails/mcp';
20
+ *
21
+ * const surfaceMap = resources.read(MCP_SURFACE_MAP_RESOURCE_URI);
22
+ * ```
23
+ */
24
+ export const MCP_SURFACE_MAP_RESOURCE_URI = 'trails://surface-map';
25
+
26
+ /**
27
+ * Prefix used for trail example resources exposed through MCP.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * import { MCP_EXAMPLES_RESOURCE_PREFIX } from '@ontrails/mcp';
32
+ *
33
+ * const uri = `${MCP_EXAMPLES_RESOURCE_PREFIX}${encodeURIComponent('tasks.create')}`;
34
+ * ```
35
+ */
36
+ export const MCP_EXAMPLES_RESOURCE_PREFIX = 'trails://examples/';
37
+
38
+ export interface McpResourceDefinition {
39
+ readonly uri: string;
40
+ readonly mimeType: string;
41
+ readonly name: string;
42
+ readonly description?: string | undefined;
43
+ }
44
+
45
+ export interface McpResourceContent {
46
+ readonly uri: string;
47
+ readonly mimeType: string;
48
+ readonly text: string;
49
+ }
50
+
51
+ export interface McpResourcesConfig {
52
+ readonly surfaceMap?: boolean | undefined;
53
+ readonly examples?: boolean | undefined;
54
+ }
55
+
56
+ export interface BuiltMcpResources {
57
+ readonly list: readonly McpResourceDefinition[];
58
+ readonly read: (uri: string) => McpResourceContent | undefined;
59
+ }
60
+
61
+ interface McpSurfaceMapTool {
62
+ readonly annotations: McpToolDefinition['annotations'];
63
+ readonly description: string | undefined;
64
+ readonly facetId?: string | undefined;
65
+ readonly inputSchema: Record<string, unknown>;
66
+ readonly memberTrailIds?: readonly string[] | undefined;
67
+ readonly name: string;
68
+ readonly outputSchema?: Record<string, unknown> | undefined;
69
+ readonly trailId?: string | undefined;
70
+ readonly versions?: McpToolDefinition['versions'];
71
+ readonly deferred?: true | undefined;
72
+ }
73
+
74
+ interface McpSurfaceMap {
75
+ readonly surface: 'mcp';
76
+ readonly tools: readonly McpSurfaceMapTool[];
77
+ }
78
+
79
+ const asJson = (value: unknown): string =>
80
+ `${JSON.stringify(value, null, 2)}\n`;
81
+
82
+ const projectSurfaceMapTool = (tool: McpToolDefinition): McpSurfaceMapTool => ({
83
+ annotations: tool.annotations,
84
+ description: tool.description,
85
+ inputSchema: tool.inputSchema,
86
+ name: tool.name,
87
+ ...(tool.facetId === undefined ? {} : { facetId: tool.facetId }),
88
+ ...(tool.memberTrailIds === undefined
89
+ ? {}
90
+ : { memberTrailIds: tool.memberTrailIds }),
91
+ ...(tool.outputSchema === undefined
92
+ ? {}
93
+ : { outputSchema: tool.outputSchema }),
94
+ ...(tool.trailId === undefined ? {} : { trailId: tool.trailId }),
95
+ ...(tool.versions === undefined ? {} : { versions: tool.versions }),
96
+ ...(tool._meta?.[MCP_TOOL_DEFERRED_META_KEY] === true
97
+ ? { deferred: true }
98
+ : {}),
99
+ });
100
+
101
+ const buildSurfaceMap = (
102
+ tools: readonly McpToolDefinition[]
103
+ ): McpSurfaceMap => ({
104
+ surface: 'mcp',
105
+ tools: tools.map(projectSurfaceMapTool),
106
+ });
107
+
108
+ const exposedTrailIds = (
109
+ tools: readonly McpToolDefinition[]
110
+ ): ReadonlySet<string> =>
111
+ new Set(
112
+ tools.flatMap((tool) => [
113
+ ...(tool.trailId === undefined ? [] : [tool.trailId]),
114
+ ...(tool.memberTrailIds ?? []),
115
+ ])
116
+ );
117
+
118
+ const examplesUriForTrail = (trailId: string): string =>
119
+ `${MCP_EXAMPLES_RESOURCE_PREFIX}${encodeURIComponent(trailId)}`;
120
+
121
+ const buildExampleResource = (
122
+ trailItem: Trail<unknown, unknown, unknown>
123
+ ):
124
+ | {
125
+ readonly content: McpResourceContent;
126
+ readonly listing: McpResourceDefinition;
127
+ }
128
+ | undefined => {
129
+ const examples = deriveStructuredTrailExamples(trailItem.examples);
130
+ if (examples === undefined) {
131
+ return undefined;
132
+ }
133
+
134
+ const uri = examplesUriForTrail(trailItem.id);
135
+ return {
136
+ content: {
137
+ mimeType: 'application/json',
138
+ text: asJson({
139
+ examples,
140
+ trailId: trailItem.id,
141
+ }),
142
+ uri,
143
+ },
144
+ listing: {
145
+ description: `Structured examples for trail "${trailItem.id}".`,
146
+ mimeType: 'application/json',
147
+ name: `Trail examples: ${trailItem.id}`,
148
+ uri,
149
+ },
150
+ };
151
+ };
152
+
153
+ const buildExampleResources = (
154
+ graph: Topo,
155
+ tools: readonly McpToolDefinition[]
156
+ ): readonly {
157
+ readonly content: McpResourceContent;
158
+ readonly listing: McpResourceDefinition;
159
+ }[] => {
160
+ const visibleTrailIds = exposedTrailIds(tools);
161
+ return graph
162
+ .list()
163
+ .filter((trailItem) => visibleTrailIds.has(trailItem.id))
164
+ .map((trailItem) =>
165
+ buildExampleResource(trailItem as Trail<unknown, unknown, unknown>)
166
+ )
167
+ .filter((resource) => resource !== undefined);
168
+ };
169
+
170
+ /**
171
+ * Build the cold-context MCP resources for a Trails graph and tool set.
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * import { buildMcpResources, deriveMcpTools } from '@ontrails/mcp';
176
+ *
177
+ * const tools = deriveMcpTools(app).value;
178
+ * const resources = buildMcpResources(app, tools);
179
+ * ```
180
+ */
181
+ export const buildMcpResources = (
182
+ graph: Topo,
183
+ tools: readonly McpToolDefinition[],
184
+ config: McpResourcesConfig = {}
185
+ ): BuiltMcpResources => {
186
+ const listings: McpResourceDefinition[] = [];
187
+ const contents = new Map<string, McpResourceContent>();
188
+
189
+ if (config.surfaceMap !== false) {
190
+ const surfaceMapListing = {
191
+ description: 'Resolved MCP surface projection for this Trails app.',
192
+ mimeType: 'application/json',
193
+ name: 'Trails MCP surface map',
194
+ uri: MCP_SURFACE_MAP_RESOURCE_URI,
195
+ };
196
+ listings.push(surfaceMapListing);
197
+ contents.set(MCP_SURFACE_MAP_RESOURCE_URI, {
198
+ mimeType: 'application/json',
199
+ text: asJson(buildSurfaceMap(tools)),
200
+ uri: MCP_SURFACE_MAP_RESOURCE_URI,
201
+ });
202
+ }
203
+
204
+ if (config.examples !== false) {
205
+ for (const resource of buildExampleResources(graph, tools)) {
206
+ listings.push(resource.listing);
207
+ contents.set(resource.content.uri, resource.content);
208
+ }
209
+ }
210
+
211
+ return {
212
+ list: listings,
213
+ read: (uri) => contents.get(uri),
214
+ };
215
+ };
216
+
217
+ /**
218
+ * Return whether an MCP tool was projected from a surface facet.
219
+ *
220
+ * @example
221
+ * ```ts
222
+ * import { isMcpFacetTool } from '@ontrails/mcp';
223
+ *
224
+ * const facetTools = tools.filter(isMcpFacetTool);
225
+ * ```
226
+ */
227
+ export const isMcpFacetTool = (tool: McpToolDefinition): boolean =>
228
+ tool._meta?.[MCP_TOOL_FACET_META_KEY] !== undefined;
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 surface().
6
6
  */
7
7
 
8
8
  import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
@@ -10,6 +10,14 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
10
10
 
11
11
  /**
12
12
  * Connect an MCP server to stdio transport.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { connectStdio, createServer } from '@ontrails/mcp';
17
+ *
18
+ * const server = createServer(graph);
19
+ * await connectStdio(server);
20
+ * ```
13
21
  */
14
22
  export const connectStdio = async (server: Server): Promise<void> => {
15
23
  const transport = new StdioServerTransport();
package/src/surface.ts ADDED
@@ -0,0 +1,279 @@
1
+ /**
2
+ * Surface helpers for exposing a topo over MCP.
3
+ */
4
+
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import {
7
+ CallToolRequestSchema,
8
+ ListResourcesRequestSchema,
9
+ ListToolsRequestSchema,
10
+ ReadResourceRequestSchema,
11
+ } from '@modelcontextprotocol/sdk/types.js';
12
+ import type {
13
+ BaseSurfaceOptions,
14
+ Layer,
15
+ ResourceOverrideMap,
16
+ Topo,
17
+ TrailContextInit,
18
+ } from '@ontrails/core';
19
+
20
+ import type {
21
+ McpSurfaceFacetMap,
22
+ McpToolDefinition,
23
+ ResolveMcpPermit,
24
+ } from './build.js';
25
+ import { deriveMcpTools } from './build.js';
26
+ import { buildMcpResources } from './resources.js';
27
+ import type { BuiltMcpResources, McpResourcesConfig } from './resources.js';
28
+ import { connectStdio } from './stdio.js';
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Options
32
+ // ---------------------------------------------------------------------------
33
+
34
+ export interface CreateServerOptions extends BaseSurfaceOptions {
35
+ readonly createContext?:
36
+ | (() => TrailContextInit | Promise<TrailContextInit>)
37
+ | undefined;
38
+ readonly description?: string | undefined;
39
+ readonly facets?: McpSurfaceFacetMap | undefined;
40
+ readonly layers?: readonly Layer[] | undefined;
41
+ readonly mcpResources?: McpResourcesConfig | false | undefined;
42
+ readonly name?: string | undefined;
43
+ readonly resources?: ResourceOverrideMap | undefined;
44
+ readonly resolvePermit?: ResolveMcpPermit | undefined;
45
+ readonly version?: string | undefined;
46
+ }
47
+
48
+ export interface SurfaceMcpResult {
49
+ readonly close: () => Promise<void>;
50
+ }
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Internal: create MCP server with tool handlers
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /**
57
+ * Create an MCP Server instance and register all tools.
58
+ *
59
+ * When provided, `info.description` is forwarded to the MCP SDK as the
60
+ * server's `instructions` field — the SDK's documented channel for
61
+ * "optional instructions describing how to use the server and its features."
62
+ */
63
+ const createMcpServer = (
64
+ tools: McpToolDefinition[],
65
+ info: {
66
+ readonly name: string;
67
+ readonly version: string;
68
+ readonly description?: string | undefined;
69
+ },
70
+ mcpResources?: BuiltMcpResources | undefined
71
+ ): Server => {
72
+ const server = new Server(
73
+ { name: info.name, version: info.version },
74
+ {
75
+ capabilities: {
76
+ ...(mcpResources === undefined ? {} : { resources: {} }),
77
+ tools: {},
78
+ },
79
+ ...(info.description === undefined
80
+ ? {}
81
+ : { instructions: info.description }),
82
+ }
83
+ );
84
+
85
+ // Build a lookup map for tool dispatch
86
+ const toolMap = new Map<string, McpToolDefinition>();
87
+ for (const tool of tools) {
88
+ toolMap.set(tool.name, tool);
89
+ }
90
+
91
+ // Register tools/list handler
92
+ // oxlint-disable-next-line require-await -- MCP SDK requires async handler
93
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
94
+ tools: tools.map((t) => ({
95
+ _meta: t._meta,
96
+ annotations: t.annotations,
97
+ description: t.description,
98
+ inputSchema: t.inputSchema,
99
+ name: t.name,
100
+ outputSchema: t.outputSchema,
101
+ })),
102
+ }));
103
+
104
+ // Register tools/call handler
105
+ server.setRequestHandler(
106
+ CallToolRequestSchema,
107
+ async (request, requestExtra) => {
108
+ const tool = toolMap.get(request.params.name);
109
+ if (tool === undefined) {
110
+ return {
111
+ content: [
112
+ {
113
+ text: `Unknown tool: ${request.params.name}`,
114
+ type: 'text' as const,
115
+ },
116
+ ],
117
+ isError: true,
118
+ } as Record<string, unknown>;
119
+ }
120
+
121
+ const args = (request.params.arguments ?? {}) as Record<string, unknown>;
122
+ const progressToken = request.params._meta?.progressToken;
123
+ const { authInfo } = requestExtra as {
124
+ readonly authInfo?:
125
+ | {
126
+ readonly accessToken?: string | undefined;
127
+ readonly sessionId?: string | undefined;
128
+ readonly token?: string | undefined;
129
+ }
130
+ | undefined;
131
+ };
132
+ const authorizationToken = authInfo?.accessToken ?? authInfo?.token;
133
+
134
+ const sendProgress =
135
+ progressToken === undefined
136
+ ? undefined
137
+ : async (current: number, total: number) => {
138
+ await server.notification({
139
+ method: 'notifications/progress',
140
+ params: {
141
+ progress: current,
142
+ progressToken,
143
+ total,
144
+ },
145
+ });
146
+ };
147
+
148
+ const extra = {
149
+ abortSignal: requestExtra.signal,
150
+ ...(authorizationToken === undefined
151
+ ? {}
152
+ : { authorization: `Bearer ${authorizationToken}` }),
153
+ progressToken,
154
+ sendProgress,
155
+ ...(authInfo?.sessionId === undefined
156
+ ? {}
157
+ : { sessionId: authInfo.sessionId }),
158
+ };
159
+
160
+ const result = await tool.handler(args, extra);
161
+ // Spread to satisfy MCP SDK's index-signature requirement
162
+ return { ...result } as Record<string, unknown>;
163
+ }
164
+ );
165
+
166
+ if (mcpResources !== undefined) {
167
+ // oxlint-disable-next-line require-await -- MCP SDK requires async handler
168
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
169
+ resources: mcpResources.list.map((resource) => ({
170
+ description: resource.description,
171
+ mimeType: resource.mimeType,
172
+ name: resource.name,
173
+ uri: resource.uri,
174
+ })),
175
+ }));
176
+
177
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
178
+ const content = mcpResources.read(request.params.uri);
179
+ return {
180
+ contents: [
181
+ content ?? {
182
+ mimeType: 'text/plain',
183
+ text: `Unknown MCP resource: ${request.params.uri}`,
184
+ uri: request.params.uri,
185
+ },
186
+ ],
187
+ };
188
+ });
189
+ }
190
+
191
+ return server;
192
+ };
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // createServer
196
+ // ---------------------------------------------------------------------------
197
+
198
+ /**
199
+ * Build MCP tools from a topo and create an MCP server.
200
+ *
201
+ * @remarks This is a host materialization boundary. Derivation failures are
202
+ * thrown for server bootstrap code after `deriveMcpTools` has already
203
+ * represented the framework error as a Result.
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * import { connectStdio, createServer } from '@ontrails/mcp';
208
+ *
209
+ * const server = createServer(graph, { name: 'demo' });
210
+ * await connectStdio(server);
211
+ * ```
212
+ */
213
+ export const createServer = (
214
+ graph: Topo,
215
+ options: CreateServerOptions = {}
216
+ ): Server => {
217
+ const toolsResult = deriveMcpTools(graph, {
218
+ configValues: options.configValues,
219
+ createContext: options.createContext,
220
+ exclude: options.exclude,
221
+ facets: options.facets,
222
+ include: options.include,
223
+ intent: options.intent,
224
+ layers: options.layers,
225
+ resolvePermit: options.resolvePermit,
226
+ resources: options.resources,
227
+ validate: options.validate,
228
+ });
229
+
230
+ if (toolsResult.isErr()) {
231
+ throw toolsResult.error;
232
+ }
233
+
234
+ const mcpResources =
235
+ options.mcpResources === false
236
+ ? undefined
237
+ : buildMcpResources(graph, toolsResult.value, options.mcpResources);
238
+
239
+ return createMcpServer(
240
+ toolsResult.value,
241
+ {
242
+ description: options.description ?? graph.description,
243
+ name: options.name ?? graph.name,
244
+ version: options.version ?? graph.version ?? '0.1.0',
245
+ },
246
+ mcpResources
247
+ );
248
+ };
249
+
250
+ // ---------------------------------------------------------------------------
251
+ // surface
252
+ // ---------------------------------------------------------------------------
253
+
254
+ /**
255
+ * Build MCP tools from a topo, create a server, and connect via stdio.
256
+ *
257
+ * @remarks Opens the MCP server on stdio. For custom transports, use
258
+ * `createServer(graph)` with `connectStdio` or your own adapter.
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * import { surface } from '@ontrails/mcp';
263
+ *
264
+ * await surface(graph, { name: 'demo' });
265
+ * ```
266
+ */
267
+ export const surface = async (
268
+ graph: Topo,
269
+ options: CreateServerOptions = {}
270
+ ): Promise<SurfaceMcpResult> => {
271
+ const server = createServer(graph, options);
272
+ await connectStdio(server);
273
+
274
+ return {
275
+ close: async () => {
276
+ await server.close();
277
+ },
278
+ };
279
+ };
@@ -1 +0,0 @@
1
- $ tsc -b
@@ -1,3 +0,0 @@
1
- $ oxlint ./src
2
- Found 0 warnings and 0 errors.
3
- Finished in 54ms on 12 files with 93 rules using 24 threads.
@@ -1 +0,0 @@
1
- $ tsc --noEmit
@@ -1,19 +0,0 @@
1
- /**
2
- * Derive MCP tool annotations from trail spec markers.
3
- */
4
- import type { Trail } from '@ontrails/core';
5
- export interface McpAnnotations {
6
- readonly readOnlyHint?: boolean | undefined;
7
- readonly destructiveHint?: boolean | undefined;
8
- readonly idempotentHint?: boolean | undefined;
9
- readonly openWorldHint?: boolean | undefined;
10
- readonly title?: string | undefined;
11
- }
12
- /**
13
- * Map trail spec fields to MCP tool annotations.
14
- *
15
- * Only sets hints that are explicitly declared on the trail.
16
- * Omitted hints let the MCP SDK use its defaults.
17
- */
18
- export declare const deriveAnnotations: (trail: Pick<Trail<unknown, unknown>, "readOnly" | "destructive" | "idempotent" | "description">) => McpAnnotations;
19
- //# sourceMappingURL=annotations.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../src/annotations.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAM5C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAMD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,IAAI,CACT,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,EACvB,UAAU,GAAG,aAAa,GAAG,YAAY,GAAG,aAAa,CAC1D,KACA,cAiBF,CAAC"}
@@ -1,29 +0,0 @@
1
- /**
2
- * Derive MCP tool annotations from trail spec markers.
3
- */
4
- // ---------------------------------------------------------------------------
5
- // Derivation
6
- // ---------------------------------------------------------------------------
7
- /**
8
- * Map trail spec fields to MCP tool annotations.
9
- *
10
- * Only sets hints that are explicitly declared on the trail.
11
- * Omitted hints let the MCP SDK use its defaults.
12
- */
13
- export const deriveAnnotations = (trail) => {
14
- const annotations = {};
15
- if (trail.readOnly === true) {
16
- annotations['readOnlyHint'] = true;
17
- }
18
- if (trail.destructive === true) {
19
- annotations['destructiveHint'] = true;
20
- }
21
- if (trail.idempotent === true) {
22
- annotations['idempotentHint'] = true;
23
- }
24
- if (trail.description !== undefined) {
25
- annotations['title'] = trail.description;
26
- }
27
- return annotations;
28
- };
29
- //# sourceMappingURL=annotations.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"annotations.js","sourceRoot":"","sources":["../src/annotations.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAGC,EACe,EAAE;IAClB,MAAM,WAAW,GAA4B,EAAE,CAAC;IAEhD,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC5B,WAAW,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;IACrC,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;QAC/B,WAAW,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAAC;IACxC,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QAC9B,WAAW,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC;IACvC,CAAC;IACD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACpC,WAAW,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC;IAC3C,CAAC;IAED,OAAO,WAA6B,CAAC;AACvC,CAAC,CAAC"}