Tamperbox MCP
by oceanrescue
README.md
# Tamperbox MCP
A code-mode [Model Context Protocol](https://modelcontextprotocol.io/) server for the [Tamperbox API](https://docs.tamperbox.dev/developers). Discover operation schemas, then write JavaScript to chain calls and return only the results you need.
**Two MCP tools. Eight API operations. stdio and Streamable HTTP. Node.js 22+.**
This repository implements the MCP adapter and sandbox. Transforms run on the Tamperbox API. It does not require an OpenAI or Anthropic key to start.
## Try the tools before automating
Start at [tamperbox.dev](https://tamperbox.dev) to explore the tools interactively. Trying a small example makes it easier to understand the accepted input, the output format, and why a tool returns a warning or rejects a value before asking an AI client to automate it.
The [Pipeline editor](https://tamperbox.dev/pipeline) supports all five transforms available through this MCP server:
1. Click **Load synthetic example** to load a sample JWT and a JWT → YAML workflow.
2. Click **Run next step** to inspect the decoded JSON, then run the next step to see the YAML. **Run locally** runs the whole workflow.
3. Change the input, add a step, or adjust an option and compare the output and warnings. Use the same sample with MCP to understand how the browser workflow maps to code.
The Pipeline editor runs locally in your browser without uploading its input. This MCP server sends operation inputs to the Tamperbox API. The website also contains tools and interactive features beyond this server's eight operations; use `tamperbox_discover` for the exact schemas supported by your installed MCP version.
## Available operations
Call these functions as `await tamperbox.<name>(args)` inside `tamperbox_execute`. The five transforms take an `input` artifact containing a `mediaType` and a text `value`, plus operation-specific `options`. Their result contains an `output` artifact, `warnings`, and `provenance`.
| Operation | Input and options | Expected result and behavior | Try it live |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- |
| `jwt_decode` | A three-part JWT as `application/jwt`; no keys or options. | JSON text containing the header and payload. Decoding does **not** verify the signature, expiration, or trust. | [JWT tool](https://tamperbox.dev/jwt) · [Pipeline](https://tamperbox.dev/pipeline) |
| `json_format` | JSON text as `application/json`; optional `indent` from 0–8, default 2. | Formatted JSON text. Rejects duplicate keys and unsafe numeric precision; does not validate your application schema. | [Pipeline](https://tamperbox.dev/pipeline) |
| `json_to_yaml` | JSON text as `application/json`; optional `indent` from 1–8, default 2. | YAML text as `application/yaml`. Rejects duplicate keys and unsafe numeric precision. | [Pipeline](https://tamperbox.dev/pipeline) |
| `timestamp_to_iso` | Timestamp text as `text/plain`; specify `unit` (`s`, `ms`, `us`, or `ns`) for epoch values, or supply calendar text. | ISO timestamp text with fractional precision preserved. Calendar input uses UTC unless it contains an explicit offset; no local-timezone guessing. | [Timestamp tool](https://tamperbox.dev/unix-timestamp) · [Pipeline](https://tamperbox.dev/pipeline) |
| `api_convert` | Postman/OpenAPI JSON or YAML, or POSIX cURL text; required `options.target`: `postman`, `openapi-json`, `openapi-yaml`, or `curl`. | Converted document text and warnings about limitations. Does not execute requests or fetch references. Recognized credentials are replaced by default, but secret detection is incomplete. | [API converter](https://tamperbox.dev/postman-converter) · [Pipeline](https://tamperbox.dev/pipeline) |
| `pipeline` | `version: 1`, an input artifact, and 1–20 ordered transform steps; discover its schema for selecting named outputs. | Named `outputs`, executed `steps`, warnings, and provenance from one API call. Useful for a predefined sequence of transforms. | [Pipeline](https://tamperbox.dev/pipeline) |
| `find` | Optional task keywords in `query`, or media-type filters `accepts` and `produces`. | Matching entries in `tools` plus provenance from the live API directory. Unlike MCP discovery, this makes a network request. | [Tool directory](https://tamperbox.dev) |
| `recipe` | `{ "id": "jwt-to-yaml" }`, or `{}` for the same recipe. | A recipe definition with `id`, `version`, and `steps`. Fetching it does not execute the workflow. | [Pipeline synthetic example](https://tamperbox.dev/pipeline) |
### Understand inputs and results
An artifact is `{ "mediaType": "…", "value": "…" }`. Its `value` is always **text**, including serialized JSON. This lets one operation's `output` become another operation's `input` without guessing the format. Use `JSON.stringify(data)` to send a JavaScript object as JSON text, or `JSON.parse(response.output.value)` when you need to work with a JSON result as an object.
For example, run this code through `tamperbox_execute`:
```js
const formatted = await tamperbox.json_format({
input: { mediaType: 'application/json', value: '{"example":true}' },
options: { indent: 2 },
});
return formatted.output;
```
Expected MCP result:
```json
{
"result": {
"mediaType": "application/json",
"value": "{\n \"example\": true\n}"
},
"apiCalls": 1
}
```
The operation response and the MCP result are two different layers. `formatted` also contains `warnings` and `provenance`; this example returns only its `output`. Return the whole response to retain those fields. Warnings explain limitations such as unverified JWTs or lossy conversions. Provenance identifies the provider, engine version, operation, attribution, and `editorUrl` for exploring the tool in your browser. An editor link does not automatically load your input or result.
The outer `result` is whatever your code returns. `apiCalls` counts **bridge calls attempted, including host-validation failures**; guest serialization failures are excluded. It is not a count of upstream HTTP requests. Successful MCP responses provide the same object as structured content and JSON text for client compatibility.
## Run from source
```sh
npm ci
npm run build
node dist/cli.js
```
The default stdio transport writes only MCP messages to stdout. Connect your client using `node /absolute/path/to/tamperbox-mcp/dist/cli.js`. The repository is prepared for npm distribution; the package must be published before using `npx -y tamperbox-mcp@0.1.0`.
For a one-shot shell call, pipe JavaScript into the example client:
```sh
printf 'return 6 * 7;\n' | node examples/stdio-execute.mjs
# {"result":42,"apiCalls":0}
```
The client waits for the response before disconnecting. Piping raw MCP requests directly into the server closes its stdin at EOF and cancels active work. See [shell usage](docs/integrations.md#shell-scripts-and-one-shot-calls).
For a local HTTP endpoint:
```sh
node dist/cli.js --transport http --port 3000
```
Connect to `http://127.0.0.1:3000/mcp`. `/health` returns readiness of the process, not upstream API availability. Public hosting requires HTTPS termination and explicit host configuration; see [deployment](docs/deployment.md).
## Code mode
Your AI client sees two MCP tools:
| MCP tool | Input | Result |
| -------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tamperbox_discover` | `{}` for all operations, optional `query` keywords, or `names` such as `["jwt_decode", "json_to_yaml"]`. | `operations` with descriptions, input/output schemas, and example arguments, plus `engineVersion` and usage instructions. Reads the bundled catalog without a network request. |
| `tamperbox_execute` | Required JavaScript `code`; optional `timeoutMs` from 1–30,000, default 15,000. | Your returned JSON in `result`, plus `apiCalls` (bridge calls attempted, including host-validation failures). Execution failures return an MCP error with a code, message, and available diagnostics. |
First call `tamperbox_discover` with `{"query":"json"}` or `{"names":["jwt_decode","json_to_yaml"]}`. Use the returned examples and schemas to build arguments; the website is useful for exploring behavior, while discovery defines the callable contract.
Then call `tamperbox_execute` with `code` containing an **async function body**:
```js
const decoded = await tamperbox.jwt_decode({
input: {
mediaType: 'application/jwt',
value: 'eyJhbGciOiJub25lIn0.eyJzdWIiOiJleGFtcGxlIn0.',
},
});
const yaml = await tamperbox.json_to_yaml({ input: decoded.output });
return {
output: yaml.output,
warnings: decoded.warnings,
provenance: yaml.provenance,
};
```
The result is `{ "result": <your returned JSON>, "apiCalls": 2 }`. `apiCalls` counts bridge calls attempted, including host-validation failures, against the per-execution call budget. It does not count upstream HTTP requests: validation can reject a bridge call before any request is sent. Arguments rejected during guest serialization never reach the bridge and are not counted. The field name is retained for compatibility.
Decoding a JWT does **not** verify its signature, validity or trust. API conversion does not execute requests and may lose unsupported features.
Use `await`, loops, conditionals, array methods and `Promise.all`. Batches queue automatically with at most four API calls in flight; all queued calls count toward the 20-call budget. There is no `fetch`, filesystem, `process`, package import, timer API or host environment inside the guest. `console`, `TextEncoder`, `TextDecoder`, `atob`, `btoa` and `Intl` are also unavailable. Use `return` to produce a result. An omitted return becomes `null`; cyclic, BigInt, function, symbol and non-finite results are rejected. JSON objects follow JSON serialization semantics (for example, undefined object fields are omitted). Await every API call; outstanding calls are cancelled when execution ends.
Guest failures return bounded `details.name`, `details.message` (up to 1,024 characters), and a one-based `details.line` when a source location is available. Locations account for JavaScript line terminators, including CR and Unicode separators. Incomplete code detected at the wrapper's closing line points to the last submitted line. These diagnostics are returned only to the caller and can contain values from the submitted code. Uncaught API failures identify the operation in `details.operation` (up to 64 characters), including when no guest source line is available. API failures remain redacted; guest `catch` blocks can inspect `error.operation`, `error.code`, `error.status` when available, and `error.details.validation` for input errors. The VM provides no host stack traces or raw upstream error bodies.
Operation arguments must serialize to JSON. Functions, symbols and objects whose `toJSON()` returns `undefined` produce a guest `TypeError` before dispatch and do not consume the API call budget. Omitting arguments or passing `undefined` still defaults to `{}`. Normal JSON serialization rules apply to nested properties.
The 64 MiB cap covers the guest VM’s WebAssembly linear memory, not total process RSS. Node heaps, native runtime overhead and transport buffers need additional memory. Successful MCP responses repeat the result as text and structured content for compatibility, so the 2 MiB result limit is not a limit on total HTTP/MCP message size.
## Connect an AI client
[Integration instructions](docs/integrations.md) cover ChatGPT custom MCP plugins, Codex, OpenAI Responses API, Claude Code, Claude Desktop, Anthropic Messages API, VS Code and other MCP clients. Ready-to-edit examples are in [examples](examples/).
Local stdio works from this checkout. Remote integrations need a deployed, reachable HTTPS URL for **this server**. The existing `mcp.tamperbox.dev` service is a separate implementation; this repository does not claim it is deployed there. Marketplace and registry publication require account ownership and provider review; see [release guide](docs/releasing.md).
## Data and execution limits
Code executes in a fresh QuickJS WebAssembly VM within a worker thread. Only allowlisted API calls cross the sandbox boundary. Inputs to those calls leave the machine and are sent to `https://api.tamperbox.dev` by default; code itself is not sent to that API. If you host this server remotely, the hosting server receives the code and all embedded inputs. The MCP client/model provider also sees tool requests and returned results. This server does not persist or log code, inputs or outputs; hosting/proxy and provider logging policies are separate.
| Limit | Default |
| ---------------------------------------------------- | ------------------------------------------------------------ |
| Code / input to each API call | 64 KiB / 1 MiB, measured as UTF-8 |
| Result / each API response | 2 MiB serialized JSON |
| JSON nesting | 40 levels |
| Wall-clock execution | 15 seconds, selectable from 1–30,000 ms |
| Upstream request | 10 seconds, no automatic retries or redirects |
| API calls per execution / parallel calls | 20 / 4 |
| Active code executions per process | 4 |
| QuickJS allocator budget / stack | 32 MiB / 512 KiB |
| Hard WebAssembly linear-memory ceiling per execution | 64 MiB, including ArrayBuffer and typed-array backing stores |
| HTTP requests per minute / active requests | 120 / 16, per process |
| HTTP request body / body read deadline | 1 MiB / 5 seconds |
See [security](SECURITY.md) for boundaries and [architecture](docs/architecture.md) for implementation details. Use browser-local Tamperbox tools for sensitive material you cannot send to a remote API.
## Develop and verify
```sh
npm ci
npm run check
npm run test:live # opt-in: calls all eight public API operations with synthetic data
```
Tests cover contracts, real stdio and HTTP MCP clients, API errors, sandbox escapes, cancellation, resource limits and packaging. Coverage gates apply to in-process host modules; the CLI and VM worker are verified through separate processes and are not included in that percentage. The default suite is offline except for loopback HTTP; it never needs model-provider credentials. See [testing](docs/testing.md) and the [verification record](docs/verification.md).
MIT licensed. Contributions should include a failing regression test before the fix; see [CONTRIBUTING.md](CONTRIBUTING.md).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues