@silkweave/mcp 3.0.0 → 3.1.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.
- package/README.md +1 -1
- package/build/cliProxy.d.mts.map +1 -1
- package/build/cliProxy.mjs +3 -4
- package/build/cliProxy.mjs.map +1 -1
- package/build/index.d.mts +1 -1
- package/build/index.mjs +1 -1
- package/build/{registerTools-DlguElKV.mjs → registerTools-Z6JnoM60.mjs} +2 -3
- package/build/registerTools-Z6JnoM60.mjs.map +1 -0
- package/build/{result-BVpEX7jU.d.mts → result-_Bg2cDAG.d.mts} +2 -3
- package/build/result-_Bg2cDAG.d.mts.map +1 -0
- package/build/tools.d.mts +1 -1
- package/build/tools.mjs +1 -1
- package/package.json +3 -9
- package/build/registerTools-DlguElKV.mjs.map +0 -1
- package/build/result-BVpEX7jU.d.mts.map +0 -1
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Exposes a single stateless `POST /mcp` (each call mints a fresh transport with `
|
|
|
62
62
|
|
|
63
63
|
### cliProxy
|
|
64
64
|
|
|
65
|
-
MCP CLI proxy client - connects to a running HTTP MCP server and invokes tools from the command line. Imported from the dedicated `@silkweave/mcp/cli-proxy` subpath (kept out of the package root so importing the `stdio`/`http` servers does not pull the CLI client's `commander`
|
|
65
|
+
MCP CLI proxy client - connects to a running HTTP MCP server and invokes tools from the command line. Imported from the dedicated `@silkweave/mcp/cli-proxy` subpath (kept out of the package root so importing the `stdio`/`http` servers does not pull the CLI client's `commander` into the server path). `commander` is an **optional peer dependency** - install it alongside `@silkweave/mcp` when you use the CLI proxy.
|
|
66
66
|
|
|
67
67
|
```typescript
|
|
68
68
|
import { silkweave } from '@silkweave/core'
|
package/build/cliProxy.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliProxy.d.mts","names":[],"sources":["../src/adapter/cliProxy.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"cliProxy.d.mts","names":[],"sources":["../src/adapter/cliProxy.ts"],"mappings":";;;;KASY,cAAA,IAAkB,OAAA,EAAS,YAAA,EAAc,KAAA,UAAe,QAAA,EAAU,YAAA;AAAA,UAE7D,eAAA;EACf,GAAA,EAAK,GAAA;EACL,SAAA,GAAY,cAAA;AAAA;AAAA,cA4DD,QAAA,EAAU,cAAA,CAAe,eAAA"}
|
package/build/cliProxy.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { i as parseResourceMessage } from "./result-B_9Eo1ey.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { createConsoleLogger } from "@silkweave/core";
|
|
3
3
|
import { kebabCase } from "change-case";
|
|
4
4
|
import { randomUUID } from "crypto";
|
|
5
|
-
import { intro } from "@clack/prompts";
|
|
6
5
|
import { Client } from "@modelcontextprotocol/sdk/client";
|
|
7
6
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
8
7
|
import { LoggingMessageNotificationSchema, ProgressNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -68,9 +67,9 @@ const cliProxy = ({ url, formatter = defaultFormatter }) => {
|
|
|
68
67
|
for (const key of Object.keys(properties)) addCliOption(command, key, properties[key]);
|
|
69
68
|
command.action(async (args) => {
|
|
70
69
|
const { silent } = program.opts();
|
|
71
|
-
const logger =
|
|
70
|
+
const logger = createConsoleLogger();
|
|
72
71
|
if (!silent) {
|
|
73
|
-
|
|
72
|
+
console.info(`${options.name} - ${tool.name}`);
|
|
74
73
|
client.setNotificationHandler(LoggingMessageNotificationSchema, ({ params: { level, data } }) => {
|
|
75
74
|
logger[level](data);
|
|
76
75
|
});
|
package/build/cliProxy.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliProxy.mjs","names":[],"sources":["../src/adapter/cliProxy.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"cliProxy.mjs","names":[],"sources":["../src/adapter/cliProxy.ts"],"sourcesContent":["import { Client } from '@modelcontextprotocol/sdk/client'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'\nimport { ContentBlock, LoggingMessageNotificationSchema, ProgressNotificationSchema, ToolResultContent } from '@modelcontextprotocol/sdk/types.js'\nimport { AdapterFactory, createConsoleLogger } from '@silkweave/core'\nimport { kebabCase } from 'change-case'\nimport { Command } from 'commander'\nimport { randomUUID } from 'crypto'\nimport { parseResourceMessage } from '../util/result.js'\n\nexport type CLIFormatterFn = (message: ContentBlock, index: number, messages: ContentBlock[]) => string | undefined\n\nexport interface CliProxyOptions {\n url: URL\n formatter?: CLIFormatterFn\n}\n\ninterface JsonSchemaProperty {\n type?: 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | string\n description?: string\n default?: unknown\n enum?: unknown[]\n}\n\ninterface JsonSchemaObject {\n type?: 'object'\n properties?: Record<string, JsonSchemaProperty>\n required?: string[]\n}\n\nfunction coerce(value: unknown, type: JsonSchemaProperty['type']): unknown {\n if (value === undefined) { return undefined }\n if (type === 'number' || type === 'integer') {\n const n = Number(value)\n return Number.isNaN(n) ? value : n\n }\n return value\n}\n\nfunction addCliOption(command: Command, key: string, prop: JsonSchemaProperty) {\n const flag = kebabCase(key)\n const description = prop.description\n const defaultValue = prop.default\n const type = prop.type\n if (type === 'boolean') {\n command.option(`--${flag}`, description, defaultValue as boolean | undefined)\n command.option(`--no-${flag}`)\n return\n }\n if (type === 'number' || type === 'integer') {\n command.option(`--${flag} <number>`, description, defaultValue as string | undefined)\n return\n }\n if (type === 'string' || prop.enum) {\n command.option(`--${flag} <string>`, description, defaultValue as string | undefined)\n return\n }\n if (type === 'object' || type === 'array') {\n command.option(`--${flag} <json>`, description ?? '', JSON.parse, defaultValue as never)\n return\n }\n throw new Error(`Unsupported JSON Schema type for CLI option \"${key}\": ${type ?? 'undefined'}`)\n}\n\nconst defaultFormatter: CLIFormatterFn = (message) => {\n if (message.type === 'text' && !message.text.includes('mcp://toolResult/')) {\n return `${message.text}`\n } else if (message.type === 'resource') {\n return parseResourceMessage(message)\n } else {\n return JSON.stringify(message)\n }\n}\n\nexport const cliProxy: AdapterFactory<CliProxyOptions> = ({ url, formatter = defaultFormatter }) => {\n return (options, baseContext) => {\n const context = baseContext.fork({ adapter: 'cliProxy' })\n const program = new Command()\n .name(options.name)\n .description(options.description)\n .version(options.version)\n .option('-s, --silent', 'Silent mode, prevent log messages', false)\n\n return {\n context,\n start: async () => {\n const client = new Client({\n name: options.name,\n description: options.description,\n version: options.version\n })\n const transport = new StreamableHTTPClientTransport(url)\n await client.connect(transport)\n const { tools } = await client.listTools()\n for (const tool of tools) {\n const name = kebabCase(tool.name)\n const command = program.command(name)\n if (tool.description) { command.description(tool.description) }\n const schema = tool.inputSchema as JsonSchemaObject\n const properties = schema.properties ?? {}\n for (const key of Object.keys(properties)) {\n addCliOption(command, key, properties[key])\n }\n command.action(async (args: Record<string, unknown>) => {\n const { silent } = program.opts<{ silent: boolean }>()\n const logger = createConsoleLogger()\n if (!silent) {\n console.info(`${options.name} - ${tool.name}`)\n client.setNotificationHandler(LoggingMessageNotificationSchema, ({ params: { level, data } }) => {\n logger[level](data)\n })\n client.setNotificationHandler(ProgressNotificationSchema, ({ params: { progress, total, message } }) => {\n logger.info({ progress, total, message })\n })\n }\n const input: Record<string, unknown> = {}\n for (const key of Object.keys(properties)) {\n const value = args[key]\n if (value !== undefined) { input[key] = coerce(value, properties[key]?.type) }\n }\n const response = await client.callTool({\n name: tool.name,\n arguments: input,\n _meta: { progressToken: randomUUID(), disposition: 'json' }\n }) as ToolResultContent\n response.content.forEach((message, index, messages) => {\n const text = formatter(message, index, messages)\n process.stdout.write(`${text}\\n`)\n })\n })\n }\n await program.parseAsync()\n await transport.close()\n },\n stop: async () => { /* noop */ }\n }\n }\n}\n"],"mappings":"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"}
|
package/build/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as smartToolResult, c as requestFromExtra, i as parseResourceMessage, n as handleToolError, o as RegisterToolsOptions, r as jsonToolResult, s as registerTools, t as errorToolResult } from "./result-
|
|
1
|
+
import { a as smartToolResult, c as requestFromExtra, i as parseResourceMessage, n as handleToolError, o as RegisterToolsOptions, r as jsonToolResult, s as registerTools, t as errorToolResult } from "./result-_Bg2cDAG.mjs";
|
|
2
2
|
import { CreateMcpExpressAppOptions } from "@modelcontextprotocol/sdk/server/express.js";
|
|
3
3
|
import { Action, AdapterFactory, SilkweaveContext, SilkweaveOptions } from "@silkweave/core";
|
|
4
4
|
import { Express, RequestHandler } from "express";
|
package/build/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as authStorage, n as requestFromExtra, r as authMiddleware, t as registerTools } from "./registerTools-
|
|
1
|
+
import { i as authStorage, n as requestFromExtra, r as authMiddleware, t as registerTools } from "./registerTools-Z6JnoM60.mjs";
|
|
2
2
|
import { a as smartToolResult, i as parseResourceMessage, n as handleToolError, r as jsonToolResult, t as errorToolResult } from "./result-B_9Eo1ey.mjs";
|
|
3
3
|
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
|
4
4
|
import { createContext } from "@silkweave/core";
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { a as smartToolResult, n as handleToolError, r as jsonToolResult } from "./result-B_9Eo1ey.mjs";
|
|
2
|
-
import { isStreamingAction, runStreamingAction } from "@silkweave/core";
|
|
2
|
+
import { createLogger, isStreamingAction, runStreamingAction } from "@silkweave/core";
|
|
3
3
|
import { validateToken } from "@silkweave/auth";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
-
import { createLogger } from "@silkweave/logger";
|
|
6
5
|
import { capitalCase, pascalCase } from "change-case";
|
|
7
6
|
//#region src/handlers/auth.ts
|
|
8
7
|
/**
|
|
@@ -142,4 +141,4 @@ function registerTools(server, actions, context, options = {}) {
|
|
|
142
141
|
//#endregion
|
|
143
142
|
export { authStorage as i, requestFromExtra as n, authMiddleware as r, registerTools as t };
|
|
144
143
|
|
|
145
|
-
//# sourceMappingURL=registerTools-
|
|
144
|
+
//# sourceMappingURL=registerTools-Z6JnoM60.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registerTools-Z6JnoM60.mjs","names":[],"sources":["../src/handlers/auth.ts","../src/handlers/registerTools.ts"],"sourcesContent":["import { AuthConfig, AuthInfo, validateToken } from '@silkweave/auth'\nimport { SilkweaveContext } from '@silkweave/core'\nimport { type RequestHandler } from 'express'\nimport { AsyncLocalStorage } from 'node:async_hooks'\n\n/**\n * Per-request bearer-token storage used by tool handlers to read the resolved\n * `AuthInfo` for the currently-handled MCP call.\n */\nexport const authStorage = new AsyncLocalStorage<AuthInfo>()\n\n/**\n * Express middleware that validates the `Authorization: Bearer …` header via\n * the supplied `AuthConfig`. On success the resolved `AuthInfo` is placed in\n * `authStorage` for the duration of the downstream handler - `mcpTransport`'s\n * tool callbacks pick it up to populate the silkweave context's `auth` key.\n *\n * The middleware should NOT be applied to OAuth-discovery / token routes -\n * compose it only on the routes that require an authenticated caller (the MCP\n * transport itself, sideload, etc.).\n */\nexport function authMiddleware(auth: AuthConfig, context: SilkweaveContext): RequestHandler {\n return async (req, res, next) => {\n const result = await validateToken(req.headers.authorization, auth, context.fork({ request: req }))\n if (result.error) {\n for (const [key, value] of Object.entries(result.error.headers)) { res.header(key, value) }\n res.status(result.error.statusCode).json(result.error.body)\n return\n }\n if (result.auth) {\n authStorage.run(result.auth, () => { next() })\n } else {\n next()\n }\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js'\nimport type { ServerNotification, ServerRequest } from '@modelcontextprotocol/sdk/types.js'\nimport { Action, ActionRun, createLogger, isStreamingAction, runStreamingAction, SilkweaveContext } from '@silkweave/core'\nimport { capitalCase, pascalCase } from 'change-case'\nimport { handleToolError, jsonToolResult, smartToolResult } from '../util/result.js'\nimport { authStorage } from './auth.js'\n\ntype LogStream = NonNullable<Parameters<typeof createLogger>[0]>['stream']\ntype ToolExtra = RequestHandlerExtra<ServerRequest, ServerNotification>\n\nexport interface RegisterToolsOptions {\n /**\n * Where the per-call logger writes its human-readable stream. The `stdio`\n * adapter MUST pass `false` (stdout is the MCP protocol channel); the HTTP\n * transports default to `process.stderr`.\n */\n logStream?: LogStream\n}\n\n/**\n * Build the generic `request` context value (the same key REST/tRPC populate)\n * from the MCP SDK's `extra.requestInfo`, so transport-agnostic consumers - e.g.\n * `@silkweave/nestjs` `@UseGuards` guards reading\n * `switchToHttp().getRequest().headers` - work over MCP. There are no path\n * `params`/`query`/`body` on the raw MCP call, so those start as empty\n * stand-ins; `@silkweave/nestjs` later fills them from the validated tool input\n * per the reflected param sources (path -> `params`, `@Query` -> `query`,\n * `@Body` -> `body`) so guards reading any of them decide as they would over\n * REST. Returns `undefined` when no HTTP request info is available.\n */\nexport function requestFromExtra(requestInfo: { headers?: unknown; url?: { toString(): string } } | undefined) {\n if (!requestInfo) { return undefined }\n return { headers: requestInfo.headers ?? {}, url: requestInfo.url?.toString(), params: {}, query: {}, body: {} }\n}\n\n/** Per-call logger that bridges silkweave logs/progress onto MCP notifications. */\nfunction createToolLogger(extra: ToolExtra, stream: LogStream) {\n return createLogger({\n stream,\n onLog: (level, data) => {\n extra.sendNotification({ method: 'notifications/message', params: { level, data } })\n },\n onProgress: ({ progress, total, message }) => {\n if (!extra._meta?.progressToken) { return }\n extra.sendNotification({\n method: 'notifications/progress',\n params: { progress, total, message, progressToken: extra._meta.progressToken }\n })\n }\n })\n}\n\n/** Run the action, streaming chunks as progress notifications when a token is set. */\nasync function runAction(action: Action, input: object, context: SilkweaveContext, extra: ToolExtra): Promise<object | object[]> {\n const progressToken = extra._meta?.progressToken\n if (isStreamingAction(action)) {\n return runStreamingAction(action, input, context, progressToken\n ? async (chunk, index) => {\n await extra.sendNotification({\n method: 'notifications/progress',\n params: { progressToken, progress: index + 1, message: JSON.stringify(chunk) }\n })\n }\n : undefined)\n }\n return (action.run as ActionRun<object, object>)(input, context)\n}\n\n/** Format via the action's `toolResult` hook, else the resolved disposition. */\nfunction formatToolResult(action: Action, result: object | object[], context: SilkweaveContext, disposition: unknown) {\n if (action.toolResult) {\n const response = action.toolResult(result, context)\n if (response) { return response }\n }\n return disposition === 'json' ? jsonToolResult(result) : smartToolResult(result)\n}\n\n/**\n * Register every action as an MCP tool on `server`. Shared by all MCP transports\n * (`stdio`, `http`, `edge`). Each tool call forks `context` with a per-call\n * `logger`, the SDK `extra`, a synthesized `request` (see `requestFromExtra`),\n * and - when bearer auth ran for this request - the resolved `auth`. The result\n * is formatted by the action's `toolResult` hook if present, otherwise per the\n * resolved disposition (client `_meta.disposition` > `action.disposition` >\n * `smart`).\n */\nexport function registerTools(\n server: McpServer,\n actions: Action[],\n context: SilkweaveContext,\n options: RegisterToolsOptions = {}\n) {\n const stream = options.logStream ?? process.stderr\n for (const action of actions) {\n server.registerTool(pascalCase(action.name), {\n title: capitalCase(action.name),\n description: action.description,\n inputSchema: action.input\n }, async (input, extra) => {\n const logger = createToolLogger(extra, stream)\n const currentAuth = authStorage.getStore()\n const actionContext = context.fork({\n logger,\n extra,\n request: requestFromExtra(extra.requestInfo),\n ...(currentAuth ? { auth: currentAuth } : {})\n })\n // Client-sent `_meta.disposition` wins; otherwise fall back to the\n // action's configured default (`smart` when neither is set).\n const disposition = extra._meta?.disposition ?? action.disposition\n try {\n const result = await runAction(action, input, actionContext, extra)\n return formatToolResult(action, result, actionContext, disposition)\n } catch (error) {\n return handleToolError(error)\n }\n })\n }\n}\n"],"mappings":";;;;;;;;;;AASA,MAAa,cAAc,IAAI,mBAA6B;;;;;;;;;;;AAY5D,SAAgB,eAAe,MAAkB,SAA2C;AAC1F,QAAO,OAAO,KAAK,KAAK,SAAS;EAC/B,MAAM,SAAS,MAAM,cAAc,IAAI,QAAQ,eAAe,MAAM,QAAQ,KAAK,EAAE,SAAS,KAAK,CAAC,CAAC;AACnG,MAAI,OAAO,OAAO;AAChB,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,MAAM,QAAQ,CAAI,KAAI,OAAO,KAAK,MAAM;AACzF,OAAI,OAAO,OAAO,MAAM,WAAW,CAAC,KAAK,OAAO,MAAM,KAAK;AAC3D;;AAEF,MAAI,OAAO,KACT,aAAY,IAAI,OAAO,YAAY;AAAE,SAAM;IAAG;MAE9C,OAAM;;;;;;;;;;;;;;;;ACDZ,SAAgB,iBAAiB,aAA8E;AAC7G,KAAI,CAAC,YAAe;AACpB,QAAO;EAAE,SAAS,YAAY,WAAW,EAAE;EAAE,KAAK,YAAY,KAAK,UAAU;EAAE,QAAQ,EAAE;EAAE,OAAO,EAAE;EAAE,MAAM,EAAE;EAAE;;;AAIlH,SAAS,iBAAiB,OAAkB,QAAmB;AAC7D,QAAO,aAAa;EAClB;EACA,QAAQ,OAAO,SAAS;AACtB,SAAM,iBAAiB;IAAE,QAAQ;IAAyB,QAAQ;KAAE;KAAO;KAAM;IAAE,CAAC;;EAEtF,aAAa,EAAE,UAAU,OAAO,cAAc;AAC5C,OAAI,CAAC,MAAM,OAAO,cAAiB;AACnC,SAAM,iBAAiB;IACrB,QAAQ;IACR,QAAQ;KAAE;KAAU;KAAO;KAAS,eAAe,MAAM,MAAM;KAAe;IAC/E,CAAC;;EAEL,CAAC;;;AAIJ,eAAe,UAAU,QAAgB,OAAe,SAA2B,OAA8C;CAC/H,MAAM,gBAAgB,MAAM,OAAO;AACnC,KAAI,kBAAkB,OAAO,CAC3B,QAAO,mBAAmB,QAAQ,OAAO,SAAS,gBAC9C,OAAO,OAAO,UAAU;AACxB,QAAM,MAAM,iBAAiB;GAC3B,QAAQ;GACR,QAAQ;IAAE;IAAe,UAAU,QAAQ;IAAG,SAAS,KAAK,UAAU,MAAM;IAAE;GAC/E,CAAC;KAEF,KAAA,EAAU;AAEhB,QAAQ,OAAO,IAAkC,OAAO,QAAQ;;;AAIlE,SAAS,iBAAiB,QAAgB,QAA2B,SAA2B,aAAsB;AACpH,KAAI,OAAO,YAAY;EACrB,MAAM,WAAW,OAAO,WAAW,QAAQ,QAAQ;AACnD,MAAI,SAAY,QAAO;;AAEzB,QAAO,gBAAgB,SAAS,eAAe,OAAO,GAAG,gBAAgB,OAAO;;;;;;;;;;;AAYlF,SAAgB,cACd,QACA,SACA,SACA,UAAgC,EAAE,EAClC;CACA,MAAM,SAAS,QAAQ,aAAa,QAAQ;AAC5C,MAAK,MAAM,UAAU,QACnB,QAAO,aAAa,WAAW,OAAO,KAAK,EAAE;EAC3C,OAAO,YAAY,OAAO,KAAK;EAC/B,aAAa,OAAO;EACpB,aAAa,OAAO;EACrB,EAAE,OAAO,OAAO,UAAU;EACzB,MAAM,SAAS,iBAAiB,OAAO,OAAO;EAC9C,MAAM,cAAc,YAAY,UAAU;EAC1C,MAAM,gBAAgB,QAAQ,KAAK;GACjC;GACA;GACA,SAAS,iBAAiB,MAAM,YAAY;GAC5C,GAAI,cAAc,EAAE,MAAM,aAAa,GAAG,EAAE;GAC7C,CAAC;EAGF,MAAM,cAAc,MAAM,OAAO,eAAe,OAAO;AACvD,MAAI;AAEF,UAAO,iBAAiB,QAAQ,MADX,UAAU,QAAQ,OAAO,eAAe,MAAM,EAC3B,eAAe,YAAY;WAC5D,OAAO;AACd,UAAO,gBAAgB,MAAM;;GAE/B"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Action, SilkweaveContext, SilkweaveError } from "@silkweave/core";
|
|
1
|
+
import { Action, SilkweaveContext, SilkweaveError, createLogger } from "@silkweave/core";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import { createLogger } from "@silkweave/logger";
|
|
4
3
|
import { CallToolResult, EmbeddedResource } from "@modelcontextprotocol/sdk/types.js";
|
|
5
4
|
|
|
6
5
|
//#region src/handlers/registerTools.d.ts
|
|
@@ -61,4 +60,4 @@ declare function parseResourceMessage({
|
|
|
61
60
|
}: EmbeddedResource): string;
|
|
62
61
|
//#endregion
|
|
63
62
|
export { smartToolResult as a, requestFromExtra as c, parseResourceMessage as i, handleToolError as n, RegisterToolsOptions as o, jsonToolResult as r, registerTools as s, errorToolResult as t };
|
|
64
|
-
//# sourceMappingURL=result-
|
|
63
|
+
//# sourceMappingURL=result-_Bg2cDAG.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-_Bg2cDAG.d.mts","names":[],"sources":["../src/handlers/registerTools.ts","../src/util/result.ts"],"mappings":";;;;;KAQK,SAAA,GAAY,WAAA,CAAY,UAAA,QAAkB,YAAA;AAAA,UAG9B,oBAAA;;AARyG;;;;EAcxH,SAAA,GAAY,SAAA;AAAA;;;;;;;;AANd;;;;iBAoBgB,gBAAA,CAAiB,WAAA;EAAe,OAAA;EAAmB,GAAA;IAAQ,QAAA;EAAA;AAAA;;;;;;;;;;;AAwD3E;;;;;iBAAgB,aAAA,CACd,MAAA,EAAQ,SAAA,EACR,OAAA,EAAS,MAAA,IACT,OAAA,EAAS,gBAAA,EACT,OAAA,GAAS,oBAAA;;;iBCvFK,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;AAAA,iBAejC,oBAAA,CAAA;EAAuB;AAAA,GAAY,gBAAA"}
|
package/build/tools.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as smartToolResult, c as requestFromExtra, i as parseResourceMessage, n as handleToolError, o as RegisterToolsOptions, r as jsonToolResult, s as registerTools, t as errorToolResult } from "./result-
|
|
1
|
+
import { a as smartToolResult, c as requestFromExtra, i as parseResourceMessage, n as handleToolError, o as RegisterToolsOptions, r as jsonToolResult, s as registerTools, t as errorToolResult } from "./result-_Bg2cDAG.mjs";
|
|
2
2
|
export { RegisterToolsOptions, errorToolResult, handleToolError, jsonToolResult, parseResourceMessage, registerTools, requestFromExtra, smartToolResult };
|
package/build/tools.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as requestFromExtra, t as registerTools } from "./registerTools-
|
|
1
|
+
import { n as requestFromExtra, t as registerTools } from "./registerTools-Z6JnoM60.mjs";
|
|
2
2
|
import { a as smartToolResult, i as parseResourceMessage, n as handleToolError, r as jsonToolResult, t as errorToolResult } from "./result-B_9Eo1ey.mjs";
|
|
3
3
|
export { errorToolResult, handleToolError, jsonToolResult, parseResourceMessage, registerTools, requestFromExtra, smartToolResult };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silkweave/mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Silkweave MCP Package",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://www.silkweave.dev",
|
|
@@ -39,20 +39,15 @@
|
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
40
40
|
"change-case": "^5.4.4",
|
|
41
41
|
"zod": "^3.25.0",
|
|
42
|
-
"@silkweave/
|
|
43
|
-
"@silkweave/
|
|
44
|
-
"@silkweave/auth": "3.0.0"
|
|
42
|
+
"@silkweave/auth": "3.1.0",
|
|
43
|
+
"@silkweave/core": "3.1.0"
|
|
45
44
|
},
|
|
46
45
|
"peerDependencies": {
|
|
47
|
-
"@clack/prompts": "^1.0.1",
|
|
48
46
|
"commander": "^13.1.0",
|
|
49
47
|
"cors": "^2.8.5",
|
|
50
48
|
"express": "^5.0.0"
|
|
51
49
|
},
|
|
52
50
|
"peerDependenciesMeta": {
|
|
53
|
-
"@clack/prompts": {
|
|
54
|
-
"optional": true
|
|
55
|
-
},
|
|
56
51
|
"commander": {
|
|
57
52
|
"optional": true
|
|
58
53
|
},
|
|
@@ -64,7 +59,6 @@
|
|
|
64
59
|
}
|
|
65
60
|
},
|
|
66
61
|
"devDependencies": {
|
|
67
|
-
"@clack/prompts": "^1.0.1",
|
|
68
62
|
"@eslint/js": "^10.0.1",
|
|
69
63
|
"@modelcontextprotocol/inspector": "^0.21.1",
|
|
70
64
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registerTools-DlguElKV.mjs","names":[],"sources":["../src/handlers/auth.ts","../src/handlers/registerTools.ts"],"sourcesContent":["import { AuthConfig, AuthInfo, validateToken } from '@silkweave/auth'\nimport { SilkweaveContext } from '@silkweave/core'\nimport { type RequestHandler } from 'express'\nimport { AsyncLocalStorage } from 'node:async_hooks'\n\n/**\n * Per-request bearer-token storage used by tool handlers to read the resolved\n * `AuthInfo` for the currently-handled MCP call.\n */\nexport const authStorage = new AsyncLocalStorage<AuthInfo>()\n\n/**\n * Express middleware that validates the `Authorization: Bearer …` header via\n * the supplied `AuthConfig`. On success the resolved `AuthInfo` is placed in\n * `authStorage` for the duration of the downstream handler - `mcpTransport`'s\n * tool callbacks pick it up to populate the silkweave context's `auth` key.\n *\n * The middleware should NOT be applied to OAuth-discovery / token routes -\n * compose it only on the routes that require an authenticated caller (the MCP\n * transport itself, sideload, etc.).\n */\nexport function authMiddleware(auth: AuthConfig, context: SilkweaveContext): RequestHandler {\n return async (req, res, next) => {\n const result = await validateToken(req.headers.authorization, auth, context.fork({ request: req }))\n if (result.error) {\n for (const [key, value] of Object.entries(result.error.headers)) { res.header(key, value) }\n res.status(result.error.statusCode).json(result.error.body)\n return\n }\n if (result.auth) {\n authStorage.run(result.auth, () => { next() })\n } else {\n next()\n }\n }\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js'\nimport type { ServerNotification, ServerRequest } from '@modelcontextprotocol/sdk/types.js'\nimport { Action, ActionRun, isStreamingAction, runStreamingAction, SilkweaveContext } from '@silkweave/core'\nimport { createLogger } from '@silkweave/logger'\nimport { capitalCase, pascalCase } from 'change-case'\nimport { handleToolError, jsonToolResult, smartToolResult } from '../util/result.js'\nimport { authStorage } from './auth.js'\n\ntype LogStream = NonNullable<Parameters<typeof createLogger>[0]>['stream']\ntype ToolExtra = RequestHandlerExtra<ServerRequest, ServerNotification>\n\nexport interface RegisterToolsOptions {\n /**\n * Where the per-call logger writes its human-readable stream. The `stdio`\n * adapter MUST pass `false` (stdout is the MCP protocol channel); the HTTP\n * transports default to `process.stderr`.\n */\n logStream?: LogStream\n}\n\n/**\n * Build the generic `request` context value (the same key REST/tRPC populate)\n * from the MCP SDK's `extra.requestInfo`, so transport-agnostic consumers - e.g.\n * `@silkweave/nestjs` `@UseGuards` guards reading\n * `switchToHttp().getRequest().headers` - work over MCP. There are no path\n * `params`/`query`/`body` on the raw MCP call, so those start as empty\n * stand-ins; `@silkweave/nestjs` later fills them from the validated tool input\n * per the reflected param sources (path -> `params`, `@Query` -> `query`,\n * `@Body` -> `body`) so guards reading any of them decide as they would over\n * REST. Returns `undefined` when no HTTP request info is available.\n */\nexport function requestFromExtra(requestInfo: { headers?: unknown; url?: { toString(): string } } | undefined) {\n if (!requestInfo) { return undefined }\n return { headers: requestInfo.headers ?? {}, url: requestInfo.url?.toString(), params: {}, query: {}, body: {} }\n}\n\n/** Per-call logger that bridges silkweave logs/progress onto MCP notifications. */\nfunction createToolLogger(extra: ToolExtra, stream: LogStream) {\n return createLogger({\n stream,\n onLog: (level, data) => {\n extra.sendNotification({ method: 'notifications/message', params: { level, data } })\n },\n onProgress: ({ progress, total, message }) => {\n if (!extra._meta?.progressToken) { return }\n extra.sendNotification({\n method: 'notifications/progress',\n params: { progress, total, message, progressToken: extra._meta.progressToken }\n })\n }\n })\n}\n\n/** Run the action, streaming chunks as progress notifications when a token is set. */\nasync function runAction(action: Action, input: object, context: SilkweaveContext, extra: ToolExtra): Promise<object | object[]> {\n const progressToken = extra._meta?.progressToken\n if (isStreamingAction(action)) {\n return runStreamingAction(action, input, context, progressToken\n ? async (chunk, index) => {\n await extra.sendNotification({\n method: 'notifications/progress',\n params: { progressToken, progress: index + 1, message: JSON.stringify(chunk) }\n })\n }\n : undefined)\n }\n return (action.run as ActionRun<object, object>)(input, context)\n}\n\n/** Format via the action's `toolResult` hook, else the resolved disposition. */\nfunction formatToolResult(action: Action, result: object | object[], context: SilkweaveContext, disposition: unknown) {\n if (action.toolResult) {\n const response = action.toolResult(result, context)\n if (response) { return response }\n }\n return disposition === 'json' ? jsonToolResult(result) : smartToolResult(result)\n}\n\n/**\n * Register every action as an MCP tool on `server`. Shared by all MCP transports\n * (`stdio`, `http`, `edge`). Each tool call forks `context` with a per-call\n * `logger`, the SDK `extra`, a synthesized `request` (see `requestFromExtra`),\n * and - when bearer auth ran for this request - the resolved `auth`. The result\n * is formatted by the action's `toolResult` hook if present, otherwise per the\n * resolved disposition (client `_meta.disposition` > `action.disposition` >\n * `smart`).\n */\nexport function registerTools(\n server: McpServer,\n actions: Action[],\n context: SilkweaveContext,\n options: RegisterToolsOptions = {}\n) {\n const stream = options.logStream ?? process.stderr\n for (const action of actions) {\n server.registerTool(pascalCase(action.name), {\n title: capitalCase(action.name),\n description: action.description,\n inputSchema: action.input\n }, async (input, extra) => {\n const logger = createToolLogger(extra, stream)\n const currentAuth = authStorage.getStore()\n const actionContext = context.fork({\n logger,\n extra,\n request: requestFromExtra(extra.requestInfo),\n ...(currentAuth ? { auth: currentAuth } : {})\n })\n // Client-sent `_meta.disposition` wins; otherwise fall back to the\n // action's configured default (`smart` when neither is set).\n const disposition = extra._meta?.disposition ?? action.disposition\n try {\n const result = await runAction(action, input, actionContext, extra)\n return formatToolResult(action, result, actionContext, disposition)\n } catch (error) {\n return handleToolError(error)\n }\n })\n }\n}\n"],"mappings":";;;;;;;;;;;AASA,MAAa,cAAc,IAAI,mBAA6B;;;;;;;;;;;AAY5D,SAAgB,eAAe,MAAkB,SAA2C;AAC1F,QAAO,OAAO,KAAK,KAAK,SAAS;EAC/B,MAAM,SAAS,MAAM,cAAc,IAAI,QAAQ,eAAe,MAAM,QAAQ,KAAK,EAAE,SAAS,KAAK,CAAC,CAAC;AACnG,MAAI,OAAO,OAAO;AAChB,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,MAAM,QAAQ,CAAI,KAAI,OAAO,KAAK,MAAM;AACzF,OAAI,OAAO,OAAO,MAAM,WAAW,CAAC,KAAK,OAAO,MAAM,KAAK;AAC3D;;AAEF,MAAI,OAAO,KACT,aAAY,IAAI,OAAO,YAAY;AAAE,SAAM;IAAG;MAE9C,OAAM;;;;;;;;;;;;;;;;ACAZ,SAAgB,iBAAiB,aAA8E;AAC7G,KAAI,CAAC,YAAe;AACpB,QAAO;EAAE,SAAS,YAAY,WAAW,EAAE;EAAE,KAAK,YAAY,KAAK,UAAU;EAAE,QAAQ,EAAE;EAAE,OAAO,EAAE;EAAE,MAAM,EAAE;EAAE;;;AAIlH,SAAS,iBAAiB,OAAkB,QAAmB;AAC7D,QAAO,aAAa;EAClB;EACA,QAAQ,OAAO,SAAS;AACtB,SAAM,iBAAiB;IAAE,QAAQ;IAAyB,QAAQ;KAAE;KAAO;KAAM;IAAE,CAAC;;EAEtF,aAAa,EAAE,UAAU,OAAO,cAAc;AAC5C,OAAI,CAAC,MAAM,OAAO,cAAiB;AACnC,SAAM,iBAAiB;IACrB,QAAQ;IACR,QAAQ;KAAE;KAAU;KAAO;KAAS,eAAe,MAAM,MAAM;KAAe;IAC/E,CAAC;;EAEL,CAAC;;;AAIJ,eAAe,UAAU,QAAgB,OAAe,SAA2B,OAA8C;CAC/H,MAAM,gBAAgB,MAAM,OAAO;AACnC,KAAI,kBAAkB,OAAO,CAC3B,QAAO,mBAAmB,QAAQ,OAAO,SAAS,gBAC9C,OAAO,OAAO,UAAU;AACxB,QAAM,MAAM,iBAAiB;GAC3B,QAAQ;GACR,QAAQ;IAAE;IAAe,UAAU,QAAQ;IAAG,SAAS,KAAK,UAAU,MAAM;IAAE;GAC/E,CAAC;KAEF,KAAA,EAAU;AAEhB,QAAQ,OAAO,IAAkC,OAAO,QAAQ;;;AAIlE,SAAS,iBAAiB,QAAgB,QAA2B,SAA2B,aAAsB;AACpH,KAAI,OAAO,YAAY;EACrB,MAAM,WAAW,OAAO,WAAW,QAAQ,QAAQ;AACnD,MAAI,SAAY,QAAO;;AAEzB,QAAO,gBAAgB,SAAS,eAAe,OAAO,GAAG,gBAAgB,OAAO;;;;;;;;;;;AAYlF,SAAgB,cACd,QACA,SACA,SACA,UAAgC,EAAE,EAClC;CACA,MAAM,SAAS,QAAQ,aAAa,QAAQ;AAC5C,MAAK,MAAM,UAAU,QACnB,QAAO,aAAa,WAAW,OAAO,KAAK,EAAE;EAC3C,OAAO,YAAY,OAAO,KAAK;EAC/B,aAAa,OAAO;EACpB,aAAa,OAAO;EACrB,EAAE,OAAO,OAAO,UAAU;EACzB,MAAM,SAAS,iBAAiB,OAAO,OAAO;EAC9C,MAAM,cAAc,YAAY,UAAU;EAC1C,MAAM,gBAAgB,QAAQ,KAAK;GACjC;GACA;GACA,SAAS,iBAAiB,MAAM,YAAY;GAC5C,GAAI,cAAc,EAAE,MAAM,aAAa,GAAG,EAAE;GAC7C,CAAC;EAGF,MAAM,cAAc,MAAM,OAAO,eAAe,OAAO;AACvD,MAAI;AAEF,UAAO,iBAAiB,QAAQ,MADX,UAAU,QAAQ,OAAO,eAAe,MAAM,EAC3B,eAAe,YAAY;WAC5D,OAAO;AACd,UAAO,gBAAgB,MAAM;;GAE/B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"result-BVpEX7jU.d.mts","names":[],"sources":["../src/handlers/registerTools.ts","../src/util/result.ts"],"mappings":";;;;;;KASK,SAAA,GAAY,WAAA,CAAY,UAAA,QAAkB,YAAA;AAAA,UAG9B,oBAAA;;AAR+B;;;;EAc9C,SAAA,GAAY,SAAA;AAAA;;;;;;;;AANd;;;;iBAoBgB,gBAAA,CAAiB,WAAA;EAAe,OAAA;EAAmB,GAAA;IAAQ,QAAA;EAAA;AAAA;;;;;;;;;;;AAwD3E;;;;;iBAAgB,aAAA,CACd,MAAA,EAAQ,SAAA,EACR,OAAA,EAAS,MAAA,IACT,OAAA,EAAS,gBAAA,EACT,OAAA,GAAS,oBAAA;;;iBCxFK,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;AAAA,iBAejC,oBAAA,CAAA;EAAuB;AAAA,GAAY,gBAAA"}
|