> Source: https://wexa.ai/docs/surfaces/mcp/overview

# The Wexa MCP server

The Wexa MCP server is Wexa's own MCP endpoint: one of the four surfaces, speaking the Model
Context Protocol so that a client somebody else wrote — a desktop assistant, an editor, a hosted
chat product — can call Wexa tools directly. It is the only surface where you write no code. You
paste a URL, authorize once, and the tools appear in the client's own tool list.

Everything on the other three surfaces is reachable here, under the same governance. A call
arriving over this surface is scope-pinned, policy-checked, quota-counted and audited exactly as the
same call arriving over the REST API is, and it refuses for the same reasons with the same message.

## It exposes tools, and only tools

This is worth stating plainly, because the protocol has three kinds of thing a server can offer and
Wexa offers one of them.

The handshake advertises a single capability. Tools, with no `resources` and no `prompts` key:

```json
{
  "capabilities": { "tools": { "listChanged": false } },
  "protocolVersion": "2025-06-18",
  "serverInfo": { "name": "wexa-fabric", "version": "0.1.0" }
}
```

And the methods that would serve the other two are not implemented, rather than implemented empty:

```json
{ "jsonrpc": "2.0", "id": 9, "error": { "code": -32601, "message": "method not found: resources/list" } }
{ "jsonrpc": "2.0", "id": 9, "error": { "code": -32601, "message": "method not found: prompts/list" } }
```

`completion/complete`, `logging/setLevel` and `resources/templates/list` answer the same way. Beyond
`initialize`, the server implements `ping`, `tools/list`, `tools/call` and the `notifications/initialized`
and `notifications/cancelled` notifications. Nothing else.

The practical consequence is that a client which surfaces documents or prompt templates from a
server will show none from Wexa. That is not a misconfiguration. Wexa's documents live in the
knowledge base and are read through a tool call like everything else.

## What the tools are

A connected client sees all 62 tools, the same set the REST API and both SDKs carry, on every
deployment. The list does not vary with which services the deployment has been given: a tool whose
backing service is not configured is still listed, and a `tools/call` naming it fails with an error
that says so — `<tool> is not configured (no data-service URL)`, `(no harness URL)` or
`(needs the harness and data-service URLs)`. That error is a fact about the deployment, not about
your account, and retrying will not clear it.

Every tool has a reference page under [the tool reference](/docs/tools/overview), and each of those
pages shows the same call on all four surfaces. The four differ mostly in naming:
`create-ontology` is the one tool whose wire name, REST route and SDK method names are all different
from each other.

## The connection URL carries your project

A Wexa connection is to one project, and the project is in the path:

```text
https://fabric.wexa.ai/mcp/{projectId}
```

There are three reasons it is there rather than inferred from the credential.

**A project is the unit of isolation.** Context, knowledge, catalog, ontology, agents and executions
all belong to exactly one project, so "connect to Wexa" is not a well-formed request — there is
nothing at the platform level to read. The URL names the thing the session is actually about.

**It makes the mismatch visible.** A credential is scoped to its own project no matter which URL it
arrives on, so a token for one project used on another project's URL would otherwise serve the first
project's data under the second project's name — a copy-paste mistake that looks like data
appearing in the wrong place. Wexa refuses instead:

```json
{ "error": "forbidden", "error_description": "this credential belongs to a different project than the one in the URL" }
```

**It lets the consent screen lock to one project.** When an OAuth client is challenged on a
project-scoped URL, the challenge points at a project-scoped discovery document, and a compliant
client threads that value back through authorization as a resource indicator. The consent screen can
then bind to that project instead of offering a picker, so the project cannot be swapped underneath
a connection that was made to a specific one. [Custom clients](/docs/surfaces/mcp/custom-clients)
walks through that exchange.

You can read the URL template for any deployment without a credential:

```bash
curl -sS https://fabric.wexa.ai/v1/connection-info
```

## The unscoped endpoint is retired, not broken

The bare `/mcp` path used to work, before connections were project-scoped. It is now permanently
gone, and it says so:

```text
HTTP/1.1 410 Gone
Content-Type: application/json

{"error":"endpoint_moved","error_description":"This URL no longer works. Each project now has its own MCP connect URL — open the dashboard's Connect page for this project and reconnect using that URL."}
```

That 410 is returned by `POST`, `GET` and `DELETE /mcp` and by `GET /sse`, with or without a
credential — a valid API key gets the same answer. This matters for two reasons. The status is 410
rather than 404, which tells a client the path used to exist and will not come back, so nothing
should retry it or treat it as a transient outage. And because the handler runs before
authentication, a stale client gets a clear "moved" answer instead of a 401 challenge that would
send it off to re-authorize a problem that is not an authorization problem.

## Two transports

Both are live, both carry the same tools, and both require the same credential.

**Streamable HTTP**, at `POST /mcp/{projectId}`, is the one to use. `initialize` mints a session
identifier returned in the `Mcp-Session-Id` response header; every later request sends it back.
`GET` on the same URL opens an optional server-to-client event stream, and `DELETE` tears the
session down. Responses come back on the same request that sent the call, framed as JSON or as a
one-shot server-sent event depending on what the request said it accepts.

**HTTP with SSE**, at `GET /sse/{projectId}` plus `POST /messages`, exists for clients that only
speak the older transport. The `GET` holds a stream open and its first event names the message
endpoint to post to; each `POST` is answered with `202 Accepted` and the actual reply arrives later
on the stream.

## This is not an MCP connection

Two different features share most of a name, and confusing them sends people to the wrong screen.

**The Wexa MCP server**, this page, is Wexa acting as a server. Your client connects *to*
Wexa, and Wexa's tools become available in your client.

**An MCP connection** is the opposite direction: a link Wexa holds to somebody else's MCP server
on your behalf, chosen from a marketplace, so that *their* tools become available inside Wexa to
your agents. It is managed in the Wexa console and has no route on the gateway, so nothing about
it is visible or configurable from a client connected to the Wexa MCP server. If you are trying to
give a Wexa agent access to a third-party tool, this tab is the wrong place.

## Pick your client

**Client — Claude Desktop**
Custom connector or the local bridge, and which one your plan gives you.

**Client — Cursor**
`mcp.json`, project-scoped or global, with an API key or with OAuth.

**Client — ChatGPT**
Developer mode connectors, and the one thing Wexa does not implement.

**Reference — Custom clients**
The authorization flow end to end, both discovery documents, and the session rules.

**Quickstart — First connection**
Mint a credential and get one tool call through, in five minutes.

**Concepts — Scope and server-bound arguments**
Why a client may not name its own project, and what happens when it tries.
