> ## Documentation Index
> Fetch the complete documentation index at: https://docs.signalmd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect your client

> Copy-paste setup for Claude Code, Claude Desktop, Cursor, VS Code and any other MCP client.

Every client needs the same two things: the address `https://first-signal-api.fly.dev/mcp` and an API key sent as `Authorization: Bearer <key>`. Only the file or command that holds them differs. [MCP overview](/mcp/overview) lists what the tools do.

## Before you start

<Steps>
  <Step title="Make a key">
    Open **API keys** in the app and select **New key**. Choose **Read** unless you want the assistant to create tests or start runs. [Authentication](/api/authentication#make-a-key) has the steps.
  </Step>

  <Step title="Copy a snippet">
    The **Key made** dialog shows snippets for Claude Code, Cursor, Claude Desktop and curl with your key filled in. The snippets below cover the same clients and more, with `sig_your_key` as a stand-in. Swap in your own key, and do not commit it to a repository.
  </Step>
</Steps>

## Set up your client

<Tabs>
  <Tab title="Claude Code">
    Run this in a terminal.

    ```bash Terminal theme={null}
    claude mcp add --transport http signal https://first-signal-api.fly.dev/mcp \
      --header "Authorization: Bearer sig_your_key"
    ```

    By default Claude Code keeps the server for you, in the current project only. Add `--scope user` to use it in every project. Avoid `--scope project`: it writes the server, key included, to a `.mcp.json` file that you would share through git.

    Check the connection with `claude mcp list`, or run `/mcp` inside Claude Code. Then ask:

    > Use Signal's whoami tool and tell me what this key can do.
  </Tab>

  <Tab title="Claude Desktop">
    Claude Desktop starts MCP servers as local programs from its config file, so it reaches the hosted endpoint through `mcp-remote`, a widely used npm package that speaks stdio to Claude Desktop and Streamable HTTP to Signal. Signal does not make or support it. It needs Node.js. Open **Settings**, then **Developer**, then **Edit Config**. That opens `claude_desktop_config.json`:

    * macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
    * Windows: `%APPDATA%\Claude\claude_desktop_config.json`

    Add the server, keeping any servers you already have.

    ```json claude_desktop_config.json theme={null}
    {
      "mcpServers": {
        "signal": {
          "command": "npx",
          "args": [
            "-y",
            "mcp-remote",
            "https://first-signal-api.fly.dev/mcp",
            "--header",
            "Authorization:${SIGNAL_AUTH}"
          ],
          "env": { "SIGNAL_AUTH": "Bearer sig_your_key" }
        }
      }
    }
    ```

    The header value sits in `env` so the argument has no space in it, which some systems mishandle. This is the same snippet the **Claude Desktop** tab in the app shows, with your key filled in. Quit Claude Desktop completely and open it again.
  </Tab>

  <Tab title="Cursor">
    Cursor reads `~/.cursor/mcp.json` for every project, or `.cursor/mcp.json` in one project.

    ```json .cursor/mcp.json theme={null}
    {
      "mcpServers": {
        "signal": {
          "url": "https://first-signal-api.fly.dev/mcp",
          "headers": { "Authorization": "Bearer sig_your_key" }
        }
      }
    }
    ```

    In a project file that you commit, keep the key out of the file. Cursor fills in environment variables.

    ```json .cursor/mcp.json theme={null}
    {
      "mcpServers": {
        "signal": {
          "url": "https://first-signal-api.fly.dev/mcp",
          "headers": { "Authorization": "Bearer ${env:SIGNAL_API_KEY}" }
        }
      }
    }
    ```

    Open the MCP section of Cursor's settings and check that `signal` is on and lists its tools. Then ask the agent to call `whoami`.
  </Tab>

  <Tab title="VS Code">
    VS Code reads `.vscode/mcp.json` in a workspace. Its file uses `servers`, not `mcpServers`. The `inputs` block makes VS Code ask for the key the first time the server starts and keep it out of the file, which you will probably commit.

    ```json .vscode/mcp.json theme={null}
    {
      "inputs": [
        {
          "type": "promptString",
          "id": "signal-api-key",
          "description": "Signal API key",
          "password": true
        }
      ],
      "servers": {
        "signal": {
          "type": "http",
          "url": "https://first-signal-api.fly.dev/mcp",
          "headers": { "Authorization": "Bearer ${input:signal-api-key}" }
        }
      }
    }
    ```

    Select **Start** above the server in the file, or run **MCP: List Servers** from the command palette. Enter your key when asked. The tools are available in Chat in agent mode.
  </Tab>

  <Tab title="Other clients">
    Any client that supports MCP servers can connect. Which of these it takes depends on the client.

    **A client that speaks Streamable HTTP and can send a header** connects to the hosted endpoint. Most use a JSON file shaped like this. The key names vary a little, so check what your client calls the URL and headers.

    ```json mcp.json theme={null}
    {
      "mcpServers": {
        "signal": {
          "type": "http",
          "url": "https://first-signal-api.fly.dev/mcp",
          "headers": { "Authorization": "Bearer sig_your_key" }
        }
      }
    }
    ```

    **Windsurf** reads `~/.codeium/windsurf/mcp_config.json`. For a remote server it may expect `serverUrl` where the file above has `url`. Signal has not tested it in Windsurf, so check Windsurf's current documentation if it does not connect.

    **A client that only starts local programs** can use the same `mcp-remote` bridge as Claude Desktop above. Give it the command `npx`, the arguments `-y mcp-remote https://first-signal-api.fly.dev/mcp --header Authorization:${SIGNAL_AUTH}`, and `SIGNAL_AUTH` set to `Bearer sig_your_key` in its environment.

    **A client that supports only the older SSE transport** cannot use the hosted endpoint. The endpoint answers `GET` with `405`, because it keeps no session and opens no stream.

    To test the endpoint without a client, ask it for its tool list.

    ```bash Terminal theme={null}
    curl -sS https://first-signal-api.fly.dev/mcp \
      -H "Authorization: Bearer $SIGNAL_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
    ```
  </Tab>
</Tabs>

## If it does not work

| What you see | Cause and fix |
| - | - |
| `401` with `mcp_unauthorized`, or "unauthorized" in the client | The key is missing, wrong or revoked. The header must read `Bearer ` followed by the key, with one space. Check the key's row on the **API keys** page |
| The write tools are not in the list | You are using a read key on the hosted endpoint, which hides them. Make a **Write** key if you want them |
| A tool answers `agent_required` | The key is for all agents. Pass `agentId` (ask the assistant to call `list_agents` first) or make a key tied to one agent |
| A tool answers `403` with `key_read_only` | A read key called a write tool. The hosted endpoint hides the write tools from a read key, so this is rare. Make a **Write** key if you need them |
| A tool answers `402` with `quota_exceeded` | Your plan's simulated test calls for the period are used up, so a run was refused whole. Run fewer tests, upgrade, or wait for the reset. See [Limits and quotas](/limits#plan-limit-errors) |
| A tool answers `429` | You reached a rate limit. Wait the number of seconds in `Retry-After`. See [Rate limits](/limits#api-rate-limits) |
| Claude Desktop shows the server as failed | Node.js is not installed or not on the path, or `SIGNAL_AUTH` does not read `Bearer ` followed by the key. Open the MCP log from **Settings**, then **Developer** |
| The client cannot connect, or reports a `405` | The client expects the older SSE transport. Use a client or bridge that speaks Streamable HTTP |

If you report a problem, include the `requestId` from the tool error.

## Next steps

<CardGroup cols={2}>
  <Card title="MCP overview" icon="plug" href="/mcp/overview">
    Every tool, example requests, and what a read or write key can do.
  </Card>

  <Card title="API reference" icon="terminal" href="/api/introduction">
    The same operations over plain HTTP.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.