@quantakrypto/mcp 0.4.3 → 0.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 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAG,KAAc,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAqB,CAAC;AA8C1D,gEAAgE;AAChE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU,EAAE,CAAC,KAAK;IAClB,cAAc,EAAE,CAAC,KAAK;IACtB,cAAc,EAAE,CAAC,KAAK;IACtB,aAAa,EAAE,CAAC,KAAK;IACrB,aAAa,EAAE,CAAC,KAAK;IACrB,qEAAqE;IACrE,gBAAgB,EAAE,CAAC,KAAK;CAChB,CAAC;AAEX,qFAAqF;AACrF,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,IAAI,CAAW;IACxB,YAAY,IAAY,EAAE,OAAe,EAAE,IAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,4CAA4C;AAC5C,MAAM,UAAU,WAAW,CAAC,EAAa,EAAE,MAAe;IACxD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AAClD,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,WAAW,CACzB,EAAa,EACb,IAAY,EACZ,OAAe,EACf,IAAc;IAEd,MAAM,KAAK,GAAuB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACpD,IAAI,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AACjD,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,OAAO,CAAC,CAAC,OAAO,KAAK,eAAe,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;AACvE,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,GAAmB;IAChD,OAAO,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC;AAChD,CAAC;AA4DD,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CAAC,GAAG,KAAe;IAC3C,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC","sourcesContent":["/**\n * JSON-RPC 2.0 + Model Context Protocol (MCP) wire types.\n *\n * This module is pure type/shape definitions plus a few small helpers for\n * constructing valid JSON-RPC responses and errors. It has no runtime\n * dependencies and no I/O — the transport layers (stdio, http) and the\n * {@link McpServer} build on top of it.\n *\n * Reference: JSON-RPC 2.0 (https://www.jsonrpc.org/specification) and the\n * Model Context Protocol specification (https://modelcontextprotocol.io).\n */\n\n/** The fixed JSON-RPC protocol marker. */\nexport const JSONRPC_VERSION = \"2.0\" as const;\n\n/**\n * MCP protocol revision this server speaks. The `initialize` handshake echoes\n * the client's requested version when we support it, otherwise advertises this.\n */\nexport const MCP_PROTOCOL_VERSION = \"2025-06-18\" as const;\n\n/** A JSON-RPC id: string or number per spec (we never originate notifications). */\nexport type JsonRpcId = string | number | null;\n\n/** Any JSON value. Kept structural rather than `any` for strict mode. */\nexport type JsonValue =\n | null\n | boolean\n | number\n | string\n | JsonValue[]\n | { [key: string]: JsonValue };\n\n/** A JSON-RPC 2.0 request or notification (notifications omit `id`). */\nexport interface JsonRpcRequest {\n jsonrpc: typeof JSONRPC_VERSION;\n /** Absent for notifications. */\n id?: JsonRpcId;\n method: string;\n params?: Record<string, unknown> | unknown[];\n}\n\n/** A successful JSON-RPC response. */\nexport interface JsonRpcSuccess {\n jsonrpc: typeof JSONRPC_VERSION;\n id: JsonRpcId;\n result: unknown;\n}\n\n/** A JSON-RPC error object. */\nexport interface JsonRpcErrorObject {\n code: number;\n message: string;\n data?: unknown;\n}\n\n/** A failed JSON-RPC response. */\nexport interface JsonRpcFailure {\n jsonrpc: typeof JSONRPC_VERSION;\n id: JsonRpcId;\n error: JsonRpcErrorObject;\n}\n\nexport type JsonRpcResponse = JsonRpcSuccess | JsonRpcFailure;\n\n/** Standard JSON-RPC 2.0 error codes (plus MCP conventions). */\nexport const ErrorCode = {\n ParseError: -32700,\n InvalidRequest: -32600,\n MethodNotFound: -32601,\n InvalidParams: -32602,\n InternalError: -32603,\n /** MCP: resource not found (`resources/read` for an unknown URI). */\n ResourceNotFound: -32002,\n} as const;\n\n/** An error that carries a JSON-RPC error code, thrown by tool handlers/dispatch. */\nexport class RpcError extends Error {\n readonly code: number;\n readonly data?: unknown;\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = \"RpcError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/** Build a successful response envelope. */\nexport function makeSuccess(id: JsonRpcId, result: unknown): JsonRpcSuccess {\n return { jsonrpc: JSONRPC_VERSION, id, result };\n}\n\n/** Build a failure response envelope. */\nexport function makeFailure(\n id: JsonRpcId,\n code: number,\n message: string,\n data?: unknown,\n): JsonRpcFailure {\n const error: JsonRpcErrorObject = { code, message };\n if (data !== undefined) error.data = data;\n return { jsonrpc: JSONRPC_VERSION, id, error };\n}\n\n/** Narrow an unknown parsed value to something request-shaped enough to dispatch. */\nexport function isJsonRpcRequestLike(value: unknown): value is JsonRpcRequest {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return v.jsonrpc === JSONRPC_VERSION && typeof v.method === \"string\";\n}\n\n/** True when a request is a notification (no `id` field present). */\nexport function isNotification(req: JsonRpcRequest): boolean {\n return !(\"id\" in req) || req.id === undefined;\n}\n\n// ---------------------------------------------------------------------------\n// MCP content + tool shapes\n// ---------------------------------------------------------------------------\n\n/** A single piece of MCP content. We only emit text content in this server. */\nexport interface TextContent {\n type: \"text\";\n text: string;\n}\n\nexport type Content = TextContent;\n\n/** The result envelope returned by a `tools/call`. */\nexport interface ToolResult {\n content: Content[];\n /** True when the tool ran but produced an error result (vs. a protocol error). */\n isError?: boolean;\n}\n\n/** A minimal JSON Schema object describing a tool's input. */\nexport interface JsonSchema {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n}\n\n/** The public descriptor of a tool, as returned by `tools/list`. */\nexport interface ToolDescriptor {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n}\n\n/**\n * Per-call context threaded from the transport into a tool handler. Carries the\n * cooperative-cancellation signal so a long-running tool (e.g. a filesystem\n * scan) can be aborted when the transport's request deadline fires, instead of\n * leaking unbounded background work after a 504/timeout.\n */\nexport interface ToolContext {\n /** Fires when the caller's request deadline elapses; abort in-flight work. */\n signal?: AbortSignal;\n}\n\n/** A registered tool: descriptor plus its async handler. */\nexport interface ToolDefinition extends ToolDescriptor {\n /**\n * Executes the tool with already-parsed arguments and an optional per-call\n * {@link ToolContext} (e.g. an `AbortSignal` for the request deadline).\n */\n handler: (\n args: Record<string, unknown>,\n context?: ToolContext,\n ) => Promise<ToolResult> | ToolResult;\n}\n\n/** Convenience: wrap one or more strings as a non-error text tool result. */\nexport function textResult(...parts: string[]): ToolResult {\n return { content: parts.map((text) => ({ type: \"text\", text })) };\n}\n\n/** Convenience: wrap a string as an error text tool result. */\nexport function errorResult(text: string): ToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n"]}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,eAAe,GAAG,KAAc,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAqB,CAAC;AAqC1D,gEAAgE;AAChE,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,UAAU,EAAE,CAAC,KAAK;IAClB,cAAc,EAAE,CAAC,KAAK;IACtB,cAAc,EAAE,CAAC,KAAK;IACtB,aAAa,EAAE,CAAC,KAAK;IACrB,aAAa,EAAE,CAAC,KAAK;IACrB,qEAAqE;IACrE,gBAAgB,EAAE,CAAC,KAAK;CAChB,CAAC;AAEX,qFAAqF;AACrF,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,IAAI,CAAW;IACxB,YAAY,IAAY,EAAE,OAAe,EAAE,IAAc;QACvD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,4CAA4C;AAC5C,MAAM,UAAU,WAAW,CAAC,EAAa,EAAE,MAAe;IACxD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AAClD,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,WAAW,CACzB,EAAa,EACb,IAAY,EACZ,OAAe,EACf,IAAc;IAEd,MAAM,KAAK,GAAuB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACpD,IAAI,IAAI,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AACjD,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,GAAG,KAAgC,CAAC;IAC3C,OAAO,CAAC,CAAC,OAAO,KAAK,eAAe,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC;AACvE,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,GAAmB;IAChD,OAAO,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC;AAChD,CAAC;AA4DD,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CAAC,GAAG,KAAe;IAC3C,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC","sourcesContent":["/**\n * JSON-RPC 2.0 + Model Context Protocol (MCP) wire types.\n *\n * This module is pure type/shape definitions plus a few small helpers for\n * constructing valid JSON-RPC responses and errors. It has no runtime\n * dependencies and no I/O — the transport layers (stdio, http) and the\n * {@link McpServer} build on top of it.\n *\n * Reference: JSON-RPC 2.0 (https://www.jsonrpc.org/specification) and the\n * Model Context Protocol specification (https://modelcontextprotocol.io).\n */\n\n/** The fixed JSON-RPC protocol marker. */\nexport const JSONRPC_VERSION = \"2.0\" as const;\n\n/**\n * MCP protocol revision this server speaks. The `initialize` handshake echoes\n * the client's requested version when we support it, otherwise advertises this.\n */\nexport const MCP_PROTOCOL_VERSION = \"2025-06-18\" as const;\n\n/** A JSON-RPC id: string or number per spec (we never originate notifications). */\ntype JsonRpcId = string | number | null;\n\n/** A JSON-RPC 2.0 request or notification (notifications omit `id`). */\nexport interface JsonRpcRequest {\n jsonrpc: typeof JSONRPC_VERSION;\n /** Absent for notifications. */\n id?: JsonRpcId;\n method: string;\n params?: Record<string, unknown> | unknown[];\n}\n\n/** A successful JSON-RPC response. */\nexport interface JsonRpcSuccess {\n jsonrpc: typeof JSONRPC_VERSION;\n id: JsonRpcId;\n result: unknown;\n}\n\n/** A JSON-RPC error object. */\ninterface JsonRpcErrorObject {\n code: number;\n message: string;\n data?: unknown;\n}\n\n/** A failed JSON-RPC response. */\nexport interface JsonRpcFailure {\n jsonrpc: typeof JSONRPC_VERSION;\n id: JsonRpcId;\n error: JsonRpcErrorObject;\n}\n\nexport type JsonRpcResponse = JsonRpcSuccess | JsonRpcFailure;\n\n/** Standard JSON-RPC 2.0 error codes (plus MCP conventions). */\nexport const ErrorCode = {\n ParseError: -32700,\n InvalidRequest: -32600,\n MethodNotFound: -32601,\n InvalidParams: -32602,\n InternalError: -32603,\n /** MCP: resource not found (`resources/read` for an unknown URI). */\n ResourceNotFound: -32002,\n} as const;\n\n/** An error that carries a JSON-RPC error code, thrown by tool handlers/dispatch. */\nexport class RpcError extends Error {\n readonly code: number;\n readonly data?: unknown;\n constructor(code: number, message: string, data?: unknown) {\n super(message);\n this.name = \"RpcError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/** Build a successful response envelope. */\nexport function makeSuccess(id: JsonRpcId, result: unknown): JsonRpcSuccess {\n return { jsonrpc: JSONRPC_VERSION, id, result };\n}\n\n/** Build a failure response envelope. */\nexport function makeFailure(\n id: JsonRpcId,\n code: number,\n message: string,\n data?: unknown,\n): JsonRpcFailure {\n const error: JsonRpcErrorObject = { code, message };\n if (data !== undefined) error.data = data;\n return { jsonrpc: JSONRPC_VERSION, id, error };\n}\n\n/** Narrow an unknown parsed value to something request-shaped enough to dispatch. */\nexport function isJsonRpcRequestLike(value: unknown): value is JsonRpcRequest {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as Record<string, unknown>;\n return v.jsonrpc === JSONRPC_VERSION && typeof v.method === \"string\";\n}\n\n/** True when a request is a notification (no `id` field present). */\nexport function isNotification(req: JsonRpcRequest): boolean {\n return !(\"id\" in req) || req.id === undefined;\n}\n\n// ---------------------------------------------------------------------------\n// MCP content + tool shapes\n// ---------------------------------------------------------------------------\n\n/** A single piece of MCP content. We only emit text content in this server. */\nexport interface TextContent {\n type: \"text\";\n text: string;\n}\n\nexport type Content = TextContent;\n\n/** The result envelope returned by a `tools/call`. */\nexport interface ToolResult {\n content: Content[];\n /** True when the tool ran but produced an error result (vs. a protocol error). */\n isError?: boolean;\n}\n\n/** A minimal JSON Schema object describing a tool's input. */\nexport interface JsonSchema {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n [key: string]: unknown;\n}\n\n/** The public descriptor of a tool, as returned by `tools/list`. */\nexport interface ToolDescriptor {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n}\n\n/**\n * Per-call context threaded from the transport into a tool handler. Carries the\n * cooperative-cancellation signal so a long-running tool (e.g. a filesystem\n * scan) can be aborted when the transport's request deadline fires, instead of\n * leaking unbounded background work after a 504/timeout.\n */\nexport interface ToolContext {\n /** Fires when the caller's request deadline elapses; abort in-flight work. */\n signal?: AbortSignal;\n}\n\n/** A registered tool: descriptor plus its async handler. */\nexport interface ToolDefinition extends ToolDescriptor {\n /**\n * Executes the tool with already-parsed arguments and an optional per-call\n * {@link ToolContext} (e.g. an `AbortSignal` for the request deadline).\n */\n handler: (\n args: Record<string, unknown>,\n context?: ToolContext,\n ) => Promise<ToolResult> | ToolResult;\n}\n\n/** Convenience: wrap one or more strings as a non-error text tool result. */\nexport function textResult(...parts: string[]): ToolResult {\n return { content: parts.map((text) => ({ type: \"text\", text })) };\n}\n\n/** Convenience: wrap a string as an error text tool result. */\nexport function errorResult(text: string): ToolResult {\n return { content: [{ type: \"text\", text }], isError: true };\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /** A resource descriptor for `resources/list`. */
2
- export interface ResourceDescriptor {
2
+ interface ResourceDescriptor {
3
3
  uri: string;
4
4
  name: string;
5
5
  description: string;
@@ -13,7 +13,7 @@ export declare function readResource(uri: string): {
13
13
  text: string;
14
14
  } | null;
15
15
  /** A prompt descriptor for `prompts/list`. */
16
- export interface PromptDescriptor {
16
+ interface PromptDescriptor {
17
17
  name: string;
18
18
  description: string;
19
19
  arguments?: {
@@ -24,7 +24,7 @@ export interface PromptDescriptor {
24
24
  }
25
25
  export declare const PROMPTS: PromptDescriptor[];
26
26
  /** A prompt message (MCP `prompts/get` shape). */
27
- export interface PromptMessage {
27
+ interface PromptMessage {
28
28
  role: "user";
29
29
  content: {
30
30
  type: "text";
@@ -36,4 +36,5 @@ export declare function getPrompt(name: string, args: Record<string, unknown>):
36
36
  description: string;
37
37
  messages: PromptMessage[];
38
38
  } | null;
39
+ export {};
39
40
  //# sourceMappingURL=resources.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAQA,kDAAkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,SAAS,EAAE,kBAAkB,EAczC,CAAC;AAmBF,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAYhG;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACzE;AAED,eAAO,MAAM,OAAO,EAAE,gBAAgB,EAOrC,CAAC;AAEF,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,GAAG,IAAI,CAc3D"}
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAQA,kDAAkD;AAClD,UAAU,kBAAkB;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,SAAS,EAAE,kBAAkB,EAczC,CAAC;AAmBF,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAYhG;AAED,8CAA8C;AAC9C,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACzE;AAED,eAAO,MAAM,OAAO,EAAE,gBAAgB,EAOrC,CAAC;AAEF,kDAAkD;AAClD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AAED,0DAA0D;AAC1D,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,GAAG,IAAI,CAc3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAUvE,MAAM,CAAC,MAAM,SAAS,GAAyB;IAC7C;QACE,GAAG,EAAE,sBAAsB;QAC3B,IAAI,EAAE,2BAA2B;QACjC,WAAW,EACT,gGAAgG;QAClG,QAAQ,EAAE,kBAAkB;KAC7B;IACD;QACE,GAAG,EAAE,gCAAgC;QACrC,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EAAE,kFAAkF;QAC/F,QAAQ,EAAE,eAAe;KAC1B;CACF,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;EActB,gBAAgB;CACjB,CAAC;AAEF,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,GAAG,KAAK,sBAAsB,EAAE,CAAC;QACnC,OAAO;YACL,GAAG;YACH,QAAQ,EAAE,kBAAkB;YAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;SAC7D,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,gCAAgC,EAAE,CAAC;QAC7C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IACnE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AASD,MAAM,CAAC,MAAM,OAAO,GAAuB;IACzC;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EACT,mFAAmF;QACrF,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,2BAA2B,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;KACzF;CACF,CAAC;AAQF,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,IAA6B;IAE7B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1E,MAAM,IAAI,GACR,WAAW,IAAI,sEAAsE;QACrF,yBAAyB,IAAI,MAAM;QACnC,sFAAsF;QACtF,uFAAuF;QACvF,0EAA0E;QAC1E,sFAAsF,CAAC;IACzF,OAAO;QACL,WAAW,EAAE,0CAA0C;QACvD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;KAC9D,CAAC;AACJ,CAAC","sourcesContent":["/**\n * MCP resources + prompts. Resources expose read-only reference data (the full\n * rule catalog + a migration guide); the prompt gives a client a one-call\n * \"migrate this path\" workflow that drives the deterministic tools. All offline\n * and static — no filesystem, no network, no key.\n */\nimport { defaultRegistry, REMEDIATE_RUBRIC } from \"@quantakrypto/core\";\n\n/** A resource descriptor for `resources/list`. */\nexport interface ResourceDescriptor {\n uri: string;\n name: string;\n description: string;\n mimeType: string;\n}\n\nexport const RESOURCES: ResourceDescriptor[] = [\n {\n uri: \"quantakrypto://rules\",\n name: \"Quantakrypto rule catalog\",\n description:\n \"Every detection rule quantakrypto can emit (id, title, severity, category, HNDL, remediation).\",\n mimeType: \"application/json\",\n },\n {\n uri: \"quantakrypto://guide/migration\",\n name: \"PQC migration guide\",\n description: \"How to migrate quantum-vulnerable cryptography using the quantakrypto MCP tools.\",\n mimeType: \"text/markdown\",\n },\n];\n\nconst MIGRATION_GUIDE = `# Post-Quantum Migration with quantakrypto\n\nA safe, deterministic loop (\"the model proposes, the engine disposes\"):\n\n1. **Inventory** — call \\`scan_path\\` on the target to list quantum-vulnerable findings.\n2. **Triage** — call \\`triage_findings\\` for the bundle, decide an exposure verdict per\n finding, then \\`apply_triage\\` to rank them (harvest-now-decrypt-later first).\n3. **Remediate** — call \\`remediate_findings\\`; for each finding propose the corrected\n full file, then \\`verify_fix\\` on your result. Keep ONLY fixes that clear the finding\n and introduce no new one. Skip any file containing secrets.\n4. Open a **draft** PR for review. Never auto-merge.\n\n## Remediation rubric\n\n${REMEDIATE_RUBRIC}\n`;\n\n/** Read a resource body by URI, or null when the URI is unknown. */\nexport function readResource(uri: string): { uri: string; mimeType: string; text: string } | null {\n if (uri === \"quantakrypto://rules\") {\n return {\n uri,\n mimeType: \"application/json\",\n text: JSON.stringify(defaultRegistry.ruleCatalog(), null, 2),\n };\n }\n if (uri === \"quantakrypto://guide/migration\") {\n return { uri, mimeType: \"text/markdown\", text: MIGRATION_GUIDE };\n }\n return null;\n}\n\n/** A prompt descriptor for `prompts/list`. */\nexport interface PromptDescriptor {\n name: string;\n description: string;\n arguments?: { name: string; description: string; required?: boolean }[];\n}\n\nexport const PROMPTS: PromptDescriptor[] = [\n {\n name: \"migrate\",\n description:\n \"Plan and apply a post-quantum migration for a path using the deterministic tools.\",\n arguments: [{ name: \"path\", description: \"Path to scan (default: .)\", required: false }],\n },\n];\n\n/** A prompt message (MCP `prompts/get` shape). */\nexport interface PromptMessage {\n role: \"user\";\n content: { type: \"text\"; text: string };\n}\n\n/** Materialize a prompt by name, or null when unknown. */\nexport function getPrompt(\n name: string,\n args: Record<string, unknown>,\n): { description: string; messages: PromptMessage[] } | null {\n if (name !== \"migrate\") return null;\n const path = typeof args.path === \"string\" && args.path ? args.path : \".\";\n const text =\n `Migrate ${path} off quantum-vulnerable cryptography using the quantakrypto tools.\\n` +\n `1) Call scan_path on \"${path}\".\\n` +\n `2) Call triage_findings, decide exposure verdicts, then apply_triage to rank them.\\n` +\n `3) For each finding: call remediate_findings, propose the corrected full file, then\\n` +\n ` verify_fix on your result — keep only fixes that clear the finding.\\n` +\n `Never touch files containing secrets; never auto-merge — open a draft PR for review.`;\n return {\n description: \"Plan and apply a post-quantum migration.\",\n messages: [{ role: \"user\", content: { type: \"text\", text } }],\n };\n}\n"]}
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAUvE,MAAM,CAAC,MAAM,SAAS,GAAyB;IAC7C;QACE,GAAG,EAAE,sBAAsB;QAC3B,IAAI,EAAE,2BAA2B;QACjC,WAAW,EACT,gGAAgG;QAClG,QAAQ,EAAE,kBAAkB;KAC7B;IACD;QACE,GAAG,EAAE,gCAAgC;QACrC,IAAI,EAAE,qBAAqB;QAC3B,WAAW,EAAE,kFAAkF;QAC/F,QAAQ,EAAE,eAAe;KAC1B;CACF,CAAC;AAEF,MAAM,eAAe,GAAG;;;;;;;;;;;;;;EActB,gBAAgB;CACjB,CAAC;AAEF,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,IAAI,GAAG,KAAK,sBAAsB,EAAE,CAAC;QACnC,OAAO;YACL,GAAG;YACH,QAAQ,EAAE,kBAAkB;YAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;SAC7D,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,gCAAgC,EAAE,CAAC;QAC7C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC;IACnE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AASD,MAAM,CAAC,MAAM,OAAO,GAAuB;IACzC;QACE,IAAI,EAAE,SAAS;QACf,WAAW,EACT,mFAAmF;QACrF,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,2BAA2B,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;KACzF;CACF,CAAC;AAQF,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,IAA6B;IAE7B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1E,MAAM,IAAI,GACR,WAAW,IAAI,sEAAsE;QACrF,yBAAyB,IAAI,MAAM;QACnC,sFAAsF;QACtF,uFAAuF;QACvF,0EAA0E;QAC1E,sFAAsF,CAAC;IACzF,OAAO;QACL,WAAW,EAAE,0CAA0C;QACvD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;KAC9D,CAAC;AACJ,CAAC","sourcesContent":["/**\n * MCP resources + prompts. Resources expose read-only reference data (the full\n * rule catalog + a migration guide); the prompt gives a client a one-call\n * \"migrate this path\" workflow that drives the deterministic tools. All offline\n * and static — no filesystem, no network, no key.\n */\nimport { defaultRegistry, REMEDIATE_RUBRIC } from \"@quantakrypto/core\";\n\n/** A resource descriptor for `resources/list`. */\ninterface ResourceDescriptor {\n uri: string;\n name: string;\n description: string;\n mimeType: string;\n}\n\nexport const RESOURCES: ResourceDescriptor[] = [\n {\n uri: \"quantakrypto://rules\",\n name: \"Quantakrypto rule catalog\",\n description:\n \"Every detection rule quantakrypto can emit (id, title, severity, category, HNDL, remediation).\",\n mimeType: \"application/json\",\n },\n {\n uri: \"quantakrypto://guide/migration\",\n name: \"PQC migration guide\",\n description: \"How to migrate quantum-vulnerable cryptography using the quantakrypto MCP tools.\",\n mimeType: \"text/markdown\",\n },\n];\n\nconst MIGRATION_GUIDE = `# Post-Quantum Migration with quantakrypto\n\nA safe, deterministic loop (\"the model proposes, the engine disposes\"):\n\n1. **Inventory** — call \\`scan_path\\` on the target to list quantum-vulnerable findings.\n2. **Triage** — call \\`triage_findings\\` for the bundle, decide an exposure verdict per\n finding, then \\`apply_triage\\` to rank them (harvest-now-decrypt-later first).\n3. **Remediate** — call \\`remediate_findings\\`; for each finding propose the corrected\n full file, then \\`verify_fix\\` on your result. Keep ONLY fixes that clear the finding\n and introduce no new one. Skip any file containing secrets.\n4. Open a **draft** PR for review. Never auto-merge.\n\n## Remediation rubric\n\n${REMEDIATE_RUBRIC}\n`;\n\n/** Read a resource body by URI, or null when the URI is unknown. */\nexport function readResource(uri: string): { uri: string; mimeType: string; text: string } | null {\n if (uri === \"quantakrypto://rules\") {\n return {\n uri,\n mimeType: \"application/json\",\n text: JSON.stringify(defaultRegistry.ruleCatalog(), null, 2),\n };\n }\n if (uri === \"quantakrypto://guide/migration\") {\n return { uri, mimeType: \"text/markdown\", text: MIGRATION_GUIDE };\n }\n return null;\n}\n\n/** A prompt descriptor for `prompts/list`. */\ninterface PromptDescriptor {\n name: string;\n description: string;\n arguments?: { name: string; description: string; required?: boolean }[];\n}\n\nexport const PROMPTS: PromptDescriptor[] = [\n {\n name: \"migrate\",\n description:\n \"Plan and apply a post-quantum migration for a path using the deterministic tools.\",\n arguments: [{ name: \"path\", description: \"Path to scan (default: .)\", required: false }],\n },\n];\n\n/** A prompt message (MCP `prompts/get` shape). */\ninterface PromptMessage {\n role: \"user\";\n content: { type: \"text\"; text: string };\n}\n\n/** Materialize a prompt by name, or null when unknown. */\nexport function getPrompt(\n name: string,\n args: Record<string, unknown>,\n): { description: string; messages: PromptMessage[] } | null {\n if (name !== \"migrate\") return null;\n const path = typeof args.path === \"string\" && args.path ? args.path : \".\";\n const text =\n `Migrate ${path} off quantum-vulnerable cryptography using the quantakrypto tools.\\n` +\n `1) Call scan_path on \"${path}\".\\n` +\n `2) Call triage_findings, decide exposure verdicts, then apply_triage to rank them.\\n` +\n `3) For each finding: call remediate_findings, propose the corrected full file, then\\n` +\n ` verify_fix on your result — keep only fixes that clear the finding.\\n` +\n `Never touch files containing secrets; never auto-merge — open a draft PR for review.`;\n return {\n description: \"Plan and apply a post-quantum migration.\",\n messages: [{ role: \"user\", content: { type: \"text\", text } }],\n };\n}\n"]}
package/dist/rules.d.ts CHANGED
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import type { AlgorithmFamily, RuleMeta } from "@quantakrypto/core";
22
22
  /** A resolved rule: the detector it belongs to (if any) and its algorithm. */
23
- export interface ResolvedRule {
23
+ interface ResolvedRule {
24
24
  /** The rule id that was looked up (echoed for convenience). */
25
25
  ruleId: string;
26
26
  /** The detector that emits this rule, when one could be resolved. */
@@ -50,4 +50,5 @@ export interface ResolvedRule {
50
50
  export declare function resolveRule(ruleId: string): ResolvedRule;
51
51
  /** Exposed for tests: the set of canonical rule ids resolvable via the catalog. */
52
52
  export declare const KNOWN_RULE_IDS: readonly string[];
53
+ export {};
53
54
  //# sourceMappingURL=rules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAY,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9E,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,oEAAoE;IACpE,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,uEAAuE;IACvE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,iEAAiE;IACjE,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,QAAQ,GAAG,YAAY,CAAC;CACxD;AAyBD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAyDxD;AAED,mFAAmF;AACnF,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EASxC,CAAC"}
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAY,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9E,8EAA8E;AAC9E,UAAU,YAAY;IACpB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,oEAAoE;IACpE,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,uEAAuE;IACvE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,iEAAiE;IACjE,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,QAAQ,GAAG,YAAY,CAAC;CACxD;AAyBD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAyDxD;AAED,mFAAmF;AACnF,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EASxC,CAAC"}
package/dist/rules.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Rule resolution for {@link explain_finding}.\n *\n * Core's detectors are coarse-grained: a single {@link Detector} (e.g. the\n * `crypto-libs` detector) emits many distinct `ruleId`s (`forge-rsa-keygen`,\n * `elliptic-ec`, `node-rsa`, …) that do NOT share the detector's `id` as a\n * prefix. The old MCP `explain_finding` matched `ruleId` against `detector.id`\n * by prefix and therefore returned \"no matching detector\" for every real\n * library finding (P0-5).\n *\n * This module resolves a finding's `ruleId` against core's rule catalog\n * ({@link defaultRegistry.ruleCatalog}) — the single source of truth declared by\n * the detectors themselves. There is no hand-curated table to keep in sync: the\n * ruleId → { detector, algorithm } mapping is derived from the catalog at load\n * time, so a new rule added in core is resolvable here the moment it ships. The\n * one non-detector rule (`dep-vulnerable`, produced by the manifest scanner\n * rather than a {@link Detector}) is supplemented explicitly. Unknown rules fall\n * back to a prefix match against the detector id space, then to unresolved.\n * Pure and synchronous — no I/O — so it is directly unit-testable.\n */\n\nimport { defaultRegistry, detectors } from \"@quantakrypto/core\";\nimport type { AlgorithmFamily, Detector, RuleMeta } from \"@quantakrypto/core\";\n\n/** A resolved rule: the detector it belongs to (if any) and its algorithm. */\nexport interface ResolvedRule {\n /** The rule id that was looked up (echoed for convenience). */\n ruleId: string;\n /** The detector that emits this rule, when one could be resolved. */\n detector?: { id: string; description: string };\n /** The classical algorithm family the rule concerns, when known. */\n algorithm?: AlgorithmFamily;\n /** The catalog metadata for the rule, when it is a known core rule. */\n meta?: RuleMeta;\n /** How the match was made — useful for tests and diagnostics. */\n via: \"index\" | \"detector-id\" | \"prefix\" | \"unresolved\";\n}\n\n/**\n * Rules that are NOT emitted by a {@link Detector} and so are absent from the\n * catalog, but are still canonical core ruleIds. Today that is only the\n * dependency-manifest scanner's `dep-vulnerable` rule.\n */\nconst EXTRA_RULES: Record<string, { algorithm: AlgorithmFamily }> = {\n \"dep-vulnerable\": { algorithm: \"unknown\" },\n};\n\n/** Build an id → Detector lookup over the active detector set (registry first). */\nfunction detectorMap(): Map<string, Detector> {\n const map = new Map<string, Detector>();\n const all = (() => {\n try {\n return defaultRegistry.all();\n } catch {\n return detectors;\n }\n })();\n for (const d of all) map.set(d.id, d);\n return map;\n}\n\n/**\n * Resolve a finding's `ruleId` to its detector and algorithm.\n *\n * Resolution order:\n * 1. The core rule catalog — the authoritative path for every detector rule.\n * 2. The {@link EXTRA_RULES} supplement (non-detector rules, e.g. dependencies).\n * 3. Exact detector id (a rule that IS a detector id, e.g. a future 1:1 rule).\n * 4. Prefix against the detector id space (`node-crypto-*`, `pem-*`, …).\n * 5. Unresolved — caller falls back to the algorithm remediation.\n *\n * Pure: depends only on its argument and the static core detector set.\n */\nexport function resolveRule(ruleId: string): ResolvedRule {\n const id = ruleId.trim();\n\n // 1. Catalog — the authoritative path for known core detector rules.\n const entry = (() => {\n try {\n return defaultRegistry.forRule(id);\n } catch {\n return undefined;\n }\n })();\n if (entry) {\n return {\n ruleId: id,\n detector: { id: entry.detector.id, description: entry.detector.description },\n algorithm: entry.rule.algorithm ?? \"unknown\",\n meta: entry.rule,\n via: \"index\",\n };\n }\n\n // 2. Non-detector supplement (dependency scanner, …). `hasOwn` guards against\n // a rule id like `__proto__`/`constructor` resolving to an Object.prototype member.\n const extra = Object.hasOwn(EXTRA_RULES, id) ? EXTRA_RULES[id] : undefined;\n if (extra) {\n return { ruleId: id, algorithm: extra.algorithm, via: \"index\" };\n }\n\n const detectorsById = detectorMap();\n\n // 3. Exact detector id.\n const exact = detectorsById.get(id);\n if (exact) {\n return {\n ruleId: id,\n detector: { id: exact.id, description: exact.description },\n via: \"detector-id\",\n };\n }\n\n // 4. Longest-prefix detector id (e.g. `node-crypto-foo` → `node-crypto`).\n let best: Detector | undefined;\n for (const det of detectorsById.values()) {\n if (id === det.id || id.startsWith(`${det.id}-`)) {\n if (!best || det.id.length > best.id.length) best = det;\n }\n }\n if (best) {\n return {\n ruleId: id,\n detector: { id: best.id, description: best.description },\n via: \"prefix\",\n };\n }\n\n // 5. Unresolved.\n return { ruleId: id, via: \"unresolved\" };\n}\n\n/** Exposed for tests: the set of canonical rule ids resolvable via the catalog. */\nexport const KNOWN_RULE_IDS: readonly string[] = (() => {\n const ids: string[] = [];\n try {\n for (const r of defaultRegistry.ruleCatalog()) ids.push(r.id);\n } catch {\n // ignore — an empty/broken catalog just yields the supplement below.\n }\n ids.push(...Object.keys(EXTRA_RULES));\n return ids;\n})();\n"]}
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Rule resolution for {@link explain_finding}.\n *\n * Core's detectors are coarse-grained: a single {@link Detector} (e.g. the\n * `crypto-libs` detector) emits many distinct `ruleId`s (`forge-rsa-keygen`,\n * `elliptic-ec`, `node-rsa`, …) that do NOT share the detector's `id` as a\n * prefix. The old MCP `explain_finding` matched `ruleId` against `detector.id`\n * by prefix and therefore returned \"no matching detector\" for every real\n * library finding (P0-5).\n *\n * This module resolves a finding's `ruleId` against core's rule catalog\n * ({@link defaultRegistry.ruleCatalog}) — the single source of truth declared by\n * the detectors themselves. There is no hand-curated table to keep in sync: the\n * ruleId → { detector, algorithm } mapping is derived from the catalog at load\n * time, so a new rule added in core is resolvable here the moment it ships. The\n * one non-detector rule (`dep-vulnerable`, produced by the manifest scanner\n * rather than a {@link Detector}) is supplemented explicitly. Unknown rules fall\n * back to a prefix match against the detector id space, then to unresolved.\n * Pure and synchronous — no I/O — so it is directly unit-testable.\n */\n\nimport { defaultRegistry, detectors } from \"@quantakrypto/core\";\nimport type { AlgorithmFamily, Detector, RuleMeta } from \"@quantakrypto/core\";\n\n/** A resolved rule: the detector it belongs to (if any) and its algorithm. */\ninterface ResolvedRule {\n /** The rule id that was looked up (echoed for convenience). */\n ruleId: string;\n /** The detector that emits this rule, when one could be resolved. */\n detector?: { id: string; description: string };\n /** The classical algorithm family the rule concerns, when known. */\n algorithm?: AlgorithmFamily;\n /** The catalog metadata for the rule, when it is a known core rule. */\n meta?: RuleMeta;\n /** How the match was made — useful for tests and diagnostics. */\n via: \"index\" | \"detector-id\" | \"prefix\" | \"unresolved\";\n}\n\n/**\n * Rules that are NOT emitted by a {@link Detector} and so are absent from the\n * catalog, but are still canonical core ruleIds. Today that is only the\n * dependency-manifest scanner's `dep-vulnerable` rule.\n */\nconst EXTRA_RULES: Record<string, { algorithm: AlgorithmFamily }> = {\n \"dep-vulnerable\": { algorithm: \"unknown\" },\n};\n\n/** Build an id → Detector lookup over the active detector set (registry first). */\nfunction detectorMap(): Map<string, Detector> {\n const map = new Map<string, Detector>();\n const all = (() => {\n try {\n return defaultRegistry.all();\n } catch {\n return detectors;\n }\n })();\n for (const d of all) map.set(d.id, d);\n return map;\n}\n\n/**\n * Resolve a finding's `ruleId` to its detector and algorithm.\n *\n * Resolution order:\n * 1. The core rule catalog — the authoritative path for every detector rule.\n * 2. The {@link EXTRA_RULES} supplement (non-detector rules, e.g. dependencies).\n * 3. Exact detector id (a rule that IS a detector id, e.g. a future 1:1 rule).\n * 4. Prefix against the detector id space (`node-crypto-*`, `pem-*`, …).\n * 5. Unresolved — caller falls back to the algorithm remediation.\n *\n * Pure: depends only on its argument and the static core detector set.\n */\nexport function resolveRule(ruleId: string): ResolvedRule {\n const id = ruleId.trim();\n\n // 1. Catalog — the authoritative path for known core detector rules.\n const entry = (() => {\n try {\n return defaultRegistry.forRule(id);\n } catch {\n return undefined;\n }\n })();\n if (entry) {\n return {\n ruleId: id,\n detector: { id: entry.detector.id, description: entry.detector.description },\n algorithm: entry.rule.algorithm ?? \"unknown\",\n meta: entry.rule,\n via: \"index\",\n };\n }\n\n // 2. Non-detector supplement (dependency scanner, …). `hasOwn` guards against\n // a rule id like `__proto__`/`constructor` resolving to an Object.prototype member.\n const extra = Object.hasOwn(EXTRA_RULES, id) ? EXTRA_RULES[id] : undefined;\n if (extra) {\n return { ruleId: id, algorithm: extra.algorithm, via: \"index\" };\n }\n\n const detectorsById = detectorMap();\n\n // 3. Exact detector id.\n const exact = detectorsById.get(id);\n if (exact) {\n return {\n ruleId: id,\n detector: { id: exact.id, description: exact.description },\n via: \"detector-id\",\n };\n }\n\n // 4. Longest-prefix detector id (e.g. `node-crypto-foo` → `node-crypto`).\n let best: Detector | undefined;\n for (const det of detectorsById.values()) {\n if (id === det.id || id.startsWith(`${det.id}-`)) {\n if (!best || det.id.length > best.id.length) best = det;\n }\n }\n if (best) {\n return {\n ruleId: id,\n detector: { id: best.id, description: best.description },\n via: \"prefix\",\n };\n }\n\n // 5. Unresolved.\n return { ruleId: id, via: \"unresolved\" };\n}\n\n/** Exposed for tests: the set of canonical rule ids resolvable via the catalog. */\nexport const KNOWN_RULE_IDS: readonly string[] = (() => {\n const ids: string[] = [];\n try {\n for (const r of defaultRegistry.ruleCatalog()) ids.push(r.id);\n } catch {\n // ignore — an empty/broken catalog just yields the supplement below.\n }\n ids.push(...Object.keys(EXTRA_RULES));\n return ids;\n})();\n"]}
package/dist/stdio.d.ts CHANGED
@@ -12,12 +12,9 @@
12
12
  * Run as the `quantakrypto-mcp` bin, or `node dist/stdio.js`.
13
13
  */
14
14
  import type { McpServer } from "./server.js";
15
- /** Serialize a value as one newline-terminated JSON line to stdout. */
16
- declare function writeLine(value: unknown): void;
17
15
  /**
18
16
  * Attach a line-delimited JSON-RPC loop to the given streams. Exposed (rather
19
17
  * than only run on import) so it can be reused or tested with custom streams.
20
18
  */
21
19
  export declare function runStdioServer(server: McpServer, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): void;
22
- export { writeLine };
23
20
  //# sourceMappingURL=stdio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,uEAAuE;AACvE,iBAAS,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAEvC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C,IAAI,CAkCN;AA6BD,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AASH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,SAAS,EACjB,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C,IAAI,CAkCN"}
package/dist/stdio.js CHANGED
@@ -17,10 +17,6 @@ import { realpathSync } from "node:fs";
17
17
  import { fileURLToPath } from "node:url";
18
18
  import { createQuantakryptoServer } from "./index.js";
19
19
  import { ErrorCode, makeFailure } from "./protocol.js";
20
- /** Serialize a value as one newline-terminated JSON line to stdout. */
21
- function writeLine(value) {
22
- process.stdout.write(JSON.stringify(value) + "\n");
23
- }
24
20
  /**
25
21
  * Attach a line-delimited JSON-RPC loop to the given streams. Exposed (rather
26
22
  * than only run on import) so it can be reused or tested with custom streams.
@@ -85,5 +81,4 @@ function isMainModule() {
85
81
  if (isMainModule()) {
86
82
  main();
87
83
  }
88
- export { writeLine };
89
84
  //# sourceMappingURL=stdio.js.map
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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","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"]}
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/**\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"]}
package/dist/tools.d.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  * crash.
9
9
  */
10
10
  import type { AlgorithmFamily, ScanOptions, ScanResult } from "@quantakrypto/core";
11
- import type { JsonSchema, ToolContext, ToolDefinition, ToolResult } from "./protocol.js";
11
+ import type { ToolContext, ToolDefinition, ToolResult } from "./protocol.js";
12
12
  /**
13
13
  * Map a core failure to a caller-safe message. Cancellation and budget overflows
14
14
  * are intentional, expected outcomes — their messages are author-controlled and
@@ -47,10 +47,17 @@ declare function staticHybridAdvice(algorithm: AlgorithmFamily): string[];
47
47
  * trusts the local user, always exposes them.
48
48
  */
49
49
  export declare const FS_TOOL_NAMES: readonly string[];
50
+ /**
51
+ * Tools that open network connections. On the HTTP transport they are OFF by
52
+ * default — a hosted MCP should not probe arbitrary hosts — but a trusted operator
53
+ * can opt in with QUANTAKRYPTO_MCP_ALLOW_NETWORK=1 (mirroring the FS-tools opt-in).
54
+ * Always available on the local stdio transport, which trusts the local user.
55
+ */
56
+ export declare const NETWORK_TOOL_NAMES: readonly string[];
50
57
  /** All quantakrypto MCP tools, in a stable order. */
51
58
  export declare const quantakryptoTools: ToolDefinition[];
52
59
  /** The core version these tools are built against (re-exported for diagnostics). */
53
- export declare const CORE_VERSION = "0.4.3";
60
+ export declare const CORE_VERSION = "0.5.0";
54
61
  /** Exposed for tests and advanced callers. */
55
62
  export declare const __test: {
56
63
  normalizeAlgorithm: typeof normalizeAlgorithm;
@@ -58,8 +65,11 @@ export declare const __test: {
58
65
  staticHybridAdvice: typeof staticHybridAdvice;
59
66
  buildScanOptions: typeof buildScanOptions;
60
67
  describeError: typeof describeError;
68
+ FIX_EXAMPLES: Partial<Record<AlgorithmFamily, {
69
+ note: string;
70
+ before: string;
71
+ after: string;
72
+ }>>;
61
73
  };
62
- /** Keep the schema type imported and referenced (documentation aid). */
63
- export type ToolInputSchema = JsonSchema;
64
74
  export {};
65
75
  //# sourceMappingURL=tools.d.ts.map
@@ -1 +1 @@
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"}
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,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAkB7E;;;;;;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;AA85BD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,MAAM,EAK1C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAAuB,CAAC;AAExE,qDAAqD;AACrD,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAoB7C,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,YAAY,UAAU,CAAC;AAEpC,8CAA8C;AAC9C,eAAO,MAAM,MAAM;;;;;;;cAj4Be,MAAM;gBAAU,MAAM;eAAS,MAAM;;CAw4BtE,CAAC"}
package/dist/tools.js CHANGED
@@ -845,6 +845,11 @@ const scoreDeltaTool = {
845
845
  if (!Array.isArray(args.before) || !Array.isArray(args.after)) {
846
846
  return errorResult("score_delta requires 'before' and 'after' arrays of findings.");
847
847
  }
848
+ // Validate element shape too (mirrors triage/remediate) — a malformed
849
+ // `severity` otherwise yields a NaN readiness score rendered as authoritative.
850
+ if (!areFindings(args.before) || !areFindings(args.after)) {
851
+ return errorResult("score_delta: 'before' and 'after' must be arrays of valid findings.");
852
+ }
848
853
  const before = args.before;
849
854
  const after = args.after;
850
855
  const invBefore = await safe("buildInventory", () => buildInventory(before));
@@ -1137,6 +1142,100 @@ const applyVerifiedPatchTool = {
1137
1142
  }, null, 2));
1138
1143
  },
1139
1144
  };
