@erickwendel/ciphersuite-mcp 0.0.2 → 0.0.3
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/package.json +5 -1
- package/src/index.ts +0 -0
- package/.github/agents/developer.agent.md +0 -79
- package/.vscode/mcp-local.json +0 -8
- package/.vscode/mcp.json +0 -8
- package/refs.txt +0 -1
- package/tests/helpers.ts +0 -19
- package/tests/mcp.test.ts +0 -109
- package/tsconfig.json +0 -26
package/package.json
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@erickwendel/ciphersuite-mcp",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ciphersuite-mcp": "./src/index.ts"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
9
12
|
"scripts": {
|
|
13
|
+
"build": "chmod 755 src/index.ts",
|
|
10
14
|
"start": "node src/index.ts",
|
|
11
15
|
"dev": "node --watch --inspect src/index.ts",
|
|
12
16
|
"test": "node --test tests/**/*.test.ts",
|
package/src/index.ts
CHANGED
|
File without changes
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Node.js + TypeScript coding agent. Implements features, fixes bugs, and refactors with test-driven discipline. Uses SOLID principles, dependency injection, and immutable patterns. LLM prompts in files, all external calls mocked in tests.
|
|
3
|
-
tools: ['vscode', 'execute', 'read', 'edit', 'search', 'web', 'agent', 'context7/*', 'todo']
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## Mission
|
|
7
|
-
|
|
8
|
-
Make minimal, safe edits that are proven by tests.
|
|
9
|
-
|
|
10
|
-
## Success Criteria
|
|
11
|
-
|
|
12
|
-
A task is done when:
|
|
13
|
-
0. Typescript types don't show errors / no warnings
|
|
14
|
-
1. Relevant test file(s) pass
|
|
15
|
-
2. Full test suite passes
|
|
16
|
-
3. User acceptance criteria met
|
|
17
|
-
|
|
18
|
-
## Scope
|
|
19
|
-
|
|
20
|
-
**Will do:**
|
|
21
|
-
- Implement features with tests
|
|
22
|
-
- Fix bugs with regression tests
|
|
23
|
-
- Refactor while preserving behavior
|
|
24
|
-
- Integrate LLM features (prompts in files, mocked in tests)
|
|
25
|
-
|
|
26
|
-
**Won't do:**
|
|
27
|
-
- Introduce unsafe patterns (`eval`, shell injection, secrets in logs)
|
|
28
|
-
- Proceed with ambiguous requirements (will ask questions first)
|
|
29
|
-
- Add dependencies without justification
|
|
30
|
-
- Reorganize files unless requested
|
|
31
|
-
- Move Typescript types to separate files (keep types co-located, never create a types.ts)
|
|
32
|
-
- Don't create index.ts files to re-export modules
|
|
33
|
-
|
|
34
|
-
## Required User Inputs
|
|
35
|
-
|
|
36
|
-
Ask if missing:
|
|
37
|
-
- Acceptance criteria and expected behavior
|
|
38
|
-
- Current vs expected behavior (for bugs)
|
|
39
|
-
- Constraints (Node version, environment)
|
|
40
|
-
|
|
41
|
-
## Core Principles
|
|
42
|
-
|
|
43
|
-
### Code Design
|
|
44
|
-
- **Immutability**: Pure functions, no mutations, side effects at edges
|
|
45
|
-
- **Single Responsibility**: One clear purpose per module/function/file
|
|
46
|
-
- **Dependency Injection**: Pass dependencies via constructors/parameters
|
|
47
|
-
- **Type Safety**: Explicit types, avoid `any`, co-locate with code
|
|
48
|
-
|
|
49
|
-
### Configuration
|
|
50
|
-
- Store all env vars and static values in config files
|
|
51
|
-
- No hardcoded values in business logic
|
|
52
|
-
|
|
53
|
-
### LLM Integration
|
|
54
|
-
- Prompts in files (`prompts/*.txt`), never inline
|
|
55
|
-
- All LLM calls through injected interface (e.g., `LLMClient`)
|
|
56
|
-
- Mock LLM responses deterministically in tests
|
|
57
|
-
|
|
58
|
-
### Testing (Node.js test runner)
|
|
59
|
-
- Use `node:test` with `node:assert/strict`
|
|
60
|
-
- Use fixures files for case scenarios
|
|
61
|
-
- Test the full pipeline end-to-end
|
|
62
|
-
- Mock only external boundaries (HTTP, LLM, DB)
|
|
63
|
-
- Run targeted tests first, then full suite
|
|
64
|
-
|
|
65
|
-
### Security
|
|
66
|
-
- Treat all input as untrusted
|
|
67
|
-
- Validate and sanitize appropriately
|
|
68
|
-
- Never log or expose secrets
|
|
69
|
-
|
|
70
|
-
## Workflow
|
|
71
|
-
|
|
72
|
-
For each task:
|
|
73
|
-
1. **Plan**: Brief summary of what changes and why
|
|
74
|
-
2. **Edit**: Minimal modifications to existing files
|
|
75
|
-
3. **Test**: Add/update tests, run targeted suite
|
|
76
|
-
4. **Verify**: Run full test suite
|
|
77
|
-
5. **Summary**: Note tradeoffs or follow-ups
|
|
78
|
-
|
|
79
|
-
Ask clarifying questions when behavior, security, or architecture is unclear.
|
package/.vscode/mcp-local.json
DELETED
package/.vscode/mcp.json
DELETED
package/refs.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
https://modelcontextprotocol.io/docs/tools/inspector
|
package/tests/helpers.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
|
|
2
|
-
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
|
|
3
|
-
|
|
4
|
-
export async function createTestClient () {
|
|
5
|
-
const transport = new StdioClientTransport({
|
|
6
|
-
command: 'node',
|
|
7
|
-
args: ['--experimental-strip-types', 'src/index.ts']
|
|
8
|
-
})
|
|
9
|
-
|
|
10
|
-
const client = new Client({
|
|
11
|
-
name: 'test-client',
|
|
12
|
-
version: '1.0.0'
|
|
13
|
-
}, {
|
|
14
|
-
capabilities: {}
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
await client.connect(transport)
|
|
18
|
-
return client
|
|
19
|
-
}
|
package/tests/mcp.test.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { describe, it, after, before } from 'node:test'
|
|
2
|
-
import assert from 'node:assert'
|
|
3
|
-
import { createTestClient,} from './helpers.ts'
|
|
4
|
-
import { Client } from '@modelcontextprotocol/sdk/client'
|
|
5
|
-
|
|
6
|
-
async function encryptMessage(client: Client, message: string, key: string) {
|
|
7
|
-
const result = await client.callTool({
|
|
8
|
-
name: "encrypt_message",
|
|
9
|
-
arguments: {
|
|
10
|
-
message,
|
|
11
|
-
encryptionKey: key
|
|
12
|
-
}
|
|
13
|
-
}) as unknown as { structuredContent: { encryptedMessage: string } }
|
|
14
|
-
|
|
15
|
-
return result
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe('MCP Tool Tests', async () => {
|
|
19
|
-
let client: Client;
|
|
20
|
-
let key: string;
|
|
21
|
-
|
|
22
|
-
before(async () => {
|
|
23
|
-
client = await createTestClient()
|
|
24
|
-
key = 'my-super-secret-passphrase';
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
after(async () => {
|
|
28
|
-
await client.close()
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('should encrypt a message', async () => {
|
|
32
|
-
const message = "Hello, World!"
|
|
33
|
-
const result = await encryptMessage(client, message, key)
|
|
34
|
-
|
|
35
|
-
assert.ok(result.structuredContent.encryptedMessage.length > 60, 'Encrypted message should not be empty')
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('should decrypt a message', async () => {
|
|
39
|
-
|
|
40
|
-
const message = "Hello, World!"
|
|
41
|
-
const encryptedMessage = (await encryptMessage(client, message, key)).structuredContent.encryptedMessage
|
|
42
|
-
|
|
43
|
-
const result = await client.callTool({
|
|
44
|
-
name: "decrypt_message",
|
|
45
|
-
arguments: {
|
|
46
|
-
encryptedMessage: encryptedMessage,
|
|
47
|
-
encryptionKey: key
|
|
48
|
-
}
|
|
49
|
-
}) as unknown as { structuredContent: { decryptedMessage: string } }
|
|
50
|
-
|
|
51
|
-
assert.strictEqual(result.structuredContent.decryptedMessage, message, 'Decrypted message should match original')
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should list the encryption://info resource', async () => {
|
|
55
|
-
const { resources } = await client.listResources()
|
|
56
|
-
const info = resources.find(r => r.uri === 'encryption://info')
|
|
57
|
-
assert.ok(info, 'encryption://info resource should be listed')
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('should read the encryption://info resource', async () => {
|
|
61
|
-
const result = await client.readResource({ uri: 'encryption://info' })
|
|
62
|
-
const content = result.contents[0]
|
|
63
|
-
assert.ok(content, 'Resource should have content')
|
|
64
|
-
assert.ok('text' in content && typeof content.text === 'string' && content.text.includes('AES-256-CBC'), 'Resource should describe the algorithm')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('should return the encrypt_message_prompt', async () => {
|
|
68
|
-
const result = await client.getPrompt({
|
|
69
|
-
name: 'encrypt_message_prompt',
|
|
70
|
-
arguments: { message: 'Secret text', encryptionKey: key }
|
|
71
|
-
})
|
|
72
|
-
const text = result.messages[0].content
|
|
73
|
-
assert.ok('text' in text && text.text.includes('encrypt_message'), 'Prompt should reference the encrypt_message tool')
|
|
74
|
-
assert.ok('text' in text && text.text.includes('Secret text'), 'Prompt should include the message')
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should return the decrypt_message_prompt', async () => {
|
|
78
|
-
const encryptedMessage = (await encryptMessage(client, 'Prompt test', key)).structuredContent.encryptedMessage
|
|
79
|
-
const result = await client.getPrompt({
|
|
80
|
-
name: 'decrypt_message_prompt',
|
|
81
|
-
arguments: { encryptedMessage, encryptionKey: key }
|
|
82
|
-
})
|
|
83
|
-
const text = result.messages[0].content
|
|
84
|
-
assert.ok('text' in text && text.text.includes('decrypt_message'), 'Prompt should reference the decrypt_message tool')
|
|
85
|
-
assert.ok('text' in text && text.text.includes(encryptedMessage), 'Prompt should include the encrypted message')
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should return isError when decrypting with wrong passphrase', async () => {
|
|
89
|
-
const encryptedMessage = (await encryptMessage(client, 'Secret', key)).structuredContent.encryptedMessage
|
|
90
|
-
|
|
91
|
-
const result = await client.callTool({
|
|
92
|
-
name: 'decrypt_message',
|
|
93
|
-
arguments: { encryptedMessage, encryptionKey: 'wrong-passphrase' }
|
|
94
|
-
}) as unknown as { isError: boolean; content: { type: string; text: string }[] }
|
|
95
|
-
|
|
96
|
-
assert.strictEqual(result.isError, true, 'Should return isError: true')
|
|
97
|
-
assert.ok(result.content[0].text.includes('Failed to decrypt'), 'Error message should describe the failure')
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('should return isError when decrypting a malformed message', async () => {
|
|
101
|
-
const result = await client.callTool({
|
|
102
|
-
name: 'decrypt_message',
|
|
103
|
-
arguments: { encryptedMessage: 'not-valid-ciphertext', encryptionKey: key }
|
|
104
|
-
}) as unknown as { isError: boolean; content: { type: string; text: string }[] }
|
|
105
|
-
|
|
106
|
-
assert.strictEqual(result.isError, true, 'Should return isError: true')
|
|
107
|
-
assert.ok(result.content[0].text.includes('Failed to decrypt'), 'Error message should describe the failure')
|
|
108
|
-
})
|
|
109
|
-
})
|
package/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"lib": [
|
|
6
|
-
"ES2022"
|
|
7
|
-
],
|
|
8
|
-
"moduleResolution": "bundler",
|
|
9
|
-
"allowImportingTsExtensions": true,
|
|
10
|
-
"noEmit": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"strict": true,
|
|
14
|
-
"skipLibCheck": true,
|
|
15
|
-
"resolveJsonModule": true,
|
|
16
|
-
"isolatedModules": true,
|
|
17
|
-
"allowSyntheticDefaultImports": true,
|
|
18
|
-
"types": [
|
|
19
|
-
"node"
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
"exclude": [
|
|
23
|
-
"node_modules",
|
|
24
|
-
"dist"
|
|
25
|
-
]
|
|
26
|
-
}
|