@quantakrypto/mcp 0.4.1 → 0.4.3

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 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,OAAO,KAAK,EAEV,eAAe,EACf,WAAW,EACX,cAAc,EACd,cAAc,EAEf,MAAM,eAAe,CAAC;AAGvB,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,mEAAmE;IACnE,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,gBAAgB;IAKrC,2EAA2E;IAC3E,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAQxC,uEAAuE;IACvE,SAAS,IAAI,cAAc,EAAE;IAM7B,wDAAwD;IACxD,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED;;;;;;;;;OASG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IA8BtF,gFAAgF;YAClE,QAAQ;IA0BtB,kEAAkE;IAClE,OAAO,CAAC,eAAe;IAavB,yEAAyE;IACzE,OAAO,CAAC,YAAY;IAiBpB,qCAAqC;IACrC,OAAO,CAAC,YAAY;IAgBpB,2DAA2D;YAC7C,WAAW;CAuB1B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAaH,OAAO,KAAK,EAEV,eAAe,EACf,WAAW,EACX,cAAc,EACd,cAAc,EAEf,MAAM,eAAe,CAAC;AAGvB,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAC;IACjB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,mEAAmE;IACnE,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,gBAAgB;IAKrC,2EAA2E;IAC3E,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAQxC,uEAAuE;IACvE,SAAS,IAAI,cAAc,EAAE;IAM7B,wDAAwD;IACxD,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED;;;;;;;;;OASG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IA8BtF,gFAAgF;YAClE,QAAQ;IA0BtB,kEAAkE;IAClE,OAAO,CAAC,eAAe;IAcvB,yEAAyE;IACzE,OAAO,CAAC,YAAY;IAiBpB,qCAAqC;IACrC,OAAO,CAAC,YAAY;IAgBpB,2DAA2D;YAC7C,WAAW;CAuB1B"}
package/dist/server.js CHANGED
@@ -124,8 +124,9 @@ export class McpServer {
124
124
  throw new RpcError(ErrorCode.InvalidParams, "resources/read requires a 'uri' string");
125
125
  }
126
126
  const contents = readResource(uri);
127
+ // MCP spec: unknown resource → -32002 (Resource not found), uri in data.
127
128
  if (!contents)
128
- throw new RpcError(ErrorCode.InvalidParams, `unknown resource: ${uri}`);
129
+ throw new RpcError(ErrorCode.ResourceNotFound, "Resource not found", { uri });
129
130
  return { contents: [contents] };
130
131
  }
