> Documentation index: https://docs.beetl.io/llms.txt

# MCP setup

> Create a key, pick a scope, wire it into Claude or Cursor.

Source: https://docs.beetl.io/mcp/setup/
Last updated: 2026-10-28

Connecting an MCP client to Beetl takes 1 API key and 1 config block. A key belongs to you and to
one tenant, so every call the client makes runs as you, inside that tenant.

    ## Create an API key [#create-an-api-key]

    Open Settings. TenantAdmins see a Tenant and a User tab and choose User; other users land there
    directly. Under MCP API keys, choose Create API key, give the key a label you will recognize
    later, such as `claude-desktop-laptop`, and pick a scope.

    The next dialog shows the key once, together with config for Claude Code, Cursor and Claude Desktop
    with the key already filled in. Copy what you need before you close it. Beetl cannot show the key
    again, so if you lose it, delete the key and create a new one.

    ## Pick a scope [#pick-a-scope]

    | Scope   | What the client can do                                                                                                                                                                                                                                                                                                                                  |
    | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `read`  | Run SQL through `execute_query`, page an existing result, list datasets and pipelines, inspect pipeline runs, preview a stored pipeline definition with `run_pipeline`, trace lineage with `get_lineage`, read automations and their runs, read apps and their runs, read reports, their documents and templates, and read the platform reference docs. |
    | `write` | Everything in `read`, plus `build_pipeline`, `update_pipeline` and `deploy_pipeline`, the tools that create, update, run, pause, resume or delete an automation, and the tools that create and update reports, tag their documents, save templates and run a report with `render_report`.                                                               |

    `read` is the default in the dialog, and a `read` key only sees the read tools in `tools/list`.
    `run_pipeline` is a read tool: it previews the stored definition and writes nothing.

    Keep `read` unless you intend the client to author and deploy pipelines, change automations or
    manage reports. Over MCP, a `write` key deploys a pipeline without the confirmation chat asks for,
    and the deploy starts a run that writes the destination dataset. `render_report` also runs without
    asking and writes PDFs to your storage. A `read` key that calls a write tool gets an error result
    naming the scope the tool needs.

    ## Wire it into your client [#wire-it-into-your-client]

    The endpoint is `https://app.beetl.io/mcp`, and the key goes in the `X-API-Key` header.

    
      **Claude Code**

        ```bash
        claude mcp add --transport http beetl https://app.beetl.io/mcp \
          --header "X-API-Key: PASTE_YOUR_KEY_HERE"
        ```
      

      **Cursor**

        The key dialog has an Add to Cursor button. To configure it by hand, add this to `mcp.json`:

        ```json
        {
          "mcpServers": {
            "beetl": {
              "url": "https://app.beetl.io/mcp",
              "headers": {
                "X-API-Key": "PASTE_YOUR_KEY_HERE"
              }
            }
          }
        }
        ```
      

      **Claude Desktop**

        Claude Desktop connects through the `mcp-remote` bridge, which needs Node.js installed:

        ```json
        {
          "mcpServers": {
            "beetl": {
              "command": "npx",
              "args": [
                "-y",
                "mcp-remote",
                "https://app.beetl.io/mcp",
                "--header",
                "X-API-Key:PASTE_YOUR_KEY_HERE"
              ]
            }
          }
        }
        ```
      
    

    ## Verify the handshake [#verify-the-handshake]

    The server is stateless, so a single POST is enough to prove the key works.

    ```bash
    curl -sS https://app.beetl.io/mcp \
      -H "Content-Type: application/json" \
      -H "X-API-Key: $BEETL_API_KEY" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "initialize",
        "params": {
          "protocolVersion": "2025-11-25",
          "capabilities": {},
          "clientInfo": { "name": "curl", "version": "1.0" }
        }
      }'
    ```

    A working key returns a `result` with `protocolVersion`, a `tools` capability with
    `listChanged: false`, `serverInfo` and `instructions`, a short guide that tells the model how to use
    the tools. A missing key returns HTTP 401 with the code `MISSING_API_KEY`, and an unknown or deleted
    key returns 401 with `INVALID_API_KEY`.

    To see what your key can call, follow up with `tools/list`:

    ```bash
    curl -sS https://app.beetl.io/mcp \
      -H "Content-Type: application/json" \
      -H "X-API-Key: $BEETL_API_KEY" \
      -d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}'
    ```

## Using the tools

Before writing SQL, a client should call `list_data_sets` to see what data exists. `search_files`
and `read_file` open the platform reference docs, including the SQL dialect.

`execute_query` requires a `purpose` argument alongside the SQL: a short, user-facing sentence
saying what the query should establish.

`execute_query` returns the first page of up to 50 rows, fewer when rows are wide, with a `result_id`, the
exact `total_rows` and a `has_more_rows` flag. When `has_more_rows` is true, call
`get_query_result` with the `result_id` and `next_page_offset` instead of running the query again. A
result stores up to 1,000 rows, so paging stops there. For larger reads, see
[Export](https://docs.beetl.io/query/export#more-than-1000-rows).

## Good practice

* Create 1 key per client and machine, so you can remove one without breaking the others.
* Label keys so you recognize them later. The key list shows when each key was last used.
* Delete keys you no longer use.
* Treat a `write` key like a deploy credential, and keep it out of shared config and repositories.
* Deactivating a user or a tenant disables their keys immediately.

## Related

- [Tool reference](https://docs.beetl.io/mcp/tool-reference): Every tool, with its scope and arguments.

- [The agent trust boundary](https://docs.beetl.io/concepts/agent-trust-boundary): What the assistant and MCP clients can read and change.
