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

# Outbound MCP

> Point Chatblocks at a third-party MCP server — Linear, GitHub, Notion, or your own internal MCP.

The outbound MCP connector lets you point Chatblocks at any Model Context Protocol server that speaks Streamable HTTP. List its tools, call one of them as the query for a block binding, and the platform refreshes on the usual cadence.

This is how you wire blocks to Linear, GitHub, Notion, or any internal MCP server you've built — without writing a custom connector.

<Note>
  Outbound MCP data sources are a **Builder beta** feature. Free workspaces can read this page, but connector creation, connection tests, refreshes, and tool discovery return `PRO_REQUIRED`.
</Note>

## Add an MCP data source

<Steps>
  <Step title="Go to the wizard">
    `/settings/data-sources/new/mcp`.
  </Step>

  <Step title="Pick a label and the server URL">
    The URL must be HTTPS. Same SSRF rules as Postgres — scheme allowlist, hostname blocklist (`localhost`, `*.local`), literal-IP private-range matcher (including the `::ffff:hex` IPv6 form).
  </Step>

  <Step title="Optionally paste a bearer token">
    Most third-party MCP servers require authentication. Paste the token; it's stored in the encrypted credential blob.
  </Step>

  <Step title="Click Test Connection">
    The wizard runs a one-off connect + `tools/list` against the URL. On success, you see the discovered tools, so you can verify the surface before binding any blocks. The connection is closed immediately after.
  </Step>

  <Step title="Pick a cadence and save">
    Same cadence options as the other connectors: `5`, `15`, `60`, `360`, or `1440` minutes.
  </Step>
</Steps>

## Connection model

The connector uses the official `@modelcontextprotocol/sdk` — the same SDK we use for inbound MCP. Transport is `StreamableHTTPClientTransport` with an optional bearer header.

Each refresh creates a **fresh client per request**. Convex actions are short-lived; a long-lived MCP client would die between invocations.

Refresh runs in a `"use node"` Convex action because the SSRF check imports `node:dns/promises`.

## SSRF and DNS rebinding

Same two-layer defense as Postgres:

* **Sync check at add time and every refresh** — HTTPS-only, hostname blocklist, literal-IP private-range matcher.
* **Async DNS re-resolve before every connect** — `dns.promises.lookup({ all: true })` rejects if any A/AAAA record falls in a private range. Defeats DNS rebinding.

A malicious server can't trick the platform into connecting to your internal network even if it controls DNS.

## Discover the tool surface

Two paths to see what's available:

<Tabs>
  <Tab title="Test Connection in the wizard">
    The wizard's Test Connection button returns the full tool list with descriptions. Useful before saving so you can copy a tool name into a binding.
  </Tab>

  <Tab title="dataSources.listMcpTools MCP read tool">
    Your agent can discover the surface programmatically through the inbound MCP server:

    ```json theme={null}
    {
      "name": "dataSources.listMcpTools",
      "arguments": { "dataSourceId": "<mcp-data-source-id>" }
    }
    ```

    Returns the discovered tool list — agent-readable so it can build a binding without human help.
  </Tab>
</Tabs>

## Bind a block

The query type is `mcp.tool`. The `params` carry the tool name, its arguments, and which field of the result to project from.

```json theme={null}
{
  "binding": {
    "dataSourceId": "<mcp-data-source-id>",
    "queryConfig": {
      "type": "mcp.tool",
      "params": {
        "tool": "linear.search_issues",
        "args": { "query": "is:open team:eng" },
        "projectionField": "issues"
      }
    },
    "projection": {
      "fields": {
        "label": { "literal": "Open eng issues" },
        "items": { "source": "issues", "format": "number" }
      }
    }
  }
}
```

`projectionField` tells the connector which field of the tool's return object to hand off to the projection mapping. If the tool returns `{ issues: [...], cursor: "..." }`, set `projectionField: "issues"`.

## Credential storage

The credential blob is JSON: `{ serverUrl, authToken? }`. Encrypted via the workspace DEK (envelope encryption). Every decryption is audit-logged with the calling actor — same pattern as the other connectors.

## What's next

<CardGroup cols={2}>
  <Card title="BYOK keys" icon="key" href="/connecting-data/byok-keys">
    Bring your own LLM key — used by scheduled runs that drive the agent loop.
  </Card>

  <Card title="Scheduled runs" icon="clock" href="/scheduled-runs/concepts">
    Drive periodic agent loops over MCP — connect outbound MCPs and let your agent compose results.
  </Card>
</CardGroup>