131
132
  /** `prompts/get`: materialize a named prompt with optional arguments. */
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EACL,SAAS,EACT,oBAAoB,EACpB,QAAQ,EACR,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,WAAW,GACZ,MAAM,eAAe,CAAC;AASvB,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAe7E;;;GAGG;AACH,MAAM,OAAO,SAAS;IACH,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC1C,IAAI,CAAa;IACjB,YAAY,CAAU;IACvC,mEAAmE;IAC3D,WAAW,GAAG,KAAK,CAAC;IAE5B,YAAY,OAAyB;QACnC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAC3C,CAAC;IAED,2EAA2E;IAC3E,YAAY,CAAC,IAAoB;QAC/B,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,uEAAuE;IACvE,SAAS;QACP,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;aAC5B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;aACjF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,wDAAwD;IACxD,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,MAAM,CAAC,OAAgB,EAAE,OAAqB;QAClD,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,2EAA2E;YAC3E,OAAO,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,GAAG,GAAG,OAAyB,CAAC;QACtC,MAAM,YAAY,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;YACjD,2DAA2D;YAC3D,IAAI,YAAY;gBAAE,OAAO,IAAI,CAAC;YAC9B,OAAO,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,YAAY;gBAAE,OAAO,IAAI,CAAC,CAAC,oCAAoC;YACnE,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;gBAC5B,8EAA8E;gBAC9E,OAAO,WAAW,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAC1D,CAAC;YACD,4EAA4E;YAC5E,uEAAuE;YACvE,8DAA8D;YAC9D,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sDAAsD,MAAM,IAAI,CAAC,CAAC;YACvF,OAAO,WAAW,CAAC,EAAE,EAAE,SAAS,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,gFAAgF;IACxE,KAAK,CAAC,QAAQ,CAAC,GAAmB,EAAE,OAAqB;QAC/D,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC;YACnB,KAAK,YAAY;gBACf,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;YAC7B,KAAK,2BAA2B;gBAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;gBACxB,OAAO,EAAE,CAAC,CAAC,4CAA4C;YACzD,KAAK,MAAM;gBACT,OAAO,EAAE,CAAC;YACZ,KAAK,YAAY;gBACf,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;YACrC,KAAK,YAAY;gBACf,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC/C,KAAK,gBAAgB;gBACnB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;YAClC,KAAK,gBAAgB;gBACnB,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1C,KAAK,cAAc;gBACjB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YAC9B,KAAK,aAAa;gBAChB,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACvC;gBACE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,qBAAqB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED,kEAAkE;IAC1D,eAAe,CAAC,MAAe;QACrC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,0CAA0C,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,GAAG,GAAI,MAA4B,CAAC,GAAG,CAAC;QAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,wCAAwC,CAAC,CAAC;QACxF,CAAC;QACD,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,qBAAqB,GAAG,EAAE,CAAC,CAAC;QACvF,OAAO,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;IAClC,CAAC;IAED,yEAAyE;IACjE,YAAY,CAAC,MAAe;QAClC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,uCAAuC,CAAC,CAAC;QACvF,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAAiD,CAAC;QACpF,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,sCAAsC,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,UAAU,GACd,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YACtD,CAAC,CAAE,IAAgC;YACnC,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAC;QACpF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,qCAAqC;IAC7B,YAAY;QAClB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,MAAM,MAAM,GAA4B;YACtC,eAAe,EAAE,oBAAoB;YACrC,YAAY,EAAE;gBACZ,sEAAsE;gBACtE,KAAK,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;gBAC7B,SAAS,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;gBACjC,OAAO,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE;aAChC;YACD,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;SACjE,CAAC;QACF,IAAI,IAAI,CAAC,YAAY;YAAE,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QAC/D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,2DAA2D;IACnD,KAAK,CAAC,WAAW,CAAC,MAAe,EAAE,OAAqB;QAC9D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,sCAAsC,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,MAGjC,CAAC;QACF,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,qCAAqC,CAAC,CAAC;QACrF,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,iBAAiB,IAAI,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC7F,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,oCAAoC,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,QAAQ,GAAG,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC;QACzD,4EAA4E;QAC5E,6EAA6E;QAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;CACF"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Transport-agnostic MCP server core.\n *\n * {@link McpServer} owns a tool registry and a single pure entry point,\n * {@link McpServer.handle}, that turns one JSON-RPC message into one JSON-RPC\n * response (or `null` for notifications, which get no reply). It performs no\n * I/O whatsoever — the stdio and http transports feed it parsed messages and\n * serialize whatever it returns. This makes the whole protocol surface\n * unit-testable by calling `handle` directly.\n *\n * The one concession to I/O is that unexpected (non-{@link RpcError}) throws are\n * logged to stderr with full detail and replaced with a generic message in the\n * response, so server internals (paths, ENOENT targets) never reach the remote\n * caller. The wire response remains a pure function of the inputs.\n */\n\nimport process from \"node:process\";\n\nimport {\n ErrorCode,\n MCP_PROTOCOL_VERSION,\n RpcError,\n isJsonRpcRequestLike,\n isNotification,\n makeFailure,\n makeSuccess,\n} from \"./protocol.js\";\nimport type {\n JsonRpcRequest,\n JsonRpcResponse,\n ToolContext,\n ToolDefinition,\n ToolDescriptor,\n ToolResult,\n} from \"./protocol.js\";\nimport { RESOURCES, PROMPTS, readResource, getPrompt } from \"./resources.js\";\n\n/** Identifying info advertised to clients during `initialize`. */\nexport interface ServerInfo {\n name: string;\n version: string;\n}\n\nexport interface McpServerOptions {\n /** Server identity returned in the `initialize` handshake. */\n info: ServerInfo;\n /** Optional human-readable instructions surfaced to the client. */\n instructions?: string;\n}\n\n/**\n * A minimal, spec-faithful MCP server. Register tools with {@link registerTool}\n * and drive it one message at a time with {@link handle}.\n */\nexport class McpServer {\n private readonly tools = new Map<string, ToolDefinition>();\n private readonly info: ServerInfo;\n private readonly instructions?: string;\n /** Set once `initialize` has been received; informational only. */\n private initialized = false;\n\n constructor(options: McpServerOptions) {\n this.info = options.info;\n this.instructions = options.instructions;\n }\n\n /** Register a tool. Throws if a tool with the same name already exists. */\n registerTool(tool: ToolDefinition): this {\n if (this.tools.has(tool.name)) {\n throw new Error(`duplicate tool registration: ${tool.name}`);\n }\n this.tools.set(tool.name, tool);\n return this;\n }\n\n /** The public descriptors of all registered tools (sorted by name). */\n listTools(): ToolDescriptor[] {\n return [...this.tools.values()]\n .map(({ name, description, inputSchema }) => ({ name, description, inputSchema }))\n .sort((a, b) => a.name.localeCompare(b.name));\n }\n\n /** Whether the `initialize` handshake has completed. */\n get isInitialized(): boolean {\n return this.initialized;\n }\n\n /**\n * Process a single JSON-RPC message.\n *\n * @param message An already-parsed JSON value (the transport handles framing\n * and `JSON.parse`). May be malformed; this method validates it.\n * @param context Optional per-call context (e.g. an `AbortSignal` for the\n * transport's request deadline) forwarded to the invoked tool handler.\n * @returns The response to send back, or `null` when no reply is due\n * (notifications, or an unparseable notification-shaped message).\n */\n async handle(message: unknown, context?: ToolContext): Promise<JsonRpcResponse | null> {\n if (!isJsonRpcRequestLike(message)) {\n // Not a valid request object. We can't know its id, so reply with null id.\n return makeFailure(null, ErrorCode.InvalidRequest, \"invalid JSON-RPC request\");\n }\n\n const req = message as JsonRpcRequest;\n const notification = isNotification(req);\n const id = notification ? null : (req.id ?? null);\n\n try {\n const result = await this.dispatch(req, context);\n // Notifications never receive a response, even on success.\n if (notification) return null;\n return makeSuccess(id, result);\n } catch (err) {\n if (notification) return null; // swallow errors from notifications\n if (err instanceof RpcError) {\n // RpcError messages are author-controlled validation strings, safe to return.\n return makeFailure(id, err.code, err.message, err.data);\n }\n // An unexpected throw may carry a server-side detail (a filesystem path, an\n // ENOENT for /etc/shadow, …). Log the detail locally; return a generic\n // message so the remote caller never learns server internals.\n const detail = err instanceof Error ? (err.stack ?? err.message) : String(err);\n process.stderr.write(`quantakrypto MCP: internal error handling request: ${detail}\\n`);\n return makeFailure(id, ErrorCode.InternalError, \"internal error\");\n }\n }\n\n /** Route a request to the right handler. Throws {@link RpcError} on failure. */\n private async dispatch(req: JsonRpcRequest, context?: ToolContext): Promise<unknown> {\n switch (req.method) {\n case \"initialize\":\n return this.onInitialize();\n case \"notifications/initialized\":\n this.initialized = true;\n return {}; // notification → result ignored by handle()\n case \"ping\":\n return {};\n case \"tools/list\":\n return { tools: this.listTools() };\n case \"tools/call\":\n return this.onToolsCall(req.params, context);\n case \"resources/list\":\n return { resources: RESOURCES };\n case \"resources/read\":\n return this.onResourcesRead(req.params);\n case \"prompts/list\":\n return { prompts: PROMPTS };\n case \"prompts/get\":\n return this.onPromptsGet(req.params);\n default:\n throw new RpcError(ErrorCode.MethodNotFound, `method not found: ${req.method}`);\n }\n }\n\n /** `resources/read`: return the body for a known resource URI. */\n private onResourcesRead(params: unknown): unknown {\n if (typeof params !== \"object\" || params === null || Array.isArray(params)) {\n throw new RpcError(ErrorCode.InvalidParams, \"resources/read requires an object params\");\n }\n const uri = (params as { uri?: unknown }).uri;\n if (typeof uri !== \"string\" || uri.length === 0) {\n throw new RpcError(ErrorCode.InvalidParams, \"resources/read requires a 'uri' string\");\n }\n const contents = readResource(uri);\n // MCP spec: unknown resource → -32002 (Resource not found), uri in data.\n if (!contents) throw new RpcError(ErrorCode.ResourceNotFound, \"Resource not found\", { uri });\n return { contents: [contents] };\n }\n\n /** `prompts/get`: materialize a named prompt with optional arguments. */\n private onPromptsGet(params: unknown): unknown {\n if (typeof params !== \"object\" || params === null || Array.isArray(params)) {\n throw new RpcError(ErrorCode.InvalidParams, \"prompts/get requires an object params\");\n }\n const { name, arguments: args } = params as { name?: unknown; arguments?: unknown };\n if (typeof name !== \"string\" || name.length === 0) {\n throw new RpcError(ErrorCode.InvalidParams, \"prompts/get requires a 'name' string\");\n }\n const promptArgs =\n args && typeof args === \"object\" && !Array.isArray(args)\n ? (args as Record<string, unknown>)\n : {};\n const prompt = getPrompt(name, promptArgs);\n if (!prompt) throw new RpcError(ErrorCode.InvalidParams, `unknown prompt: ${name}`);\n return prompt;\n }\n\n /** Build the `initialize` result. */\n private onInitialize(): unknown {\n this.initialized = true;\n const result: Record<string, unknown> = {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: {\n // Everything we expose is static, so listChanged is false throughout.\n tools: { listChanged: false },\n resources: { listChanged: false },\n prompts: { listChanged: false },\n },\n serverInfo: { name: this.info.name, version: this.info.version },\n };\n if (this.instructions) result.instructions = this.instructions;\n return result;\n }\n\n /** Validate params and execute a tool for `tools/call`. */\n private async onToolsCall(params: unknown, context?: ToolContext): Promise<ToolResult> {\n if (typeof params !== \"object\" || params === null || Array.isArray(params)) {\n throw new RpcError(ErrorCode.InvalidParams, \"tools/call requires an object params\");\n }\n const { name, arguments: args } = params as {\n name?: unknown;\n arguments?: unknown;\n };\n if (typeof name !== \"string\" || name.length === 0) {\n throw new RpcError(ErrorCode.InvalidParams, \"tools/call requires a 'name' string\");\n }\n const tool = this.tools.get(name);\n if (!tool) {\n throw new RpcError(ErrorCode.InvalidParams, `unknown tool: ${name}`);\n }\n if (args !== undefined && (typeof args !== \"object\" || args === null || Array.isArray(args))) {\n throw new RpcError(ErrorCode.InvalidParams, \"tool 'arguments' must be an object\");\n }\n const toolArgs = (args ?? {}) as Record<string, unknown>;\n // Tool-level failures are reported as isError results, not protocol errors,\n // so the model can read and react to them. Only unexpected throws bubble up.\n return tool.handler(toolArgs, context);\n }\n}\n"]}
package/dist/stdio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * quantakrypto-mcp — stdio transport.\n *\n * MCP's stdio transport is newline-delimited JSON: exactly one JSON-RPC 2.0\n * message per line on stdin, one per line on stdout. (This is NOT HTTP-style\n * Content-Length framing.) This module reads stdin line-by-line with\n * {@link node:readline}, hands each parsed message to {@link McpServer.handle},\n * and writes any response back as a single line on stdout. Diagnostics go to\n * stderr so they never corrupt the protocol stream.\n *\n * Run as the `quantakrypto-mcp` bin, or `node dist/stdio.js`.\n */\n\nimport { createInterface } from \"node:readline\";\nimport process from \"node:process\";\nimport { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { createQuantakryptoServer } from \"./index.js\";\nimport { ErrorCode, makeFailure } from \"./protocol.js\";\nimport type { McpServer } from \"./server.js\";\n\n/** Serialize a value as one newline-terminated JSON line to stdout. */\nfunction writeLine(value: unknown): void {\n process.stdout.write(JSON.stringify(value) + \"\\n\");\n}\n\n/**\n * Attach a line-delimited JSON-RPC loop to the given streams. Exposed (rather\n * than only run on import) so it can be reused or tested with custom streams.\n */\nexport function runStdioServer(\n server: McpServer,\n input: NodeJS.ReadableStream = process.stdin,\n output: NodeJS.WritableStream = process.stdout,\n): void {\n const rl = createInterface({ input, crlfDelay: Infinity });\n\n rl.on(\"line\", (raw: string) => {\n const line = raw.trim();\n if (line.length === 0) return; // tolerate blank lines / keepalives\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n // Parse error: we have no id, so reply with a null-id error per JSON-RPC.\n output.write(JSON.stringify(makeFailure(null, ErrorCode.ParseError, \"parse error\")) + \"\\n\");\n return;\n }\n\n // Process asynchronously; responses are written as they resolve. Ordering\n // within a single client is preserved because handlers here are fast and\n // the event loop drains line events in order.\n void server\n .handle(parsed)\n .then((response) => {\n if (response !== null) output.write(JSON.stringify(response) + \"\\n\");\n })\n .catch((err: unknown) => {\n // Defensive: handle() already catches, but never let a rejection escape.\n const messageText = err instanceof Error ? err.message : String(err);\n process.stderr.write(`quantakrypto-mcp internal error: ${messageText}\\n`);\n });\n });\n\n rl.on(\"close\", () => {\n process.exitCode = 0;\n });\n}\n\n/** Entry point when executed directly (the bin / `node dist/stdio.js`). */\nfunction main(): void {\n const server = createQuantakryptoServer();\n process.stderr.write(`quantakrypto MCP server (stdio) ready\\n`);\n runStdioServer(server);\n}\n\n/**\n * True when this module is the program's entry point. Resolves symlinks so the\n * check also holds when launched via the `quantakrypto-mcp` bin shim in node_modules/.bin.\n */\nfunction isMainModule(): boolean {\n const argv1 = process.argv[1];\n if (!argv1) return false;\n const thisPath = fileURLToPath(import.meta.url);\n try {\n return realpathSync(argv1) === realpathSync(thisPath);\n } catch {\n return argv1 === thisPath;\n }\n}\n\n// Only auto-run when invoked as a script, not when imported by tests.\nif (isMainModule()) {\n main();\n}\n\nexport { writeLine };\n"]}
package/dist/tools.d.ts CHANGED
@@ -27,13 +27,13 @@ declare function describeError(label: string, err: unknown): string;
27
27
  * directly. The `signal` from the transport's request deadline (when present) is
