@ontrails/mcp 1.0.0-beta.15 → 1.0.0-beta.16

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 +34 -0
  2. package/README.md +19 -3
  3. package/package.json +11 -3
  4. package/src/build.ts +642 -70
  5. package/src/index.ts +5 -0
  6. package/src/surface.ts +71 -53
  7. package/.turbo/turbo-build.log +0 -1
  8. package/.turbo/turbo-lint.log +0 -3
  9. package/.turbo/turbo-typecheck.log +0 -1
  10. package/dist/annotations.d.ts +0 -19
  11. package/dist/annotations.d.ts.map +0 -1
  12. package/dist/annotations.js +0 -31
  13. package/dist/annotations.js.map +0 -1
  14. package/dist/build.d.ts +0 -49
  15. package/dist/build.d.ts.map +0 -1
  16. package/dist/build.js +0 -220
  17. package/dist/build.js.map +0 -1
  18. package/dist/index.d.ts +0 -7
  19. package/dist/index.d.ts.map +0 -1
  20. package/dist/index.js +0 -13
  21. package/dist/index.js.map +0 -1
  22. package/dist/progress.d.ts +0 -13
  23. package/dist/progress.d.ts.map +0 -1
  24. package/dist/progress.js +0 -51
  25. package/dist/progress.js.map +0 -1
  26. package/dist/stdio.d.ts +0 -12
  27. package/dist/stdio.d.ts.map +0 -1
  28. package/dist/stdio.js +0 -15
  29. package/dist/stdio.js.map +0 -1
  30. package/dist/surface.d.ts +0 -35
  31. package/dist/surface.d.ts.map +0 -1
  32. package/dist/surface.js +0 -123
  33. package/dist/surface.js.map +0 -1
  34. package/dist/tool-name.d.ts +0 -15
  35. package/dist/tool-name.d.ts.map +0 -1
  36. package/dist/tool-name.js +0 -19
  37. package/dist/tool-name.js.map +0 -1
  38. package/dist/trailhead.d.ts +0 -57
  39. package/dist/trailhead.d.ts.map +0 -1
  40. package/dist/trailhead.js +0 -136
  41. package/dist/trailhead.js.map +0 -1
  42. package/src/__tests__/annotations.test.ts +0 -63
  43. package/src/__tests__/build.test.ts +0 -648
  44. package/src/__tests__/progress.test.ts +0 -136
  45. package/src/__tests__/surface.test.ts +0 -191
  46. package/src/__tests__/tool-name.test.ts +0 -46
  47. package/tsconfig.json +0 -9
  48. package/tsconfig.tests.json +0 -10
  49. package/tsconfig.tsbuildinfo +0 -1
