@sebastienrousseau/crypto-mcp 0.0.7 → 0.0.9

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.
Files changed (45) hide show
  1. package/README.md +75 -22
  2. package/dist/protocol.d.ts +18 -0
  3. package/dist/protocol.d.ts.map +1 -0
  4. package/dist/protocol.js +63 -0
  5. package/dist/server.d.ts +1 -0
  6. package/dist/server.d.ts.map +1 -1
  7. package/dist/server.js +16 -14
  8. package/dist/tools/annotations.d.ts +6 -0
  9. package/dist/tools/annotations.d.ts.map +1 -0
  10. package/dist/tools/annotations.js +48 -0
  11. package/dist/tools/definitions.d.ts +4 -0
  12. package/dist/tools/definitions.d.ts.map +1 -1
  13. package/dist/tools/definitions.js +190 -132
  14. package/dist/tools/index.d.ts +1 -0
  15. package/dist/tools/index.d.ts.map +1 -1
  16. package/dist/tools/index.js +24 -6
  17. package/dist/tools/kem.d.ts +4 -0
  18. package/dist/tools/kem.d.ts.map +1 -0
  19. package/dist/tools/kem.js +20 -0
  20. package/dist/tools/keyimport.d.ts +5 -0
  21. package/dist/tools/keyimport.d.ts.map +1 -0
  22. package/dist/tools/keyimport.js +206 -0
  23. package/dist/tools/keys.d.ts +9 -0
  24. package/dist/tools/keys.d.ts.map +1 -1
  25. package/dist/tools/keys.js +56 -41
  26. package/dist/tools/keystore.d.ts +25 -0
  27. package/dist/tools/keystore.d.ts.map +1 -0
  28. package/dist/tools/keystore.js +81 -0
  29. package/dist/tools/kms.d.ts +1 -0
  30. package/dist/tools/kms.d.ts.map +1 -1
  31. package/dist/tools/kms.js +27 -18
  32. package/dist/tools/result.d.ts +0 -1
  33. package/dist/tools/result.d.ts.map +1 -1
  34. package/dist/tools/result.js +0 -8
  35. package/dist/tools/signing.d.ts.map +1 -1
  36. package/dist/tools/signing.js +81 -34
  37. package/dist/tools/symmetric.d.ts +1 -0
  38. package/dist/tools/symmetric.d.ts.map +1 -1
  39. package/dist/tools/symmetric.js +18 -7
  40. package/dist/tools/validate.d.ts +3 -0
  41. package/dist/tools/validate.d.ts.map +1 -0
  42. package/dist/tools/validate.js +76 -0
  43. package/dist/types.d.ts +19 -2
  44. package/dist/types.d.ts.map +1 -1
  45. package/package.json +25 -18
package/README.md CHANGED
@@ -20,12 +20,13 @@ Instead of relying on fragile shell scripts or unverified LLM math, agents invok
20
20
 
21
21
  ## Features
22
22
 
23
- - **Standard MCP Protocol**: Full compliance with the Model Context Protocol JSON-RPC 2.0 specification via stdio transport.
24
- - **Post-Quantum Cryptography (PQC)**: Tools for NIST FIPS 203 (ML-KEM / Kyber), FIPS 204 (ML-DSA), and hybrid X25519 + ML-KEM key encapsulation.
25
- - **Classical Primitives**: RSA-2048/4096, ECC (P-256, P-384, P-521, secp256k1), Ed25519, OpenPGP (RFC 4880/9580), and AES-256-GCM / ChaCha20-Poly1305.
26
- - **Envelope Encryption**: Direct orchestration of multi-cloud Key Management Systems (AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault).
27
- - **Cryptographic Bill of Materials (CBOM)**: Automated discovery and inventory of cryptographic assets for DORA Articles 9/13 and CRA compliance.
28
- - **Zero Runtime Dependencies**: Lightweight, secure stdio architecture operating with strict input schema validation.
23
+ - **Standard MCP Protocol**: JSON-RPC 2.0 over stdio, with tools, resources and prompts.
24
+ - **Key handles, not key material**: keys are generated, unwrapped or derived inside the server process. Tools return an opaque `keyHandle` (`kh_` followed by 32 hex characters) plus public metadata; no tool returns a private key, a symmetric key or a DEK, and no tool accepts one.
25
+ - **Post-Quantum Cryptography (PQC)**: ML-KEM-768 (NIST FIPS 203) key generation, encapsulation and decapsulation.
26
+ - **Classical Primitives**: RSA-2048/3072/4096 (RSASSA-PSS), ECDSA on P-256, P-384 and secp256k1, Ed25519, HMAC-SHA256, and AES-256-GCM / ChaCha20-Poly1305.
27
+ - **Envelope Encryption**: wrap and unwrap DEKs under a key-encryption key. Only the `local` provider (random, in-process keys that do not survive a restart) is configured; `aws`, `gcp`, `azure` and `vault` return an error.
28
+ - **Cryptographic Bill of Materials (CBOM)**: classify algorithm names into a CycloneDX 1.6 CBOM inventory.
29
+ - **Validated input**: every tool call is checked against the tool's declared JSON schema before it runs.
29
30
 
