A Rust-based Model Context Protocol (MCP) server that exposes a V8 JavaScript runtime as a tool for AI agents like Claude and Cursor. Supports persistent heap snapshots via S3 or local filesystem, and is ready for integration with modern AI development environments. - V8 JavaScript Execution: Run arbitrary JavaScript code in a secure, isolated V8 engine. - TypeScript Support: Run TypeScript code d
Add this skill
npx mdskills install r33drichards/mcp-jsProduction-ready V8 runtime with excellent storage flexibility, transport options, and clustering
1# mcp-v8: V8 JavaScript MCP Server23A Rust-based Model Context Protocol (MCP) server that exposes a V8 JavaScript runtime as a tool for AI agents like Claude and Cursor. Supports persistent heap snapshots via S3 or local filesystem, and is ready for integration with modern AI development environments.45## Features67- **V8 JavaScript Execution**: Run arbitrary JavaScript code in a secure, isolated V8 engine.8- **TypeScript Support**: Run TypeScript code directly — types are stripped before execution using [SWC](https://swc.rs/). This is type removal only, not type checking.9- **Content-Addressed Heap Snapshots**: Persist and restore V8 heap state between runs using content-addressed storage, supporting both S3 and local file storage.10- **Stateless Mode**: Optional mode for fresh executions without heap persistence, ideal for serverless environments.11- **MCP Protocol**: Implements the Model Context Protocol for seamless tool integration with Claude, Cursor, and other MCP clients.12- **Configurable Storage**: Choose between S3, local directory, or stateless mode at runtime.13- **Multiple Transports**: Supports stdio, Streamable HTTP (MCP 2025-03-26+), and SSE (Server-Sent Events) transport protocols.14- **Clustering**: Optional Raft-based clustering for distributed coordination, replicated session logging, and horizontal scaling.15- **Concurrency Control**: Configurable concurrent V8 execution limits with semaphore-based throttling.1617## Installation1819Install `mcp-v8` using the provided install script:2021```bash22curl -fsSL https://raw.githubusercontent.com/r33drichards/mcp-js/main/install.sh | sudo bash23```2425This will automatically download and install the latest release for your platform to `/usr/local/bin/mcp-v8` (you may be prompted for your password).2627---2829*Advanced users: If you prefer to build from source, see the [Build from Source](#build-from-source) section at the end of this document.*3031## Command Line Arguments3233`mcp-v8` supports the following command line arguments:3435### Storage Options3637- `--s3-bucket <bucket>`: Use AWS S3 for heap snapshots. Specify the S3 bucket name. (Conflicts with `--stateless`)38- `--cache-dir <path>`: Local filesystem cache directory for S3 write-through caching. Reduces latency by caching snapshots locally. (Requires `--s3-bucket`)39- `--directory-path <path>`: Use a local directory for heap snapshots. Specify the directory path. (Conflicts with `--stateless`)40- `--stateless`: Run in stateless mode - no heap snapshots are saved or loaded. Each JavaScript execution starts with a fresh V8 isolate. (Conflicts with `--s3-bucket` and `--directory-path`)4142**Note:** For heap storage, if neither `--s3-bucket`, `--directory-path`, nor `--stateless` is provided, the server defaults to using `/tmp/mcp-v8-heaps` as the local directory.4344### Transport Options4546- `--http-port <port>`: Enable Streamable HTTP transport (MCP 2025-03-26+) on the specified port. Serves the MCP endpoint at `/mcp` and a plain API at `/api/exec`. If not provided, the server uses stdio transport (default). (Conflicts with `--sse-port`)47- `--sse-port <port>`: Enable SSE (Server-Sent Events) transport on the specified port. Exposes `/sse` for the event stream and `/message` for client requests. (Conflicts with `--http-port`)4849### Execution Limits5051- `--heap-memory-max <megabytes>`: Maximum V8 heap memory per isolate in megabytes (1–64, default: 8).52- `--execution-timeout <seconds>`: Maximum execution timeout in seconds (1–300, default: 30).53- `--max-concurrent-executions <n>`: Maximum number of concurrent V8 executions (default: CPU core count). Controls how many JavaScript executions can run in parallel.5455### Session Logging5657- `--session-db-path <path>`: Path to the sled database used for session logging (default: `/tmp/mcp-v8-sessions`). Only applies in stateful mode. (Conflicts with `--stateless`)5859### Cluster Options6061These options enable Raft-based clustering for distributed coordination and replicated session logging.6263- `--cluster-port <port>`: Port for the Raft cluster HTTP server. Enables cluster mode when set. (Requires `--http-port` or `--sse-port`)64- `--node-id <id>`: Unique node identifier within the cluster (default: `node1`).65- `--peers <peers>`: Comma-separated list of seed peer addresses. Format: `id@host:port` or `host:port`. Peers can also join dynamically via `POST /raft/join`.66- `--join <address>`: Join an existing cluster by contacting this seed address (`host:port`). The node registers itself with the cluster leader.67- `--advertise-addr <addr>`: Advertise address for this node (`host:port`). Used for peer discovery and write forwarding. Defaults to `<node-id>:<cluster-port>`.68- `--heartbeat-interval <ms>`: Raft heartbeat interval in milliseconds (default: 100).69- `--election-timeout-min <ms>`: Minimum election timeout in milliseconds (default: 300).70- `--election-timeout-max <ms>`: Maximum election timeout in milliseconds (default: 500).7172## Quick Start7374After installation, you can run the server directly. Choose one of the following options:7576### Stdio Transport (Default)7778```bash79# Use S3 for heap storage (recommended for cloud/persistent use)80mcp-v8 --s3-bucket my-bucket-name8182# Use local filesystem directory for heap storage (recommended for local development)83mcp-v8 --directory-path /tmp/mcp-v8-heaps8485# Use stateless mode - no heap persistence (recommended for one-off computations)86mcp-v8 --stateless87```8889### HTTP Transport (Streamable HTTP)9091The HTTP transport uses the Streamable HTTP protocol (MCP 2025-03-26+), which supports bidirectional communication over standard HTTP. The MCP endpoint is served at `/mcp`:9293```bash94# Start HTTP server on port 8080 with local filesystem storage95mcp-v8 --directory-path /tmp/mcp-v8-heaps --http-port 80809697# Start HTTP server on port 8080 with S3 storage98mcp-v8 --s3-bucket my-bucket-name --http-port 808099100# Start HTTP server on port 8080 in stateless mode101mcp-v8 --stateless --http-port 8080102```103104The HTTP transport also exposes a plain HTTP API at `POST /api/exec` for direct JavaScript execution without MCP framing.105106The HTTP transport is useful for:107- Network-based MCP clients108- Load-balanced and horizontally-scaled deployments109- Testing and debugging with tools like the MCP Inspector110- Containerized deployments111- Remote MCP server access112113### SSE Transport114115Server-Sent Events (SSE) transport for streaming responses:116117```bash118# Start SSE server on port 8081 with local filesystem storage119mcp-v8 --directory-path /tmp/mcp-v8-heaps --sse-port 8081120121# Start SSE server on port 8081 in stateless mode122mcp-v8 --stateless --sse-port 8081123```124125## Stateless vs Stateful Mode126127### Stateless Mode (`--stateless`)128129Stateless mode runs each JavaScript execution in a fresh V8 isolate without any heap persistence.130131**Benefits:**132- **Faster execution**: No snapshot creation/serialization overhead133- **No storage I/O**: Doesn't read or write heap files134- **Fresh isolates**: Every JS execution starts clean135- **Perfect for**: One-off computations, stateless functions, serverless environments136137**Example use case:** Simple calculations, data transformations, or any scenario where you don't need to persist state between executions.138139### Stateful Mode (default)140141Stateful mode persists the V8 heap state between executions using content-addressed storage backed by either S3 or local filesystem.142143Each execution returns a `heap` content hash (a 64-character SHA-256 hex string) that identifies the snapshot. Pass this hash in the next `run_js` call to resume from that state. Omit `heap` to start a fresh session.144145**Benefits:**146- **State persistence**: Variables and objects persist between runs147- **Content-addressed**: Snapshots are keyed by their SHA-256 hash — no naming collisions, safe concurrent access, and natural deduplication148- **Immutable snapshots**: Once written, a snapshot at a given hash never changes149- **Perfect for**: Interactive sessions, building up complex state over time150151**Example use case:** Building a data structure incrementally, maintaining session state, or reusing expensive computations.152153#### Named Sessions154155You can tag executions with a human-readable **session name** by passing the `session` parameter to `run_js`. When a session name is provided, the server logs each execution (input heap, output heap, code, and timestamp) to an embedded sled database.156157Two additional tools are available in stateful mode for browsing session history:158159- **`list_sessions`** — Returns an array of all session names that have been used.160- **`list_session_snapshots`** — Returns the log entries for a given session. Accepts a required `session` parameter and an optional `fields` parameter (comma-separated) to select specific fields: `index`, `input_heap`, `output_heap`, `code`, `timestamp`.161162The session database path defaults to `/tmp/mcp-v8-sessions` and can be overridden with `--session-db-path`.163164**Example workflow:**1651661. Call `run_js` with `code: "var x = 1; x;"` and `session: "my-project"` — the execution is logged.1672. Pass the returned `heap` hash and `session: "my-project"` in subsequent calls to continue and log the session.1683. Call `list_sessions` to see `["my-project"]`.1694. Call `list_session_snapshots` with `session: "my-project"` to see the full execution history.170171## Integration172173### Claude for Desktop1741751. Install the server as above.1762. Open Claude Desktop → Settings → Developer → Edit Config.1773. Add your server to `claude_desktop_config.json`:178179**Stateful mode with S3:**180```json181{182 "mcpServers": {183 "js": {184 "command": "mcp-v8",185 "args": ["--s3-bucket", "my-bucket-name"]186 }187 }188}189```190191**Stateful mode with local filesystem:**192```json193{194 "mcpServers": {195 "js": {196 "command": "mcp-v8",197 "args": ["--directory-path", "/tmp/mcp-v8-heaps"]198 }199 }200}201```202203**Stateless mode:**204```json205{206 "mcpServers": {207 "js": {208 "command": "mcp-v8",209 "args": ["--stateless"]210 }211 }212}213```2142154. Restart Claude Desktop. The new tools will appear under the hammer icon.216217### Claude Code CLI218219Add the MCP server to Claude Code using the `claude mcp add` command:220221**Stdio transport (local):**222```bash223# Stateful mode with local filesystem224claude mcp add mcp-v8 -- mcp-v8 --directory-path /tmp/mcp-v8-heaps225226# Stateless mode227claude mcp add mcp-v8 -- mcp-v8 --stateless228```229230**SSE transport (remote):**231```bash232claude mcp add mcp-v8 -t sse https://mcp-js-production.up.railway.app/sse233```234235Then test by running `claude` and asking: "Run this JavaScript: `[1,2,3].map(x => x * 2)`"236237### Cursor2382391. Install the server as above.2402. Create or edit `.cursor/mcp.json` in your project root:241242**Stateful mode with local filesystem:**243```json244{245 "mcpServers": {246 "js": {247 "command": "mcp-v8",248 "args": ["--directory-path", "/tmp/mcp-v8-heaps"]249 }250 }251}252```253254**Stateless mode:**255```json256{257 "mcpServers": {258 "js": {259 "command": "mcp-v8",260 "args": ["--stateless"]261 }262 }263}264```2652663. Restart Cursor. The MCP tools will be available in the UI.267268### Claude (Web/Cloud) via Railway269270You can also use the hosted version on Railway without installing anything locally:2712721. Go to Claude's connectors settings page2732. Add a new custom connector:274 - **Name**: "mcp-v8"275 - **URL**: `https://mcp-js-production.up.railway.app/sse`276277## Example Usage278279- Ask Claude or Cursor: "Run this JavaScript: `1 + 2`"280- Use content-addressed heap snapshots to persist state between runs. The `run_js` tool returns a `heap` content hash after each execution — pass it back in the next call to resume that session.281282## Heap Storage Options283284You can configure heap storage using the following command line arguments:285286- **S3**: `--s3-bucket <bucket>`287 - Example: `mcp-v8 --s3-bucket my-bucket-name`288 - Requires AWS credentials in your environment.289 - Ideal for cloud deployments and sharing state across instances.290- **S3 with write-through cache**: `--s3-bucket <bucket> --cache-dir <path>`291 - Example: `mcp-v8 --s3-bucket my-bucket-name --cache-dir /tmp/mcp-v8-cache`292 - Reads from local cache first, writes to both local cache and S3.293 - Reduces latency for repeated snapshot access.294- **Filesystem**: `--directory-path <path>`295 - Example: `mcp-v8 --directory-path /tmp/mcp-v8-heaps`296 - Stores heap snapshots locally on disk.297 - Ideal for local development and testing.298- **Stateless**: `--stateless`299 - Example: `mcp-v8 --stateless`300 - No heap persistence - each execution starts fresh.301 - Ideal for one-off computations and serverless environments.302303**Note:** Only one storage option can be used at a time. If multiple are provided, the server will return an error.304305## Limitations306307While `mcp-v8` provides a powerful and persistent JavaScript execution environment, there are limitations to its runtime.308309- **No `async`/`await` or Promises**: Asynchronous JavaScript is not supported. All code must be synchronous.310- **No `fetch` or network access**: There is no built-in way to make HTTP requests or access the network.311- **No `console.log` or standard output**: Output from `console.log` or similar functions will not appear. To return results, ensure the value you want is the last line of your code.312- **No file system access**: The runtime does not provide access to the local file system or environment variables.313- **No `npm install` or external packages**: You cannot install or import npm packages. Only standard JavaScript (ECMAScript) built-ins are available.314- **No timers**: Functions like `setTimeout` and `setInterval` are not available.315- **No DOM or browser APIs**: This is not a browser environment; there is no access to `window`, `document`, or other browser-specific objects.316- **TypeScript: type removal only**: TypeScript type annotations are stripped before execution. No type checking is performed — invalid types are silently removed, not reported as errors.317318---319320## Build from Source (Advanced)321322If you prefer to build from source instead of using the install script:323324### Prerequisites325- Rust (nightly toolchain recommended)326- (Optional) AWS credentials for S3 storage327328### Build the Server329330```bash331cd server332cargo build --release333```334335The built binary will be located at `server/target/release/server`. You can use this path in the integration steps above instead of `/usr/local/bin/mcp-v8` if desired.336337<!-- load-test-report -->338# MCP-V8 Load Test Benchmark Report v0.1.0339340Comparison of single-node vs 3-node cluster at various request rates.341342## Results343344ran on railway gha runners on [pr](https://github.com/r33drichards/mcp-js/pull/36#issuecomment-3946074130)345346| Topology | Target Rate | Actual Iter/s | HTTP Req/s | Exec Avg (ms) | Exec p95 (ms) | Exec p99 (ms) | Success % | Dropped | Max VUs |347|----------|-------------|---------------|------------|----------------|----------------|----------------|-----------|---------|---------|348| cluster-stateful | 100/s | 99.5 | 99.5 | 44.9 | 196.88 | 416.99 | 100% | 31 | 41 |349| cluster-stateful | 200/s | 199.6 | 199.6 | 23.22 | 79.32 | 131.13 | 100% | 13 | 33 |350| cluster-stateless | 1000/s | 999.9 | 999.9 | 3.82 | 7.72 | 13.09 | 100% | 0 | 100 |351| cluster-stateless | 100/s | 100 | 100 | 3.67 | 5.65 | 8.03 | 100% | 0 | 10 |352| cluster-stateless | 200/s | 200 | 200 | 3.56 | 5.9 | 8.61 | 100% | 0 | 20 |353| cluster-stateless | 500/s | 500 | 500 | 3.42 | 5.85 | 9.2 | 100% | 0 | 50 |354| single-stateful | 100/s | 99.1 | 99.1 | 215.12 | 362.5 | 376.6 | 100% | 32 | 42 |355| single-stateful | 200/s | 97.8 | 97.8 | 1948.82 | 2212.55 | 2960.96 | 100% | 5939 | 200 |356| single-stateless | 1000/s | 977.1 | 977.1 | 60.98 | 482.98 | 602.38 | 100% | 843 | 561 |357| single-stateless | 100/s | 100 | 100 | 3.71 | 5.73 | 8.73 | 100% | 0 | 10 |358| single-stateless | 200/s | 200 | 200 | 3.61 | 5.43 | 7.74 | 100% | 0 | 20 |359| single-stateless | 500/s | 500 | 500 | 4.67 | 8.49 | 27.98 | 100% | 0 | 50 |360361## P95 Latency362363| Topology | Rate | P95 (ms) | |364|----------|------|----------|-|365| cluster-stateful | 100/s | 196.88 | `█████████████████████` |366| cluster-stateful | 200/s | 79.32 | `█████████████████` |367| cluster-stateless | 100/s | 5.65 | `███████` |368| cluster-stateless | 200/s | 5.9 | `███████` |369| cluster-stateless | 500/s | 5.85 | `███████` |370| cluster-stateless | 1000/s | 7.72 | `████████` |371| single-stateful | 100/s | 362.5 | `███████████████████████` |372| single-stateful | 200/s | 2212.55 | `██████████████████████████████` |373| single-stateless | 100/s | 5.73 | `███████` |374| single-stateless | 200/s | 5.43 | `██████` |375| single-stateless | 500/s | 8.49 | `████████` |376| single-stateless | 1000/s | 482.98 | `████████████████████████` |377378## Notes379380- **Target Rate**: The configured constant-arrival-rate (requests/second k6 attempts)381- **Actual Iter/s**: Achieved iterations per second (each iteration = 1 POST /api/exec)382- **HTTP Req/s**: Total HTTP requests per second (1 per iteration)383- **Dropped**: Iterations k6 couldn't schedule because VUs were exhausted (indicates server saturation)384- **Topology**: `single` = 1 MCP-V8 node; `cluster` = 3 MCP-V8 nodes with Raft385386
Full transparency — inspect the skill content before installing.