package/dist/progress.js DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * Bridge Trails ProgressCallback to MCP sendProgress notifications.
3
- */
4
- /** Fire-and-forget a progress send, swallowing transport errors. */
5
- const fireSend = async (send, current, total) => {
6
- try {
7
- await send(current, total);
8
- }
9
- catch {
10
- /* Transport errors are expected and safe to ignore */
11
- }
12
- };
13
- const handleProgress = (event, send) => {
14
- if (event.current !== undefined && event.total !== undefined) {
15
- fireSend(send, event.current, event.total);
16
- }
17
- else if (event.current !== undefined) {
18
- fireSend(send, event.current, 0);
19
- }
20
- };
21
- const progressHandlers = {
22
- complete: (_event, send) => fireSend(send, 1, 1),
23
- error: () => {
24
- /* No progress notification for errors */
25
- },
26
- progress: handleProgress,
27
- start: (_event, send) => fireSend(send, 0, 1),
28
- };
29
- // ---------------------------------------------------------------------------
30
- // Factory
31
- // ---------------------------------------------------------------------------
32
- /**
33
- * Create a ProgressCallback that bridges to MCP's sendProgress.
34
- *
35
- * Returns `undefined` if the MCP client did not provide a progressToken
36
- * (meaning no progress reporting was requested).
37
- */
38
- export const createMcpProgressCallback = (extra) => {
39
- if (extra.progressToken === undefined || extra.progressToken === null) {
40
- return undefined;
41
- }
42
- if (typeof extra.sendProgress !== 'function') {
43
- return undefined;
44
- }
45
- const send = extra.sendProgress;
46
- return (event) => {
47
- const handler = progressHandlers[event.type];
48
- handler?.(event, send);
49
- };
50
- };
51
- //# sourceMappingURL=progress.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,oEAAoE;AACpE,MAAM,QAAQ,GAAG,KAAK,EACpB,IAAY,EACZ,OAAe,EACf,KAAa,EACE,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,KAAoB,EAAE,IAAY,EAAQ,EAAE;IAClE,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC7D,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACvC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAGlB;IACF,QAAQ,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,KAAK,EAAE,GAAG,EAAE;QACV,yCAAyC;IAC3C,CAAC;IACD,QAAQ,EAAE,cAAc;IACxB,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;CAC9C,CAAC;AAEF,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,KAAe,EACe,EAAE;IAChC,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;QACtE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;QAC7C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC;IAChC,OAAO,CAAC,KAAoB,EAAQ,EAAE;QACpC,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC,CAAC"}
package/dist/stdio.d.ts DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * Thin wrapper around MCP SDK's StdioServerTransport.
3
- *
4
- * Exists as a separate function so it can be swapped for other transports
5
- * (SSE, streamable HTTP) without changing surface().
6
- */
7
- import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
8
- /**
9
- * Connect an MCP server to stdio transport.
10
- */
11
- export declare const connectStdio: (server: Server) => Promise<void>;
12
- //# sourceMappingURL=stdio.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAGxE;;GAEG;AACH,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC,IAAI,CAG/D,CAAC"}
package/dist/stdio.js DELETED
@@ -1,15 +0,0 @@
1
- /**
2
- * Thin wrapper around MCP SDK's StdioServerTransport.
3
- *
4
- * Exists as a separate function so it can be swapped for other transports
5
- * (SSE, streamable HTTP) without changing surface().
6
- */
7
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
- /**
9
- * Connect an MCP server to stdio transport.
10
- */
11
- export const connectStdio = async (server) => {
12
- const transport = new StdioServerTransport();
13
- await server.connect(transport);
14
- };
15
- //# sourceMappingURL=stdio.js.map
package/dist/stdio.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;IAClE,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC,CAAC"}
package/dist/surface.d.ts DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * Surface helpers for exposing a topo over MCP.
3
- */
4
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
5
- import type { Intent, Layer, ResourceOverrideMap, Topo, TrailContextInit } from '@ontrails/core';
6
- export interface CreateServerOptions {
7
- /** Config values for resources that declare a `config` schema, keyed by resource ID. */
8
- readonly configValues?: Readonly<Record<string, Record<string, unknown>>> | undefined;
9
- readonly createContext?: (() => TrailContextInit | Promise<TrailContextInit>) | undefined;
10
- readonly description?: string | undefined;
11
- readonly exclude?: readonly string[] | undefined;
12
- readonly include?: readonly string[] | undefined;
13
- readonly intent?: readonly Intent[] | undefined;
14
- readonly layers?: readonly Layer[] | undefined;
15
- readonly name?: string | undefined;
16
- readonly resources?: ResourceOverrideMap | undefined;
17
- /** Set to `false` to skip topo validation at startup. Defaults to `true`. */
18
- readonly validate?: boolean | undefined;
19
- readonly version?: string | undefined;
20
- }
21
- export interface SurfaceMcpResult {
22
- readonly close: () => Promise<void>;
23
- }
24
- /**
25
- * Build MCP tools from a topo and create an MCP server.
26
- */
27
- export declare const createServer: (graph: Topo, options?: CreateServerOptions) => Server;
28
- /**
29
- * Build MCP tools from a topo, create a server, and connect via stdio.
30
- *
31
- * @remarks Opens the MCP server on stdio. For custom transports, use
32
- * `createServer(graph)` with `connectStdio` or your own connector.
33
- */
34
- export declare const surface: (graph: Topo, options?: CreateServerOptions) => Promise<SurfaceMcpResult>;
35
- //# sourceMappingURL=surface.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EACV,MAAM,EACN,KAAK,EACL,mBAAmB,EACnB,IAAI,EACJ,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAUxB,MAAM,WAAW,mBAAmB;IAClC,wFAAwF;IACxF,QAAQ,CAAC,YAAY,CAAC,EAClB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GACjD,SAAS,CAAC;IACd,QAAQ,CAAC,aAAa,CAAC,EACnB,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,GACpD,SAAS,CAAC;IACd,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrD,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAkGD;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,OAAO,IAAI,EACX,UAAS,mBAAwB,KAChC,MAqBF,CAAC;AAMF;;;;;GAKG;AACH,eAAO,MAAM,OAAO,GAClB,OAAO,IAAI,EACX,UAAS,mBAAwB,KAChC,OAAO,CAAC,gBAAgB,CAS1B,CAAC"}
package/dist/surface.js DELETED
@@ -1,123 +0,0 @@
1
- /**
2
- * Surface helpers for exposing a topo over MCP.
3
- */
4
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
5
- import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
6
- import { deriveMcpTools } from './build.js';
7
- import { connectStdio } from './stdio.js';
8
- // ---------------------------------------------------------------------------
9
- // Internal: create MCP server with tool handlers
10
- // ---------------------------------------------------------------------------
11
- /**
12
- * Create an MCP Server instance and register all tools.
13
- *
14
- * When provided, `info.description` is forwarded to the MCP SDK as the
15
- * server's `instructions` field — the SDK's documented channel for
16
- * "optional instructions describing how to use the server and its features."
17
- */
18
- const createMcpServer = (tools, info) => {
19
- const server = new Server({ name: info.name, version: info.version }, {
20
- capabilities: { tools: {} },
21
- ...(info.description === undefined
22
- ? {}
23
- : { instructions: info.description }),
24
- });
25
- // Build a lookup map for tool dispatch
26
- const toolMap = new Map();
27
- for (const tool of tools) {
28
- toolMap.set(tool.name, tool);
29
- }
30
- // Register tools/list handler
31
- // oxlint-disable-next-line require-await -- MCP SDK requires async handler
32
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
33
- tools: tools.map((t) => ({
34
- annotations: t.annotations,
35
- description: t.description,
36
- inputSchema: t.inputSchema,
37
- name: t.name,
38
- })),
39
- }));
40
- // Register tools/call handler
41
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
42
- const tool = toolMap.get(request.params.name);
43
- if (tool === undefined) {
44
- return {
45
- content: [
46
- {
47
- text: `Unknown tool: ${request.params.name}`,
48
- type: 'text',
49
- },
50
- ],
51
- isError: true,
52
- };
53
- }
54
- const args = (request.params.arguments ?? {});
55
- const progressToken = request.params._meta?.progressToken;
56
- const sendProgress = progressToken === undefined
57
- ? undefined
58
- : async (current, total) => {
59
- await server.notification({
60
- method: 'notifications/progress',
61
- params: {
62
- progress: current,
63
- progressToken: progressToken,
64
- total,
65
- },
66
- });
67
- };
68
- const extra = {
69
- abortSignal: undefined,
70
- progressToken,
71
- sendProgress,
72
- };
73
- const result = await tool.handler(args, extra);
74
- // Spread to satisfy MCP SDK's index-signature requirement
75
- return { ...result };
76
- });
77
- return server;
78
- };
79
- // ---------------------------------------------------------------------------
80
- // createServer
81
- // ---------------------------------------------------------------------------
82
- /**
83
- * Build MCP tools from a topo and create an MCP server.
84
- */
85
- export const createServer = (graph, options = {}) => {
86
- const toolsResult = deriveMcpTools(graph, {
87
- configValues: options.configValues,
88
- createContext: options.createContext,
89
- exclude: options.exclude,
90
- include: options.include,
91
- intent: options.intent,
92
- layers: options.layers,
93
- resources: options.resources,
94
- validate: options.validate,
95
- });
96
- if (toolsResult.isErr()) {
97
- throw toolsResult.error;
98
- }
99
- return createMcpServer(toolsResult.value, {
100
- description: options.description ?? graph.description,
101
- name: options.name ?? graph.name,
102
- version: options.version ?? graph.version ?? '0.1.0',
103
- });
104
- };
105
- // ---------------------------------------------------------------------------
106
- // surface
107
- // ---------------------------------------------------------------------------
108
- /**
109
- * Build MCP tools from a topo, create a server, and connect via stdio.
110
- *
111
- * @remarks Opens the MCP server on stdio. For custom transports, use
112
- * `createServer(graph)` with `connectStdio` or your own connector.
113
- */
114
- export const surface = async (graph, options = {}) => {
115
- const server = createServer(graph, options);
116
- await connectStdio(server);
117
- return {
118
- close: async () => {
119
- await server.close();
120
- },
121
- };
122
- };
123
- //# sourceMappingURL=surface.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"surface.js","sourceRoot":"","sources":["../src/surface.ts"],"names":[],"mappings":"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"}
@@ -1,15 +0,0 @@
1
- /**
2
- * Derive MCP-safe tool names from app name + trail ID.
3
- *
4
- * MCP tool names must be [a-z0-9_]+. We prefix with the app name,
5
- * replace dots and hyphens with underscores, and lowercase everything.
6
- */
7
- /**
8
- * Convert app name + trail ID to an MCP-safe tool name.
9
- *
10
- * @example
11
- * deriveToolName("myapp", "entity.show") // "myapp_entity_show"
12
- * deriveToolName("dispatch", "patch.search") // "dispatch_patch_search"
13
- */
14
- export declare const deriveToolName: (appName: string, trailId: string) => string;
15
- //# sourceMappingURL=tool-name.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-name.d.ts","sourceRoot":"","sources":["../src/tool-name.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,EAAE,SAAS,MAAM,KAAG,MAIjE,CAAC"}
package/dist/tool-name.js DELETED
@@ -1,19 +0,0 @@
1
- /**
2
- * Derive MCP-safe tool names from app name + trail ID.
3
- *
4
- * MCP tool names must be [a-z0-9_]+. We prefix with the app name,
5
- * replace dots and hyphens with underscores, and lowercase everything.
6
- */
7
- /**
8
- * Convert app name + trail ID to an MCP-safe tool name.
9
- *
10
- * @example
11
- * deriveToolName("myapp", "entity.show") // "myapp_entity_show"
12
- * deriveToolName("dispatch", "patch.search") // "dispatch_patch_search"
13
- */
14
- export const deriveToolName = (appName, trailId) => {
15
- const prefix = appName.toLowerCase().replaceAll(/[.-]/g, '_');
16
- const suffix = trailId.toLowerCase().replaceAll(/[.-]/g, '_');
17
- return `${prefix}_${suffix}`;
18
- };
19
- //# sourceMappingURL=tool-name.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-name.js","sourceRoot":"","sources":["../src/tool-name.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAe,EAAE,OAAe,EAAU,EAAE;IACzE,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC9D,OAAO,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAC/B,CAAC,CAAC"}
@@ -1,57 +0,0 @@
1
- /**
2
- * trailhead() -- the one-liner MCP server launcher.
3
- *
4
- * Three lines to expose trails as MCP tools:
5
- *
6
- * ```ts
7
- * const app = topo("myapp", entity);
8
- * await trailhead(app);
9
- * ```
10
- */
11
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
12
- import type { Intent, Layer, ResourceOverrideMap, Topo, TrailContextInit } from '@ontrails/core';
13
- import type { McpToolDefinition } from './build.js';
14
- export interface TrailheadMcpOptions {
15
- /** Config values for resources that declare a `config` schema, keyed by resource ID. */
16
- readonly configValues?: Readonly<Record<string, Record<string, unknown>>> | undefined;
17
- readonly createContext?: (() => TrailContextInit | Promise<TrailContextInit>) | undefined;
18
- readonly description?: string | undefined;
19
- readonly exclude?: readonly string[] | undefined;
20
- readonly include?: readonly string[] | undefined;
21
- readonly intent?: readonly Intent[] | undefined;
22
- readonly layers?: readonly Layer[] | undefined;
23
- readonly name?: string | undefined;
24
- readonly resources?: ResourceOverrideMap | undefined;
25
- /** Set to `false` to skip topo validation at startup. Defaults to `true`. */
26
- readonly validate?: boolean | undefined;
27
- readonly version?: string | undefined;
28
- }
29
- export type CreateServerOptions = TrailheadMcpOptions;
30
- export interface SurfaceMcpResult {
31
- readonly close: () => Promise<void>;
32
- }
33
- /**
34
- * Create an MCP Server instance and register all tools.
35
- *
36
- * When provided, `info.description` is forwarded to the MCP SDK as the
37
- * server's `instructions` field — the SDK's documented channel for
38
- * "optional instructions describing how to use the server and its features."
39
- */
40
- export declare const createMcpServer: (tools: McpToolDefinition[], info: {
41
- readonly name: string;
42
- readonly version: string;
43
- readonly description?: string | undefined;
44
- }) => Server;
45
- /**
46
- * Build MCP tools from a topo and create an MCP server.
47
- */
48
- export declare const createServer: (app: Topo, options?: CreateServerOptions) => Server;
49
- /**
50
- * Build MCP tools from a topo, create a server, and connect via stdio.
51
- */
52
- export declare const surface: (app: Topo, options?: TrailheadMcpOptions) => Promise<SurfaceMcpResult>;
53
- /**
54
- * Build MCP tools from a topo, create a server, and connect via stdio.
55
- */
56
- export declare const trailhead: (app: Topo, options?: TrailheadMcpOptions) => Promise<void>;
57
- //# sourceMappingURL=trailhead.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trailhead.d.ts","sourceRoot":"","sources":["../src/trailhead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAKnE,OAAO,KAAK,EACV,MAAM,EACN,KAAK,EACL,mBAAmB,EACnB,IAAI,EACJ,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAQpD,MAAM,WAAW,mBAAmB;IAClC,wFAAwF;IACxF,QAAQ,CAAC,YAAY,CAAC,EAClB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GACjD,SAAS,CAAC;IACd,QAAQ,CAAC,aAAa,CAAC,EACnB,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,GACpD,SAAS,CAAC;IACd,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrD,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,iBAAiB,EAAE,EAC1B,MAAM;IACJ,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C,KACA,MAwEF,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,KAAK,IAAI,EACT,UAAS,mBAAwB,KAChC,MAqBF,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,OAAO,GAClB,KAAK,IAAI,EACT,UAAS,mBAAwB,KAChC,OAAO,CAAC,gBAAgB,CAS1B,CAAC;AAMF;;GAEG;AACH,eAAO,MAAM,SAAS,GACpB,KAAK,IAAI,EACT,UAAS,mBAAwB,KAChC,OAAO,CAAC,IAAI,CAEd,CAAC"}
package/dist/trailhead.js DELETED
@@ -1,136 +0,0 @@
1
- /**
2
- * trailhead() -- the one-liner MCP server launcher.
3
- *
4
- * Three lines to expose trails as MCP tools:
5
- *
6
- * ```ts
7
- * const app = topo("myapp", entity);
8
- * await trailhead(app);
9
- * ```
10
- */
11
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
12
- import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
13
- import { deriveMcpTools } from './build.js';
14
- import { connectStdio } from './stdio.js';
15
- // ---------------------------------------------------------------------------
16
- // Internal: create MCP server with tool handlers
17
- // ---------------------------------------------------------------------------
18
- /**
19
- * Create an MCP Server instance and register all tools.
20
- *
21
- * When provided, `info.description` is forwarded to the MCP SDK as the
22
- * server's `instructions` field — the SDK's documented channel for
23
- * "optional instructions describing how to use the server and its features."
24
- */
25
- export const createMcpServer = (tools, info) => {
26
- const server = new Server({ name: info.name, version: info.version }, {
27
- capabilities: { tools: {} },
28
- ...(info.description === undefined
29
- ? {}
30
- : { instructions: info.description }),
31
- });
32
- // Build a lookup map for tool dispatch
33
- const toolMap = new Map();
34
- for (const tool of tools) {
35
- toolMap.set(tool.name, tool);
36
- }
37
- // Register tools/list handler
38
- // oxlint-disable-next-line require-await -- MCP SDK requires async handler
39
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
40
- tools: tools.map((t) => ({
41
- annotations: t.annotations,
42
- description: t.description,
43
- inputSchema: t.inputSchema,
44
- name: t.name,
45
- })),
46
- }));
47
- // Register tools/call handler
48
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
49
- const tool = toolMap.get(request.params.name);
50
- if (tool === undefined) {
51
- return {
52
- content: [
53
- {
54
- text: `Unknown tool: ${request.params.name}`,
55
- type: 'text',
56
- },
57
- ],
58
- isError: true,
59
- };
60
- }
61
- const args = (request.params.arguments ?? {});
62
- const progressToken = request.params._meta?.progressToken;
63
- const sendProgress = progressToken === undefined
64
- ? undefined
65
- : async (current, total) => {
66
- await server.notification({
67
- method: 'notifications/progress',
68
- params: {
69
- progress: current,
70
- progressToken: progressToken,
71
- total,
72
- },
73
- });
74
- };
75
- const extra = {
76
- abortSignal: undefined,
77
- progressToken,
78
- sendProgress,
79
- };
80
- const result = await tool.handler(args, extra);
81
- // Spread to satisfy MCP SDK's index-signature requirement
82
- return { ...result };
83
- });
84
- return server;
85
- };
86
- // ---------------------------------------------------------------------------
87
- // createServer
88
- // ---------------------------------------------------------------------------
89
- /**
90
- * Build MCP tools from a topo and create an MCP server.
91
- */
92
- export const createServer = (app, options = {}) => {
93
- const toolsResult = deriveMcpTools(app, {
94
- configValues: options.configValues,
95
- createContext: options.createContext,
96
- exclude: options.exclude,
97
- include: options.include,
98
- intent: options.intent,
99
- layers: options.layers,
100
- resources: options.resources,
101
- validate: options.validate,
102
- });
103
- if (toolsResult.isErr()) {
104
- throw toolsResult.error;
105
- }
106
- return createMcpServer(toolsResult.value, {
107
- description: options.description ?? app.description,
108
- name: options.name ?? app.name,
109
- version: options.version ?? app.version ?? '0.1.0',
110
- });
111
- };
112
- // ---------------------------------------------------------------------------
113
- // surface
114
- // ---------------------------------------------------------------------------
115
- /**
116
- * Build MCP tools from a topo, create a server, and connect via stdio.
117
- */
118
- export const surface = async (app, options = {}) => {
119
- const server = createServer(app, options);
120
- await connectStdio(server);
121
- return {
122
- close: async () => {
123
- await server.close();
124
- },
125
- };
126
- };
127
- // ---------------------------------------------------------------------------
128
- // trailhead
129
- // ---------------------------------------------------------------------------
130
- /**
131
- * Build MCP tools from a topo, create a server, and connect via stdio.
132
- */
133
- export const trailhead = async (app, options = {}) => {
134
- await surface(app, options);
135
- };
136
- //# sourceMappingURL=trailhead.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"trailhead.js","sourceRoot":"","sources":["../src/trailhead.ts"],"names":[],"mappings":"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"}
@@ -1,63 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
-
3
- import { deriveAnnotations } from '../annotations.js';
4
-
5
- describe('deriveAnnotations', () => {
6
- test('read intent produces readOnlyHint', () => {
7
- const annotations = deriveAnnotations({ intent: 'read' });
8
- expect(annotations.readOnlyHint).toBe(true);
9
- expect(annotations.destructiveHint).toBeUndefined();
10
- expect(annotations.idempotentHint).toBeUndefined();
11
- });
12
-
13
- test('destroy intent produces destructiveHint', () => {
14
- const annotations = deriveAnnotations({ intent: 'destroy' });
15
- expect(annotations.destructiveHint).toBe(true);
16
- expect(annotations.readOnlyHint).toBeUndefined();
17
- });
18
-
19
- test('idempotent trail produces idempotentHint', () => {
20
- const annotations = deriveAnnotations({
21
- idempotent: true,
22
- intent: 'write',
23
- });
24
- expect(annotations.idempotentHint).toBe(true);
25
- });
26
-
27
- test('read intent with idempotent combines correctly', () => {
28
- const annotations = deriveAnnotations({
29
- idempotent: true,
30
- intent: 'read',
31
- });
32
- expect(annotations.readOnlyHint).toBe(true);
33
- expect(annotations.idempotentHint).toBe(true);
34
- expect(annotations.destructiveHint).toBeUndefined();
35
- });
36
-
37
- test('write intent produces empty annotations', () => {
38
- const annotations = deriveAnnotations({ intent: 'write' });
39
- expect(annotations.readOnlyHint).toBeUndefined();
40
- expect(annotations.destructiveHint).toBeUndefined();
41
- expect(annotations.idempotentHint).toBeUndefined();
42
- expect(annotations.title).toBeUndefined();
43
- });
44
-
45
- test('description maps to title', () => {
46
- const annotations = deriveAnnotations({
47
- description: 'Show entity details',
48
- intent: 'write',
49
- });
50
- expect(annotations.title).toBe('Show entity details');
51
- });
52
-
53
- test('all hints plus description', () => {
54
- const annotations = deriveAnnotations({
55
- description: 'A trail',
56
- idempotent: true,
57
- intent: 'destroy',
58
- });
59
- expect(annotations.destructiveHint).toBe(true);
60
- expect(annotations.idempotentHint).toBe(true);
61
- expect(annotations.title).toBe('A trail');
62
- });
63
- });