@ontrails/mcp 1.0.0-beta.4 → 1.0.0-beta.41

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 (50) hide show
  1. package/CHANGELOG.md +391 -12
  2. package/README.md +69 -17
  3. package/package.json +11 -3
  4. package/src/annotations.ts +24 -1
  5. package/src/build.ts +1335 -136
  6. package/src/index.ts +32 -4
  7. package/src/progress.ts +22 -0
  8. package/src/resources.ts +336 -0
  9. package/src/stdio.ts +9 -1
  10. package/src/surface.ts +295 -0
  11. package/src/tool-name.ts +6 -7
  12. package/.turbo/turbo-build.log +0 -1
  13. package/.turbo/turbo-lint.log +0 -3
  14. package/.turbo/turbo-typecheck.log +0 -1
  15. package/dist/annotations.d.ts +0 -19
  16. package/dist/annotations.d.ts.map +0 -1
  17. package/dist/annotations.js +0 -31
  18. package/dist/annotations.js.map +0 -1
  19. package/dist/blaze.d.ts +0 -36
  20. package/dist/blaze.d.ts.map +0 -1
  21. package/dist/blaze.js +0 -96
  22. package/dist/blaze.js.map +0 -1
  23. package/dist/build.d.ts +0 -40
  24. package/dist/build.d.ts.map +0 -1
  25. package/dist/build.js +0 -227
  26. package/dist/build.js.map +0 -1
  27. package/dist/index.d.ts +0 -7
  28. package/dist/index.d.ts.map +0 -1
  29. package/dist/index.js +0 -13
  30. package/dist/index.js.map +0 -1
  31. package/dist/progress.d.ts +0 -13
  32. package/dist/progress.d.ts.map +0 -1
  33. package/dist/progress.js +0 -51
  34. package/dist/progress.js.map +0 -1
  35. package/dist/stdio.d.ts +0 -12
  36. package/dist/stdio.d.ts.map +0 -1
  37. package/dist/stdio.js +0 -15
  38. package/dist/stdio.js.map +0 -1
  39. package/dist/tool-name.d.ts +0 -15
  40. package/dist/tool-name.d.ts.map +0 -1
  41. package/dist/tool-name.js +0 -19
  42. package/dist/tool-name.js.map +0 -1
  43. package/src/__tests__/annotations.test.ts +0 -63
  44. package/src/__tests__/blaze.test.ts +0 -105
  45. package/src/__tests__/build.test.ts +0 -453
  46. package/src/__tests__/progress.test.ts +0 -136
  47. package/src/__tests__/tool-name.test.ts +0 -46
  48. package/src/blaze.ts +0 -146
  49. package/tsconfig.json +0 -9
  50. package/tsconfig.tsbuildinfo +0 -1
