The solution involves creating a new entry point in the src/node/ directory that functions as the MCP Server. This server interfaces with the existing CyberChef Core Node API (src/node/index.mjs) to execute operations.
graph TD
A[MCP Client AI/IDE] -->|Stdio/HTTP| B[Transport Layer]
B -->|Routes| C[CyberChef MCP Server]
C -->|Imports| D[CyberChef Node API]
D -->|Uses| E[CyberChef Core]
E -->|Config| F[OperationConfig.json]
E -->|Logic| G[Operations]
C -->|Offloads| H[Worker Thread Pool]
- Role: Handles the MCP protocol connection (stdio transport).
- Dependencies:
@modelcontextprotocol/sdk,zod. - Responsibilities:
- Initialize the MCP server instance.
- Load
OperationConfigandCategoriesto discover available operations. - Register the
listToolshandler. - Register the
callToolhandler. - Translate MCP tool calls into CyberChef
bake()calls.
There are two layers of tools provided:
Direct access to the core bake function.
- Input:
input: The string/data to process.recipe: A JSON array describing the operations (e.g.,[{"op": "From Base64"}, {"op": "Gunzip"}]).
- Output: Result string and type information.
Programmatically generated tools for every supported CyberChef operation.
- Name: Normalized operation name (e.g., "AES Decrypt" ->
cyberchef_aes_decrypt). - Description: Taken from
OperationConfig.description. - Arguments: Mapped from
OperationConfig.args.type: "option"-> Zod Enum.type: "string"-> Zod String.type: "number"-> Zod Number.type: "boolean"-> Zod Boolean.
- Execution: Internally constructs a single-step recipe and calls
bake().
A specialized Docker build for the server.
- Base: Chainguard distroless Node.js 22 (
cgr.dev/chainguard/node:latest). - Context: Multi-stage build; copies
src/,package.json. - Command:
node src/node/mcp-server.mjs. - Security: Non-root (UID 65532), zero-CVE baseline, read-only filesystem support.
- Discovery: Client requests
listTools. Server iteratesOperationConfigand generates tool schemas. - Invocation: Client calls
cyberchef_to_base64({ input: "hello" }). - Translation: Server maps this to a recipe:
[{ op: "To Base64", args: [] }]. - Execution: Server calls
CyberChef.bake("hello", recipe). - Response: Server returns the output string to the Client.