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

# MCP Server

> Connect AI clients and external agents to CRAFT's tool gateway over the Model Context Protocol — IDE integrations, headless agent access, and tool reference

# MCP Server

CRAFT handles the **"what"** — governed, accurate data retrieval from your enterprise systems — so your AI tools and agents can focus on the **"why"**: validating hypotheses, identifying root causes, running what-if scenarios, and surfacing anomalies. Use `resolve_term` so your agent knows what "active customer" means in *your* warehouse before generating SQL; use `execute_query` to validate results; use `generate_plotly_chart` to surface patterns instantly. Connect Claude Code, Cursor, Goose, or a purpose-built agent to `https://craft.emergence.ai/mcp` and CRAFT becomes a governed data layer for any reasoning workflow.

Two connection patterns: **(a) interactive** — IDE clients query CRAFT while you code; **(b) programmatic** — embed CRAFT as a tool server in an agent pipeline for hypothesis testing, root cause analysis, anomaly detection, or what-if modeling.

## Server details

| Property  | Value                                                                                                                                         |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Endpoint  | `https://craft.emergence.ai/mcp`                                                                                                              |
| Transport | Streamable HTTP ([MCP 2025-11-25 spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports); SSE-compat path available) |
| Auth      | OAuth 2.0 PKCE (authorization code + S256, via Keycloak)                                                                                      |
| Health    | `GET https://craft.emergence.ai/health` → `{"status": "ok"}`                                                                                  |

## Verify the endpoint (no auth needed)

Before setting up OAuth, confirm the server is reachable with the no-auth `hello_world` tool:

```bash theme={null}
curl -s -X POST https://craft.emergence.ai/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"hello_world","arguments":{}}}' \
| jq .
```

Expected response:

```json theme={null}
{"jsonrpc": "2.0", "id": 1, "result": {"content": [{"type": "text", "text": "Hello from CRAFT MCP server"}]}}
```

If this succeeds, network connectivity and DNS are confirmed. If you prefer a CLI tool:

```bash theme={null}
npx @mcpjam/cli server doctor --url https://craft.emergence.ai/mcp
```

## Authentication

### Interactive clients (OAuth)

Supported IDE clients use the [MCP OAuth 2.0 PKCE authorization flow](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization).

On first connection, the client opens a browser window to `craft.emergence.ai`, where you sign in with your **Google** or **Microsoft** account. The access token is stored and refreshed by the client automatically — no manual token handling required.

### X-Project-ID header

All tools except `hello_world` require an `X-Project-ID` header scoping the request to your CRAFT project. Find your project ID in the CRAFT console under **Settings → Project → ID**.

`X-Project-ID` selects a project scope but does **not** grant access — project membership is enforced server-side against your JWT's claims. Passing an arbitrary project ID returns an authorization error if you are not a member.

### Token requirements for headless callers

Programmatic callers (agents, pipelines) must obtain an access token before calling tools:

| Requirement     | Value                                                                    |
| --------------- | ------------------------------------------------------------------------ |
| Issuer (`iss`)  | `https://craft.emergence.ai/keycloak/realms/emergence`                   |
| Required scopes | `openid profile email`                                                   |
| Grant type      | Authorization code (interactive) or Client credentials (service account) |
| Token TTL       | \~5 minutes; refresh token manages rotation for interactive clients      |

For service accounts and CI pipelines, see [Service Accounts](/platform/service-accounts) and [Authentication](/platform/authentication).

## Connect your AI client

