# Capsule MCP Server

Query your Capsule tenant from Claude Code, GitHub Copilot, Codex, or any other MCP-compatible AI client.

> **Beta.** The MCP server and the service accounts it authenticates with are in preview. Tool names, configuration, and the underlying schema may change between releases. Do not build production automation on it yet.


## Overview

The Capsule MCP server is a small program that runs on your own machine and exposes your Capsule tenant to an AI client over the [Model Context Protocol](https://modelcontextprotocol.io). Once it is configured, you can ask your coding assistant questions like "which AI agents in our inventory have no owner" or "summarize the policy violations from the last 7 days" and it will query Capsule directly instead of guessing.

It is distributed on npm as [`@capsulesecurity/capsule-mcp-server`](https://www.npmjs.com/package/@capsulesecurity/capsule-mcp-server) and runs over stdio, so there is nothing to host and no inbound network access to allow.

Access is **read-only** and scoped to the **single tenant** that owns the service account you configure.

### What the client can do

The server exposes two tools:

| Tool | Purpose |
|  --- | --- |
| `describe_type` | Returns the GraphQL schema for any type, input, or enum, so the client can build a correct query rather than guess at field names |
| `query_graphql` | Runs a read-only GraphQL query against your tenant |


Queries are validated against a schema bundled into the package before they are sent, so a wrong field name comes back as a specific, correctable error. Non-query operations are rejected, so the client cannot mutate anything through this server.

## Prerequisites

Before you begin, ensure you have:

- **Node.js 20 or later** on the machine running the AI client
- A **Capsule Security** account with permission to manage service accounts
- An **MCP-compatible client** - Claude Code, GitHub Copilot in VS Code, Codex, Cursor, or another client that supports MCP


## Step 1: Create a Service Account

The MCP server authenticates as a Capsule service account using the OAuth 2.0 `client_credentials` grant. Each service account gets a client ID and a client secret.

### Steps

1. Log in to the **Capsule Security** portal
2. Go to **Settings** and open the **Service Accounts** tab
3. Click **Create service account**
4. Give it a name that identifies the client and the person using it, for example `claude-code-dhaval`
5. Copy the **Client ID** and the **Client secret**


The client secret is displayed **only once, at creation time**, and cannot be retrieved later. If you lose it, add a new secret to the account rather than recreating the account.

Give each connected client its own service account. Requests are rate limited to **60 per minute per service account**, so a shared account means one busy client can throttle everyone else. Separate accounts also let you revoke one client without disrupting the rest.

## Step 2: Configure Your AI Client

Pick the section for your client. In every case the server is launched with `npx`, which downloads the package on first use and caches it afterwards.

The examples below target the **US** deployment, which is the default. **EU tenants must also set `CAPSULE_API_URL`**, as described under [Configuration Reference](#configuration-reference).

### Claude Code

Run this from a terminal, substituting your credentials:

```bash
claude mcp add capsule \
  --scope user \
  --env CAPSULE_CLIENT_ID=<client id> \
  --env CAPSULE_CLIENT_SECRET=<client secret> \
  -- npx -y @capsulesecurity/capsule-mcp-server
```

`--scope user` makes the server available in every project on your machine. Use `--scope local` to limit it to the current project instead.

To configure it by hand instead, add the server to `~/.claude.json`:

```json
{
  "mcpServers": {
    "capsule": {
      "command": "npx",
      "args": ["-y", "@capsulesecurity/capsule-mcp-server"],
      "env": {
        "CAPSULE_CLIENT_ID": "<client id>",
        "CAPSULE_CLIENT_SECRET": "<client secret>"
      }
    }
  }
}
```

Verify the connection with `/mcp` inside Claude Code. The `capsule` server should be listed as connected.

### GitHub Copilot (VS Code)

Copilot reads MCP servers from `.vscode/mcp.json` in your workspace, or from your user profile via **MCP: Open User Configuration** in the command palette.

Use an `input` for the secret so it is prompted for and stored in VS Code's secret storage rather than written to a file:

```json
{
  "inputs": [
    {
      "id": "capsule-client-secret",
      "type": "promptString",
      "description": "Capsule service account client secret",
      "password": true
    }
  ],
  "servers": {
    "capsule": {
      "command": "npx",
      "args": ["-y", "@capsulesecurity/capsule-mcp-server"],
      "env": {
        "CAPSULE_CLIENT_ID": "<client id>",
        "CAPSULE_CLIENT_SECRET": "${input:capsule-client-secret}"
      }
    }
  }
}
```

MCP tools are available in Copilot's **Agent** mode. Open Chat, switch the mode selector to Agent, then use the tools picker to confirm `capsule` is listed.

Note that Copilot uses a `servers` key, where most other clients use `mcpServers`.

### Codex

Add the server to `~/.codex/config.toml`:

```toml
[mcp_servers.capsule]
command = "npx"
args = ["-y", "@capsulesecurity/capsule-mcp-server"]
env = { CAPSULE_CLIENT_ID = "<client id>", CAPSULE_CLIENT_SECRET = "<client secret>" }
```

Restart Codex after editing the file.

### Other clients

Most MCP clients, including Cursor and Claude Desktop, use the same JSON shape. Add this to the client's MCP configuration file:

```json
{
  "mcpServers": {
    "capsule": {
      "command": "npx",
      "args": ["-y", "@capsulesecurity/capsule-mcp-server"],
      "env": {
        "CAPSULE_CLIENT_ID": "<client id>",
        "CAPSULE_CLIENT_SECRET": "<client secret>"
      }
    }
  }
}
```

## Step 3: Verify the Connection

Ask your client a question that requires live data, for example:

> Using Capsule, list our AI agents and how many policy violations each one has in the last 7 days.


A working setup returns data from your tenant. If the credentials are missing or wrong, the server exits immediately and prints the variables it needs, which most clients surface as a failed server startup.

## Configuration Reference

| Variable | Required | Default | Notes |
|  --- | --- | --- | --- |
| `CAPSULE_CLIENT_ID` | yes | - | From the service account you created |
| `CAPSULE_CLIENT_SECRET` | yes | - | Shown only once, at creation time |
| `CAPSULE_API_URL` | no | `https://portal.us-east1.capsulesecurity.io/api` | The regional deployment your tenant is hosted on |
| `CAPSULE_TELEMETRY_DISABLED` | no | - | Set to `1` to disable usage telemetry |


`CAPSULE_API_URL` selects your region. It defaults to US, so US tenants can leave it unset:

| Region | `CAPSULE_API_URL` |
|  --- | --- |
| US | `https://portal.us-east1.capsulesecurity.io/api` |
| EU | `https://portal.eu-west4.capsulesecurity.io/api` |


If you are on EU, add it to the `env` block alongside your credentials:

```json
"env": {
  "CAPSULE_CLIENT_ID": "<client id>",
  "CAPSULE_CLIENT_SECRET": "<client secret>",
  "CAPSULE_API_URL": "https://portal.eu-west4.capsulesecurity.io/api"
}
```

If you are not sure which region your tenant is on, check the hostname you use to reach the Capsule portal.

## Access Model

A service account reads what the **Viewer** role permits, within its own tenant only. There is no finer-grained control: there are no per-tool scopes, and no way to grant one connected client less access than another.

What a connected client **can** read:

- Inventory and discovery, including agents, MCP servers, models, and tools
- Findings, detections, and their evidence
- Policy violations, with severity and reasoning
- The structure of sessions and activities


What it **cannot** read:

- The contents of prompts and AI responses. Message bodies come back redacted, and tool inputs, tool responses, raw events, and attached files are stripped.


Because message bodies are redacted, free-text session search matches resource names only. A search for sensitive phrasing that returns nothing is not evidence that nothing happened, only that the text was never searched.

All of this is enforced by the Capsule API, not by the package. The server runs on the user's machine and is therefore untrusted. Treat the credentials the same way you treat any other API key: do not commit them to source control, and prefer your client's secret storage where it offers one.

## Telemetry

The server reports usage analytics to Capsule to help us improve the integration experience: which tools are called and with what arguments and results, client name and version, latency, and errors. Message bodies are never included, because the Capsule API redacts them before they reach the server, as described under [Access Model](#access-model).

To opt out, set `CAPSULE_TELEMETRY_DISABLED=1` in the server's `env` block.

## Rotating and Revoking Credentials

A service account holds up to **two active secrets**, so you can roll credentials without downtime:

1. Open **Settings** > **Service Accounts** and click **Add secret** on the account
2. Update the client configuration with the new secret
3. Revoke the old secret


Revoking a secret stops new access tokens from being issued immediately, but an access token that has already been issued stays valid until it expires, within 15 minutes. To cut off access without waiting, **delete the service account**.

## Troubleshooting

**The server fails to start and reports missing environment variables.** The client is not passing `CAPSULE_CLIENT_ID` and `CAPSULE_CLIENT_SECRET`. Check that they are set in the server's `env` block and not in your shell profile, since MCP servers do not inherit an interactive shell environment.

**Capsule rejected the access token.** The service account or its secret was revoked, or the secret was copied incorrectly. Add a new secret in **Settings** > **Service Accounts** and update the configuration.

**Queries fail with schema errors.** The GraphQL schema is bundled into the package, so the installed version pins the schema version. Update to the latest release, then restart the client.

**Results look incomplete.** Large results are trimmed, with a `__truncated` marker carrying the original count. Ask the client to narrow the filter and query again. Capsule also applies a default lookback window when a query does not pass an explicit date range, so ask for an explicit range when you need full history.