# Connect an agent over MCP

The Bastide MCP server gives your coding agent the same actions as the console: create a project, deploy, read logs, roll back. This page explains how to connect Claude Code, Claude Desktop, Cursor or any other MCP client, how the agent discovers its tools, and what their results cost in tokens.

## What to know first

- There is a single server address for every organisation: `https://mcp.bastide.app/mcp`. The token you present says who you are and what you may do.
- The server runs no language model and calls no third-party MCP server. The reasoning happens in your agent, on your own subscription.
- Every tool calls the Bastide API under your identity: your rank on the organisation or project, bounded by the token's scopes. An agent can never do more than you can. The details are in [What an agent can do](agent-safety.md).
- An MCP tool carries the name of its operation with the dots replaced by underscores: `deployment.create` becomes `deployment_create`.

## Two ways to authenticate

| Method | How | For |
| --- | --- | --- |
| OAuth authorisation | The client opens your browser on the console, you consent, and it receives a thirty-minute agent token that it renews on its own. | Clients that identify themselves with a Client ID Metadata Document. |
| Personal token in a header | You mint a token in the console and put it in the `Authorization: Bearer …` header of the client's configuration. | Any client that lets you set an HTTP header. |

> **Note.** Dynamic OAuth client registration (RFC 7591) is not open on `bastide.app`. A client that only knows that mode, as Cursor does today, connects with a personal token in a header.

### OAuth authorisation

1. The client calls the server without a token. The server answers `401` with a `WWW-Authenticate` header pointing to its metadata: `https://mcp.bastide.app/.well-known/oauth-protected-resource/mcp`. The authorisation server is `https://api.bastide.app`.
2. The client opens your browser on the console screen **Autoriser un client MCP** (Authorise an MCP client), at `https://console.bastide.app/autoriser`. Sign in if needed.
3. The screen shows the name the client gives itself, its address, the return address and the requested scopes. The name is written by the client: check the address. Choose **Autoriser** (Authorise) or **Refuser** (Deny). The request expires after ten minutes.
4. The client receives an agent token valid for thirty minutes and a refresh token valid for thirty days, rotated on every use. The exchange code is bound to the PKCE challenge (S256), lives sixty seconds and works once.

A client that requests no scope receives `project:read` only. Granted scopes never exceed your rank.

### Remove an authorised client

Open **Compte** (Account), section "Clients MCP autorisés" (authorised MCP clients). Each client is listed with its scopes, the date of the grant and the date of its last token. **Retirer** (Remove) refuses its tokens from the next call. The underlying operations are `mcp_client.list` and `mcp_client.revoke`; they are not MCP tools, since an agent does not manage its own authorisations.

### Personal token

Open **Compte**, section "Vos jetons" (your tokens), then **Frapper un jeton** (mint a token). Give it a name, a lifetime (7 to 365 days) and the scopes it needs. For the deployment journey, `project:read`, `project:write` and `deploy:write` are enough; add `secrets:write` if the agent must write variables. The token is shown once. See [Service accounts and tokens](service-accounts.md).

## Claude Code

With OAuth, add the server, then run `/mcp` in a session to open the sign-in in your browser:

```sh
claude mcp add --transport http bastide https://mcp.bastide.app/mcp
```

With a personal token, pass the header:

```sh
claude mcp add --transport http bastide https://mcp.bastide.app/mcp \
  --header "Authorization: Bearer $BASTIDE_TOKEN"
```

To share the configuration with your team without writing the token into it, use a `.mcp.json` file at the root of the repository. Claude Code replaces `${BASTIDE_TOKEN}` with each person's environment variable:

```json
{
  "mcpServers": {
    "bastide": {
      "type": "http",
      "url": "https://mcp.bastide.app/mcp",
      "headers": { "Authorization": "Bearer ${BASTIDE_TOKEN}" }
    }
  }
}
```

## Claude Desktop

Add a custom connector ("Add custom connector") with the address `https://mcp.bastide.app/mcp`. For the OAuth client identity, choose Claude's published identity, which relies on a metadata document: that is the mode Bastide accepts. On first connection, the connector then sends you to the **Autoriser un client MCP** screen. The exact menu location depends on your Claude version and plan: see Claude's documentation.

## Cursor

Cursor reads `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for all your projects. Its OAuth sign-in uses dynamic registration, which is not open: use a personal token read from an environment variable.

```json
{
  "mcpServers": {
    "bastide": {
      "url": "https://mcp.bastide.app/mcp",
      "headers": { "Authorization": "Bearer ${env:BASTIDE_TOKEN}" }
    }
  }
}
```

## Any other MCP client

- Streamable HTTP transport: JSON-RPC 2.0 envelopes posted to `https://mcp.bastide.app/mcp`. The server keeps no session and opens no stream: a `GET` receives `405`.
- Protocol revisions accepted at `initialize`: `2025-11-25`, `2025-06-18` and `2025-03-26`.
- Methods served: `initialize`, `ping`, `tools/list`, `tools/call`, `resources/list`, `resources/read`.
- The first call without an `Authorization` header receives the `401` challenge, which triggers OAuth discovery in a client that supports it.

