# Platter

> MCP server exposing Read, Write, Edit, Bash, Glob, Grep, and JS tools over stdio.

- **Type:** MCP server
- **Install:** `agentstack add mcp-scriptsmith-platter`
- **Verified:** Pending review
- **Seller:** [hadriangateway](https://agentstack.voostack.com/s/hadriangateway)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 2.0.2-rc1
- **License:** MIT
- **Upstream author:** [hadriangateway](https://github.com/hadriangateway)
- **Source:** https://github.com/hadriangateway/platter

## Install

```sh
agentstack add mcp-scriptsmith-platter
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# platter

*Your computer, served on a platter.*

MCP server that exposes **Read**, **Write**, **Edit**, **Bash**, **Glob**, **Grep**, and **JS** tools over Stdio and StreamableHTTP transports. Built with [Bun](https://bun.sh), compiles to standalone executables.

Designed to be used by browser-based (or any MCP-compatible) agents, like [Hadrian](https://github.com/ScriptSmith/hadrian), to control a computer.

## Tools

| Tool | Description |
|------|-------------|
| **read** | Read file contents with pagination (offset/limit). Detects image files (JPEG, PNG, GIF, WebP) and returns metadata. Truncates text to 2000 lines or 50KB. |
| **write** | Create or overwrite files. Auto-creates parent directories. |
| **edit** | Find-and-replace with exact or fuzzy matching (normalizes smart quotes, dashes, and Unicode whitespace). Requires a unique match, or use `replace_all` for every occurrence (exact matches only). Returns a unified diff. |
| **bash** | Execute shell commands with optional timeout. Output truncated to last 2000 lines or 50KB. |
| **glob** | Fast file pattern matching. Returns up to 500 paths matching a glob pattern (e.g. `**/*.ts`). |
| **grep** | Search file contents using [ripgrep](https://github.com/BurntSushi/ripgrep). Supports regex, file filtering, context lines, and multiple output modes. Requires `rg` to be installed. |
| **js** | Evaluate JavaScript/TypeScript in a persistent Node.js `vm` context. State persists across calls within a session. Supports `await`, `console.log`, and loading packages from unpkg.com via `await load("package")`. Auto-returns the last expression. **Not a security sandbox** — see [Security](#security) below. |

## Quick start

### From a release binary

Download the latest binary for your platform from [Releases](https://github.com/hadriangateway/platter/releases), or grab it with `curl`:

```bash
# Download (replace the filename for your platform)
# Available: platter-linux-x64, platter-linux-arm64, platter-darwin-x64, platter-darwin-arm64
curl -fsSL https://github.com/hadriangateway/platter/releases/latest/download/platter-linux-x64 -o platter
chmod +x platter

./platter          # stdio mode
./platter -t http  # HTTP mode on :3100
```

### Docker

```bash
docker run --rm -i ghcr.io/hadriangateway/platter                                   # stdio mode
docker run --rm -p 3100:3100 ghcr.io/hadriangateway/platter -t http --host 0.0.0.0  # HTTP mode
```

See [Docker](#docker-1) below for mounting paths, networking, installing extra software, and building custom images.

### From source

```bash
bun install
bun run dev      # run directly from TypeScript
bun run compile  # build standalone binary for current platform
```

## Usage

```
platter v1.x.x

Your computer, served on a platter.

Usage: platter [options]

Options:
  -t, --transport    Transport mode (default: stdio)
      --tray                     Run the HTTP server with a Linux system tray
                                 (implies --transport=http, persists state
                                 across restarts in ~/.config/platter)
  -p, --port             HTTP port (default: 3100)
      --host            HTTP bind address (default: 127.0.0.1)
      --cwd                Working directory for tools (default: current directory)
      --cors-origin      Allowed CORS origin (default: *)
      --auth               Auth mode: oauth, bearer, jwks, none (default: oauth)
      --auth-token        Bearer token for HTTP auth (auto-generated if omitted)
      --tls-cert           TLS certificate file (PEM) — enables HTTPS
      --tls-key            TLS private key file (PEM)

External JWKS / OIDC (--auth jwks — verify tokens from an external IdP):
      --oauth-issuer        Issuer URL; OIDC-discovers the JWKS endpoint
      --jwks-url            Explicit JWKS endpoint (overrides discovery)
      --oauth-audience      Expected token audience (strongly recommended)
      --jwks-scope-grants        Map tools: token scopes to tool access
                                 (fail closed: a token with no tools:
                                 scopes is granted no tools)

Process management:
      --max-processes    Max concurrent bash processes per session (default: 20)
      --max-sessions     Max concurrent HTTP sessions (default: unlimited)

Restrictions:
      --tools              Comma-separated tools to enable (default: all)
                                 Valid: read, write, edit, bash, glob, grep, js
      --allow-path         Restrict read/write/edit/glob/grep to this path (repeatable)
                                 Does not restrict bash or js
      --allow-command     Allow bash commands matching this pattern (repeatable)
                                 Pattern must match the entire command string
                                 Applies to bash only; does not restrict js

Sandbox (applies to bash only; the js tool is never sandboxed):
      --sandbox                  Use just-bash sandbox instead of native bash
      --sandbox-fs         Filesystem backend: memory, overlay, readwrite (default: readwrite)
      --sandbox-allow-url   Allow network access to URL prefix (repeatable)

  -h, --help                     Show this help message
  -v, --version                  Show version number
```

### Restrictions

You can limit which tools are registered, which filesystem paths file tools can access, and which commands the bash tool can execute.

#### Tool selection

Only register specific tools. Unregistered tools are completely hidden from MCP clients:

```bash
platter --tools read,glob,grep    # read-only server
platter --tools read,write,edit   # no bash/search/js
```

#### Path restrictions

Restrict file-accessing tools (read, write, edit, glob, grep) to one or more directory trees. Paths are resolved to absolute form and symlinks are resolved via `realpath` to prevent escaping:

```bash
platter --allow-path /home/user/project
platter --allow-path /home/user/project --allow-path /tmp
```

#### Command restrictions

Only allow bash commands whose **entire** command string matches at least one regex pattern:

```bash
platter --allow-command "git( .*)?"                             # git only
platter --allow-command "git( .*)?" --allow-command "npm( .*)?" # git or npm
platter --allow-command "ls( .*)?" --allow-command "cat .*"     # ls or cat
```

Patterns are anchored: `--allow-command "git( .*)?"` compiles to `^(?:git( .*)?)$`, so `git status` matches but `rm -rf / && git status` does not.

#### Combined example

```bash
# Locked-down: read-only tools, scoped to one directory
platter --tools read,glob,grep --allow-path /home/user/project

# Full tools, but bash restricted to git/npm, files restricted to project
platter --allow-path ./my-project --allow-command "git( .*)?" --allow-command "npm( .*)?"
```

Active restrictions are logged to stderr at startup.

### Authentication

Controlled by `--auth `:

| Mode | Description |
|------|-------------|
| `oauth` (default) | OAuth 2.1 Authorization Code + PKCE, with a static bearer token as fallback |
| `bearer` | Static bearer token only |
| `jwks` | Resource-server mode: verifies JWT access tokens issued by an external OAuth/OIDC issuer (Auth0, Keycloak, Okta, Entra) via JWKS |
| `none` | No authentication |

#### OAuth 2.1 (`--auth oauth`)

MCP clients that support [RFC 9728](https://datatracker.ietf.org/doc/html/rfc9728) (Protected Resource Metadata) can discover platter's OAuth endpoints automatically and authenticate without manual token copying.

The flow:

1. Client discovers `/.well-known/oauth-authorization-server` and `/.well-known/oauth-protected-resource/mcp`
2. Client registers via `POST /register` ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591) dynamic client registration)
3. Client initiates Authorization Code + PKCE flow via `/authorize`
4. A **confirmation code** is displayed out-of-band (printed to stderr, or shown as a desktop notification in tray mode)
5. User sees a consent page, enters the confirmation code, selects which tools to grant, and approves or denies the request
6. Client exchanges the authorization code for tokens at `/token`
7. Subsequent requests use `Authorization: Bearer `

The confirmation code proves that the person approving the request has access to the platter process — a remote attacker who can reach the consent page cannot approve without it. Codes are single-use and expire after 5 minutes, with a maximum of 5 attempts.

Access tokens expire after 1 hour and can be refreshed. Client registrations are persisted to `~/.config/platter/clients.json`. A static bearer token is also accepted as a fallback for clients that don't support OAuth.

#### Bearer token (`--auth bearer`)

A random bearer token is generated at startup and printed to stderr (or stored in the system keyring in tray mode). Every request must include `Authorization: Bearer `. You can provide your own:

```bash
platter -t http --auth bearer --auth-token my-secret-token
```

#### No authentication (`--auth none`)

Disable authentication entirely (e.g. behind a reverse proxy that handles auth):

```bash
platter -t http --auth none
```

#### External JWKS / OIDC (`--auth jwks`)

In `jwks` mode platter acts as a pure **resource server**: it does not mint its own tokens. Instead it verifies JWT access tokens issued by an **external** OAuth/OIDC authorization server (Auth0, Keycloak, Okta, Microsoft Entra) — validating the signature against the issuer's JWKS, plus the `iss`, `aud`, and `exp` claims. This lets you put platter behind your existing IdP without a reverse proxy.

```bash
# Auth0 (root issuer)
platter -t http --auth jwks \
  --oauth-issuer https://YOUR_TENANT.auth0.com/ \
  --oauth-audience https://platter.example.com/mcp

# Keycloak (realm issuer)
platter -t http --auth jwks \
  --oauth-issuer https://kc.example.com/realms/myrealm \
  --oauth-audience platter-api

# Skip discovery / point at a JWKS endpoint directly
platter -t http --auth jwks \
  --jwks-url https://idp.example.com/.well-known/jwks.json \
  --oauth-audience platter-api
```

**Audience validation (strongly recommended).** Set `--oauth-audience` to the API identifier configured in your IdP. If you omit it, platter accepts *any* valid token from the issuer — including tokens minted for a different resource server (a confused-deputy risk). platter prints a warning at startup when audience validation is disabled.

**Discovery.** With `--oauth-issuer`, platter fetches the issuer's `/.well-known/openid-configuration` (falling back to `/.well-known/oauth-authorization-server`) at startup to find the `jwks_uri` and re-advertise the authorization server to RFC 9728-capable MCP clients (at `/.well-known/oauth-protected-resource/mcp`). Pass `--jwks-url` to skip discovery, or if the IdP isn't reachable at startup. If discovery fails but `--jwks-url` is set, token verification still works — only the RFC 9728 auto-advertisement is skipped.

**Authorization (what a token can do).** By default a verified token gets admin-level access, bounded only by the operator's CLI restrictions (`--tools`, `--allow-path`, `--allow-command`, `--sandbox`) — the IdP controls *who* gets in, the CLI flags control *what* they can do. Pass `--jwks-scope-grants` to additionally honor `tools:` scopes in the token (e.g. `tools:read tools:bash`), which further narrow the granted tools (they can only narrow, never widen the operator's ceiling). The `scope` claim and Entra-style `scp` claim are both supported. In this mode access is **fail closed**: a token carrying no `tools:*` scope is granted no tools at all, so a token must explicitly request the tools it needs.

**No static fallback.** Unlike `oauth` mode, `jwks` mode accepts *only* externally-issued JWTs — `--auth-token` is rejected.

> **Note:** `MCP_DANGEROUSLY_ALLOW_INSECURE_ISSUER_URL` is unrelated to this mode. It only concerns platter serving its *own* issuer over http in `--auth oauth` mode. An external `https` issuer needs no such flag. If you point `--auth jwks` at a plain-`http` issuer (e.g. a localhost Keycloak), platter warns and skips RFC 9728 metadata advertisement, but token verification still works.

### TLS (HTTPS)

To serve over HTTPS, provide a PEM-encoded certificate and private key:

```bash
platter -t http --tls-cert cert.pem --tls-key key.pem
```

Both `--tls-cert` and `--tls-key` are required together. When provided, the server listens over HTTPS instead of plain HTTP.

To generate a self-signed certificate for development or trusted internal use:

```bash
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/CN=myserver'
platter -t http --tls-cert cert.pem --tls-key key.pem
```

### Stdio mode

For use with Claude Desktop, Cursor, and other MCP clients that spawn a subprocess:

```json
{
  "mcpServers": {
    "platter": {
      "command": "/path/to/platter"
    }
  }
}
```

### HTTP mode (StreamableHTTP)

For browser-based agents and remote connections:

```bash
platter -t http -p 3100
```

The server exposes a single endpoint at `/mcp` that handles:
- `POST /mcp` - JSON-RPC messages (initialize, tool calls)
- `GET /mcp` - SSE notification stream
- `DELETE /mcp` - session teardown

CORS is enabled for all origins by default (reflects the request `Origin`). To restrict to a specific origin:

```bash
platter -t http --cors-origin https://myapp.example.com
```

Sessions are managed via the `Mcp-Session-Id` header per the StreamableHTTP spec.

The server validates the `Host` header to prevent [DNS rebinding attacks](https://github.com/modelcontextprotocol/typescript-sdk/security/advisories/GHSA-w48q-cv73-mx4w). When `--cors-origin` is set, the `Origin` header is also validated server-side (not just via CORS response headers).

### Tray mode (Linux)

Run platter as a persistent background service with a system tray icon:

```bash
platter --tray
```

This implies `--transport=http` and adds:

- **System tray icon** via DBus (StatusNotifierItem protocol), compatible with KDE, GNOME (with AppIndicator extension), and other desktop environments.
- **Persistent configuration** in `~/.config/platter/config.json` — auth token, enabled tools, port, host, and working directory survive restarts.
- **Dynamic tool toggling** — enable or disable individual tools at runtime from the tray menu. Changes are persisted and take effect immediately.
- **Auth token management** — copy the server URL or auth token to clipboard, or regenerate the token. Tokens are stored in the system keyring when available, falling back to the config file.
- **Server controls** — start, stop, and restart the HTTP server from the tray menu.

#### Linux installer

The `linux/install.sh` script performs a user-level install (no `sudo` required):

```bash
./linux/install.sh                  # install
./linux/install.sh --uninstall      # remove
```

This installs:
- `~/.local/bin/platter` — the binary
- `~/.local/share/applications/platter.desktop` — desktop launcher entry
- `~/.local/share/icons/hicolor/scalable/apps/platter.svg` — application icon
- `~/.config/systemd/user/platter.service` — systemd user unit for autostart

## Security

### Network (HTTP mode)

- **TLS (HTTPS)** - optional transport encryption via `--tls-cert` and `--tls-key`. Uses Node.js `https` module with PEM-encoded certificate and key files.
- **OAuth 2.1 + PKCE** (`--auth oauth`, default) - MCP clients authenticate via Authorization Code flow with PKCE ([RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)). Supports dynamic client registration ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) and token revocation ([RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009)).
- **External JWKS / OIDC** (`--auth jwks`) - resource-server mode: platter verifies JWT access tokens from an external issuer (Auth0, Keycloak, Okta, Entra) against the issuer's JWKS, validating signature, `iss`, `aud`, and `exp`. Asymmetric algorithms only (`alg: none` and

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [hadriangateway](https://github.com/hadriangateway)
- **Source:** [hadriangateway/platter](https://github.com/hadriangateway/platter)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v2.0.2-rc1 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **2.0.2-rc1** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-scriptsmith-platter
- Seller: https://agentstack.voostack.com/s/hadriangateway
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
