@silkweave/mcp 1.4.0 → 1.5.0

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.
@@ -1,18 +1,17 @@
1
1
 
2
2
  
3
- > @silkweave/mcp@1.3.2 build /Users/atomic/projects/ai/silkweave/packages/mcp
4
- > tsup
3
+ > @silkweave/mcp@1.4.1 build /Users/atomic/projects/ai/silkweave/packages/mcp
4
+ > tsdown
5
5
 
6
- CLI Building entry: src/index.ts
7
- CLI Using tsconfig: tsconfig.json
8
- CLI tsup v8.5.1
9
- CLI Using tsup config: /Users/atomic/projects/ai/silkweave/packages/mcp/tsup.config.ts
10
- CLI Target: es2022
11
- CLI Cleaning output folder
12
- ESM Build start
13
- ESM build/index.js 16.40 KB
14
- ESM build/index.js.map 30.34 KB
15
- ESM ⚡️ Build success in 9ms
16
- DTS Build start
17
- DTS ⚡️ Build success in 711ms
18
- DTS build/index.d.ts 1.34 KB
6
+ ℹ tsdown v0.21.8 powered by rolldown v1.0.0-rc.15
7
+ ℹ config file: /Users/atomic/projects/ai/silkweave/packages/mcp/tsdown.config.ts
8
+ ℹ entry: src/index.ts
9
+ ℹ tsconfig: tsconfig.json
10
+ ℹ Build start
11
+ ℹ Cleaning 4 files
12
+ ℹ build/index.mjs 15.25 kB │ gzip: 4.33 kB
13
+ ℹ build/index.mjs.map 28.57 kB │ gzip: 7.76 kB
14
+ ℹ build/index.d.mts.map  0.77 kB │ gzip: 0.38 kB
15
+ ℹ build/index.d.mts  1.62 kB │ gzip: 0.60 kB
16
+ ℹ 4 files, total: 46.22 kB
17
+ ✔ Build complete in 797ms
@@ -1,12 +1,13 @@
1
-
2
- > @silkweave/mcp@1.3.2 check /Users/atomic/projects/ai/silkweave/packages/mcp
3
- > pnpm lint && pnpm typecheck
4
-
5
-
6
- > @silkweave/mcp@1.3.2 lint /Users/atomic/projects/ai/silkweave/packages/mcp
7
- > eslint
8
-
9
-
10
- > @silkweave/mcp@1.3.2 typecheck /Users/atomic/projects/ai/silkweave/packages/mcp
11
- > tsc --noEmit
12
-
1
+
2
+ 
3
+ > @silkweave/mcp@1.4.1 check /Users/atomic/projects/ai/silkweave/packages/mcp
4
+ > pnpm lint && pnpm typecheck
5
+
6
+
7
+ > @silkweave/mcp@1.4.1 lint /Users/atomic/projects/ai/silkweave/packages/mcp
8
+ > eslint
9
+
10
+
11
+ > @silkweave/mcp@1.4.1 typecheck /Users/atomic/projects/ai/silkweave/packages/mcp
12
+ > tsc --noEmit
13
+
@@ -1,5 +1,5 @@
1
1
 
2
2
  
3
- > @silkweave/mcp@1.3.2 lint /Users/atomic/projects/ai/silkweave/packages/mcp
3
+ > @silkweave/mcp@1.4.1 lint /Users/atomic/projects/ai/silkweave/packages/mcp
4
4
  > eslint
5
5
 
@@ -1,26 +1,24 @@
1
1
 
2
2
  
3
- > @silkweave/mcp@1.4.0 prepack /Users/atomic/projects/ai/silkweave/packages/mcp
3
+ > @silkweave/mcp@1.5.0 prepack /Users/atomic/projects/ai/silkweave/packages/mcp
4
4
  > pnpm clean && pnpm build
5
5
 
6
6
 
7
- > @silkweave/mcp@1.4.0 clean /Users/atomic/projects/ai/silkweave/packages/mcp
7
+ > @silkweave/mcp@1.5.0 clean /Users/atomic/projects/ai/silkweave/packages/mcp
8
8
  > rimraf build
