X-TKN MCP server
Lets an AI agent hand a secret to a person as a one-time link, with no way to read it back.
npx -y @fennecstudio/x-tkn-mcp
- No read tool. The server has
create_secret, check_status,
revoke_secret and claim_sandbox. Once a secret is handed over, the agent
can see whether it was opened and can cancel it. It cannot see the secret
again.
- Encrypted on your machine.
create_secret encrypts with AES-256-GCM
before anything is sent. X-TKN stores only ciphertext. The key travels in the
link's #fragment, which browsers never send to a server.
- Up to 256 KB per secret: 64 KB on the free Developer plan, 256 KB on Team
and Enterprise. Enough for a certificate bundle or a
.env file, not just a
password.
It runs locally over stdio for a reason. A hosted MCP server would receive the
plaintext before encrypting it, and the whole point is that nobody but the
recipient can read it.
Setup
You need Node 20 or later. An X-TKN API key is optional.
With no key, the server starts a sandbox on its first tool call, with no
signup. Nothing is minted at startup. The key is saved in
$XDG_CONFIG_HOME/x-tkn/sandbox.json (~/.config/x-tkn/sandbox.json by
default), the directory 0700 and the file 0600, and later starts reuse it until
it expires. The key never appears in a tool result or in the server's log.
Servers that start together share one sandbox: while one mints, it holds a
sandbox.json.lock beside the file, and the others wait for it and use its key.
- A sandbox lasts 24 hours, and so does every secret it creates:
create_secret refuses an expiresIn that runs past the sandbox's end.
Every result on a sandbox key ends with a line giving that end.
- When it ends, the next call starts a new sandbox and says so. Codes from the
old one no longer work with
check_status or revoke_secret.
- To keep a sandbox, call
claim_sandbox. It returns a one-time link for the
person who should keep it, and the key never leaves this machine. A sandbox
has to be claimed before it can be upgraded. The sandbox key still ends on
schedule after a claim, so a claimed account goes on with a Developer key
created for it and set here.
- Once a sandbox has spent its operations, the server does not start another,
because that would lose the old one's codes. Call
claim_sandbox, or set a
key.
For a key that stays, Developer keys are free: sign up at
x-tkn.com and create one in the account console. A key in
X_TKN_API_KEY always wins: then nothing is minted and nothing is written.
Claude Code
claude mcp add x-tkn -- npx -y @fennecstudio/x-tkn-mcp
claude mcp add x-tkn -e X_TKN_API_KEY=your-key -- npx -y @fennecstudio/x-tkn-mcp
Claude Desktop, Cursor, Windsurf and other clients take the same block in
their MCP config file. Leave env out for a sandbox:
{
"mcpServers": {
"x-tkn": {
"command": "npx",
"args": ["-y", "@fennecstudio/x-tkn-mcp"],
"env": { "X_TKN_API_KEY": "your-key" }
}
}
}
Tools
create_secret
Encrypts a secret and returns a link that opens it once.
secret | yes | The text to hand over. |
expiresIn | no | { days, hours, minutes }. Defaults to the plan's: 7 days on Developer, 30 on Team. On a sandbox key, defaults to the sandbox's end and cannot be later. |
passphrase | no | The recipient has to type this before the secret opens. 8 to 256 characters. Team and above. |
recipientEmail | no | The recipient has to enter a 6-digit code sent to this address. Team and above. Not with passphrase. |
note | no | For your own records in the X-TKN console. Stored unencrypted and never shown to the recipient. |
Returns the link, a code for check_status and revoke_secret, and
expiresAt.
Send a passphrase by a different channel than the link. Anyone holding both can
open the secret.
check_status
Takes the code. Returns waiting, opened, expired or revoked, with
openedAt once it has been opened. It never returns the secret.
Each call is one metered operation, and a sandbox has 100 in all. Call it no
more often than every 30 seconds: at one call every 5 seconds, a link nobody
opens spends a whole sandbox in under nine minutes.
revoke_secret
Takes the code. Stops the link working, immediately and for good. A secret
that was already opened stays opened.
claim_sandbox
Takes no arguments. Returns a claimUrl and its expiresAt: a one-time link a
person opens to claim the sandbox this server's key belongs to, so the account
outlives its 24 hours. Claiming keeps the sandbox's secrets.
Give the link only to the person who should keep the sandbox. It works once,
until expiresAt: 30 minutes, or the sandbox's end if that is sooner. Calling
claim_sandbox again voids the earlier link. It is not metered.
The sandbox key still ends when the sandbox would have, claimed or not. For a
key that lasts, create a Developer key for the account in the account console
and set X_TKN_API_KEY. On a key that is not an unclaimed sandbox (one already
claimed, merged into another account or ended, or a Developer key), it says so
and claims nothing.
What X-TKN sees
The ciphertext, the expiry, your note, and, if you set them, a hash of the
passphrase or the recipient's email address. The passphrase gates the link and
plays no part in the encryption. X-TKN never receives the plaintext or the key.
Opening the link uses it up, so give it only to the person it is for. The
retrieval page takes the key out of the address bar after it decrypts the
secret. If opening fails, the full link, key included, stays in that browser's
history.
Publishing
For whoever ships a release. Run these in order, from this directory. The
registry steps read what npm holds, so none of them can come before the first.
Keep one version everywhere: version in package.json, VERSION in
src/version.ts, and both version fields in server.json. Specs fail when
they disagree. Keep server.json's description equal to the first paragraph
of this README, and no longer than 100 characters, which is the registry's limit.
-
npm. npm run deploy -- --otp=<code>. That is npm publish, and
prepublishOnly typechecks, tests and builds first. It goes first because
the registry reads mcpName out of the published package, and npm will not
take the same version twice.
-
Official MCP Registry. Install the CLI with brew install mcp-publisher,
then:
mcp-publisher login github
mcp-publisher publish
Log in as an Owner of the fennecstudio GitHub organization. The registry
grants io.github.fennecstudio/* to its owners only, and an ordinary member
is refused. Check it landed with
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.fennecstudio/x-tkn-mcp".
-
Smithery. smithery mcp publish. It does not run bare: Smithery takes a
server URL or a pre-built .mcpb bundle, and -n <org>/<server>. This
package serves no URL and builds no bundle, so read smithery mcp publish --help
and Smithery's publishing docs for the current form before running it.
-
Glama and PulseMCP. Both crawl on their own, so there is nothing to
submit. Once the listing appears, claim it on each site.
Links