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

# MCP gateway

> Configure and operate your Flowyte tenant from any MCP client — Claude Code, Claude.ai, or your own agent runtime — over a remote MCP server.

The **Control MCP gateway** is a remote [MCP](https://modelcontextprotocol.io) server that lets an
MCP client — Claude Code, a Claude.ai connector, or any agent runtime — configure and operate your
Flowyte tenant through a curated set of safe tools. It's a thin, scoped wrapper over the same
`/api/v1` the rest of the platform uses: every tool call re-enters the API, carrying your key, so
your organization scoping, scopes, and audit trail all apply exactly as they would over REST.

Use it when you want an agent to *drive* Flowyte — list agents, create and configure one, add
knowledge, wire skills and guardrails, deploy the chat widget, test, and publish — without writing
REST glue. If you're calling the API directly instead, see [For AI agents](/get-started/for-ai-agents).

* **Endpoint:** `https://mcp.flowyte.com/mcp` (`https://builder.flowyte.com/mcp` also works as an alias)
* **Transport:** Streamable HTTP + JSON-RPC 2.0 (stateless, plain JSON)
* **Protocol:** MCP `2025-11-25`, negotiated down for older clients
* **Auth:** `Authorization: Bearer flowyte_sk_…`

## Connect

<CodeGroup>
  ```bash Claude Code theme={null}
  claude mcp add --transport http flowyte https://mcp.flowyte.com/mcp \
    --header "Authorization: Bearer flowyte_sk_…"
  ```

  ```jsonc Generic MCP client theme={null}
  // Point any Streamable-HTTP MCP client at the endpoint with a Flowyte key.
  {
    "flowyte": {
      "transport": "http",
      "url": "https://mcp.flowyte.com/mcp",
      "headers": { "Authorization": "Bearer flowyte_sk_…" }
    }
  }
  ```
</CodeGroup>

The client runs `initialize` to negotiate the protocol, then `tools/list` to discover the tools your
key can call. The server is stateless — there is no session id, and it never pushes changes — so each
request is authorized on its own.

<Note>
  Mint a scoped key in the dashboard's **Developer** page (Settings → API keys) and grant only the
  scopes you need. Your key alone determines your organization — no other headers. See
  [Authentication](/get-started/authentication).
</Note>

## Authentication

The gateway accepts only **Flowyte-issued** bearers — a foreign token is rejected `401`. Two
credentials work, both resolved by the same resolver `/api/v1` uses:

| Credential      | Notes                                                                                   |
| --------------- | --------------------------------------------------------------------------------------- |
| `flowyte_sk_…`  | A secret API key from the dashboard; org-scoped, with the scopes you chose at creation. |
| `flowyte_oat_…` | An OAuth access token — the same tokens `/api/v1` accepts.                              |

The gateway holds no credentials of its own and never touches the database directly. Because each
tool call re-runs your key's scopes and organization isolation, a revoked key stops working instantly
and a scope your key lacks fails the same way it would over REST.

<Note>
  Full OAuth (authorization-server metadata, dynamic client registration) is on the roadmap. Today,
  API-key auth is the supported path — a compliant MCP posture. OAuth-capable clients can already
  discover the seam: an unauthenticated request returns `401` with a
  `WWW-Authenticate: Bearer resource_metadata="…"` header pointing at
  `/.well-known/oauth-protected-resource`.
</Note>

## Tools

Tools split into **two capability domains**, and `tools/list` is **scope-filtered** — a key sees only
the tools whose scopes it holds. A config-only key never sees the escalation tools, and a
connector-only key never sees the control tools.

### Control tools

Configure and run an agent. Reads are safe; writes re-run your scopes on the underlying endpoint.

| Tool                                                                         | Scope                           | What it does                                                                    |
| ---------------------------------------------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------- |
| `list_agents`                                                                | `agents:read`                   | List agents (id, name, status).                                                 |
| `get_agent`                                                                  | `agents:read`                   | Full agent config — persona, goals, voice, languages.                           |
| `create_agent`                                                               | `agents:write`                  | Create a new draft agent.                                                       |
| `configure_agent`                                                            | `agents:write`                  | Partial update of the draft — persona, goals, tone, greeting, voice, languages. |
| `add_knowledge`                                                              | `knowledge:write`               | Add a knowledge source (`url`, `file`, `text`, or `faq`).                       |
| `list_knowledge`                                                             | `knowledge:read`                | List an agent's knowledge sources and their ingest status.                      |
| `list_skills`                                                                | `skills:read`                   | List an agent's configured skills.                                              |
| `configure_skill`                                                            | `skills:write`                  | Create or update one skill.                                                     |
| `configure_guardrails`                                                       | `guardrails:write`              | Replace the agent's guardrail-policy set.                                       |
| `deploy_chat_widget`                                                         | `pubkeys:write`                 | Mint a publishable key for the [chat widget](/channels/widget).                 |
| `test_agent`                                                                 | `agents:read`                   | Run one test turn against the draft.                                            |
| `get_prepublish_report`                                                      | `agents:read`                   | Draft readiness report — plus the token `publish_agent` needs.                  |
| `publish_agent`                                                              | `agents:write`                  | Freeze the draft as a new live version (see the confirm gate below).            |
| `list_conversations` · `get_conversation_receipts` · `get_analytics_summary` | `analytics:read` · `audit:read` | Read past conversations, signed receipts, and analytics rollups.                |

<Warning>
  `test_agent` is **not** a safe read. It runs the draft agent's LLM, and the agent's configured skills
  may take **real actions** (webhooks, emails, integration calls). Its annotations say so — prefer a
  test tenant.
</Warning>

### Escalation tools

Manage where and when an agent hands a conversation to an external operator agent, and — for
connector runtimes — work the live handoff. These tools carry their own scope family, so they only
appear for a key that holds it, and they're enabled once you've connected an
[AI Harness](/integrations/ai-harness).

| Sub-domain            | Scopes                                                  | Tools                                                                                                                                                    |
| --------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Destinations (config) | `escalation_destinations:read` / `:write`               | `list_escalation_destinations`, `create_escalation_destination`, `update_escalation_destination`, `test_escalation_destination`                          |
| Policy (config)       | `escalation_policies:read` / `:write`                   | `get_escalation_policy`, `configure_escalation_policy`                                                                                                   |
| Runtime (connector)   | `escalations:read` / `:claim` / `:respond` / `:resolve` | `list_escalations`, `get_escalation`, `claim_escalation`, `post_escalation_message`, `resolve_escalation`, `return_escalation`, `request_human_takeover` |

A **connector key** holding only `escalations:*` sees exactly the runtime tools — never a config or
control tool. See [AI Harnesses](/integrations/ai-harness) for the full setup.

## The publish confirm gate

`publish_agent` changes live traffic, so it's a **two-call** operation — never a one-shot:

<Steps>
  <Step title="Get the report">
    Call `get_prepublish_report`. It compiles the draft, returns what will and won't change, and mints
    a short-lived `prepublishToken` bound to the exact draft you reviewed. The token expires in 10
    minutes and is absent if the draft doesn't compile.
  </Step>

  <Step title="Publish with the token">
    Call `publish_agent` with that `prepublish_token`. It verifies the token and that the draft hasn't
    changed since the report ran, then freezes a new version. Any edit in between (a `configure_agent`
    or `configure_skill`) invalidates the token — re-run the report and publish with the fresh one.
  </Step>
</Steps>

This guarantees you publish exactly what you reviewed.

## A worked example

The tool-call flow to list, build, and publish an agent. Each call is a JSON-RPC `tools/call` request
to `POST /mcp`; the response carries both a structured `ApiResponse` envelope and the same JSON as text.

```jsonc theme={null}
// 1. See what's there
{ "method": "tools/call",
  "params": { "name": "list_agents", "arguments": { "status": "published" } } }

// 2. Create a draft — capture data.id from the result
{ "method": "tools/call",
  "params": { "name": "create_agent", "arguments": { "name": "Front Desk" } } }

// 3. Configure it
{ "method": "tools/call",
  "params": { "name": "configure_agent",
    "arguments": { "agent_id": "agt_123",
                   "persona": "A warm, concise front-desk assistant.",
                   "greeting": "Thanks for calling — how can I help?" } } }

// 4. Read the pre-publish report to get a token
{ "method": "tools/call",
  "params": { "name": "get_prepublish_report", "arguments": { "agent_id": "agt_123" } } }
// ← result carries data.prepublishToken

// 5. Publish with that exact token
{ "method": "tools/call",
  "params": { "name": "publish_agent",
    "arguments": { "agent_id": "agt_123", "prepublish_token": "eyJvcmdf…" } } }
```

<Tip>
  Make a retried create or publish safe by passing a client-generated `_meta.idempotencyKey` on the
  `tools/call` request — a retry with the same key and arguments replays the original result instead of
  creating a second agent or version.
</Tip>

## Safety

* **Curated, task-level tools** — not a raw endpoint mirror. Each tool has a closed input schema and
  is written for an operator agent.
* **Writes re-run your scopes.** Every call re-enters `/api/v1` with your key, so scope enforcement,
  organization isolation, and rate limits all apply per call.
* **Publish needs the confirm token** from a fresh `get_prepublish_report` — you can't publish blind.
* **Everything is audited.** Each tool call lands in your audit trail exactly as the equivalent REST
  call would.

## Errors

Business, validation, and permission failures come back as a `tools/call` **result** with
`isError: true` and actionable text (the REST error body) so the model can self-correct — for example,
a downstream `403` when your key lacks the underlying scope. JSON-RPC **error objects** are reserved
for protocol faults (unknown tool, malformed request, auth).

Next: build against the REST API directly in [For AI agents](/get-started/for-ai-agents), or set up an
[AI Harness](/integrations/ai-harness) to work escalated conversations.
