@erickwendel/ciphersuite-mcp 0.0.5 → 0.0.7

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,15 +1,11 @@
1
- #!/usr/bin/env node
2
-
3
1
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { server } from "./mcp.ts";
5
-
2
+ import { server } from "./mcp.js";
6
3
  async function main() {
7
4
  const transport = new StdioServerTransport();
8
5
  await server.connect(transport);
9
6
  console.error("Encrypt MCP Server running on stdio");
10
7
  }
11
-
12
8
  main().catch((error) => {
13
9
  console.error("Fatal error in main():", error);
14
10
  process.exit(1);
15
- });
11
+ });
package/build/mcp.js ADDED
@@ -0,0 +1,137 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'node:crypto';
3
+ import z from "zod";
4
+ export const server = new McpServer({
5
+ name: "@erickwendel/ciphersuite-mcp",
6
+ version: "0.0.1",
7
+ });
8
+ // Fixed salt — same passphrase always derives the same key so decryption works across calls
9
+ const SALT = 'mcp-encrypter-salt';
10
+ function deriveKey(passphrase) {
11
+ return scryptSync(passphrase, SALT, 32);
12
+ }
13
+ function encrypt(text, key) {
14
+ const iv = randomBytes(16);
15
+ const cipher = createCipheriv('aes-256-cbc', deriveKey(key), iv);
16
+ const encrypted = Buffer.concat([
17
+ cipher.update(Buffer.from(text, 'utf8')),
18
+ cipher.final(),
19
+ ]);
20
+ return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
21
+ }
22
+ function decrypt(encryptedText, key) {
23
+ const [ivHex, ...rest] = encryptedText.split(':');
24
+ const iv = Buffer.from(ivHex, 'hex');
25
+ const encrypted = Buffer.from(rest.join(':'), 'hex');
26
+ const decipher = createDecipheriv('aes-256-cbc', deriveKey(key), iv);
27
+ const decrypted = Buffer.concat([
28
+ decipher.update(encrypted),
29
+ decipher.final(),
30
+ ]);
31
+ return decrypted.toString('utf8');
32
+ }
33
+ server.registerTool("encrypt_message", {
34
+ description: "Encrypt a message",
35
+ inputSchema: {
36
+ message: z.string().describe("The message to encrypt"),
37
+ encryptionKey: z.string().describe("Any passphrase to use for encryption — the server derives a strong key from it automatically"),
38
+ },
39
+ outputSchema: {
40
+ encryptedMessage: z.string().describe("The encrypted message (format: iv:ciphertext)"),
41
+ }
42
+ }, async ({ message, encryptionKey }) => {
43
+ try {
44
+ const encryptedMessage = encrypt(message, encryptionKey);
45
+ return {
46
+ content: [{ type: "text", text: encryptedMessage }],
47
+ structuredContent: { encryptedMessage },
48
+ };
49
+ }
50
+ catch (err) {
51
+ return {
52
+ isError: true,
53
+ content: [{ type: "text", text: `Failed to encrypt message! Check if the message and encryption key are correct. Error details: ${err instanceof Error ? err.message : String(err)}` }],
54
+ };
55
+ }
56
+ });
57
+ server.registerTool("decrypt_message", {
58
+ description: "Decrypt a message that was encrypted with the encrypt_message tool",
59
+ inputSchema: {
60
+ encryptedMessage: z.string().describe("The encrypted message to decrypt (format: iv:ciphertext)"),
61
+ encryptionKey: z.string().describe("The same passphrase used during encryption"),
62
+ },
63
+ outputSchema: {
64
+ decryptedMessage: z.string().describe("The decrypted plain-text message"),
65
+ }
66
+ }, async ({ encryptedMessage, encryptionKey }) => {
67
+ try {
68
+ const decryptedMessage = decrypt(encryptedMessage, encryptionKey);
69
+ return {
70
+ content: [{ type: "text", text: decryptedMessage }],
71
+ structuredContent: { decryptedMessage },
72
+ };
73
+ }
74
+ catch (err) {
75
+ return {
76
+ isError: true,
77
+ content: [
78
+ {
79
+ type: "text",
80
+ text: `Failed to decrypt message! Check if the encrypted message is correct and if the encryption key matches the one used for encryption. Error details: ${err instanceof Error ? err.message : String(err)}`,
81
+ },
82
+ ],
83
+ };
84
+ }
85
+ });
86
+ server.registerResource("encryption://info", "encryption://info", { description: "Describes the encryption algorithm, key requirements, and output format used by this server." }, async () => ({
87
+ contents: [
88
+ {
89
+ uri: "encryption://info",
90
+ mimeType: "text/plain",
91
+ text: `
92
+ Algorithm : AES-256-CBC
93
+ Key derivation: scrypt (passphrase + fixed server salt → 32-byte key)
94
+ Output format: <16-byte IV in hex>:<ciphertext in hex> (separated by ":")
95
+ Notes:
96
+ - Users pass any passphrase — the server derives a strong 32-byte key automatically using scrypt.
97
+ - A random IV is generated for every encryption — the same message encrypted twice will produce different output.
98
+ - Use the exact same passphrase to decrypt.
99
+ - Keep the full "iv:ciphertext" string to decrypt later.
100
+ `.trim(),
101
+ },
102
+ ],
103
+ }));
104
+ server.registerPrompt("encrypt_message_prompt", {
105
+ description: "Prompt to encrypt a plain-text message using the encrypt_message tool",
106
+ argsSchema: {
107
+ message: z.string().describe("The plain-text message to encrypt"),
108
+ encryptionKey: z.string().describe("Any passphrase — the server derives a strong key automatically"),
109
+ },
110
+ }, ({ message, encryptionKey }) => ({
111
+ messages: [
112
+ {
113
+ role: "user",
114
+ content: {
115
+ type: "text",
116
+ text: `Please encrypt the following message using the encrypt_message tool.\nMessage: ${message}\nEncryption key: ${encryptionKey}`,
117
+ },
118
+ },
119
+ ],
120
+ }));
121
+ server.registerPrompt("decrypt_message_prompt", {
122
+ description: "Prompt to decrypt a message using the decrypt_message tool",
123
+ argsSchema: {
124
+ encryptedMessage: z.string().describe("The iv:ciphertext string to decrypt"),
125
+ encryptionKey: z.string().describe("The same passphrase used during encryption"),
126
+ },
127
+ }, ({ encryptedMessage, encryptionKey }) => ({
128
+ messages: [
129
+ {
130
+ role: "user",
131
+ content: {
132
+ type: "text",
133
+ text: `Please decrypt the following message using the decrypt_message tool.\nEncrypted message: ${encryptedMessage}\nEncryption key: ${encryptionKey}`,
134
+ },
135
+ },
136
+ ],
137
+ }));
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@erickwendel/ciphersuite-mcp",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
7
- "ciphersuite-mcp": "./src/index.ts"
7
+ "ciphersuite-mcp": "./build/index.js"
8
8
  },