package/dist/build.js DELETED
@@ -1,227 +0,0 @@
1
- /**
2
- * Build MCP tool definitions from a Trails App.
3
- *
4
- * Iterates the topo, generates McpToolDefinition[] with handlers that
5
- * validate input, compose layers, execute the implementation, and map
6
- * Results to MCP responses.
7
- */
8
- import { composeLayers, createTrailContext, isBlobRef, validateInput, zodToJsonSchema, } from '@ontrails/core';
9
- import { deriveAnnotations } from './annotations.js';
10
- import { createMcpProgressCallback } from './progress.js';
11
- import { deriveToolName } from './tool-name.js';
12
- // ---------------------------------------------------------------------------
13
- // Internal helpers (defined before use)
14
- // ---------------------------------------------------------------------------
15
- /** Concatenate an array of Uint8Array chunks into a single Uint8Array. */
16
- const concatChunks = (chunks, totalLength) => {
17
- const result = new Uint8Array(totalLength);
18
- let offset = 0;
19
- for (const chunk of chunks) {
20
- result.set(chunk, offset);
21
- offset += chunk.length;
22
- }
23
- return result;
24
- };
25
- /** Collect a ReadableStream into a single Uint8Array. */
26
- const collectStream = async (stream) => {
27
- const reader = stream.getReader();
28
- const chunks = [];
29
- let totalLength = 0;
30
- for (;;) {
31
- const { done, value } = await reader.read();
32
- if (done) {
33
- break;
34
- }
35
- chunks.push(value);
36
- totalLength += value.length;
37
- }
38
- return concatChunks(chunks, totalLength);
39
- };
40
- /** Resolve BlobRef data to Uint8Array (handles ReadableStream). */
41
- const resolveBlobData = (blob) => {
42
- if (blob.data instanceof ReadableStream) {
43
- return collectStream(blob.data);
44
- }
45
- return blob.data;
46
- };
47
- const uint8ArrayToBase64 = (bytes) => {
48
- // Use btoa with manual conversion for runtime-agnostic base64
49
- let binary = '';
50
- for (const byte of bytes) {
51
- binary += String.fromCodePoint(byte);
52
- }
53
- return btoa(binary);
54
- };
55
- const blobToContent = async (blob) => {
56
- const bytes = await resolveBlobData(blob);
57
- if (blob.mimeType.startsWith('image/')) {
58
- return {
59
- data: uint8ArrayToBase64(bytes),
60
- mimeType: blob.mimeType,
61
- type: 'image',
62
- };
63
- }
64
- return {
65
- mimeType: blob.mimeType,
66
- type: 'resource',
67
- uri: `blob://${blob.name}`,
68
- };
69
- };
70
- /** Separate blob fields from non-blob fields in an object. */
71
- const separateBlobFields = async (obj) => {
72
- const blobContents = [];
73
- const textFields = {};
74
- let hasBlobFields = false;
75
- for (const [key, val] of Object.entries(obj)) {
76
- if (isBlobRef(val)) {
77
- hasBlobFields = true;
78
- blobContents.push(await blobToContent(val));
79
- }
80
- else {
81
- textFields[key] = val;
82
- }
83
- }
84
- return { blobContents, hasBlobFields, textFields };
85
- };
86
- /** Serialize a mixed blob/text object to MCP content. */
87
- const serializeMixedObject = async (obj) => {
88
- const { blobContents, hasBlobFields, textFields } = await separateBlobFields(obj);
89
- if (!hasBlobFields) {
90
- return undefined;
91
- }
92
- if (Object.keys(textFields).length > 0) {
93
- blobContents.unshift({ text: JSON.stringify(textFields), type: 'text' });
94
- }
95
- return blobContents;
96
- };
97
- const serializeOutput = async (value) => {
98
- if (isBlobRef(value)) {
99
- return [await blobToContent(value)];
100
- }
101
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
102
- const mixed = await serializeMixedObject(value);
103
- if (mixed) {
104
- return mixed;
105
- }
106
- }
107
- return [{ text: JSON.stringify(value), type: 'text' }];
108
- };
109
- // ---------------------------------------------------------------------------
110
- // Handler factory
111
- // ---------------------------------------------------------------------------
112
- /** Create an error result for MCP responses. */
113
- const mcpError = (message) => ({
114
- content: [{ text: message, type: 'text' }],
115
- isError: true,
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;
123
- 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);
139
- }
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);
151
- };
152
- // ---------------------------------------------------------------------------
153
- // Builder
154
- // ---------------------------------------------------------------------------
155
- /**
156
- * Build MCP tool definitions from an App's topology.
157
- *
158
- * Each trail in the topo becomes an McpToolDefinition with:
159
- * - A derived tool name (app-prefixed, underscore-delimited)
160
- * - JSON Schema input from zodToJsonSchema
161
- * - MCP annotations from trail metadata
162
- * - A handler that validates, composes layers, executes, and maps results
163
- */
164
- /** Check if a trail should be included based on metadata and filters. */
165
- const shouldInclude = (trail, options) => {
166
- if (trail.metadata?.['internal'] === true) {
167
- return false;
168
- }
169
- if (options.includeTrails !== undefined && options.includeTrails.length > 0) {
170
- return options.includeTrails.includes(trail.id);
171
- }
172
- if (options.excludeTrails !== undefined &&
173
- options.excludeTrails.includes(trail.id)) {
174
- return false;
175
- }
176
- return true;
177
- };
178
- /** Build a description with optional example input appended. */
179
- const buildDescription = (trail) => {
180
- let { description } = trail;
181
- if (description !== undefined &&
182
- trail.examples !== undefined &&
183
- trail.examples.length > 0) {
184
- const [firstExample] = trail.examples;
185
- if (firstExample !== undefined) {
186
- description = `${description}\n\nExample input: ${JSON.stringify(firstExample.input)}`;
187
- }
188
- }
189
- return description;
190
- };
191
- /** Build a single MCP tool definition from a trail. */
192
- const buildToolDefinition = (app, trail, layers, options) => {
193
- const rawAnnotations = deriveAnnotations(trail);
194
- const annotations = Object.keys(rawAnnotations).length > 0 ? rawAnnotations : undefined;
195
- return {
196
- annotations,
197
- description: buildDescription(trail),
198
- handler: createHandler(trail, layers, options),
199
- inputSchema: zodToJsonSchema(trail.input),
200
- name: deriveToolName(app.name, trail.id),
201
- };
202
- };
203
- /** Register a trail as an MCP tool, checking for name collisions. */
204
- const registerTool = (app, trailItem, layers, options, nameToTrailId, tools) => {
205
- const toolName = deriveToolName(app.name, trailItem.id);
206
- const existingId = nameToTrailId.get(toolName);
207
- if (existingId !== undefined) {
208
- throw new Error(`MCP tool-name collision: trails "${existingId}" and "${trailItem.id}" both derive the tool name "${toolName}"`);
209
- }
210
- nameToTrailId.set(toolName, trailItem.id);
211
- tools.push(buildToolDefinition(app, trailItem, layers, options));
212
- };
213
- /** Filter topo items to eligible trails. */
214
- const eligibleTrails = (app, options) => app
215
- .list()
216
- .filter((item) => item.kind === 'trail' &&
217
- shouldInclude(item, options));
218
- export const buildMcpTools = (app, options = {}) => {
219
- const layers = options.layers ?? [];
220
- const tools = [];
221
- const nameToTrailId = new Map();
222
- for (const trailItem of eligibleTrails(app, options)) {
223
- registerTool(app, trailItem, layers, options, nameToTrailId, tools);
224
- }
225
- return tools;
226
- };
227
- //# sourceMappingURL=build.js.map
package/dist/build.js.map DELETED
@@ -1 +0,0 @@
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"}
package/dist/index.d.ts DELETED
@@ -1,7 +0,0 @@
1
- export { buildMcpTools, type BuildMcpToolsOptions, type McpToolDefinition, type McpToolResult, type McpContent, type McpExtra, } from './build.js';
2
- export { deriveToolName } from './tool-name.js';
3
- export { deriveAnnotations, type McpAnnotations } from './annotations.js';
4
- export { createMcpProgressCallback } from './progress.js';
5
- export { blaze, type BlazeMcpOptions } from './blaze.js';
6
- export { connectStdio } from './stdio.js';
7
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,OAAO,EAAE,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAG1D,OAAO,EAAE,KAAK,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js DELETED
@@ -1,13 +0,0 @@
1
- // Build
2
- export { buildMcpTools, } from './build.js';
3
- // Tool naming
4
- export { deriveToolName } from './tool-name.js';
5
- // Annotations
6
- export { deriveAnnotations } from './annotations.js';
7
- // Progress
8
- export { createMcpProgressCallback } from './progress.js';
9
- // Blaze
10
- export { blaze } from './blaze.js';
11
- // Transport
12
- export { connectStdio } from './stdio.js';
13
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,OAAO,EACL,aAAa,GAMd,MAAM,YAAY,CAAC;AAEpB,cAAc;AACd,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,cAAc;AACd,OAAO,EAAE,iBAAiB,EAAuB,MAAM,kBAAkB,CAAC;AAE1E,WAAW;AACX,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAE1D,QAAQ;AACR,OAAO,EAAE,KAAK,EAAwB,MAAM,YAAY,CAAC;AAEzD,YAAY;AACZ,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -1,13 +0,0 @@
1
- /**
2
- * Bridge Trails ProgressCallback to MCP sendProgress notifications.
3
- */
4
- import type { ProgressCallback } from '@ontrails/core';
5
- import type { McpExtra } from './build.js';
6
- /**
7
- * Create a ProgressCallback that bridges to MCP's sendProgress.
8
- *
9
- * Returns `undefined` if the MCP client did not provide a progressToken
10
- * (meaning no progress reporting was requested).
11
- */
12
- export declare const createMcpProgressCallback: (extra: McpExtra) => ProgressCallback | undefined;
13
- //# sourceMappingURL=progress.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAiB,MAAM,gBAAgB,CAAC;AAEtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA6C3C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,QAAQ,KACd,gBAAgB,GAAG,SAarB,CAAC"}
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 blaze().
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 blaze().
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"}
@@ -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,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
- });
@@ -1,105 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
-
3
- import { Result, trail, topo } from '@ontrails/core';
4
- import { z } from 'zod';
5
-
6
- import { createMcpServer } from '../blaze.js';
7
- import { buildMcpTools } from '../build.js';
8
-
9
- // ---------------------------------------------------------------------------
10
- // Tests
11
- // ---------------------------------------------------------------------------
12
-
13
- const requireTool = (tools: ReturnType<typeof buildMcpTools>, name: string) => {
14
- const tool = tools.find((entry) => entry.name === name);
15
- expect(tool).toBeDefined();
16
- if (!tool) {
17
- throw new Error(`Expected tool: ${name}`);
18
- }
19
- return tool;
20
- };
21
-
22
- const createIntegrationTools = () => {
23
- const greetTrail = trail('greet', {
24
- description: 'Greet someone',
25
- input: z.object({ name: z.string() }),
26
- intent: 'read',
27
- run: (input) => Result.ok({ greeting: `Hello, ${input.name}!` }),
28
- });
29
-
30
- const deleteTrail = trail('item.delete', {
31
- description: 'Delete an item',
32
- input: z.object({ id: z.string() }),
33
- intent: 'destroy',
34
- run: (_input) => Result.ok({ deleted: true }),
35
- });
36
-
37
- return buildMcpTools(topo('myapp', { deleteTrail, greetTrail }));
38
- };
39
-
40
- describe('blaze', () => {
41
- test('createMcpServer registers tools that can be listed', () => {
42
- const echoTrail = trail('echo', {
43
- description: 'Echo',
44
- input: z.object({ message: z.string() }),
45
- intent: 'read',
46
- run: (input) => Result.ok({ reply: input.message }),
47
- });
48
-
49
- const app = topo('testapp', { echoTrail });
50
- const tools = buildMcpTools(app);
51
- const server = createMcpServer(tools, {
52
- name: 'testapp',
53
- version: '0.1.0',
54
- });
55
-
56
- // Server is created successfully
57
- expect(server).toBeDefined();
58
- });
59
-
60
- test('createMcpServer handles multiple tools', () => {
61
- const echoTrail = trail('echo', {
62
- description: 'Echo',
63
- input: z.object({ message: z.string() }),
64
- run: (input) => Result.ok({ reply: input.message }),
65
- });
66
-
67
- const searchTrail = trail('search', {
68
- description: 'Search',
69
- input: z.object({ query: z.string() }),
70
- intent: 'read',
71
- run: (input) => Result.ok({ results: [input.query] }),
72
- });
73
-
74
- const app = topo('testapp', { echoTrail, searchTrail });
75
- const tools = buildMcpTools(app);
76
-
77
- expect(tools).toHaveLength(2);
78
-
79
- const server = createMcpServer(tools, {
80
- name: 'testapp',
81
- version: '0.1.0',
82
- });
83
- expect(server).toBeDefined();
84
- });
85
-
86
- test('buildMcpTools + createMcpServer integration', () => {
87
- const tools = createIntegrationTools();
88
- const names = tools.map((t) => t.name);
89
- expect(names).toContain('myapp_greet');
90
- expect(names).toContain('myapp_item_delete');
91
-
92
- expect(requireTool(tools, 'myapp_greet').annotations?.readOnlyHint).toBe(
93
- true
94
- );
95
- expect(
96
- requireTool(tools, 'myapp_item_delete').annotations?.destructiveHint
97
- ).toBe(true);
98
-
99
- const server = createMcpServer(tools, {
100
- name: 'myapp',
101
- version: '1.0.0',
102
- });
103
- expect(server).toBeDefined();
104
- });
105
- });