1145
+ /**
1146
+ * `probe_endpoint` — actively probe ONE live TLS/SSH endpoint the caller OWNS for
1147
+ * post-quantum readiness. This is the ONLY MCP tool that opens a network socket;
1148
+ * the qprobe plane is loaded via dynamic import so the server stays offline until
1149
+ * the tool is actually invoked, and the ownership attestation gate is enforced in
1150
+ * qProbe's `runProbe` before any connection. On the HTTP transport it is OFF by
1151
+ * default (see {@link NETWORK_TOOL_NAMES}) — a hosted endpoint should not probe
1152
+ * arbitrary hosts — but a trusted operator can opt in with
1153
+ * QUANTAKRYPTO_MCP_ALLOW_NETWORK=1.
1154
+ */
1155
+ const probeEndpointTool = {
1156
+ name: "probe_endpoint",
1157
+ description: "Actively probe ONE live TLS/SSH endpoint YOU OWN for post-quantum readiness " +
1158
+ "(PQC-hybrid key exchange X25519MLKEM768, classical certificate posture). REQUIRES " +
1159
+ "an ownership attestation: set i_own_this=true to confirm you are authorized to test " +
1160
+ "the target. Refuses CIDR ranges / wildcards / lists — one host at a time. Performs " +
1161
+ "only a benign, unauthenticated handshake and never modifies the endpoint. NOTE: this " +
1162
+ "is the ONLY quantakrypto MCP tool that opens a network connection; the server is " +
1163
+ "otherwise offline. Over HTTP it is disabled unless the operator sets " +
1164
+ "QUANTAKRYPTO_MCP_ALLOW_NETWORK=1.",
1165
+ inputSchema: {
1166
+ type: "object",
1167
+ properties: {
1168
+ target: {
1169
+ type: "string",
1170
+ description: "A single host or host:port you own (no ranges/CIDRs/wildcards).",
1171
+ },
1172
+ mode: {
1173
+ type: "string",
1174
+ enum: ["tls", "ssh", "auto"],
1175
+ description: "Probe mode (default: auto — SSH on :22, TLS otherwise).",
1176
+ },
1177
+ i_own_this: {
1178
+ type: "boolean",
1179
+ description: "Attestation that you are authorized to probe this endpoint. Must be true; the probe is refused otherwise.",
1180
+ },
1181
+ timeout_ms: { type: "number", description: "Per-connection timeout in ms (default 8000)." },
1182
+ },
1183
+ required: ["target", "i_own_this"],
1184
+ additionalProperties: false,
1185
+ },
1186
+ async handler(args) {
1187
+ const target = args.target;
1188
+ if (typeof target !== "string" || target.length === 0) {
1189
+ return errorResult("probe_endpoint requires a non-empty 'target' string.");
1190
+ }
1191
+ if (args.i_own_this !== true) {
1192
+ return errorResult("probe_endpoint refused: set i_own_this=true to attest you are authorized to probe this endpoint. Active probing of endpoints you do not own may be unlawful.");
1193
+ }
1194
+ const mode = args.mode === "tls" || args.mode === "ssh" ? args.mode : "auto";
1195
+ const timeoutMs = typeof args.timeout_ms === "number" ? args.timeout_ms : undefined;
1196
+ // Dynamic import keeps the networked qprobe plane out of the server process
1197
+ // until this tool is actually used; runProbe enforces the attestation gate.
1198
+ const qprobe = await import("@quantakrypto/qprobe");
1199
+ // Parse the target explicitly so a CIDR/range/list refusal returns a helpful
1200
+ // message rather than a scrubbed internal error.
1201
+ let parsed;
1202
+ try {
1203
+ parsed = qprobe.parseTarget(target, mode === "ssh" ? 22 : 443);
1204
+ }
1205
+ catch (e) {
1206
+ return errorResult(`probe_endpoint: ${e instanceof Error ? e.message : String(e)}`);
1207
+ }
1208
+ const probed = await safe("probe_endpoint", () => qprobe.runProbe({ targets: [parsed], mode, attest: { iOwnThis: true }, timeoutMs }));
1209
+ if (!probed.ok)
1210
+ return probed.result;
1211
+ const { reports, findings, inventory } = probed.value;
1212
+ const lines = [];
1213
+ let unreachable = 0;
1214
+ for (const r of reports) {
1215
+ lines.push(`${r.target.host}:${r.target.port} [${r.mode}]`);
1216
+ const err = r.ssh?.error ?? r.tls?.error ?? r.hybrid?.error;
1217
+ if (err && r.findings.length === 0) {
1218
+ unreachable++;
1219
+ // Do NOT let an unreachable/errored endpoint read as a clean 100/100.
1220
+ lines.push(` ⚠ probe error: ${err} — endpoint NOT assessed (not a clean result)`);
1221
+ }
1222
+ for (const p of r.positives)
1223
+ lines.push(` ✓ ${p}`);
1224
+ for (const f of r.findings)
1225
+ lines.push(` [${f.severity}] ${f.title} — ${f.message}`);
1226
+ }
1227
+ const note = unreachable > 0
1228
+ ? " — NOTE: an endpoint could not be reached/handshaken, so this is NOT a clean bill of health"
1229
+ : "";
1230
+ lines.push(`\n${findings.length} finding${findings.length === 1 ? "" : "s"} · ${inventory.hndlCount} HNDL-exposed · readiness ${inventory.readinessScore}/100${note}`);
1231
+ return {
1232
+ content: [
1233
+ { type: "text", text: lines.join("\n") },
1234
+ { type: "text", text: JSON.stringify({ findings, inventory }, null, 2) },
1235
+ ],
1236
+ };
1237
+ },
1238
+ };
1140
1239
  /**
1141
1240
  * Tools that read arbitrary filesystem paths. Disabled by default on the HTTP
1142
1241
  * transport (see {@link ./http.ts}) because a hosted endpoint must not be an
@@ -1149,6 +1248,13 @@ export const FS_TOOL_NAMES = [
1149
1248
  "generate_cbom",
1150
1249
  "plan_migration",
1151
1250
  ];
1251
+ /**
1252
+ * Tools that open network connections. On the HTTP transport they are OFF by
1253
+ * default — a hosted MCP should not probe arbitrary hosts — but a trusted operator
1254
+ * can opt in with QUANTAKRYPTO_MCP_ALLOW_NETWORK=1 (mirroring the FS-tools opt-in).
1255
+ * Always available on the local stdio transport, which trusts the local user.
1256
+ */
1257
+ export const NETWORK_TOOL_NAMES = ["probe_endpoint"];
1152
1258
  /** All quantakrypto MCP tools, in a stable order. */
1153
1259
  export const quantakryptoTools = [
1154
1260
  scanPathTool,
@@ -1168,6 +1274,8 @@ export const quantakryptoTools = [
1168
1274
  applyTriageTool,
1169
1275
  remediateFindingsTool,
1170
1276
  applyVerifiedPatchTool,
1277
+ // The only networked tool — offline until invoked; refused on the HTTP transport.
1278
+ probeEndpointTool,
1171
1279
  ];
1172
1280
  /** The core version these tools are built against (re-exported for diagnostics). */
1173
1281
  export const CORE_VERSION = VERSION;
@@ -1178,5 +1286,6 @@ export const __test = {
1178
1286
  staticHybridAdvice,
1179
1287
  buildScanOptions,
1180
1288
  describeError,
1289
+ FIX_EXAMPLES,
1181
1290
  };
1182
1291
  //# sourceMappingURL=tools.js.map