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

# MCP Protocol

> Noorle's MCP gateway surface: Streamable HTTP transport, tools-only capabilities, session posture, rate limits, and what is not implemented

Every MCP gateway you compose is a Model Context Protocol server on its own
host. It exposes the tools you bound to it — plugins, built-ins, and connectors —
to any MCP client.

```
https://mcp-{handle}.noorle.com
```

The host is derived from the gateway's handle, not its UUID.

## Transport

**Streamable HTTP, mounted at the gateway origin.** Because the transport is the
router's fallback, it answers on the origin root and on any path the gateway does
not otherwise claim.

<Warning>
  There is **no `/sse` endpoint**, no `/messages` endpoint, and no WebSocket
  transport. Streamable HTTP replaced the separate SSE and HTTP transports.
  SSE is the *response encoding* of a POST, not a separate connection.
</Warning>

A request must accept both content types, or the gateway returns **406**:

```bash theme={null}
curl -X POST https://mcp-my-gateway.noorle.com/ \
  -H "Authorization: Bearer eyJhbGc..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

The JSON-RPC response comes back as `text/event-stream` frames on that POST
response. SSE keep-alive is disabled.

## Protocol version and sessions

Version negotiation happens at the transport. The gateway echoes any protocol
version it recognizes and falls back to **`2025-11-25`** for a version it does
not.

Session behavior follows from the version the client asks for:

| Client protocol version | Session                                                 |
| ----------------------- | ------------------------------------------------------- |
| `2026-07-28` and later  | **Stateless.** No `Mcp-Session-Id` is issued            |
| Earlier versions        | A session is created and a `Mcp-Session-Id` is returned |

For a modern stateless client, `GET` on the origin returns **405 Method Not
Allowed** — there is no server-to-client stream to open, and stateless SSE
resume via `Last-Event-ID` is not offered. Legacy-protocol clients holding a
valid session id can still open the `GET` stream.

<Note>
  **Never send `Mcp-Session-Id` expecting it to select your workspace.** The
  gateway does not consult it for scoping. The workspace anchor that backs
  file, sandbox, and browser-artifact tools is derived server-side from the
  gateway and the authenticated user, and nothing comes off the wire.
</Note>

Where a session does exist, it is stored for **7 days** and is not refreshed on
activity.

## Methods

The gateway implements four methods and declines the rest.

| Method       | Behavior                                               |
| ------------ | ------------------------------------------------------ |
| `initialize` | Returns server info and capabilities                   |
| `ping`       | Returns success                                        |
| `tools/list` | [Lists the gateway's tools](/docs/reference/mcp/tools-list) |
| `tools/call` | [Executes a tool](/docs/reference/mcp/tools-call)           |

### What is not implemented

The gateway advertises **tools only**. It does not declare resources, prompts,
logging, or completions capabilities.

| Method                                                           | Response                                                |
| ---------------------------------------------------------------- | ------------------------------------------------------- |
| `resources/list`, `resources/templates/list`, `prompts/list`     | **Empty success result** — an empty array, not an error |
| `resources/read`, `resources/subscribe`, `resources/unsubscribe` | Method not found (-32601)                               |
| `prompts/get`                                                    | Method not found (-32601)                               |
| `logging/setLevel`                                               | Method not found (-32601)                               |
| `completion/complete`                                            | Method not found (-32601)                               |

There is no resource or prompt implementation behind any of these. An empty
`resources/list` is not an empty gateway — it is a gateway that does not serve
resources at all.

### No `list_changed` notification

`notifications/tools/list_changed` is **never sent**. Bindings can change, a
gateway's presentation mode can change, and a connector's upstream server can
change its own tools on someone else's deploy schedule — none of it produces a
notification.

The only staleness signal a client gets is the `ttlMs` freshness hint on
`tools/list`. See [tools/list](/docs/reference/mcp/tools-list).

## Server info

`initialize` returns:

```json theme={null}
{
  "protocolVersion": "2025-11-25",
  "capabilities": { "tools": {} },
  "serverInfo": {
    "name": "noorle",
    "title": "Noorle",
    "version": "...",
    "websiteUrl": "https://noorle.com"
  }
}
```

`capabilities` carries `tools` and nothing else — note that `listChanged` is not
advertised, consistent with the section above.

## Authentication

Gateways are Public, Private, or Private with dynamic client registration. Each
gateway origin is its own OAuth authorization server, with discovery at
`/.well-known/oauth-authorization-server` and
`/.well-known/oauth-protected-resource`.

A token minted for one gateway does not validate at another.

<Card title="Authentication" icon="key" href="/docs/reference/authentication">
  Header forms, admission rules, and the advertised OAuth metadata.
</Card>

Once a request clears the gateway's auth mode, the gateway checks the account's
billing state before the request reaches a method. This runs on **every**
request — not just `tools/call`, and including anonymous requests to a public
gateway. No available budget returns **402 Payment Required**; a failure to
determine the state returns **503**.

`tools/call` allocates budget a second time, at dispatch, and reports that
failure inside the JSON-RPC envelope rather than as an HTTP status — see
[Call a tool](/docs/reference/mcp/tools-call).

## Limits

| Limit                  | Value                                                           |
| ---------------------- | --------------------------------------------------------------- |
| Request rate           | **600 / minute** per gateway per caller, 60-second fixed window |
| `initialize` rate      | **60 / minute** per gateway per caller, 60-second fixed window  |
| Maximum POST body      | **4 MiB**                                                       |
| Request timeout        | **240 seconds**, then 504                                       |
| `tools/list` page size | 50 tools per page                                               |

`tools/call` and `tools/list` share the request budget — it is flood control,
not per-method fairness. Exceeding it returns JSON-RPC **-32029**; exceeding the
handshake limit returns HTTP **429** with `Retry-After: 60`. Both limiters fail
open if their counter is unreachable.

Anonymous callers on a public gateway are keyed by peer IP rather than sharing
one bucket, so one abusive client cannot starve the rest.

<Card title="Errors and limits" icon="triangle-exclamation" href="/docs/reference/errors-and-rate-limits">
  Error codes and retry guidance.
</Card>

## What reaches the tool list

Three capability kinds surface on a gateway: **plugins** (WASM), **built-ins**,
and **connectors** (REST, MCP registry servers, custom MCP servers).

Not every built-in is MCP-reachable. Each declares an exposure scope, and the
gateway surface requires the MCP flag:

* **`Computer` never appears on an MCP gateway** — it is agent-surface only.
* Plugin Builder, Skill Builder, and Workflow Builder appear on MCP gateways but
  not in workflows.
* Everything else is available on all three surfaces.

Beyond capabilities, only workflow tools attached to the gateway appear as
system tools. The skills read surface, the journal tools, the scheduling and
trigger tools, and form rendering are all **absent** from MCP gateways.

## Autonomy on this surface

MCP is an unattended surface: there is no live channel to ask a human for
approval. A call that would pause for approval **auto-denies** instead, with the
reason `non_interactive_surface`.

Each listed tool carries its static autonomy outcome so a well-built client can
skip calls that will deterministically fail. See
[tools/list](/docs/reference/mcp/tools-list).

## Next steps

* [tools/list](/docs/reference/mcp/tools-list)
* [tools/call](/docs/reference/mcp/tools-call)
* [Authentication](/docs/reference/authentication)
