metaphi command line, or from your own agent (Claude Code, Codex, Cursor, Hum, or any MCP client).
From the command line
Install the CLI and make an organization key once:<name>.twin<ext> beside the input, or where -o says. From a server, set METAPHI_API_KEY to an organization key and add --json to print {"output"} on stdout.
From your agent
1. Connect
Add the server to your agent. In Claude Code:https://kennet.metaphi.ai/mcp/.
2. Sign in
Authenticate the server from your agent (in Claude Code:/mcp, choose kennet, then Authenticate). Your browser opens on app.metaphi.ai. Sign in with Google or GitHub.
The first time, your account has no access yet: choose Request access. You get an email when it is approved; then authenticate again and choose Allow. Access is the kennet:twin scope.
Your agent now lists five tools: upload_trace, twin_trace, pull_trace, get_task and cancel_task.
3. Twin a trace
Ask your agent in plain words, from the directory that holds the file:curl command and an upload_id. Your agent runs the command in your shell, which uploads the file. The URL answers for 10 minutes. A trace is JSON, JSON Lines or text.
get_task until it ends; a trace takes a few minutes. The result carries output_path, or the reason the run failed.
curl command that downloads the twin into your working directory.
twin_trace takes the same options as the command line: key (64 hex characters) and confidential (a list of organisations).
What is replaced
After the replacement a second reader, shown only the twin, looks for anything still real, and one repair round follows.
Keep the key if you will twin more traces of the same corpus later. Kennet does not keep it.
Credits
Each completed trace draws your organization’s prepaid credit. A run that fails costs nothing. When the balance reaches zero, new runs are refused until credit is added (metaphi credits).
What Kennet keeps
- Your upload is deleted when its run ends, whether it completed or failed. An upload never run is deleted after a day.
- The twin stays under your account for 7 days; nobody else’s account reaches it.
- The table of what became what is neither returned nor stored.
Errors
Every error carries a stablecode. Switch on the code, never on the message text: messages may be reworded, but a code is never renamed or reused.
A refused call comes back flagged isError. Its text is the message, and its structured content is the error object:
get_task as {run_id, status: "failed", error}. The error is the same object, with the run_id added.
retryable says whether the same call, made again unchanged later, may succeed. For a run error, it means a fresh upload of the same trace may succeed. Quote the request_id when you contact support.
The command line raises one class per
type (BillingError, RateLimitError, and so on) and prints error: <message> (code: <code>, request: <request_id>). With --json, it also prints the error object on stdout.