9
9
  "files": [
10
- "src"
10
+ "build"
11
11
  ],
12
12
  "scripts": {
13
- "build": "chmod 755 src/index.ts",
14
- "start": "node src/index.ts",
15
- "dev": "node --watch --inspect src/index.ts",
13
+ "build": "npx tsc && chmod 755 build/index.js",
14
+ "prepublishOnly": "npm run build",
15
+ "start": "node --experimental-strip-types src/index.ts",
16
+ "dev": "node --watch --inspect --experimental-strip-types src/index.ts",
16
17
  "test": "node --test tests/**/*.test.ts",
17
18
  "mcp:inspect": "npx @modelcontextprotocol/inspector node src/index.ts",
18
19
  "test:dev": "node --inspect --test --watch tests/**/*.test.ts",
@@ -30,7 +31,10 @@
30
31
  },
31
32
  "dependencies": {
32
33
  "@modelcontextprotocol/sdk": "^1.27.1",
33
- "@types/node": "^24.11.0",
34
34
  "zod": "^3.25.76"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^24.11.0",
38
+ "typescript": "^5.9.3"
35
39
  }
36
40
  }
package/src/mcp.ts DELETED
@@ -1,168 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'node:crypto';
3
- import z from "zod";
4
-
5
- export const server = new McpServer({
6
- name: "@erickwendel/ciphersuite-mcp",
7
- version: "0.0.1",
8
- });
9
-
10
-
11
- // Fixed salt — same passphrase always derives the same key so decryption works across calls
12
- const SALT = 'mcp-encrypter-salt';
13
-
14
- function deriveKey(passphrase: string): Buffer {
15
- return scryptSync(passphrase, SALT, 32);
16
- }
17
-
18
- function encrypt(text: string, key: string): string {
19
- const iv = randomBytes(16);
20
- const cipher = createCipheriv('aes-256-cbc', deriveKey(key), iv);
21
- const encrypted = Buffer.concat([
22
- cipher.update(Buffer.from(text, 'utf8')),
23
- cipher.final(),
24
- ]);
25
- return `${iv.toString('hex')}:${encrypted.toString('hex')}`;
26
- }
27
-
28
- function decrypt(encryptedText: string, key: string): string {
29
- const [ivHex, ...rest] = encryptedText.split(':');
30
- const iv = Buffer.from(ivHex, 'hex');
31
- const encrypted = Buffer.from(rest.join(':'), 'hex');
32
- const decipher = createDecipheriv('aes-256-cbc', deriveKey(key), iv);
33
- const decrypted = Buffer.concat([
34
- decipher.update(encrypted),
35
- decipher.final(),
36
- ]);
37
- return decrypted.toString('utf8');
38
- }
39
-
40
-
41
- server.registerTool(
42
- "encrypt_message",
43
- {
44
- description: "Encrypt a message",
45
- inputSchema: {
46
- message: z.string().describe("The message to encrypt"),
47
- encryptionKey: z.string().describe("Any passphrase to use for encryption — the server derives a strong key from it automatically"),
48
- },
49
- outputSchema: {
50
- encryptedMessage: z.string().describe("The encrypted message (format: iv:ciphertext)"),
51
- }
52
- },
53
- async ({ message, encryptionKey }) => {
54
- try {
55
- const encryptedMessage = encrypt(message, encryptionKey);
56
- return {
57
- content: [{ type: "text", text: encryptedMessage }],
58
- structuredContent: { encryptedMessage },
59
- };
60
- } catch (err) {
61
- return {
62
- isError: true,
63
- content: [{ type: "text", text: `Failed to encrypt message! Check if the message and encryption key are correct. Error details: ${err instanceof Error ? err.message : String(err)}` }],
64
- };
65
- }
66
- },
67
- );
68
-
69
- server.registerTool(
70
- "decrypt_message",
71
- {
72
- description: "Decrypt a message that was encrypted with the encrypt_message tool",
73
- inputSchema: {
74
- encryptedMessage: z.string().describe("The encrypted message to decrypt (format: iv:ciphertext)"),
75
- encryptionKey: z.string().describe("The same passphrase used during encryption"),
76
- },
77
- outputSchema: {
78
- decryptedMessage: z.string().describe("The decrypted plain-text message"),
79
- }
80
- },
81
- async ({ encryptedMessage, encryptionKey }) => {
82
- try {
83
- const decryptedMessage = decrypt(encryptedMessage, encryptionKey);
84
- return {
85
- content: [{ type: "text", text: decryptedMessage }],
86
- structuredContent: { decryptedMessage },
87
- };
88
- } catch (err) {
89
- return {
90
- isError: true,
91
- content: [
92
- {
93
- type: "text",
94
- text: `Failed to decrypt message! Check if the encrypted message is correct and if the encryption key matches the one used for encryption. Error details: ${err instanceof Error ? err.message : String(err)}`,
95
- },
96
- ],
97
- };
98
- }
99
- },
100
- );
101
-
102
- server.registerResource(
103
- "encryption://info",
104
- "encryption://info",
105
- { description: "Describes the encryption algorithm, key requirements, and output format used by this server." },
106
- async () => ({
107
- contents: [
108
- {
109
- uri: "encryption://info",
110
- mimeType: "text/plain",
111
- text: `
112
- Algorithm : AES-256-CBC
113
- Key derivation: scrypt (passphrase + fixed server salt → 32-byte key)
114
- Output format: <16-byte IV in hex>:<ciphertext in hex> (separated by ":")
115
- Notes:
116
- - Users pass any passphrase — the server derives a strong 32-byte key automatically using scrypt.
117
- - A random IV is generated for every encryption — the same message encrypted twice will produce different output.
118
- - Use the exact same passphrase to decrypt.
119
- - Keep the full "iv:ciphertext" string to decrypt later.
120
- `.trim(),
121
- },
122
- ],
123
- }),
124
- );
125
-
126
- server.registerPrompt(
127
- "encrypt_message_prompt",
128
- {
129
- description: "Prompt to encrypt a plain-text message using the encrypt_message tool",
130
- argsSchema: {
131
- message: z.string().describe("The plain-text message to encrypt"),
132
- encryptionKey: z.string().describe("Any passphrase — the server derives a strong key automatically"),
133
- },
134
- },
135
- ({ message, encryptionKey }) => ({
136
- messages: [
137
- {
138
- role: "user",
139
- content: {
140
- type: "text",
141
- text: `Please encrypt the following message using the encrypt_message tool.\nMessage: ${message}\nEncryption key: ${encryptionKey}`,
142
- },
143
- },
144
- ],
145
- }),
146
- );
147
-
148
- server.registerPrompt(
149
- "decrypt_message_prompt",
150
- {
151
- description: "Prompt to decrypt a message using the decrypt_message tool",
152
- argsSchema: {
153
- encryptedMessage: z.string().describe("The iv:ciphertext string to decrypt"),
154
- encryptionKey: z.string().describe("The same passphrase used during encryption"),
155
- },
156
- },
157
- ({ encryptedMessage, encryptionKey }) => ({
158
- messages: [
159
- {
160
- role: "user",
161
- content: {
162
- type: "text",
163
- text: `Please decrypt the following message using the decrypt_message tool.\nEncrypted message: ${encryptedMessage}\nEncryption key: ${encryptionKey}`,
164
- },
165
- },
166
- ],
167
- }),
168
- );