30
31
  ---
31
32
 
@@ -62,18 +63,71 @@ Add the server to your `claude_desktop_config.json` or `.cursor/mcp.json`:
62
63
 
63
64
  ## Tools Exposed
64
65
 
65
- | Tool Name | Description | Key Parameters |
66
- | --------------------- | ------------------------------------------------------------- | ----------------------------------------------------- |
67
- | `crypto_generate_key` | Generate classical or post-quantum keypairs | `type` (rsa, ecc, ed25519, ml-kem-768), `passphrase` |
68
- | `crypto_encrypt` | Encrypt data with symmetric, asymmetric, or hybrid algorithms | `data`, `key`, `algorithm`, `armor` |
69
- | `crypto_decrypt` | Decrypt encrypted ciphertexts or armored blocks | `ciphertext`, `key`, `passphrase` |
70
- | `crypto_sign` | Create cryptographic signatures (clearsign, detached, raw) | `data`, `privateKey`, `passphrase`, `detached` |
71
- | `crypto_verify` | Verify digital signatures against public keys | `data`, `signature`, `publicKey` |
72
- | `crypto_hash` | Compute cryptographic hashes or post-quantum signatures | `data`, `algorithm` (sha256, sha512, blake2b, blake3) |
73
- | `crypto_kms_wrap` | Wrap a local data encryption key using cloud KMS | `provider` (aws, gcp, azure, vault), `keyId`, `dek` |
74
- | `crypto_kms_unwrap` | Unwrap a wrapped data encryption key using cloud KMS | `provider`, `keyId`, `wrappedKey` |
75
- | `crypto_inspect_key` | Parse armored OpenPGP keys or PEM certificates | `keyData` |
76
- | `crypto_audit_cbom` | Audit a directory for cryptographic assets and produce CBOM | `targetPath`, `format` (cyclonedx, spdx, summary) |
66
+ | Tool Name | Description | Key Parameters |
67
+ | ------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
68
+ | `crypto_generate_key` | Generate a key in the server; returns its handle and public key | `type` (rsa, ecc, ed25519, ml-kem-768, symmetric-256, hmac-sha256), `modulusLength`, `curve` |
69
+ | `crypto_key_list` | List held key handles with type and public metadata | none |
70
+ | `crypto_key_destroy` | Wipe a key and invalidate its handle | `keyHandle` |
71
+ | `crypto_key_import` | Load a key from a file in `CRYPTO_MCP_KEY_DIR` into a handle | `path`, `kind` (symmetric-256, hmac-sha256; raw keys only) |
72
+ | `crypto_encrypt` | AEAD-encrypt under a key handle (a new key if none is given) | `plaintext`, `keyHandle`, `algorithm` (aes-256-gcm, chacha20-poly1305) |
73
+ | `crypto_decrypt` | Authenticate and decrypt an AEAD ciphertext | `ciphertext`, `keyHandle`, `iv`, `authTag`, `algorithm` |
74
+ | `crypto_sign` | Sign with a key handle; the algorithm follows the key | `data`, `keyHandle` |
75
+ | `crypto_verify` | Verify against a public key PEM or a key handle | `data`, `signature`, `publicKey` or `keyHandle` |
76
+ | `crypto_hash` | Compute a digest | `data`, `algorithm` (sha256, sha384, sha512, sha3-256, blake2b512) |
77
+ | `crypto_kem_encapsulate` | ML-KEM-768 encapsulation; the shared secret becomes a key handle | `publicKey` |
78
+ | `crypto_kem_decapsulate` | ML-KEM-768 decapsulation with a key handle | `keyHandle`, `ciphertext` |
79
+ | `crypto_kms_wrap` | Wrap the DEK behind a key handle under a KMS-held KEK | `provider`, `keyId`, `keyHandle` |
80
+ | `crypto_kms_unwrap` | Unwrap a DEK into a new key handle | `provider`, `keyId`, `wrappedKey` |
81
+ | `crypto_inspect_key` | Classify a PEM or OpenPGP armored key and fingerprint it | `keyData` |
82
+ | `crypto_audit_cbom` | Classify algorithm names into a CBOM | `algorithms` |
83
+
84
+ Signature algorithms by key type: `ed25519` signs Ed25519, `rsa` signs RSASSA-PSS (SHA-256, MGF1-SHA-256, 32-byte salt), `ecc` signs ECDSA with SHA-256 (SHA-384 on P-384, DER-encoded), and `hmac-sha256` computes HMAC-SHA256.
85
+
86
+ ### Key handles
87
+
88
+ A key handle is a capability: whoever can call the server with it can use the key, but cannot read it. Handles live only as long as the server process. The store holds at most 64 keys; adding one more destroys the least recently used key, so a client that needs a key for long should keep using it or expect to generate a new one. `crypto_key_destroy` removes a key at once.
89
+
90
+ A typical session:
91
+
92
+ 1. `crypto_generate_key` with `type: "ed25519"` returns `keyHandle` and `publicKey`.
93
+ 2. `crypto_sign` with `data` and that `keyHandle` returns `algorithm: "ed25519"` and `signature`.
94
+ 3. Anyone can check the signature with `crypto_verify` and the `publicKey`.
95
+
96
+ ### Importing existing keys
97
+
98
+ `crypto_key_import` brings in a key that already exists, for example to decrypt data encrypted outside the server, without the key passing through the conversation: the client names a file, and the server reads it into the key store and returns a handle.
99
+
100
+ It is disabled unless the operator sets `CRYPTO_MCP_KEY_DIR` to a directory; without it the tool is still listed but every call returns `Key import is disabled`. Keeping it listed means a client sees why an import fails instead of a tool that is sometimes missing.
101
+
102
+ ```json
103
+ {
104
+ "mcpServers": {
105
+ "crypto-service": {
106
+ "command": "npx",
107
+ "args": ["-y", "@sebastienrousseau/crypto-mcp"],
108
+ "env": { "CRYPTO_MCP_KEY_DIR": "/home/me/.config/crypto-mcp/keys" }
109
+ }
110
+ }
111
+ }
112
+ ```
113
+
114
+ Accepted files (at most 64 KiB):
115
+
116
+ | File content | Imported as |
117
+ | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
118
+ | Unencrypted PKCS#8 PEM (`BEGIN PRIVATE KEY`), Ed25519 | `ed25519` |
119
+ | Unencrypted PKCS#8 PEM, RSA 2048, 3072 or 4096 bits | `rsa` |
120
+ | Unencrypted PKCS#8 PEM, EC on P-256, P-384 or secp256k1 | `ecc` |
121
+ | Exactly 32 bytes (binary), or 64 hex digits and optional final whitespace | `symmetric-256` (AES-256-GCM / ChaCha20-Poly1305, as `crypto_encrypt` uses), or `hmac-sha256` with `kind` |
122
+
123
+ The key type and public key of a PEM file come from the key itself; `kind` is refused for PEM files. Refused: encrypted PKCS#8 (decrypt it first with `openssl pkcs8 -nocrypt`), PKCS#1 and SEC1 PEM (convert with `openssl pkcs8 -topk8 -nocrypt`), and public keys, which carry nothing secret and can be passed to `crypto_verify` as `publicKey` directly.
124
+
125
+ Security model:
126
+
127
+ - `path` is relative to `CRYPTO_MCP_KEY_DIR`. Absolute paths, `..` segments and control characters are refused. The path is resolved with `realpath`, so a symlink is followed, but a target outside the directory is refused; the last component is then opened with `O_NOFOLLOW` where the platform has it, and the file is checked again through the open descriptor. Only regular files are read.
128
+ - The bytes read are overwritten with zeros once parsed; hex is decoded byte by byte, never into a string. The PEM text is parsed into a `KeyObject`, which cannot be wiped (see below).
129
+ - Results carry the handle and public metadata (`source: "crypto_key_import"`, public key, size or curve) only. Errors never contain the file's contents or its absolute path.
130
+ - Anyone who can call the server can import any key file in the directory, so put only keys meant for this server there.
77
131
 