28
28
  * threaded in so a timed-out request actually aborts the underlying scan.
29
29
  */
30
- declare function buildScanOptions(requested: string, context?: ToolContext): {
30
+ declare function buildScanOptions(requested: string, context?: ToolContext): Promise<{
31
31
  ok: true;
32
32
  options: ScanOptions;
33
33
  } | {
34
34
  ok: false;
35
35
  result: ToolResult;
36
- };
36
+ }>;
37
37
  /** Map a free-text algorithm string onto a known {@link AlgorithmFamily}. */
38
38
  declare function normalizeAlgorithm(input: string): AlgorithmFamily;
39
39
  /** Render a scan result as a compact human-readable summary. */
@@ -50,7 +50,7 @@ export declare const FS_TOOL_NAMES: readonly string[];
50
50
  /** All quantakrypto MCP tools, in a stable order. */
51
51
  export declare const quantakryptoTools: ToolDefinition[];
52
52
  /** The core version these tools are built against (re-exported for diagnostics). */
53
- export declare const CORE_VERSION = "0.4.1";
53
+ export declare const CORE_VERSION = "0.4.3";
54
54
  /** Exposed for tests and advanced callers. */
55
55
  export declare const __test: {
56
56
  normalizeAlgorithm: typeof normalizeAlgorithm;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH,OAAO,KAAK,EACV,eAAe,EAIf,WAAW,EACX,UAAU,EAGX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAkBzF;;;;;;GAMG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAS1D;AAkBD;;;;;;;;;GASG;AACH,iBAAS,gBAAgB,CACvB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,WAAW,GACpB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAexE;AAED,6EAA6E;AAC7E,iBAAS,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAmB1D;AAED,gEAAgE;AAChE,iBAAS,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAmCjD;AAwPD,+EAA+E;AAC/E,iBAAS,kBAAkB,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,EAAE,CA4BhE;AAusBD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAK1C,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAiB7C,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,8CAA8C;AAC9C,eAAO,MAAM,MAAM;;;;;;CAMlB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAyBH,OAAO,KAAK,EACV,eAAe,EAIf,WAAW,EACX,UAAU,EAGX,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAkBzF;;;;;;GAMG;AACH,iBAAS,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAS1D;AAkBD;;;;;;;;;GASG;AACH,iBAAe,gBAAgB,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CAuBjF;AAED,6EAA6E;AAC7E,iBAAS,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAmB1D;AAED,gEAAgE;AAChE,iBAAS,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAmCjD;AAuQD,+EAA+E;AAC/E,iBAAS,kBAAkB,CAAC,SAAS,EAAE,eAAe,GAAG,MAAM,EAAE,CA4BhE;AAqzBD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAK1C,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAkB7C,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,8CAA8C;AAC9C,eAAO,MAAM,MAAM;;;;;;CAMlB,CAAC;AAEF,wEAAwE;AACxE,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC"}
package/dist/tools.js CHANGED
@@ -8,10 +8,10 @@
8
8
  * crash.
9
9
  */
10
10
  import process from "node:process";
11
- import { VERSION, AbortError, BudgetExceededError, buildInventory, buildRemediateRequest, buildTriageRequest, compareFindings, detectors, fingerprintFinding, languageToExtension, remediationFor, scan, SEVERITY_ORDER, toCbom, verifyFix, vulnerableDependencies, } from "@quantakrypto/core";
11
+ import { VERSION, AbortError, BudgetExceededError, buildInventory, buildRemediateRequest, buildTriageRequest, compareFindings, detectors, fingerprintFinding, isManifestFile, languageToExtension, remediateFindings, remediationFor, remediationForTier, scan, SEVERITY_ORDER, toCbom, verifyFix, vulnerableDependencies, } from "@quantakrypto/core";
12
12
  import { errorResult, textResult } from "./protocol.js";
13
13
  import { resolveRule } from "./rules.js";
14
- import { resolveFsConfig, resolveScanPath } from "./fsconfig.js";
14
+ import { realpathInsideRoots, resolveFsConfig, resolveScanPath } from "./fsconfig.js";
15
15
  /** All classical algorithm families we can advise on, used for validation/help. */
16
16
  const ALGORITHM_FAMILIES = [
17
17
  "RSA",
@@ -66,12 +66,20 @@ async function safe(label, fn) {
66
66
  * directly. The `signal` from the transport's request deadline (when present) is
67
67
  * threaded in so a timed-out request actually aborts the underlying scan.
68
68
  */
69
- function buildScanOptions(requested, context) {
69
+ async function buildScanOptions(requested, context) {
70
70
  const config = resolveFsConfig(process.env);
71
71
  const decision = resolveScanPath(config, requested);
72
72
  if (!decision.ok) {
73
73
  return { ok: false, result: errorResult(`scan rejected: ${decision.reason}`) };
74
74
  }
75
+ // Symlink-escape hardening: re-verify containment against the real, resolved
76
+ // paths so a symlink inside a root can't read outside it (audit: mcp #1).
77
+ if (!(await realpathInsideRoots(decision.path, config))) {
78
+ return {
79
+ ok: false,
80
+ result: errorResult("scan rejected: path resolves outside the configured root(s) (symlink)."),
81
+ };
82
+ }
75
83
  return {
76
84
  ok: true,
77
85
  options: {
@@ -178,7 +186,7 @@ const scanPathTool = {
178
186
  return errorResult("scan_path requires a non-empty 'path' string.");
179
187
  }
180
188
  const format = args.format === "json" ? "json" : "summary";
181
- const opts = buildScanOptions(path, context);
189
+ const opts = await buildScanOptions(path, context);
182
190
  if (!opts.ok)
183
191
  return opts.result;
184
192
  const scanned = await safe("scan", () => scan(opts.options));
@@ -211,7 +219,7 @@ const inventoryCryptoTool = {
211
219
  if (typeof path !== "string" || path.length === 0) {
212
220
  return errorResult("inventory_crypto requires a non-empty 'path' string.");
213
221
  }
214
- const opts = buildScanOptions(path, context);
222
+ const opts = await buildScanOptions(path, context);
215
223
  if (!opts.ok)
216
224
  return opts.result;
217
225
  const scanned = await safe("scan", () => scan(opts.options));
@@ -331,7 +339,8 @@ const explainFindingTool = {
331
339
  const suggestHybridTool = {
332
340
  name: "suggest_hybrid",
333
341
  description: "Recommend a post-quantum / hybrid migration. Provide an 'algorithm' " +
334
- "(e.g. RSA, ECDH, ECDSA) or free-text 'context' describing the usage.",
342
+ "(e.g. RSA, ECDH, ECDSA) or free-text 'context' describing the usage. " +
343
+ "Set 'tier' to 'category-5' for CNSA 2.0 / national-security systems.",
335
344
  inputSchema: {
336
345
  type: "object",
337
346
  properties: {
@@ -343,6 +352,12 @@ const suggestHybridTool = {
343
352
  type: "string",
344
353
  description: "Free-text description of the cryptographic usage (used when no algorithm is given).",
345
354
  },
355
+ tier: {
356
+ type: "string",
357
+ enum: ["category-3", "category-5"],
358
+ description: "Security tier: 'category-3' (default, commercial — ML-KEM-768 / ML-DSA-65) or " +
359
+ "'category-5' (CNSA 2.0 / NSS, long-lived secrets — ML-KEM-1024 / ML-DSA-87).",
360
+ },
346
361
  },
347
362
  additionalProperties: false,
348
363
  },
@@ -353,10 +368,17 @@ const suggestHybridTool = {
353
368
  return errorResult("suggest_hybrid requires either 'algorithm' or 'context'.");
354
369
  }
355
370
  const algorithm = normalizeAlgorithm(algoInput || context);
371
+ const tier = args.tier === "category-5"
372
+ ? "category-5"
373
+ : args.tier === "category-3"
374
+ ? "category-3"
375
+ : undefined;
356
376
  const lines = [];
357
377
  lines.push(`Migration guidance for: ${algoInput || context}`);
358
378
  lines.push(`Detected family: ${algorithm}`);
359
- const rem = await safe("remediationFor", () => remediationFor(algorithm));
379
+ if (tier)
380
+ lines.push(`Security tier: ${tier}`);
381
+ const rem = await safe("remediationFor", () => tier ? remediationForTier(algorithm, tier) : remediationFor(algorithm));
360
382
  if (rem.ok && rem.value) {
361
383
  lines.push(`Recommended replacement: ${rem.value.recommendation}`);
362
384
  lines.push(`Rationale: ${rem.value.detail}`);
@@ -452,7 +474,7 @@ const generateCbomTool = {
452
474
  if (typeof path !== "string" || path.length === 0) {
453
475
  return errorResult("generate_cbom requires a non-empty 'path' string.");
454
476
  }
455
- const opts = buildScanOptions(path, context);
477
+ const opts = await buildScanOptions(path, context);
456
478
  if (!opts.ok)
457
479
  return opts.result;
458
480
  const scanned = await safe("scan", () => scan(opts.options));
@@ -533,7 +555,7 @@ const planMigrationTool = {
533
555
  if (typeof path !== "string" || path.length === 0) {
534
556
  return errorResult("plan_migration requires a non-empty 'path' string.");
535
557
  }
536
- const opts = buildScanOptions(path, context);
558
+ const opts = await buildScanOptions(path, context);
537
559
  if (!opts.ok)
538
560
  return opts.result;
539
561
  const scanned = await safe("scan", () => scan(opts.options));
@@ -869,6 +891,18 @@ const scoreDeltaTool = {
869
891
  };
870
892
  },
871
893
  };
894
+ /**
895
+ * True when every element looks like a scan Finding (a string `ruleId` and a
896
+ * `location.file`). Guards the triage/remediate tools so a malformed `findings`
897
+ * element surfaces as a tool `isError` result rather than throwing a protocol
898
+ * `-32603` internal error downstream (audit: mcp #4).
899
+ */
900
+ function areFindings(arr) {
901
+ return arr.every((f) => f !== null &&
902
+ typeof f === "object" &&
903
+ typeof f.ruleId === "string" &&
904
+ typeof f.location?.file === "string");
905
+ }
872
906
  const triageFindingsTool = {
873
907
  name: "triage_findings",
874
908
  description: "Produce a deterministic triage REQUEST bundle (rubric + verdict schema + " +
@@ -885,8 +919,8 @@ const triageFindingsTool = {
885
919
  additionalProperties: false,
886
920
  },
887
921
  async handler(args) {
888
- if (!Array.isArray(args.findings)) {
889
- return errorResult("triage_findings requires a 'findings' array.");
922
+ if (!Array.isArray(args.findings) || !areFindings(args.findings)) {
923
+ return errorResult("triage_findings requires a 'findings' array of scan findings (each with a string ruleId and location.file).");
890
924
  }
891
925
  const findings = args.findings;
892
926
  const request = buildTriageRequest(findings, "metadata");
@@ -895,7 +929,16 @@ const triageFindingsTool = {
895
929
  fingerprint: fingerprintFinding(f),
896
930
  context: request.contexts[i],
897
931
  }));
898
- const bundle = { rubric: request.rubric, schema: request.schema, items };
932
+ // The verdict schema advertised to the agent MUST include `fingerprint`
933
+ // (the instructions require it, and apply_triage keys on it) — core's
934
+ // single-verdict schema doesn't, so extend it here (audit: mcp bundle).
935
+ const props = request.schema.properties ?? {};
936
+ const schema = {
937
+ type: "object",
938
+ required: ["fingerprint", "exposureScore", "priority", "rationale"],
939
+ properties: { fingerprint: { type: "string" }, ...props },
940
+ };
941
+ const bundle = { rubric: request.rubric, schema, items };
899
942
  return {
900
943
  content: [
901
944
  {
@@ -920,7 +963,11 @@ function parseVerdict(v) {
920
963
  const rationale = o.rationale;
921
964
  if (typeof fingerprint !== "string")
922
965
  return null;
923
- if (typeof exposureScore !== "number" || exposureScore < 0 || exposureScore > 100)
966
+ // `Number.isFinite` rejects NaN/Infinity NaN passes both `< 0` and `> 100`
967
+ // (they're false) and would poison the exposure sort comparator (audit: mcp #3).
968
+ if (typeof exposureScore !== "number" || !Number.isFinite(exposureScore))
969
+ return null;
970
+ if (exposureScore < 0 || exposureScore > 100)
924
971
  return null;
925
972
  if (priority !== "now" && priority !== "soon" && priority !== "later")
926
973
  return null;
@@ -946,6 +993,9 @@ const applyTriageTool = {
946
993
  if (!Array.isArray(args.findings) || !Array.isArray(args.verdicts)) {
947
994
  return errorResult("apply_triage requires 'findings' and 'verdicts' arrays.");
948
995
  }
996
+ if (!areFindings(args.findings)) {
997
+ return errorResult("apply_triage: each 'findings' element needs a string ruleId and location.file.");
998
+ }
949
999
  const findings = args.findings;
950
1000
  const byFingerprint = new Map();
951
1001
  let skipped = 0;
@@ -1004,8 +1054,8 @@ const remediateFindingsTool = {
1004
1054
  additionalProperties: false,
1005
1055
  },
1006
1056
  async handler(args) {
1007
- if (!Array.isArray(args.findings)) {
1008
- return errorResult("remediate_findings requires a 'findings' array.");
1057
+ if (!Array.isArray(args.findings) || !areFindings(args.findings)) {
1058
+ return errorResult("remediate_findings requires a 'findings' array of scan findings (each with a string ruleId and location.file).");
1009
1059
  }
1010
1060
  const findings = args.findings;
1011
1061
  const request = buildRemediateRequest(findings, "metadata");
@@ -1027,6 +1077,66 @@ const remediateFindingsTool = {
1027
1077
  };
1028
1078
  },
1029
1079
  };
1080
+ const applyVerifiedPatchTool = {
1081
+ name: "apply_verified_patch",
1082
+ description: "Deterministically VERIFY a proposed fix before writing it — runs the same " +
1083
+ "patch-policy + verify_fix + blast-radius gates as `qremediate` (offline, no " +
1084
+ "key, no network). Give the finding, the file's current content, and your " +
1085
+ "proposed FULL corrected content; returns approved:true only if the patch is " +
1086
+ "in-policy, clears the finding, adds no new finding, introduces no network/exec " +
1087
+ "sink, and is bounded in size. This does NOT write the file — you write it, " +
1088
+ "only when approved, and never auto-merge.",
1089
+ inputSchema: {
1090
+ type: "object",
1091
+ properties: {
1092
+ finding: {
1093
+ type: "object",
1094
+ description: "The scan finding being fixed (needs a string ruleId and location.file).",
1095
+ },
1096
+ originalContent: { type: "string", description: "The file's current full content." },
1097
+ newContent: { type: "string", description: "Your proposed full corrected file content." },
1098
+ },
1099
+ required: ["finding", "originalContent", "newContent"],
1100
+ additionalProperties: false,
1101
+ },
1102
+ async handler(args) {
1103
+ const finding = args.finding;
1104
+ if (!finding || typeof finding !== "object" || !areFindings([finding])) {
1105
+ return errorResult("apply_verified_patch requires a 'finding' with a string ruleId and location.file.");
1106
+ }
1107
+ if (typeof args.originalContent !== "string" || typeof args.newContent !== "string") {
1108
+ return errorResult("apply_verified_patch requires string 'originalContent' and 'newContent'.");
1109
+ }
1110
+ const file = finding.location.file;
1111
+ const originalContent = args.originalContent;
1112
+ const patch = {
1113
+ path: file,
1114
+ newContent: args.newContent,
1115
+ ruleId: finding.ruleId,
1116
+ source: "llm",
1117
+ };
1118
+ const res = await safe("apply_verified_patch", () => remediateFindings([finding], {
1119
+ readContent: () => originalContent,
1120
+ patchSource: () => patch,
1121
+ policy: {
1122
+ findingFiles: new Set([file]),
1123
+ manifestFiles: new Set(isManifestFile(file) ? [file] : []),
1124
+ },
1125
+ }));
1126
+ if (!res.ok)
1127
+ return res.result;
1128
+ const approved = res.value.applied.length > 0;
1129
+ return textResult(JSON.stringify({
1130
+ approved,
1131
+ path: file,
1132
+ ruleId: finding.ruleId,
1133
+ ...(approved ? {} : { reason: res.value.rejected[0]?.reason ?? "rejected" }),
1134
+ note: approved
1135
+ ? "Cleared every deterministic gate — safe to write. Open a diff/PR for review; never auto-merge."
1136
+ : "Rejected by the deterministic gates — do NOT write this patch.",
1137
+ }, null, 2));
1138
+ },
1139
+ };
1030
1140
  /**
1031
1141
  * Tools that read arbitrary filesystem paths. Disabled by default on the HTTP
1032
1142
  * transport (see {@link ./http.ts}) because a hosted endpoint must not be an
@@ -1057,6 +1167,7 @@ export const quantakryptoTools = [
1057
1167
  triageFindingsTool,
1058
1168
  applyTriageTool,
1059
1169
  remediateFindingsTool,
1170
+ applyVerifiedPatchTool,
1060
1171
  ];
1061
1172
  /** The core version these tools are built against (re-exported for diagnostics). */
1062
1173
  export const CORE_VERSION = VERSION;