9
9
 
10
10
 
11
- > @silkweave/mcp@1.4.0 build /Users/atomic/projects/ai/silkweave/packages/mcp
12
- > tsup
11
+ > @silkweave/mcp@1.5.0 build /Users/atomic/projects/ai/silkweave/packages/mcp
12
+ > tsdown
13
13
 
14
- CLI Building entry: src/index.ts
15
- CLI Using tsconfig: tsconfig.json
16
- CLI tsup v8.5.1
17
- CLI Using tsup config: /Users/atomic/projects/ai/silkweave/packages/mcp/tsup.config.ts
18
- CLI Target: es2022
19
- CLI Cleaning output folder
20
- ESM Build start
21
- ESM build/index.js 16.40 KB
22
- ESM build/index.js.map 30.34 KB
23
- ESM ⚡️ Build success in 8ms
24
- DTS Build start
25
- DTS ⚡️ Build success in 728ms
26
- DTS build/index.d.ts 1.34 KB
14
+ ℹ tsdown v0.21.8 powered by rolldown v1.0.0-rc.15
15
+ ℹ config file: /Users/atomic/projects/ai/silkweave/packages/mcp/tsdown.config.ts
16
+ ℹ entry: src/index.ts
17
+ ℹ tsconfig: tsconfig.json
18
+ ℹ Build start
19
+ ℹ build/index.mjs 15.25 kB │ gzip: 4.33 kB
20
+ ℹ build/index.mjs.map 28.57 kB │ gzip: 7.76 kB
21
+ ℹ build/index.d.mts.map  0.77 kB │ gzip: 0.38 kB
22
+ ℹ build/index.d.mts  1.62 kB │ gzip: 0.60 kB
23
+ ℹ 4 files, total: 46.22 kB
24
+ ✔ Build complete in 598ms
@@ -0,0 +1,46 @@
1
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ import { AdapterFactory, SilkweaveError } from "@silkweave/core";
3
+ import { CreateMcpExpressAppOptions } from "@modelcontextprotocol/sdk/server/express.js";
4
+ import { AuthConfig } from "@silkweave/auth";
5
+
6
+ //#region src/adapter/cliProxy.d.ts
7
+ interface CliProxyOptions {
8
+ url: URL;
9
+ }
10
+ declare const cliProxy: AdapterFactory<CliProxyOptions>;
11
+ //#endregion
12
+ //#region src/adapter/http.d.ts
13
+ interface HttpAdapterOptions extends CreateMcpExpressAppOptions {
14
+ host: string;
15
+ port: number;
16
+ auth?: AuthConfig;
17
+ }
18
+ declare const http: AdapterFactory<HttpAdapterOptions>;
19
+ //#endregion
20
+ //#region src/adapter/stdio.d.ts
21
+ declare const stdio: AdapterFactory;
22
+ //#endregion
23
+ //#region src/util/result.d.ts
24
+ declare function smartToolResult(data: string | object | object[]): CallToolResult;
25
+ declare function jsonToolResult(data: object, isError?: boolean): CallToolResult;
26
+ declare function errorToolResult({
27
+ code,
28
+ name,
29
+ message
30
+ }: SilkweaveError): CallToolResult;
31
+ declare function handleToolError(error: unknown): CallToolResult;
32
+ //#endregion
33
+ //#region src/util/sideload.d.ts
34
+ interface SideloadResource {
35
+ id: string;
36
+ name: string;
37
+ contentType: string;
38
+ size: number;
39
+ }
40
+ declare function createSideloadResource(buffer: Buffer, {
41
+ name,
42
+ contentType
43
+ }: Pick<SideloadResource, 'name' | 'contentType'>): Promise<SideloadResource>;
44
+ //#endregion
45
+ export { CliProxyOptions, HttpAdapterOptions, SideloadResource, cliProxy, createSideloadResource, errorToolResult, handleToolError, http, jsonToolResult, smartToolResult, stdio };
46
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/adapter/cliProxy.ts","../src/adapter/http.ts","../src/adapter/stdio.ts","../src/util/result.ts","../src/util/sideload.ts"],"mappings":";;;;;;UAYiB,eAAA;EACf,GAAA,EAAK,GAAA;AAAA;AAAA,cA4DM,QAAA,EAAU,cAAA,CAAe,eAAA;;;UCrDrB,kBAAA,SAA2B,0BAAA;EAC1C,IAAA;EACA,IAAA;EACA,IAAA,GAAO,UAAA;AAAA;AAAA,cAqLI,IAAA,EAAM,cAAA,CAAe,kBAAA;;;cCzKrB,KAAA,EAAO,cAAA;;;iBC/BJ,eAAA,CAAgB,IAAA,+BAAmC,cAAA;AAAA,iBAqBnD,cAAA,CAAe,IAAA,UAAc,OAAA,aAAkB,cAAA;AAAA,iBAM/C,eAAA,CAAA;EAAkB,IAAA;EAAM,IAAA;EAAM;AAAA,GAAW,cAAA,GAAiB,cAAA;AAAA,iBAU1D,eAAA,CAAgB,KAAA,YAAiB,cAAA;;;UCtChC,gBAAA;EACf,EAAA;EACA,IAAA;EACA,WAAA;EACA,IAAA;AAAA;AAAA,iBAGoB,sBAAA,CAAuB,MAAA,EAAQ,MAAA;EAAU,IAAA;EAAM;AAAA,GAAe,IAAA,CAAK,gBAAA,4BAAyC,OAAA,CAAA,gBAAA"}
@@ -0,0 +1,475 @@
1
+ import { intro } from "@clack/prompts";
2
+ import { Client } from "@modelcontextprotocol/sdk/client";
3
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
+ import { LoggingMessageNotificationSchema, ProgressNotificationSchema, isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
5
+ import { SilkweaveError, unwrap } from "@silkweave/core";
6
+ import { createCLILogger, createLogger } from "@silkweave/logger";
7
+ import { capitalCase, kebabCase, pascalCase } from "change-case";
8
+ import { Command } from "commander";
9
+ import { randomUUID } from "crypto";
10
+ import { z } from "zod";
11
+ import { InMemoryEventStore } from "@modelcontextprotocol/sdk/examples/shared/inMemoryEventStore.js";
12
+ import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
13
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
15
+ import { generateProtectedResourceMetadata, validateToken } from "@silkweave/auth";
16
+ import cors from "cors";
17
+ import express from "express";
18
+ import { readFile, writeFile } from "fs/promises";
19
+ import { AsyncLocalStorage } from "node:async_hooks";
20
+ import { randomUUID as randomUUID$1 } from "node:crypto";
21
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
+ //#region src/adapter/cliProxy.ts
23
+ function addCliOption(command, key, type, defaultValue) {
24
+ const description = type.description;
25
+ const flag = kebabCase(key);
26
+ if (type instanceof z.ZodBoolean) {
27
+ command.option(`--${flag}`, description, defaultValue);
28
+ command.option(`--no-${flag}`);
29
+ } else if (type instanceof z.ZodNumber) command.option(`--${flag} <number>`, description, defaultValue);
30
+ else if (type instanceof z.ZodString || type instanceof z.ZodEnum) command.option(`--${flag} <string>`, description, defaultValue);
31
+ else if (type instanceof z.ZodObject || type instanceof z.ZodRecord || type instanceof z.ZodArray) command.option(`--${flag} <json>`, description ?? "", JSON.parse, defaultValue);
32
+ else throw new Error(`Invalid zod type: ${type.def.type}`);
33
+ }
34
+ function registerProxyCommand(program, client, tool, options) {
35
+ const name = kebabCase(tool.name);
36
+ const command = program.command(name);
37
+ if (tool.description) command.description(tool.description);
38
+ const schema = z.fromJSONSchema(tool.inputSchema);
39
+ if (!(schema instanceof z.ZodObject)) throw new Error("Invalid schema");
40
+ const shape = schema.shape;
41
+ for (const key of Object.keys(shape)) {
42
+ const [type, { defaultValue }] = unwrap(shape[key]);
43
+ addCliOption(command, key, type, defaultValue);
44
+ }
45
+ command.action(async (args) => {
46
+ const { silent } = program.opts();
47
+ const logger = createCLILogger();
48
+ if (!silent) {
49
+ intro(`${options.name} - ${tool.name}`);
50
+ client.setNotificationHandler(LoggingMessageNotificationSchema, ({ params: { level, data } }) => {
51
+ logger[level](data);
52
+ });
53
+ client.setNotificationHandler(ProgressNotificationSchema, ({ params: { progress, total, message } }) => {
54
+ logger.info({
55
+ progress,
56
+ total,
57
+ message
58
+ });
59
+ });
60
+ }
61
+ const input = await schema.parseAsync(args);
62
+ const response = await client.callTool({
63
+ name: tool.name,
64
+ arguments: input,
65
+ _meta: { progressToken: randomUUID() }
66
+ });
67
+ process.stdout.write(JSON.stringify(response));
68
+ });
69
+ }
70
+ const cliProxy = ({ url }) => {
71
+ return (options, baseContext) => {
72
+ const context = baseContext.fork({ adapter: "cliProxy" });
73
+ const program = new Command().name(options.name).description(options.description).version(options.version).option("-s, --silent", "Silent mode, prevent log messages", false);
74
+ return {
75
+ context,
76
+ start: async () => {
77
+ const client = new Client({
78
+ name: options.name,
79
+ description: options.description,
80
+ version: options.version
81
+ });
82
+ const transport = new StreamableHTTPClientTransport(url);
83
+ await client.connect(transport);
84
+ const { tools } = await client.listTools();
85
+ for (const tool of tools) registerProxyCommand(program, client, tool, options);
86
+ await program.parseAsync();
87
+ await transport.close();
88
+ },
89
+ stop: async () => {}
90
+ };
91
+ };
92
+ };
93
+ //#endregion
94
+ //#region src/util/result.ts
95
+ function smartToolResult(data) {
96
+ const text = typeof data === "string" ? data : JSON.stringify(data);
97
+ const mimeType = typeof data === "string" ? "text/plain" : "application/json";
98
+ const ext = typeof data === "string" ? "txt" : "json";
99
+ if (text.length > 4096) {
100
+ const uri = `mcp://toolResult/${randomUUID$1()}.${ext}`;
101
+ const buffer = Buffer.from(text);
102
+ const blob = buffer.toString("base64");
103
+ return { content: [{
104
+ type: "text",
105
+ text: `Received resource ${uri} with ${buffer.byteLength} bytes`
106
+ }, {
107
+ type: "resource",
108
+ resource: {
109
+ uri,
110
+ mimeType,
111
+ blob
112
+ }
113
+ }] };
114
+ } else return { content: [{
115
+ type: "text",
116
+ text
117
+ }] };
118
+ }
119
+ function jsonToolResult(data, isError = false) {
120
+ const result = { content: [{
121
+ type: "text",
122
+ text: JSON.stringify(data)
123
+ }] };
124
+ if (isError) result.isError = true;
125
+ return result;
126
+ }
127
+ function errorToolResult({ code, name, message }) {
128
+ return {
129
+ isError: true,
130
+ content: [{
131
+ type: "text",
132
+ text: JSON.stringify({
133
+ success: false,
134
+ code,
135
+ name,
136
+ message
137
+ })
138
+ }]
139
+ };
140
+ }
141
+ function handleToolError(error) {
142
+ if (error instanceof SilkweaveError) return jsonToolResult({
143
+ success: false,
144
+ name: error.name,
145
+ message: error.message,
146
+ code: error.code
147
+ }, true);
148
+ else if (error instanceof Error) return jsonToolResult({
149
+ success: false,
150
+ name: error.name,
151
+ message: error.message,
152
+ stack: error.stack
153
+ }, true);
154
+ else return jsonToolResult({
155
+ success: false,
156
+ name: "Unknown error",
157
+ message: "An unknown error occurred",
158
+ error
159
+ }, true);
160
+ }
161
+ //#endregion
162
+ //#region src/adapter/http.ts
163
+ const authStorage = new AsyncLocalStorage();
164
+ function mountOAuthRoutes(app, auth) {
165
+ const provider = auth.provider;
166
+ const callbackPath = auth.callbackPath ?? "/auth/callback";
167
+ const toOAuthReq = (req) => ({
168
+ method: req.method,
169
+ url: new URL(req.url, `${req.protocol}://${req.get("host")}`),
170
+ headers: Object.fromEntries(Object.entries(req.headers).map(([k, v]) => [k, Array.isArray(v) ? v[0] : v])),
171
+ body: req.body
172
+ });
173
+ const sendOAuth = (res, oauthRes) => {
174
+ for (const [key, value] of Object.entries(oauthRes.headers)) res.header(key, value);
175
+ if (oauthRes.body) res.status(oauthRes.status).send(typeof oauthRes.body === "string" ? oauthRes.body : JSON.stringify(oauthRes.body));
176
+ else res.status(oauthRes.status).end();
177
+ };
178
+ app.get("/.well-known/oauth-authorization-server", (_req, res) => {
179
+ sendOAuth(res, provider.metadata());
180
+ });
181
+ app.get("/authorize", async (req, res) => {
182
+ sendOAuth(res, await provider.authorize(toOAuthReq(req)));
183
+ });
184
+ app.get(callbackPath, async (req, res) => {
185
+ sendOAuth(res, await provider.callback(toOAuthReq(req)));
186
+ });
187
+ app.post("/token", express.urlencoded({ extended: false }), async (req, res) => {
188
+ sendOAuth(res, await provider.token(toOAuthReq(req)));
189
+ });
190
+ app.post("/register", express.json(), async (req, res) => {
191
+ sendOAuth(res, await provider.register(toOAuthReq(req)));
192
+ });
193
+ return new Set([
194
+ "/.well-known/oauth-authorization-server",
195
+ "/authorize",
196
+ callbackPath,
197
+ "/token",
198
+ "/register"
199
+ ]);
200
+ }
201
+ function mountAuthMiddleware(app, auth, oauthPaths, context) {
202
+ app.use(async (req, res, next) => {
203
+ if (req.path.startsWith("/.well-known/") || oauthPaths.has(req.path)) return next();
204
+ const result = await validateToken(req.headers.authorization, auth, context.fork({ request: req }));
205
+ if (result.error) {
206
+ for (const [key, value] of Object.entries(result.error.headers)) res.header(key, value);
207
+ res.status(result.error.statusCode).json(result.error.body);
208
+ return;
209
+ }
210
+ if (result.auth) authStorage.run(result.auth, () => {
211
+ next();
212
+ });
213
+ else next();
214
+ });
215
+ }
216
+ function registerTools$1(server, actions, context) {
217
+ for (const action of actions) server.registerTool(pascalCase(action.name), {
218
+ title: capitalCase(action.name),
219
+ description: action.description,
220
+ inputSchema: action.input
221
+ }, async (input, extra) => {
222
+ const logger = createLogger({
223
+ stream: process.stderr,
224
+ onLog: (level, data) => {
225
+ extra.sendNotification({
226
+ method: "notifications/message",
227
+ params: {
228
+ level,
229
+ data
230
+ }
231
+ });
232
+ },
233
+ onProgress: ({ progress, total, message }) => {
234
+ if (!extra._meta?.progressToken) return;
235
+ extra.sendNotification({
236
+ method: "notifications/progress",
237
+ params: {
238
+ progress,
239
+ total,
240
+ message,
241
+ progressToken: extra._meta.progressToken
242
+ }
243
+ });
244
+ }
245
+ });
246
+ const currentAuth = authStorage.getStore();
247
+ const actionContext = context.fork({
248
+ logger,
249
+ extra,
250
+ ...currentAuth ? { auth: currentAuth } : {}
251
+ });
252
+ return action.run(input, actionContext).then((result) => {
253
+ return action.toolResult?.(result, actionContext) ?? smartToolResult(result);
254
+ }).catch(handleToolError);
255
+ });
256
+ }
257
+ function createMcpServer(options, actions, context) {
258
+ const server = new McpServer({
259
+ name: options.name,
260
+ description: options.description,
261
+ version: options.version
262
+ }, { capabilities: {
263
+ tools: {},
264
+ logging: {}
265
+ } });
266
+ registerTools$1(server, actions, context);
267
+ return server;
268
+ }
269
+ function createSessionTransport(transports) {
270
+ const transport = new StreamableHTTPServerTransport({
271
+ sessionIdGenerator: () => randomUUID(),
272
+ enableJsonResponse: false,
273
+ eventStore: new InMemoryEventStore(),
274
+ onsessioninitialized: (sId) => {
275
+ console.log(`Session initialized with ID: ${sId}`);
276
+ transports[sId] = transport;
277
+ }
278
+ });
279
+ transport.onerror = (error) => {
280
+ console.error(error);
281
+ };
282
+ transport.onclose = () => {
283
+ const sid = transport.sessionId;
284
+ if (sid && transports[sid]) {
285
+ console.log(`Transport closed for session ${sid}, removing from transports map`);
286
+ delete transports[sid];
287
+ }
288
+ };
289
+ return transport;
290
+ }
291
+ function mountMcpTransport(app, transports, createServer) {
292
+ app.post("/mcp", async (req, res) => {
293
+ const sessionId = req.headers["mcp-session-id"];
294
+ try {
295
+ if (sessionId && transports[sessionId]) {
296
+ await transports[sessionId].handleRequest(req, res, req.body);
297
+ return;
298
+ }
299
+ if (!isInitializeRequest(req.body)) {
300
+ res.status(404).json({
301
+ jsonrpc: "2.0",
302
+ error: {
303
+ code: -32e3,
304
+ message: "Session not found"
305
+ },
306
+ id: null
307
+ });
308
+ return;
309
+ }
310
+ const transport = createSessionTransport(transports);
311
+ await createServer().connect(transport);
312
+ await transport.handleRequest(req, res, req.body);
313
+ } catch (error) {
314
+ console.error("Error handling MCP request:", error);
315
+ if (!res.headersSent) res.status(500).json({
316
+ jsonrpc: "2.0",
317
+ error: {
318
+ code: -32603,
319
+ message: "Internal server error"
320
+ },
321
+ id: null
322
+ });
323
+ }
324
+ });
325
+ const handleSessionStream = async (req, res) => {
326
+ const sessionId = req.headers["mcp-session-id"];
327
+ if (!sessionId || !transports[sessionId]) {
328
+ res.status(400).send("Invalid or missing session ID");
329
+ return;
330
+ }
331
+ await transports[sessionId].handleRequest(req, res);
332
+ };
333
+ app.get("/mcp", handleSessionStream);
334
+ app.delete("/mcp", handleSessionStream);
335
+ app.get("/mcp/resource/:id", handleSessionStream);
336
+ }
337
+ const http = ({ host, port, auth, ...mcpOptions }) => {
338
+ return (options, baseContext) => {
339
+ const context = baseContext.fork({ adapter: "http" });
340
+ const app = createMcpExpressApp({
341
+ ...mcpOptions,
342
+ host
343
+ });
344
+ app.use(cors({
345
+ exposedHeaders: [
346
+ "WWW-Authenticate",
347
+ "Mcp-Session-Id",
348
+ "Last-Event-Id",
349
+ "Mcp-Protocol-Version"
350
+ ],
351
+ origin: "*"
352
+ }));
353
+ if (auth?.authorizationServers?.length && auth.resourceUrl) app.get("/.well-known/oauth-protected-resource", (_req, res) => {
354
+ const metadata = generateProtectedResourceMetadata(auth.resourceUrl, auth.authorizationServers);
355
+ res.json(metadata);
356
+ });
357
+ const oauthPaths = auth?.provider ? mountOAuthRoutes(app, auth) : /* @__PURE__ */ new Set();
358
+ if (auth) mountAuthMiddleware(app, auth, oauthPaths, context);
359
+ const transports = {};
360
+ let mountedActions = [];
361
+ app.get("/resource/:id", async (req, res) => {
362
+ const id = req.params.id;
363
+ if (!id || typeof id !== "string") throw new Error("Invalid ID");
364
+ const resourceMeta = JSON.parse(await readFile(`resources/${id}.json`, "utf-8"));
365
+ const buffer = await readFile(`resources/${id}`);
366
+ res.status(200);
367
+ res.header("Content-Type", resourceMeta.contentType);
368
+ res.send(buffer);
369
+ });
370
+ mountMcpTransport(app, transports, () => createMcpServer(options, mountedActions, context));
371
+ let httpServer;
372
+ return {
373
+ context,
374
+ start: async (actions) => {
375
+ mountedActions = actions;
376
+ httpServer = app.listen(port, host, (error) => {
377
+ if (error) {
378
+ console.error("Failed to start server:", error);
379
+ process.exit(1);
380
+ }
381
+ console.log(`MCP Streamable HTTP Server listening on http://${host}:${port}/mcp`);
382
+ });
383
+ },
384
+ stop: async () => {
385
+ if (httpServer) await new Promise((resolve, reject) => {
386
+ return httpServer.close((err) => {
387
+ if (err) reject(err);
388
+ else resolve();
389
+ });
390
+ });
391
+ httpServer = void 0;
392
+ }
393
+ };
394
+ };
395
+ };
396
+ //#endregion
397
+ //#region src/adapter/stdio.ts
398
+ function registerTools(server, actions, context) {
399
+ for (const action of actions) server.registerTool(pascalCase(action.name), {
400
+ title: capitalCase(action.name),
401
+ description: action.description,
402
+ inputSchema: action.input
403
+ }, async (input, extra) => {
404
+ const logger = createLogger({
405
+ stream: false,
406
+ onLog: (level, data) => {
407
+ extra.sendNotification({
408
+ method: "notifications/message",
409
+ params: {
410
+ level,
411
+ data
412
+ }
413
+ });
414
+ },
415
+ onProgress: ({ progress, total, message }) => {
416
+ if (!extra._meta?.progressToken) return;
417
+ extra.sendNotification({
418
+ method: "notifications/progress",
419
+ params: {
420
+ progress,
421
+ total,
422
+ message,
423
+ progressToken: extra._meta.progressToken
424
+ }
425
+ });
426
+ }
427
+ });
428
+ const actionContext = context.fork({
429
+ logger,
430
+ extra
431
+ });
432
+ return action.run(input, actionContext).then((result) => action.toolResult?.(result, actionContext) ?? smartToolResult(result)).catch(handleToolError);
433
+ });
434
+ }
435
+ const stdio = () => {
436
+ return (options, baseContext) => {
437
+ const context = baseContext.fork({ adapter: "stdio" });
438
+ const server = new McpServer({
439
+ name: options.name,
440
+ description: options.description,
441
+ version: options.version
442
+ }, { capabilities: {
443
+ tools: {},
444
+ logging: {}
445
+ } });
446
+ return {
447
+ context,
448
+ start: async (actions) => {
449
+ registerTools(server, actions, context);
450
+ const transport = new StdioServerTransport();
451
+ await server.connect(transport);
452
+ },
453
+ stop: async () => {
454
+ await server?.close();
455
+ }
456
+ };
457
+ };
458
+ };
459
+ //#endregion
460
+ //#region src/util/sideload.ts
461
+ async function createSideloadResource(buffer, { name, contentType }) {
462
+ const id = randomUUID();
463
+ const resource = {
464
+ id,
465
+ name,
466
+ contentType,
467
+ size: buffer.length
468
+ };
469
+ await Promise.all([writeFile(`resources/${id}`, buffer), writeFile(`resources/${id}.json`, JSON.stringify(resource), "utf-8")]);
470
+ return resource;
471
+ }
472
+ //#endregion
473
+ export { cliProxy, createSideloadResource, errorToolResult, handleToolError, http, jsonToolResult, smartToolResult, stdio };
474
+
475
+ //# sourceMappingURL=index.mjs.map