<AccordionGroup>
  <Accordion title="Claude Code">
    Add the CRAFT MCP server from the CLI:

    ```bash theme={null}
    claude mcp add --transport http craft https://craft.emergence.ai/mcp \
      --header "X-Project-ID: <your-project-id>"
    ```

    Or add it to `.mcp.json` in your project root (or `~/.claude.json` for user-scope):

    ```json theme={null}
    {
      "mcpServers": {
        "craft": {
          "type": "http",
          "url": "https://craft.emergence.ai/mcp",
          "headers": {
            "X-Project-ID": "<your-project-id>"
          }
        }
      }
    }
    ```

    The OAuth browser flow triggers automatically on first tool call. Token refresh is handled by Claude Code.

    <Note>
      Find your project ID in the CRAFT console under **Settings → Project → ID**.
    </Note>
  </Accordion>

  <Accordion title="Cursor">
    Add to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):

    ```json theme={null}
    {
      "mcpServers": {
        "craft": {
          "type": "http",
          "url": "https://craft.emergence.ai/mcp",
          "headers": {
            "X-Project-ID": "${env:CRAFT_PROJECT_ID}"
          }
        }
      }
    }
    ```

    Set `CRAFT_PROJECT_ID` as a shell environment variable — Cursor expands `${env:VAR}` at runtime. The OAuth browser window opens on first use.
  </Accordion>

  <Accordion title="VS Code">
    Create `.vscode/mcp.json` in your project:

    ```json theme={null}
    {
      "inputs": [
        {
          "type": "promptString",
          "id": "craft-project-id",
          "description": "Your CRAFT project ID"
        }
      ],
      "servers": {
        "craft": {
          "type": "http",
          "url": "https://craft.emergence.ai/mcp",
          "headers": {
            "X-Project-ID": "${input:craft-project-id}"
          }
        }
      }
    }
    ```

    VS Code prompts for the project ID once and stores it securely. OAuth handles the access token automatically.

    <Warning>
      If tool calls fail silently, headers may not be forwarded — a known issue in some VS Code versions ([#264095](https://github.com/microsoft/vscode/issues/264095)). Workaround: replace the `type`/`url` block with `mcp-remote`:

      ```json theme={null}
      {
        "servers": {
          "craft": {
            "command": "npx",
            "args": [
              "mcp-remote@latest",
              "https://craft.emergence.ai/mcp",
              "--header",
              "X-Project-ID: <your-project-id>"
            ]
          }
        }
      }
      ```

      Note: `mcp-remote` handles the OAuth flow locally rather than delegating it to the server.
    </Warning>
  </Accordion>

  <Accordion title="Goose">
    Add to `~/.config/goose/config.yaml`:

    ```yaml theme={null}
    extensions:
      craft:
        name: craft
        type: http
        url: https://craft.emergence.ai/mcp
        enabled: true
        headers:
          X-Project-ID: "${CRAFT_PROJECT_ID}"
    ```

    Set `CRAFT_PROJECT_ID` in your environment. Alternatively, run `goose configure`, select **Remote Extension (Streamable HTTP)**, and the interactive wizard will prompt you for the URL and any custom headers. OAuth triggers on first connection.
  </Accordion>
</AccordionGroup>

## Interactive charts — MCP Apps extension

`generate_plotly_chart` returns both a raw `plotly_json` response (all clients) and an embedded interactive UI resource for clients that support the [MCP Apps protocol](https://modelcontextprotocol.io/extensions/apps/overview). The embedded resource is a sandboxed iframe containing the full Plotly chart with a modebar — including an **SVG download** button — rendered inline alongside the chat without switching tabs.

The interactive iframe is enabled by default (`MCP_APPS_ENABLED=true`). No client-side configuration is required; supported clients detect and render it automatically.

Clients that support MCP Apps interactive chart rendering (verified 2026-05-28):

| Client                       | MCP Apps | Notes                                                     |
| ---------------------------- | :------: | --------------------------------------------------------- |
| Cursor 2.6+                  |     ✅    | Desktop IDE; renders interactive Plotly iframe inline     |
| VS Code Copilot Chat v1.109+ |     ✅    | Browser-rendered panel with modebar                       |
| Goose                        |     ✅    | Desktop app; renders iframes inline                       |
| Postman                      |     ✅    | Renders in Postman canvas; good for dev/testing           |
| MCPJam                       |     ✅    | Inspector UI; best for debugging chart output             |
| Claude Code (CLI)            |     ❌    | Terminal — no browser context; receives raw `plotly_json` |

<Note>
  Claude Code and other non-Apps clients receive the raw `plotly_json` response. Render it locally with `plotly.io.show(fig)` in Python or `Plotly.newPlot(...)` in JavaScript. To disable the embedded resource globally, set `MCP_APPS_ENABLED=false` on the Talk2Data service.
</Note>

## Developer tools

Use these tools to test and debug CRAFT's MCP server during development, especially the MCP Apps / Plotly rendering path.

<AccordionGroup>
  <Accordion title="MCPJam Inspector">
    [MCPJam](https://app.mcpjam.com) is a dedicated MCP inspector — web app (no install), desktop app, or CLI. It supports the MCP Apps extension and renders interactive Plotly charts inline.

    **Web app or desktop**: Add a server with URL `https://craft.emergence.ai/mcp`, enable OAuth, and set `X-Project-ID` in the headers field:

    ```json theme={null}
    {
      "name": "craft",
      "type": "http",
      "url": "https://craft.emergence.ai/mcp",
      "headers": { "X-Project-ID": "<your-project-id>" },
      "useOAuth": true
    }
    ```

    **CLI**: Run a health check and OAuth flow validation:

    ```bash theme={null}
    npx @mcpjam/cli server doctor \
      --url https://craft.emergence.ai/mcp \
      --header "X-Project-ID: <your-project-id>"
    ```

    MCPJam provides full JSON-RPC trace visibility and guided OAuth conformance checks (DCR, PKCE, CIMD) — useful for validating the MCP server before shipping tool changes.
  </Accordion>

  <Accordion title="Postman">
    Postman can act as an MCP host (client), connecting to external MCP servers — distinct from Postman's own MCP server for managing Postman resources.

    Go to **Settings → MCP Hosts → Add** and configure:

    * **URL**: `https://craft.emergence.ai/mcp`
    * **Auth**: OAuth (recommended) or access token
    * **Headers**: `X-Project-ID: <your-project-id>`

    Postman supports the MCP Apps extension — Plotly charts appear inline in the Postman canvas. Once you have a working configuration, use Postman's **Export MCP config** button to generate a ready-to-paste config for Claude Code, Cursor, or VS Code.
  </Accordion>
</AccordionGroup>

## Calling CRAFT from an external agent

Any MCP-compatible agent framework can use CRAFT as a tool server, bringing governed data access to any reasoning pipeline.

```mermaid theme={null}
%%{init: {'theme': 'base', 'themeVariables': {'lineColor': '#555555', 'fontFamily': 'sans-serif', 'edgeLabelBackground': '#ffffff'}}}%%
flowchart LR
    EA["External agent\n(any framework)"]
    GW["gateway-external\n(public HTTPS)"]
    MCP["em-runtime-mcp\n(tool gateway)"]
    ALLOW["Allowlist check\n+ audit event"]
    CATALOG["Catalog tools\nlist · get · search"]
    T2D["Talk2Data tools\nSQL · query · chart"]

    EA -->|"Streamable HTTP\nOAuth + X-Project-ID"| GW
    GW --> MCP
    MCP --> ALLOW
    ALLOW --> CATALOG
    ALLOW --> T2D

    classDef entry fill:#56B4E9,stroke:#555555,color:#000
    classDef infra fill:#0072B2,stroke:#555555,color:#fff
    classDef decision fill:#F0E442,stroke:#555555,color:#000
    classDef action fill:#E69F00,stroke:#555555,color:#000
    class EA entry
    class GW,MCP infra
    class ALLOW decision
    class CATALOG,T2D action
```

<Tabs>
  <Tab title="Pydantic AI">
    Requires `pydantic-ai-slim[fastmcp]` and `fastmcp`:

    ```python theme={null}
    from fastmcp import Client
    from fastmcp.client.transports import StreamableHttpTransport
    from pydantic_ai import Agent
    from pydantic_ai.toolsets.fastmcp import FastMCPToolset

    transport = StreamableHttpTransport(
        url="https://craft.emergence.ai/mcp",
        headers={
            "Authorization": "Bearer <token>",
            "X-Project-ID": "<your-project-id>",
        },
    )
    toolset = FastMCPToolset(Client(transport))
    agent = Agent("anthropic:claude-opus-4-8", toolsets=[toolset])

    async def main():
        result = await agent.run(
            "What databases are available? Generate SQL to count active customers."
        )
        print(result.output)
    ```

    <Note>
      `MCPServerHTTP` is deprecated — use `FastMCPToolset` with `StreamableHttpTransport`.
    </Note>
  </Tab>

  <Tab title="Google ADK">
    Requires `google-adk`:

    ```python theme={null}
    from google.adk.agents import LlmAgent
    from google.adk.tools.mcp_tool import MCPToolset, StreamableHTTPConnectionParams

    agent = LlmAgent(
        model="gemini-3.5-flash",
        tools=[
            MCPToolset(
                connection_params=StreamableHTTPConnectionParams(
                    url="https://craft.emergence.ai/mcp",
                    headers={
                        "Authorization": "Bearer <token>",
                        "X-Project-ID": "<your-project-id>",
                    },
                )
            )
        ],
    )
    ```

    <Note>
      `SseServerParams` is the legacy SSE transport. Use `StreamableHTTPConnectionParams` for the MCP 2025-11-25 streamable-HTTP transport.
    </Note>
  </Tab>

  <Tab title="Raw HTTP">
    Any HTTP client can speak the MCP JSON-RPC protocol. List available tools:

    ```bash theme={null}
    # 1. Initialize a session
    curl -s -X POST https://craft.emergence.ai/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer <token>" \
      -H "X-Project-ID: <your-project-id>" \
      -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}}' \
    | jq .
    ```

    ```bash theme={null}
    # 2. List tools (include MCP-Session-Id from initialize response)
    curl -s -X POST https://craft.emergence.ai/mcp \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer <token>" \
      -H "X-Project-ID: <your-project-id>" \
      -H "MCP-Session-Id: <session-id>" \
      -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
    | jq '.result.tools[].name'
    ```

    ```bash theme={null}
    # 3. Call a tool
    curl -s -X POST https://craft.emergence.ai/mcp \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer <token>" \
      -H "X-Project-ID: <your-project-id>" \
      -H "MCP-Session-Id: <session-id>" \
      -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_schema","arguments":{"query":"customer"}}}' \
    | jq .
    ```

    Include `MCP-Session-Id` on all requests after initialization for stateful sessions.
  </Tab>
</Tabs>

<Note>
  Headless callers need a programmatic access token. Obtain one via a Keycloak service account (client credentials grant). See [Service Accounts](/platform/service-accounts) for setup.
</Note>

## Available tools

### Catalog tools

Always available — provide governed access to your project's data catalog.

| Tool             | Required parameters                                                  | Returns                                                   |
| ---------------- | -------------------------------------------------------------------- | --------------------------------------------------------- |
| `hello_world`    | —                                                                    | Server greeting; confirms connectivity (no auth required) |
| `list_databases` | `resource_uri` — data connection UUID                                | Database metadata list                                    |
| `get_schema`     | `resource_uri`, `fqn` — 2 segments = database, 3 = schema, 4 = table | Full entity schema including columns and types            |
| `search_schema`  | `query` — Elasticsearch-style text query                             | Matching metadata entries across the project              |

### Talk2Data tools

Available when the deployment includes the Data Insights solution. See [Data Connections](/platform/data-connections) to connect your data sources.

| Tool                    | Required parameters                                                                               | Returns                                                                           |
| ----------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `generate_sql`          | `question` (natural language), `database` (connection UUID), `schema` (object with `schema_name`) | `sql`, `explanation`, `assumptions`                                               |
| `execute_query`         | `sql` (SELECT statements only), `database`                                                        | `columns`, `rows`, `row_count`, `truncated`                                       |
| `resolve_term`          | `term` — business term (e.g., "ARR", "churn rate")                                                | `definition`, `related_columns`, `sql_pattern`                                    |
| `generate_plotly_chart` | `data` (tabular), `chart_type` (bar, line, scatter, pie, …)                                       | Plotly JSON figure spec (`plotly_json`) + interactive iframe for MCP Apps clients |
| `sample_data`           | `resource_uri`, `table_fqn` — `database.schema.table`                                             | `columns`, `rows` (up to 100 rows preview)                                        |

<Note>
  `execute_query` only accepts SELECT statements — DDL, DML, and admin functions are rejected. `generate_sql` delegates to the Text2SQL A2A agent; the first call in a session may take 3–8 s (cold start), subsequent calls \~1–2 s. `generate_plotly_chart` emits per-stage MCP progress notifications (parse → validate → render → verify) forwarded as A2A status events — visible in clients that display progress.
</Note>

## Per-project allowlist and governance

CRAFT enforces a per-project tool allowlist — each project defines which tools each agent identity may call. This is the key difference between the CRAFT MCP gateway and a raw FastMCP server.

Configure allowlists in [Platform → Authorization](/platform/authorization) (RBAC model) and [Platform → Agents](/platform/agents) (agent identity → allowlist mapping). Denied calls return a structured error:

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "tool_not_allowed",
    "message": "Tool 'generate_sql' is not in the allowlist for this agent identity"
  }
}
```

Every tool call — allowed or denied — writes an audit event to the governance event log. Each event records:

* Timestamp, agent identity, tool name, project ID
* Input parameters (PII-scrubbed per governance policy)
* Result status (allowed / denied / error)

Query audit events via [Audit Log](/guides/customer-admin/audit-log). Tool calls are tracked separately from LLM completions and do not flow through the LiteLLM gateway. See [LLM Gateway](/platform/llm-gateway) for the complementary table.

## Errors and limits

| Condition                         | HTTP | MCP error code          | Remediation                                                                                                  |
| --------------------------------- | ---- | ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| Missing `Authorization` header    | 401  | `missing_authorization` | Complete the OAuth flow; verify token is fresh                                                               |
| Missing `X-Project-ID` header     | 400  | `missing_project`       | Add `X-Project-ID` header with your project UUID                                                             |
| Tool not in allowlist             | 403  | `tool_not_allowed`      | Ask project admin to add tool to allowlist                                                                   |
| Non-SELECT SQL in `execute_query` | 422  | `validation_error`      | Only SELECT statements are permitted                                                                         |
| Text2SQL agent unavailable        | 503  | `upstream_unavailable`  | Retry; `generate_sql` depends on the Talk2Data A2A agent                                                     |
| Query row limit hit               | 200  | —                       | Response includes `"truncated": true`; add a `LIMIT` or more selective `WHERE` clause to fit within 500 rows |

**Limits:**

* `execute_query`: server-enforced cap of 500 rows; `truncated: true` in response when exceeded
* `sample_data`: up to 100 rows (`limit` parameter; default 10)
* `generate_sql`: first call may take 3–8 s (Text2SQL agent cold-start); subsequent calls \~1–2 s

## Next steps

<CardGroup cols={2}>
  <Card title="LLM Gateway" icon="brain" href="/platform/llm-gateway">
    The complementary gateway for LLM completions — model allowlist, rate limits, and cost attribution.
  </Card>

  <Card title="Data Connections" icon="database" href="/platform/data-connections">
    Connect your data sources to enable Talk2Data tools.
  </Card>

  <Card title="Release Notes" icon="newspaper" href="/releases">
    Track new tools, breaking changes, and platform updates.
  </Card>
</CardGroup>