78
132
  ---
79
133
 
@@ -93,10 +147,9 @@ Add the server to your `claude_desktop_config.json` or `.cursor/mcp.json`:
93
147
 
94
148
  ## Security & Memory Hygiene
95
149
 
96
- `@sebastienrousseau/crypto-mcp` enforces strict separation of concerns:
97
-
98
- - **No Private Key Retention**: Private keys and sensitive plaintext inputs are processed in-memory and never cached across MCP requests.
99
- - **Input Validation**: Strict JSON schema bounds on all inputs prevent buffer overflow and injection attacks.
150
+ - **No secret material in the conversation**: private keys, symmetric keys, DEKs and KEM shared secrets stay in the server process behind key handles. `crypto_verify` refuses a private key PEM instead of deriving its public half.
151
+ - **Bounded key store**: at most 64 keys, least recently used evicted first. Raw secret bytes (symmetric, HMAC and ML-KEM secret keys) are overwritten with zeros when a key is evicted or destroyed. Asymmetric private keys are Node.js `KeyObject`s, which JavaScript cannot wipe; they are released for garbage collection. Transient copies (for example the hex strings `@sebastienrousseau/crypto-lib` uses for ML-KEM) are not wiped either.
152
+ - **Input Validation**: every `tools/call` is checked against the tool's `inputSchema`: unknown properties, missing required properties, wrong types, values outside an enum and strings outside their declared length or format are rejected before the tool runs. Error messages name the property but never echo its value.
100
153
  - **Stdio Transport Isolation**: The server communicates over standard input/output with zero open network ports.