> **Attention.** On these protocol revisions, an operation that needs a person's confirmation cannot be confirmed from the client: the tool returns an error that sends you to the console. This applies to deleting a project or a domain.

## Discovering the tools

The server offers three tool profiles, chosen with the `profile` parameter of the address:

| Profile | Address | Contents |
| --- | --- | --- |
| `essentiel` (default) | `https://mcp.bastide.app/mcp` | Sixteen tools: the journey from a repository to a production address. |
| `complet` | `https://mcp.bastide.app/mcp?profile=complet` | Every served tool, sixty-four at most. |
| `lecture` | `https://mcp.bastide.app/mcp?profile=lecture` | Only the tools with no effect. |

The `essentiel` profile holds `project_list`, `project_read`, `project_create`, `project_settings_write`, `deployment_create`, `deployment_read`, `deployment_log_read`, `task_read`, `deployment_cancel`, `deployment_rollback`, `env_list`, `env_pull_nonproduction`, `env_write_nonproduction`, `backend_read`, `action_undo`, and the discovery tool `toolset_read`. Writing production variables is deliberately left out. `project_create_with_backend`, which creates the project, its database and its first deployment in one call, is in `complet`.

Two tools are served by the server itself, without calling the API:

- `toolset_read` returns, for one domain (the object in the tool name: `deployment`, `env`, `database`…), each tool's input schema, an example call and the keys of its output. An agent reads three schemas instead of loading the whole catalogue.
- `documentation_search` searches the platform documentation (operations, error codes, resources) and returns excerpts bounded by a token budget, each with the address of its source. Matching is lexical: no model is called.

Every tool publishes in its `_meta` its reversibility class (`bastide/reversibility`), its scope and minimum rank, its error codes, its rate limits, and whether it requires confirmation. The full catalogue, with each input schema, is published in [mcp-tools.json](../mcp-tools.json) and in [the MCP reference](../reference/en/mcp.md). The tool list may be cached for an hour: it is the same for everyone.

## The token budget of results

Your agent pays for its tokens. Each tool announces in `_meta` the indicative budget of its result (`bastide/tokenBudget`): 700 for `task_read`, 1,200 for `deployment_read`, 8,000 for `deployment_log_read`, for example. Long reads are split to fit that budget:

- `deployment_log_read` stops at `limite` lines or at the budget, and `nextRank` says where to resume (argument `depuis`).
- Lists are paginated by cursor, a hundred items per page at most.
- `documentation_search` accepts a `tokenBudget` argument, from 100 to 4,800 tokens (1,200 by default), which the response never exceeds.

## MCP resources

A resource is read with `resources/read`, without a tool call. Five are served:

| Address | Contents | Cache |
| --- | --- | --- |
| `glowsoft://catalogue/tools` | The tool catalogue by domain, with scope, rank and reversibility. | public, one hour |
| `glowsoft://docs/llms.txt` | The map of what the platform publishes for an agent. | public, one hour |
| `glowsoft://docs/errors` | Every error code, its cause in French and English, and the next call to make. | public, one hour |
| `glowsoft://project/{projectId}` | A project's state, its environments and its configuration drift. | private, one minute |
| `glowsoft://project/{projectId}/schema` | The project's database schema and the tables exposed without a policy. | private, one minute |

A private resource is served by the same operation as a tool (`project.read`, `database.posture.read`), under the same rights. Resources for incidents and for a project's conventions are not available yet.

## Limits

They do not depend on the tier.

- Per token, 600 calls per minute, 60 of them writes, as for the [API](api.md).
- Per token presented to the MCP server, 2,000 calls per hour, 200 of them changing something. Beyond that, the server answers `429` with `Retry-After`. A client that keeps calling despite that delay (twenty refusals within the hour) has its token frozen for up to twenty-four hours, and you are notified.
- Five project creations per rolling day per organisation through the agent channel.

## Common errors

| Symptom | Cause | Fix |
| --- | --- | --- |
| `401` on the first call, the client offers no sign-in | The client cannot follow OAuth discovery, or only through dynamic registration. | Connect it with a personal token in a header. |
| `unauthenticated` after a few weeks | The personal token expired, was revoked, or was disabled after 90 days without use. | Mint another one, or reactivate it from **Compte**. |
| `token_scope_missing` | The token lacks the tool's scope. | Mint a token with the scope, or authorise the client again. |
| `insufficient_rank` | Your rank on the project is too low. | Ask an administrator of the organisation for the rank. |
| The expected tool does not appear | It is not in the `essentiel` profile. | Add `?profile=complet` to the address. |
| "This operation requires a person's confirmation" | The operation is irreversible. | Do it from the console. |

Every error carries a stable code, its cause and the next call to make, under the tool's name. The full catalogue is the `glowsoft://docs/errors` resource.

## See also

- [What an agent can and cannot do](agent-safety.md)
- [Create a project](project.md) and [Deploy](deploy.md)
- [Service accounts and tokens](service-accounts.md)
- [The MCP reference](../reference/en/mcp.md)
