@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.
- package/README.md +75 -22
- package/dist/protocol.d.ts +18 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +63 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +16 -14
- package/dist/tools/annotations.d.ts +6 -0
- package/dist/tools/annotations.d.ts.map +1 -0
- package/dist/tools/annotations.js +48 -0
- package/dist/tools/definitions.d.ts +4 -0
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/definitions.js +190 -132
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +24 -6
- package/dist/tools/kem.d.ts +4 -0
- package/dist/tools/kem.d.ts.map +1 -0
- package/dist/tools/kem.js +20 -0
- package/dist/tools/keyimport.d.ts +5 -0
- package/dist/tools/keyimport.d.ts.map +1 -0
- package/dist/tools/keyimport.js +206 -0
- package/dist/tools/keys.d.ts +9 -0
- package/dist/tools/keys.d.ts.map +1 -1
- package/dist/tools/keys.js +56 -41
- package/dist/tools/keystore.d.ts +25 -0
- package/dist/tools/keystore.d.ts.map +1 -0
- package/dist/tools/keystore.js +81 -0
- package/dist/tools/kms.d.ts +1 -0
- package/dist/tools/kms.d.ts.map +1 -1
- package/dist/tools/kms.js +27 -18
- package/dist/tools/result.d.ts +0 -1
- package/dist/tools/result.d.ts.map +1 -1
- package/dist/tools/result.js +0 -8
- package/dist/tools/signing.d.ts.map +1 -1
- package/dist/tools/signing.js +81 -34
- package/dist/tools/symmetric.d.ts +1 -0
- package/dist/tools/symmetric.d.ts.map +1 -1
- package/dist/tools/symmetric.js +18 -7
- package/dist/tools/validate.d.ts +3 -0
- package/dist/tools/validate.d.ts.map +1 -0
- package/dist/tools/validate.js +76 -0
- package/dist/types.d.ts +19 -2
- package/dist/types.d.ts.map +1 -1
- 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**:
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
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
|
|
66
|
-
|
|
|
67
|
-
| `crypto_generate_key`
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
- **
|
|
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"}
|
package/dist/protocol.js
ADDED
|
@@ -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
package/dist/server.d.ts.map
CHANGED
|
@@ -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;
|
|
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:
|
|
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
|
|
59
|
-
const
|
|
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
|
|
80
|
-
const
|
|
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
|
|
126
|
+
catch {
|
|
125
127
|
const parseError = {
|
|
126
128
|
jsonrpc: "2.0",
|
|
127
129
|
id: null,
|
|
@@ -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,
|
|
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"}
|