101
154
 
102
155
  ---
@@ -0,0 +1,18 @@
1
+ import type { JSONRPCRequest } from "./types";
2
+ export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
3
+ export declare function negotiateProtocolVersion(requested: unknown): string;
4
+ export declare const INVALID_PARAMS = -32602;
5
+ export declare class McpError extends Error {
6
+ readonly code: number;
7
+ constructor(code: number, message: string);
8
+ }
9
+ export declare const isNotification: (request: JSONRPCRequest) => boolean;
10
+ export declare function requireName(params: Record<string, unknown> | undefined, known: readonly {
11
+ name: string;
12
+ }[], kind: string): string;
13
+ export declare function requireArguments(params: Record<string, unknown> | undefined): Record<string, unknown>;
14
+ export declare function requirePromptArguments(declared: readonly {
15
+ name: string;
16
+ required?: boolean;
17
+ }[] | undefined, args: Record<string, unknown>): Record<string, string>;
18
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,eAAO,MAAM,2BAA2B,mEAK9B,CAAC;AAOX,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAInE;AAGD,eAAO,MAAM,cAAc,SAAS,CAAC;AAGrC,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM;CAKlB;AAGD,eAAO,MAAM,cAAc,GAAI,SAAS,cAAc,KAAG,OACT,CAAC;AAMjD,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,KAAK,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,EAClC,IAAI,EAAE,MAAM,GACX,MAAM,CAeR;AAGD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC1C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAGD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG,SAAS,EACrE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoBxB"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isNotification = exports.McpError = exports.INVALID_PARAMS = exports.SUPPORTED_PROTOCOL_VERSIONS = void 0;
4
+ exports.negotiateProtocolVersion = negotiateProtocolVersion;
5
+ exports.requireName = requireName;
6
+ exports.requireArguments = requireArguments;
7
+ exports.requirePromptArguments = requirePromptArguments;
8
+ exports.SUPPORTED_PROTOCOL_VERSIONS = [
9
+ "2025-11-25",
10
+ "2025-06-18",
11
+ "2025-03-26",
12
+ "2024-11-05",
13
+ ];
14
+ function negotiateProtocolVersion(requested) {
15
+ return exports.SUPPORTED_PROTOCOL_VERSIONS.includes(requested)
16
+ ? requested
17
+ : exports.SUPPORTED_PROTOCOL_VERSIONS[0];
18
+ }
19
+ exports.INVALID_PARAMS = -32602;
20
+ class McpError extends Error {
21
+ code;
22
+ constructor(code, message) {
23
+ super(message);
24
+ this.code = code;
25
+ this.name = "McpError";
26
+ }
27
+ }
28
+ exports.McpError = McpError;
29
+ const isNotification = (request) => !("id" in request) || request.id === undefined;
30
+ exports.isNotification = isNotification;
31
+ function requireName(params, known, kind) {
32
+ const name = params?.name;
33
+ if (typeof name !== "string" || name === "") {
34
+ throw new McpError(exports.INVALID_PARAMS, `Invalid params: ${kind} name is required`);
35
+ }
36
+ if (!known.some((k) => k.name === name)) {
37
+ throw new McpError(exports.INVALID_PARAMS, `Invalid params: unknown ${kind}: ${name}`);
38
+ }
39
+ return name;
40
+ }
41
+ function requireArguments(params) {
42
+ const args = params?.arguments ?? {};
43
+ if (typeof args !== "object" || args === null || Array.isArray(args)) {
44
+ throw new McpError(exports.INVALID_PARAMS, "Invalid params: arguments must be an object");
45
+ }
46
+ return args;
47
+ }
48
+ function requirePromptArguments(declared, args) {
49
+ const out = {};
50
+ for (const [key, value] of Object.entries(args)) {
51
+ if (typeof value !== "string") {
52
+ throw new McpError(exports.INVALID_PARAMS, `Invalid params: argument ${key} must be a string`);
53
+ }
54
+ out[key] = value;
55
+ }
56
+ for (const arg of declared ?? []) {
57
+ if (arg.required && !out[arg.name]) {
58
+ throw new McpError(exports.INVALID_PARAMS, `Invalid params: missing required argument ${arg.name}`);
59
+ }
60
+ }
61
+ return out;
62
+ }
63
+ //# sourceMappingURL=protocol.js.map
package/dist/server.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { JSONRPCRequest, JSONRPCResponse } from "./types";
2
+ export declare const SERVER_INSTRUCTIONS: string;
2
3
  export declare const SERVER_VERSION: string;
