Agents
Five tools, three surfaces
MCP server, Pi extension and OMP extension all call the same executors in src/tool-operations.ts. They answer identically and a fix lands once, which is the whole reason the file exists.
| Tool | Does | Arguments |
|---|---|---|
cipher_encode | Encode with a cipher named exactly | cipher, text, plus the cipher's options |
cipher_decode | Decode with a cipher named exactly | same |
cipher_brute_caesar | Every shift from 1 to 25 | text |
cipher_frequency | Histogram and index of coincidence | text, language |
cipher_info | List the ciphers, or one cipher's options | cipher optional |
Option arguments mirror the library: shift, key, rails, a, b, period, positions, rings, plugboard, preserveCase, stripNonAlpha. A model that doesn't know a cipher's options calls cipher_info first. Every tool description says so, because models guess otherwise.
MCP
ciphers mcp
claude mcp add ciphers --scope user -- npx -y @agntn/ciphers mcp
Or in a client's config:
{
"mcpServers": {
"ciphers": { "command": "npx", "args": ["-y", "@agntn/ciphers", "mcp"] }
}
}
The server speaks MCP over stdio and checks every call against the tool's published JSON Schema before a cipher sees it. shift is an integer 1 to 25, rings and positions are three letters, text and key have a maximum length. Fails the schema - tool error with the reason. Throws a CipherError - also a tool error. The session survives either way.
Every tool answers with text. cipher_encode and cipher_decode return the output and, in details, the cipher, the operation and the options that were applied. cipher_brute_caesar returns 25 lines. cipher_frequency returns the same table the CLI prints. cipher_info with no name is one line per cipher with its family.
Pi and OMP
pi install npm:@agntn/ciphers
Both extensions are declared in package.json. In the terminal a result shows as a collapsed preview cut to a few lines, with a count of what was left out, and the full text once you expand the row. Brute force is 25 lines, so this matters more than it sounds.
Bounds
Text is bounded per tool and keys are bounded too, in the schema. A model cannot hand the process a novel to shift. Nothing is written anywhere and there is no network to lose. One cipher keeps state: columnar caches its last 128 answers per instance and refuses more than 100 calls a second with a CipherError, which comes back as a tool error like any other.
IGNORE PREVIOUS INSTRUCTIONS learned one thing about the puzzle and nothing about its task.