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

# MCP servers

> Connect remote tools over MCP, authenticate them, and decide which ones the model may call.

An MCP server gives the model tools seri does not ship. seri speaks MCP over HTTPS, with OAuth
where the server asks for it, and every server's tools go through the same permission gate your
own tools do.

## Adding one

```text theme={null}
/mcp add <name> <url>
```

The name must be lowercase letters, digits and `-`, starting with a letter or digit. The URL must
be `https`.

`/mcp add` always writes to your **profile root**, never to the project. Adding a server is a
personal action, and a project's `servers.yaml` is a committable file. Writing a URL you typed in
a terminal into a file you might share is not seri's call to make.

## The panel

`/mcp` opens the panel. Each row is a server, grouped by scope with the project's first, showing
its connection state and how many tools are cached for it.

| State                       | Means                                  |
| --------------------------- | -------------------------------------- |
| idle, connects on first use | configured, not dialled this session   |
| connected                   | dialled and answering                  |
| needs authentication        | reachable, but it wants you to sign in |
| unreachable                 | the dial failed                        |

| Command                 | Does                                              |
| ----------------------- | ------------------------------------------------- |
| `/mcp`                  | open the panel                                    |
| `/mcp list`             | the same rows as flat lines                       |
| `/mcp add <name> <url>` | add a server to your profile root                 |
| `/mcp connect <name>`   | dial it and fetch its tool catalog                |
| `/mcp auth <name>`      | authenticate it, renewing silently when it can    |
| `/mcp remove <name>`    | remove it, and drop any stored credential with it |

## Connect, then trust

A server you added is not yet a server the model can call. You connect it from the panel, which
dials it and fetches its tool catalog, then you look at what it offers and trust it.

That order is the point. The catalog is what you are actually approving, and a server nobody has
looked at has no business putting tools in front of the model.

## Authenticating

`/mcp auth <name>` runs the OAuth flow for one server. Run it when the panel says the server
needs authentication, and run it again whenever you want to renew.

**It only opens a browser when it has to.** The first thing it does is ask for authorization with
whatever credentials are already stored. If the refresh token is still good, that call comes back
authorized and the command finishes without a browser, without a consent screen, and without you
doing anything. Re-running `/mcp auth` on a working server is therefore a cheap way to refresh it
rather than a fresh sign-in.

When it does need you, it opens your browser and **also prints the URL**, because a headless
machine, a broken `xdg-open` or a browser that opens in the wrong profile all leave that URL as
the only way through.

You have five minutes to finish. A consent screen can involve a password manager, a second device
and a scope list worth reading, and the only thing the wait costs is a bound loopback port.

There are five ways it can end, and each is one line in the transcript rather than a crash.

| Outcome   | Means                                                |
| --------- | ---------------------------------------------------- |
| success   | authorized, either silently or through the browser   |
| denied    | you refused consent, or the server did               |
| timeout   | five minutes passed with no callback                 |
| cancelled | you interrupted it                                   |
| error     | discovery, registration or the token exchange failed |

Credentials are stored one file per server, at `mcp/auth/<name>.json` in your profile root, so two
servers have independent lifecycles.

<Note>
  **A stored credential is bound to the URL it was minted against.** Repoint a name in
  `servers.yaml` at a different host and the old record stops counting as authentication, so the new
  host gets its own authorization rather than the previous host's bearer token.
</Note>

## The file

A server can also be written by hand, at `.seri/mcp/servers.yaml` in the project or under your
profile root.

```yaml theme={null}
servers:
  github:
    url: https://api.example.com/mcp
    headers:
      Authorization: "Bearer ${env:GITHUB_TOKEN}"
```

`${env:VAR}` is the only expansion, and it reads an environment variable. Nothing here spawns a
shell. `$(…)` and every other shell-looking syntax is left exactly as written, because config
that executes shell at load is an anti-pattern seri refuses by design.

A server whose name or shape does not parse is skipped with a warning at startup rather than
failing the session.

## What the tools are called

**The model gets one tool, named `mcp`.** Its description lists every trusted server tool as
`mcp_<server>_<tool>`, and a call names one of those in its input rather than being a tool of its
own. So `search` on a server named `github` is `mcp_github_search`.

One composite tool rather than one per remote tool keeps the model's tool array stable when a
server is added mid-session.

That composed name is what the permission gate, the approval prompt, a stored grant and a hook
matcher all see. It is computed once and never parsed back apart, because `-` in a server name
folds to `_` and `mcp_my_server_x` would be ambiguous to decompose. The server itself only ever
receives its own unprefixed name.

## Permissions

An MCP tool is not in the gate's read list, so it is classified as a write and prompts in every
mode. That is deliberate. A third party's tool is exactly the case where "seri has not heard of
it" is not evidence that it is safe.

A permanent approval for an MCP tool is stored as `mcp_<server>_<tool>@<digest>`, where the
digest fingerprints the tool's name, description and input schema at the moment you approved it.
Change the tool on the server's end and the digest stops matching, so seri asks again rather than
trusting your old answer about a tool you never saw. See [Permissions](/guides/permissions).

## Removing one

`/mcp remove <name>` deletes the server and clears any stored credential for it. Dropping the
credential is not tidiness. Reusing that name later must not inherit a live access token the
previous server was trusted with.
