@quantakrypto/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tools.js ADDED
@@ -0,0 +1,421 @@
1
+ /**
2
+ * quantakrypto MCP tools, backed by {@link @quantakrypto/core}.
3
+ *
4
+ * Every tool returns an MCP {@link ToolResult} ({ content, isError? }). Because
5
+ * `@quantakrypto/core` is still partly stubbed (several functions throw "not
6
+ * implemented"), each handler runs core calls through {@link safe} so a missing
7
+ * implementation surfaces as a readable `isError` tool result instead of a
8
+ * protocol-level crash. When core lands, the tools work unchanged.
9
+ */
10
+ import { VERSION, buildInventory, detectors, remediationFor, scan, toCbom, } from "@quantakrypto/core";
11
+ import { errorResult, textResult } from "./protocol.js";
12
+ import { resolveRule } from "./rules.js";
13
+ /** Severity order for stable, human-friendly summaries. */
14
+ const SEVERITY_ORDER = ["critical", "high", "medium", "low", "info"];
15
+ /** All classical algorithm families we can advise on, used for validation/help. */
16
+ const ALGORITHM_FAMILIES = [
17
+ "RSA",
18
+ "ECDH",
19
+ "ECDSA",
20
+ "EdDSA",
21
+ "DH",
22
+ "DSA",
23
+ "X25519",
24
+ "ECIES",
25
+ "unknown",
26
+ ];
27
+ /**
28
+ * Run a possibly-throwing core call, mapping any failure to an error tool
29
+ * result. Returns either the value or a {@link ToolResult} sentinel.
30
+ */
31
+ async function safe(label, fn) {
32
+ try {
33
+ return { ok: true, value: await fn() };
34
+ }
35
+ catch (err) {
36
+ const detail = err instanceof Error ? err.message : String(err);
37
+ return { ok: false, result: errorResult(`${label} failed: ${detail}`) };
38
+ }
39
+ }
40
+ /** Map a free-text algorithm string onto a known {@link AlgorithmFamily}. */
41
+ function normalizeAlgorithm(input) {
42
+ const cleaned = input
43
+ .trim()
44
+ .toUpperCase()
45
+ .replace(/[\s_-]+/g, "");
46
+ for (const fam of ALGORITHM_FAMILIES) {
47
+ if (fam.toUpperCase() === cleaned)
48
+ return fam;
49
+ }
50
+ // Common aliases / families folded into the canonical set.
51
+ if (cleaned.startsWith("RSA"))
52
+ return "RSA";
53
+ if (cleaned.includes("ECDSA"))
54
+ return "ECDSA";
55
+ if (cleaned.includes("ED25519") || cleaned.includes("EDDSA"))
56
+ return "EdDSA";
57
+ if (cleaned.includes("X25519") || cleaned.includes("CURVE25519"))
58
+ return "X25519";
59
+ if (cleaned.includes("ECDH"))
60
+ return "ECDH";
61
+ if (cleaned.includes("ECIES"))
62
+ return "ECIES";
63
+ if (cleaned === "DH" || cleaned.includes("DIFFIEHELLMAN"))
64
+ return "DH";
65
+ if (cleaned === "DSA")
66
+ return "DSA";
67
+ return "unknown";
68
+ }
69
+ /** Render a scan result as a compact human-readable summary. */
70
+ function summarizeScan(result) {
71
+ const inv = result.inventory;
72
+ const lines = [];
73
+ lines.push(`quantakrypto scan of ${result.root}`);
74
+ lines.push(`Files scanned: ${result.filesScanned}`);
75
+ lines.push(`Findings: ${result.findings.length}`);
76
+ lines.push(`Readiness score: ${inv.readinessScore}/100`);
77
+ lines.push(`Harvest-now-decrypt-later exposure: ${inv.hndlCount} finding(s)`);
78
+ const sev = SEVERITY_ORDER.filter((s) => (inv.bySeverity[s] ?? 0) > 0)
79
+ .map((s) => `${s}: ${inv.bySeverity[s]}`)
80
+ .join(", ");
81
+ if (sev)
82
+ lines.push(`By severity: ${sev}`);
83
+ const algos = Object.entries(inv.byAlgorithm)
84
+ .filter(([, n]) => (n ?? 0) > 0)
85
+ .map(([a, n]) => `${a}: ${n}`)
86
+ .join(", ");
87
+ if (algos)
88
+ lines.push(`By algorithm: ${algos}`);
89
+ if (result.findings.length > 0) {
90
+ lines.push("");
91
+ lines.push("Top findings:");
92
+ const top = [...result.findings]
93
+ .sort((a, b) => SEVERITY_ORDER.indexOf(a.severity) - SEVERITY_ORDER.indexOf(b.severity))
94
+ .slice(0, 20);
95
+ for (const f of top) {
96
+ const loc = `${f.location.file}:${f.location.line}`;
97
+ lines.push(`- [${f.severity}] ${f.ruleId} (${loc}) — ${f.message}`);
98
+ }
99
+ if (result.findings.length > top.length) {
100
+ lines.push(`… and ${result.findings.length - top.length} more.`);
101
+ }
102
+ }
103
+ return lines.join("\n");
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Tool definitions
107
+ // ---------------------------------------------------------------------------
108
+ const scanPathTool = {
109
+ name: "scan_path",
110
+ description: "Scan a file or directory for classical (quantum-vulnerable) asymmetric " +
111
+ "cryptography using quantakrypto. Returns a readiness summary and findings.",
112
+ inputSchema: {
113
+ type: "object",
114
+ properties: {
115
+ path: {
116
+ type: "string",
117
+ description: "Absolute or relative path to a file or directory to scan.",
118
+ },
119
+ format: {
120
+ type: "string",
121
+ enum: ["summary", "json"],
122
+ description: "Output format: 'summary' (default) for readable text, 'json' for the raw ScanResult.",
123
+ },
124
+ },
125
+ required: ["path"],
126
+ additionalProperties: false,
127
+ },
128
+ async handler(args) {
129
+ const path = args.path;
130
+ if (typeof path !== "string" || path.length === 0) {
131
+ return errorResult("scan_path requires a non-empty 'path' string.");
132
+ }
133
+ const format = args.format === "json" ? "json" : "summary";
134
+ const scanned = await safe("scan", () => scan({ root: path }));
135
+ if (!scanned.ok)
136
+ return scanned.result;
137
+ const result = scanned.value;
138
+ if (format === "json") {
139
+ return textResult(JSON.stringify(result, null, 2));
140
+ }
141
+ return textResult(summarizeScan(result));
142
+ },
143
+ };
144
+ const inventoryCryptoTool = {
145
+ name: "inventory_crypto",
146
+ description: "Produce a post-quantum readiness inventory for a path: a 0-100 readiness " +
147
+ "score plus counts of cryptographic findings by algorithm, category, and severity.",
148
+ inputSchema: {
149
+ type: "object",
150
+ properties: {
151
+ path: {
152
+ type: "string",
153
+ description: "Absolute or relative path to a file or directory to inventory.",
154
+ },
155
+ },
156
+ required: ["path"],
157
+ additionalProperties: false,
158
+ },
159
+ async handler(args) {
160
+ const path = args.path;
161
+ if (typeof path !== "string" || path.length === 0) {
162
+ return errorResult("inventory_crypto requires a non-empty 'path' string.");
163
+ }
164
+ const scanned = await safe("scan", () => scan({ root: path }));
165
+ if (!scanned.ok)
166
+ return scanned.result;
167
+ const result = scanned.value;
168
+ // Prefer a freshly built inventory from findings; fall back to the scan's own.
169
+ const built = await safe("buildInventory", () => buildInventory(result.findings));
170
+ const inventory = built.ok ? built.value : result.inventory;
171
+ const lines = [];
172
+ lines.push(`Post-quantum readiness for ${result.root}`);
173
+ lines.push(`Readiness score: ${inventory.readinessScore}/100`);
174
+ lines.push(`HNDL exposure: ${inventory.hndlCount}`);
175
+ lines.push("");
176
+ lines.push("By algorithm:");
177
+ for (const [algo, n] of Object.entries(inventory.byAlgorithm)) {
178
+ if ((n ?? 0) > 0)
179
+ lines.push(` ${algo}: ${n}`);
180
+ }
181
+ lines.push("By category:");
182
+ for (const [cat, n] of Object.entries(inventory.byCategory)) {
183
+ if ((n ?? 0) > 0)
184
+ lines.push(` ${cat}: ${n}`);
185
+ }
186
+ lines.push("By severity:");
187
+ for (const sev of SEVERITY_ORDER) {
188
+ const n = inventory.bySeverity[sev] ?? 0;
189
+ if (n > 0)
190
+ lines.push(` ${sev}: ${n}`);
191
+ }
192
+ return {
193
+ content: [
194
+ { type: "text", text: lines.join("\n") },
195
+ { type: "text", text: JSON.stringify(inventory, null, 2) },
196
+ ],
197
+ };
198
+ },
199
+ };
200
+ const explainFindingTool = {
201
+ name: "explain_finding",
202
+ description: "Explain a quantakrypto finding and its post-quantum remediation. Provide a " +
203
+ "ruleId (e.g. 'forge-rsa-keygen', 'elliptic-ec', 'node-rsa', 'pem-ec-private-key') " +
204
+ "and/or an algorithm (e.g. 'RSA', 'ECDSA'). The ruleId is resolved against the " +
205
+ "core detector set, so library and config rules explain correctly.",
206
+ inputSchema: {
207
+ type: "object",
208
+ properties: {
209
+ ruleId: {
210
+ type: "string",
211
+ description: "The finding's rule id, matching a detector id prefix.",
212
+ },
213
+ algorithm: {
214
+ type: "string",
215
+ description: "The classical algorithm family involved (e.g. RSA, ECDH, ECDSA).",
216
+ },
217
+ },
218
+ additionalProperties: false,
219
+ },
220
+ async handler(args) {
221
+ const ruleId = typeof args.ruleId === "string" ? args.ruleId.trim() : "";
222
+ const algoInput = typeof args.algorithm === "string" ? args.algorithm.trim() : "";
223
+ if (!ruleId && !algoInput) {
224
+ return errorResult("explain_finding requires at least one of 'ruleId' or 'algorithm'.");
225
+ }
226
+ const lines = [];
227
+ // Resolve the rule against core's actual detector set/registry (P0-5),
228
+ // not by a fragile id-prefix match. Library rules (forge-*, elliptic-ec,
229
+ // node-rsa, …) resolve to their `crypto-libs` detector and carry their
230
+ // algorithm, so they now explain correctly.
231
+ let resolvedAlgorithm;
232
+ if (ruleId) {
233
+ const resolved = resolveRule(ruleId);
234
+ resolvedAlgorithm = resolved.algorithm;
235
+ lines.push(`Rule: ${ruleId}`);
236
+ if (resolved.detector) {
237
+ lines.push(`Detector: ${resolved.detector.id} — ${resolved.detector.description}`);
238
+ }
239
+ else if (resolved.via === "unresolved") {
240
+ lines.push("No matching detector found in the catalog (rule may be unknown to this core version).");
241
+ }
242
+ }
243
+ // Prefer an explicit algorithm; otherwise use the one the rule resolved to.
244
+ const algorithm = algoInput
245
+ ? normalizeAlgorithm(algoInput)
246
+ : resolvedAlgorithm && resolvedAlgorithm !== "unknown"
247
+ ? resolvedAlgorithm
248
+ : undefined;
249
+ if (algorithm) {
250
+ if (lines.length)
251
+ lines.push("");
252
+ lines.push(`Algorithm: ${algorithm}`);
253
+ const rem = await safe("remediationFor", () => remediationFor(algorithm));
254
+ if (rem.ok && rem.value) {
255
+ lines.push(`Why it matters: ${algorithm} relies on hardness assumptions (integer factorization / discrete log) that Shor's algorithm breaks on a cryptographically-relevant quantum computer.`);
256
+ lines.push(`Recommendation: ${rem.value.recommendation}`);
257
+ lines.push(`Detail: ${rem.value.detail}`);
258
+ }
259
+ else if (rem.ok) {
260
+ lines.push("No specific remediation is registered for this algorithm.");
261
+ }
262
+ else {
263
+ return rem.result;
264
+ }
265
+ }
266
+ return textResult(lines.join("\n"));
267
+ },
268
+ };
269
+ const suggestHybridTool = {
270
+ name: "suggest_hybrid",
271
+ description: "Recommend a post-quantum / hybrid migration. Provide an 'algorithm' " +
272
+ "(e.g. RSA, ECDH, ECDSA) or free-text 'context' describing the usage.",
273
+ inputSchema: {
274
+ type: "object",
275
+ properties: {
276
+ algorithm: {
277
+ type: "string",
278
+ description: "Classical algorithm family to migrate away from.",
279
+ },
280
+ context: {
281
+ type: "string",
282
+ description: "Free-text description of the cryptographic usage (used when no algorithm is given).",
283
+ },
284
+ },
285
+ additionalProperties: false,
286
+ },
287
+ async handler(args) {
288
+ const algoInput = typeof args.algorithm === "string" ? args.algorithm.trim() : "";
289
+ const context = typeof args.context === "string" ? args.context.trim() : "";
290
+ if (!algoInput && !context) {
291
+ return errorResult("suggest_hybrid requires either 'algorithm' or 'context'.");
292
+ }
293
+ const algorithm = normalizeAlgorithm(algoInput || context);
294
+ const lines = [];
295
+ lines.push(`Migration guidance for: ${algoInput || context}`);
296
+ lines.push(`Detected family: ${algorithm}`);
297
+ const rem = await safe("remediationFor", () => remediationFor(algorithm));
298
+ if (rem.ok && rem.value) {
299
+ lines.push(`Recommended replacement: ${rem.value.recommendation}`);
300
+ lines.push(`Rationale: ${rem.value.detail}`);
301
+ }
302
+ else {
303
+ // Static fallback table so the tool stays useful even with a stubbed core.
304
+ lines.push(...staticHybridAdvice(algorithm));
305
+ }
306
+ lines.push("");
307
+ lines.push("Hybrid migrations combine a classical primitive with a NIST PQC algorithm " +
308
+ "so security holds if either survives. Roll out hybrids first, then drop the " +
309
+ "classical half once the PQC side is proven in your environment.");
310
+ return textResult(lines.join("\n"));
311
+ },
312
+ };
313
+ /** Built-in PQC guidance used when core's remediation table is unavailable. */
314
+ function staticHybridAdvice(algorithm) {
315
+ switch (algorithm) {
316
+ case "RSA":
317
+ case "ECIES":
318
+ return [
319
+ "Recommended replacement: ML-KEM-768 for key establishment (hybrid X25519MLKEM768).",
320
+ "For signatures use ML-DSA-65 (Dilithium) or SLH-DSA (SPHINCS+) where statelessness matters.",
321
+ ];
322
+ case "ECDH":
323
+ case "DH":
324
+ case "X25519":
325
+ return [
326
+ "Recommended replacement: hybrid X25519MLKEM768 key exchange (ML-KEM-768 + X25519).",
327
+ "Supported in modern TLS 1.3 stacks; prefer the hybrid named group over bare ML-KEM.",
328
+ ];
329
+ case "ECDSA":
330
+ case "EdDSA":
331
+ case "DSA":
332
+ return [
333
+ "Recommended replacement: ML-DSA-65 (Dilithium) for general signatures.",
334
+ "Use SLH-DSA (SPHINCS+) for long-lived roots or where a stateless hash-based scheme is preferred.",
335
+ ];
336
+ default:
337
+ return [
338
+ "Recommended replacement: adopt NIST PQC — ML-KEM for key establishment, ML-DSA for signatures.",
339
+ "Deploy as hybrids (classical + PQC) during transition.",
340
+ ];
341
+ }
342
+ }
343
+ const listRulesTool = {
344
+ name: "list_rules",
345
+ description: "List the quantakrypto detector catalog: every detector id and what it looks for.",
346
+ inputSchema: {
347
+ type: "object",
348
+ properties: {},
349
+ additionalProperties: false,
350
+ },
351
+ async handler() {
352
+ const detectorList = await safe("detectors", () => detectors);
353
+ if (!detectorList.ok)
354
+ return detectorList.result;
355
+ const catalog = detectorList.value.map((d) => ({ id: d.id, description: d.description }));
356
+ if (catalog.length === 0) {
357
+ return textResult("No detectors are registered in @quantakrypto/core yet (the catalog is empty).");
358
+ }
359
+ const human = catalog.map((d) => `- ${d.id}: ${d.description}`).join("\n");
360
+ return {
361
+ content: [
362
+ {
363
+ type: "text",
364
+ text: `quantakrypto detector catalog (${catalog.length} rules):\n${human}`,
365
+ },
366
+ { type: "text", text: JSON.stringify(catalog, null, 2) },
367
+ ],
368
+ };
369
+ },
370
+ };
371
+ const generateCbomTool = {
372
+ name: "generate_cbom",
373
+ description: "Scan a path and emit a CycloneDX 1.6 Cryptographic Bill of Materials (CBOM) " +
374
+ "of the classical cryptographic assets found, for compliance / supply-chain " +
375
+ "tooling. Reads the filesystem, so it is gated like scan_path over HTTP.",
376
+ inputSchema: {
377
+ type: "object",
378
+ properties: {
379
+ path: {
380
+ type: "string",
381
+ description: "Absolute or relative path to a file or directory to inventory.",
382
+ },
383
+ },
384
+ required: ["path"],
385
+ additionalProperties: false,
386
+ },
387
+ async handler(args) {
388
+ const path = args.path;
389
+ if (typeof path !== "string" || path.length === 0) {
390
+ return errorResult("generate_cbom requires a non-empty 'path' string.");
391
+ }
392
+ const scanned = await safe("scan", () => scan({ root: path }));
393
+ if (!scanned.ok)
394
+ return scanned.result;
395
+ const cbom = await safe("toCbom", () => toCbom(scanned.value));
396
+ if (!cbom.ok)
397
+ return cbom.result;
398
+ return textResult(JSON.stringify(cbom.value, null, 2));
399
+ },
400
+ };
401
+ /**
402
+ * Tools that read arbitrary filesystem paths. Disabled by default on the HTTP
403
+ * transport (see {@link ./http.ts}) because a hosted endpoint must not be an
404
+ * arbitrary-file-read oracle (security audit Q-01). The stdio transport, which
405
+ * trusts the local user, always exposes them.
406
+ */
407
+ export const FS_TOOL_NAMES = ["scan_path", "inventory_crypto", "generate_cbom"];
408
+ /** All quantakrypto MCP tools, in a stable order. */
409
+ export const quantakryptoTools = [
410
+ scanPathTool,
411
+ inventoryCryptoTool,
412
+ explainFindingTool,
413
+ suggestHybridTool,
414
+ listRulesTool,
415
+ generateCbomTool,
416
+ ];
417
+ /** The core version these tools are built against (re-exported for diagnostics). */
418
+ export const CORE_VERSION = VERSION;
419
+ /** Exposed for tests and advanced callers. */
420
+ export const __test = { normalizeAlgorithm, summarizeScan, staticHybridAdvice };
421
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ # Examples
2
+
3
+ ## `transcript.jsonl`
4
+
5
+ A sample MCP session against the quantakrypto server, one JSON object per line. Each
6
+ line has a `direction` (`client→server` / `server→client`), an optional `note`,
7
+ and the JSON-RPC `message` actually exchanged.
8
+
9
+ It walks through a full lifecycle:
10
+
11
+ 1. `initialize` handshake (and its response advertising `serverInfo` + capabilities)
12
+ 2. the `notifications/initialized` notification (no response is returned)
13
+ 3. a `ping` keepalive
14
+ 4. `tools/list` (the complete tool catalog with input schemas)
15
+ 5. two `tools/call` invocations (`suggest_hybrid`, `explain_finding`)
16
+ 6. an error case: an unknown method returning JSON-RPC error `-32601`
17
+
18
+ The `direction`/`note` wrappers are illustrative metadata; on the wire only the
19
+ `message` payloads are sent (newline-delimited over stdio, or as the `POST /mcp`
20
+ body over HTTP).
21
+
22
+ The `explain_finding` / detector text shown reflects a populated `@quantakrypto/core`;
23
+ with the current stub the catalog may be empty, but the protocol shapes are
24
+ identical.
25
+
26
+ ### Replaying over HTTP
27
+
28
+ ```bash
29
+ PORT=3000 node ../dist/http.js &
30
+
31
+ curl -s localhost:3000/mcp -H 'content-type: application/json' \
32
+ -d '{"jsonrpc":"2.0","id":3,"method":"tools/list"}' | jq
33
+
34
+ curl -s localhost:3000/mcp -H 'content-type: application/json' \
35
+ -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"suggest_hybrid","arguments":{"algorithm":"RSA"}}}' | jq
36
+ ```
@@ -0,0 +1,13 @@
1
+ {"direction":"client→server","note":"handshake","message":{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"example-client","version":"1.0.0"}}}}
2
+ {"direction":"server→client","message":{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{"listChanged":false}},"serverInfo":{"name":"quantakrypto","version":"0.1.0"},"instructions":"quantakrypto checks code for quantum-vulnerable cryptography and recommends post-quantum (NIST PQC) migrations. Use scan_path / inventory_crypto to assess a path, list_rules to see detectors, and explain_finding / suggest_hybrid for remediation guidance."}}}
3
+ {"direction":"client→server","note":"notification — no response is sent","message":{"jsonrpc":"2.0","method":"notifications/initialized"}}
4
+ {"direction":"client→server","note":"liveness check","message":{"jsonrpc":"2.0","id":2,"method":"ping"}}
5
+ {"direction":"server→client","message":{"jsonrpc":"2.0","id":2,"result":{}}}
6
+ {"direction":"client→server","note":"discover tools","message":{"jsonrpc":"2.0","id":3,"method":"tools/list"}}
7
+ {"direction":"server→client","message":{"jsonrpc":"2.0","id":3,"result":{"tools":[{"name":"explain_finding","description":"Explain a quantakrypto finding and its post-quantum remediation. Provide a ruleId (e.g. 'rsa-keygen') and/or an algorithm (e.g. 'RSA', 'ECDSA').","inputSchema":{"type":"object","properties":{"ruleId":{"type":"string","description":"The finding's rule id, matching a detector id prefix."},"algorithm":{"type":"string","description":"The classical algorithm family involved (e.g. RSA, ECDH, ECDSA)."}},"additionalProperties":false}},{"name":"inventory_crypto","description":"Produce a post-quantum readiness inventory for a path: a 0-100 readiness score plus counts of cryptographic findings by algorithm, category, and severity.","inputSchema":{"type":"object","properties":{"path":{"type":"string","description":"Absolute or relative path to a file or directory to inventory."}},"required":["path"],"additionalProperties":false}},{"name":"list_rules","description":"List the quantakrypto detector catalog: every detector id and what it looks for.","inputSchema":{"type":"object","properties":{},"additionalProperties":false}},{"name":"scan_path","description":"Scan a file or directory for classical (quantum-vulnerable) asymmetric cryptography using quantakrypto. Returns a readiness summary and findings.","inputSchema":{"type":"object","properties":{"path":{"type":"string","description":"Absolute or relative path to a file or directory to scan."},"format":{"type":"string","enum":["summary","json"],"description":"Output format: 'summary' (default) for readable text, 'json' for the raw ScanResult."}},"required":["path"],"additionalProperties":false}},{"name":"suggest_hybrid","description":"Recommend a post-quantum / hybrid migration. Provide an 'algorithm' (e.g. RSA, ECDH, ECDSA) or free-text 'context' describing the usage.","inputSchema":{"type":"object","properties":{"algorithm":{"type":"string","description":"Classical algorithm family to migrate away from."},"context":{"type":"string","description":"Free-text description of the cryptographic usage (used when no algorithm is given)."}},"additionalProperties":false}}]}}}
8
+ {"direction":"client→server","note":"call a tool","message":{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"suggest_hybrid","arguments":{"algorithm":"RSA"}}}}
9
+ {"direction":"server→client","message":{"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"Migration guidance for: RSA\nDetected family: RSA\nRecommended replacement: ML-KEM-768 for key establishment (hybrid X25519MLKEM768).\nFor signatures use ML-DSA-65 (Dilithium) or SLH-DSA (SPHINCS+) where statelessness matters.\n\nHybrid migrations combine a classical primitive with a NIST PQC algorithm so security holds if either survives. Roll out hybrids first, then drop the classical half once the PQC side is proven in your environment."}]}}}
10
+ {"direction":"client→server","note":"explain a finding","message":{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"explain_finding","arguments":{"ruleId":"rsa-keygen","algorithm":"RSA"}}}}
11
+ {"direction":"server→client","message":{"jsonrpc":"2.0","id":5,"result":{"content":[{"type":"text","text":"Rule: rsa-keygen\nDetector: rsa — detects RSA key generation and usage.\n\nAlgorithm: RSA\nWhy it matters: RSA relies on hardness assumptions (integer factorization / discrete log) that Shor's algorithm breaks on a cryptographically-relevant quantum computer.\nRecommendation: ML-KEM-768 (hybrid X25519MLKEM768)\nDetail: Replace RSA key transport/encryption with ML-KEM; deploy as a hybrid during transition."}]}}}
12
+ {"direction":"client→server","note":"error case — unknown method","message":{"jsonrpc":"2.0","id":6,"method":"resources/list"}}
13
+ {"direction":"server→client","message":{"jsonrpc":"2.0","id":6,"error":{"code":-32601,"message":"method not found: resources/list"}}}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@quantakrypto/mcp",
3
+ "version": "0.1.0",
4
+ "description": "quantakrypto MCP — post-quantum readiness for AI coding agents via the Model Context Protocol. Zero runtime dependencies (stdio JSON-RPC implemented in-house).",
5
+ "license": "Apache-2.0",
6
+ "author": "Dandelion Labs <hello@dandelionlabs.io> (https://dandelionlabs.io)",
7
+ "homepage": "https://github.com/dandelionlabs-io/qproof-tools/tree/main/packages/mcp#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/dandelionlabs-io/qproof-tools.git",
11
+ "directory": "packages/mcp"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/dandelionlabs-io/qproof-tools/issues"
15
+ },
16
+ "type": "module",
17
+ "bin": {
18
+ "quantakrypto-mcp": "./dist/stdio.js"
19
+ },
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ }
27
+ },
28
+ "files": [
29
+ "dist",
30
+ "README.md",
31
+ "HOSTING.md",
32
+ "examples"
33
+ ],
34
+ "engines": {
35
+ "node": ">=20"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "dependencies": {
41
+ "@quantakrypto/core": "0.1.0"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -b",
45
+ "test": "node --import tsx --test test/*.test.ts"
46
+ }
47
+ }