3
4
  export declare class CryptoMcpServer {
4
5
  private initialized;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAuB,MAAM,SAAS,CAAC;AAU/E,eAAO,MAAM,cAAc,EAAE,MAIpB,CAAC;AAEV,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAKnC,aAAa,IAAI,OAAO;IAOlB,aAAa,CACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC;IAuGpB,WAAW,CAChB,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C,IAAI;CAwBR"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAuB,MAAM,SAAS,CAAC;AAc/E,eAAO,MAAM,mBAAmB,QAId,CAAC;AAOnB,eAAO,MAAM,cAAc,EAAE,MAIpB,CAAC;AAEV,qBAAa,eAAe;IAC1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAKnC,aAAa,IAAI,OAAO;IAOlB,aAAa,CACxB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,eAAe,CAAC;IAqGpB,WAAW,CAChB,KAAK,GAAE,MAAM,CAAC,cAA8B,EAC5C,MAAM,GAAE,MAAM,CAAC,cAA+B,GAC7C,IAAI;CA0BR"}
package/dist/server.js CHANGED
@@ -3,13 +3,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.CryptoMcpServer = exports.SERVER_VERSION = void 0;
6
+ exports.CryptoMcpServer = exports.SERVER_VERSION = exports.SERVER_INSTRUCTIONS = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_readline_1 = __importDefault(require("node:readline"));
10
10
  const tools_1 = require("./tools");
11
11
  const resources_1 = require("./resources");
12
12
  const prompts_1 = require("./prompts");
13
+ const protocol_1 = require("./protocol");
14
+ exports.SERVER_INSTRUCTIONS = "Cryptographic tools that keep key material inside this server: " +
15
+ "generate or import a key to get a handle, then pass the handle to " +
16
+ "encrypt, decrypt, sign, KEM and KMS tools. No tool returns a private " +
17
+ "or secret key.";
13
18
  exports.SERVER_VERSION = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(__dirname, "..", "package.json"), "utf8")).version;
14
19
  class CryptoMcpServer {
15
20
  initialized = false;
@@ -35,7 +40,7 @@ class CryptoMcpServer {
35
40
  case "initialize": {
36
41
  this.initialized = true;
37
42
  const result = {
38
- protocolVersion: "2024-11-05",
43
+ protocolVersion: (0, protocol_1.negotiateProtocolVersion)(request.params?.protocolVersion),
39
44
  capabilities: {
40
45
  tools: {},
41
46
  resources: {},
@@ -45,6 +50,7 @@ class CryptoMcpServer {
45
50
  name: this.name,
46
51
  version: this.version,
47
52
  },
53
+ instructions: exports.SERVER_INSTRUCTIONS,
48
54
  };
49
55
  return { jsonrpc: "2.0", id, result };
50
56
  }
@@ -55,11 +61,8 @@ class CryptoMcpServer {
55
61
  return { jsonrpc: "2.0", id, result: { tools: tools_1.TOOLS } };
56
62
  }
57
63
  case "tools/call": {
58
- const params = request.params;
59
- const toolName = params ? String(params.name) : "";
60
- const toolArgs = params && params.arguments
61
- ? params.arguments
62
- : {};
64
+ const toolName = (0, protocol_1.requireName)(request.params, tools_1.TOOLS, "tool");
65
+ const toolArgs = (0, protocol_1.requireArguments)(request.params);
63
66
  const result = await (0, tools_1.executeTool)(toolName, toolArgs);
64
67
  return { jsonrpc: "2.0", id, result };
65
68
  }
@@ -76,11 +79,8 @@ class CryptoMcpServer {
76
79
  return { jsonrpc: "2.0", id, result: { prompts: prompts_1.PROMPTS } };
77
80
  }
78
81
  case "prompts/get": {
79
- const params = request.params;
80
- const promptName = params ? String(params.name) : "";
81
- const promptArgs = params && params.arguments
82
- ? params.arguments
83
- : {};
82
+ const promptName = (0, protocol_1.requireName)(request.params, prompts_1.PROMPTS, "prompt");
83
+ const promptArgs = (0, protocol_1.requirePromptArguments)(prompts_1.PROMPTS.find((p) => p.name === promptName)?.arguments, (0, protocol_1.requireArguments)(request.params));
84
84
  const result = await (0, prompts_1.getPrompt)(promptName, promptArgs);
85
85
  return { jsonrpc: "2.0", id, result };
86
86
  }
@@ -100,7 +100,7 @@ class CryptoMcpServer {
100
100
  jsonrpc: "2.0",
101
101
  id,
102
102
  error: {
103
- code: -32603,
103
+ code: err instanceof protocol_1.McpError ? err.code : -32603,
104
104
  message: err.message,
105
105
  },
106
106
  };
@@ -119,9 +119,11 @@ class CryptoMcpServer {
119
119
  try {
120
120
  const req = JSON.parse(trimmed);
121
121
  const res = await this.handleRequest(req);
122
+ if ((0, protocol_1.isNotification)(req))
123
+ return;
122
124
  output.write(JSON.stringify(res) + "\n");
123
125
  }
124
- catch (e) {
126
+ catch {
125
127
  const parseError = {
126
128
  jsonrpc: "2.0",
127
129
  id: null,
@@ -0,0 +1,6 @@
1
+ import type { MCPToolAnnotations } from "../types";
2
+ export declare function annotationsFor(name: string): {
3
+ title: string;
4
+ annotations: MCPToolAnnotations;
5
+ } | undefined;
6
+ //# sourceMappingURL=annotations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotations.d.ts","sourceRoot":"","sources":["../../src/tools/annotations.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AA8CnD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GACX;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAA;CAAE,GAAG,SAAS,CAKhE"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.annotationsFor = annotationsFor;
4
+ const HINTS = {
5
+ read: {
6
+ readOnlyHint: true,
7
+ destructiveHint: false,
8
+ idempotentHint: true,
9
+ openWorldHint: false,
10
+ },
11
+ add: {
12
+ readOnlyHint: false,
13
+ destructiveHint: false,
14
+ idempotentHint: false,
15
+ openWorldHint: false,
16
+ },
17
+ destroy: {
18
+ readOnlyHint: false,
19
+ destructiveHint: true,
20
+ idempotentHint: true,
21
+ openWorldHint: false,
22
+ },
23
+ };
24
+ const TOOL_BEHAVIOUR = {
25
+ crypto_generate_key: ["Generate a key", "add"],
26
+ crypto_key_list: ["List key handles", "read"],
27
+ crypto_key_destroy: ["Destroy a key", "destroy"],
28
+ crypto_key_import: ["Import a key from a file", "add"],
29
+ crypto_inspect_key: ["Inspect a public key", "read"],
30
+ crypto_encrypt: ["Encrypt data", "add"],
31
+ crypto_decrypt: ["Decrypt data", "read"],
32
+ crypto_kem_encapsulate: ["Encapsulate a shared secret", "add"],
33
+ crypto_kem_decapsulate: ["Decapsulate a shared secret", "add"],
34
+ crypto_sign: ["Sign data", "read"],
35
+ crypto_verify: ["Verify a signature", "read"],
36
+ crypto_hash: ["Hash data", "read"],
37
+ crypto_kms_wrap: ["Wrap a key (KMS)", "add"],
38
+ crypto_kms_unwrap: ["Unwrap a key (KMS)", "add"],
39
+ crypto_audit_cbom: ["Audit a CBOM", "read"],
40
+ };
41
+ function annotationsFor(name) {
42
+ const entry = TOOL_BEHAVIOUR[name];
43
+ if (!entry)
44
+ return undefined;
45
+ const [title, behaviour] = entry;
46
+ return { title, annotations: { title, ...HINTS[behaviour] } };
47
+ }
48
+ //# sourceMappingURL=annotations.js.map
@@ -2,6 +2,10 @@ import { MCPTool } from "../types";
2
2
  export declare const KEY_TYPES: string[];
3
3
  export declare const RSA_MODULUS_LENGTHS: number[];
4
4
  export declare const EC_CURVES: string[];
5
+ export declare const KEY_DIR_ENV = "CRYPTO_MCP_KEY_DIR";
6
+ export declare const MAX_KEY_FILE_BYTES = 65536;
5
7
  export declare const HASH_ALGORITHMS: string[];
8
+ export declare const MAX_TEXT_LENGTH = 1048576;
9
+ export declare const MAX_KEY_LENGTH = 16384;
6
10
  export declare const TOOLS: MCPTool[];
7
11
  //# sourceMappingURL=definitions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGnC,eAAO,MAAM,SAAS,UAA0C,CAAC;AAGjE,eAAO,MAAM,mBAAmB,UAAqB,CAAC;AAGtD,eAAO,MAAM,SAAS,UAA2C,CAAC;AAGlE,eAAO,MAAM,eAAe,UAM3B,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,OAAO,EAmP1B,CAAC"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAA4B,MAAM,UAAU,CAAC;AAK7D,eAAO,MAAM,SAAS,UAOrB,CAAC;AAGF,eAAO,MAAM,mBAAmB,UAAqB,CAAC;AAGtD,eAAO,MAAM,SAAS,UAA2C,CAAC;AAGlE,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAGhD,eAAO,MAAM,kBAAkB,QAAS,CAAC;AASzC,eAAO,MAAM,eAAe,UAM3B,CAAC;AASF,eAAO,MAAM,eAAe,UAAY,CAAC;AAGzC,eAAO,MAAM,cAAc,QAAS,CAAC;AAgVrC,eAAO,MAAM,KAAK,EAAE,OAAO,EAKiC,CAAC"}