# Connect Codex to Serpel over MCP

URL: https://serpel.app/docs/mcp/codex

Updated: 2026-10-10

Run `codex mcp add` to register the Serpel MCP server at `https://serpel.app/mcp`, then run `codex mcp login serpel` to sign in with your Serpel account. Codex can then read your rankings, crawl issues and search data while it works on your code. The server offers 13 tools, and only one of them uses credits.

## How do you add the Serpel MCP server to Codex?

1. **Add the server.** `--url` registers a streamable HTTP server. Codex stores the entry in `~/.codex/config.toml`.

```bash
codex mcp add serpel --url https://serpel.app/mcp
```

2. **Sign in.** This starts the OAuth login. Sign in to Serpel in the browser, choose the workspace and allow access.

```bash
codex mcp login serpel
```

3. **Check the server.** `codex mcp list` shows the configured servers and `codex mcp get serpel` shows one entry. Then ask Codex a question about your site.

```bash
codex mcp list
codex mcp get serpel
```

### Edit config.toml directly

You can write the same entry by hand. A `url` key makes Codex treat the server as a streamable HTTP server. Run `codex mcp login serpel` afterwards.

```toml
[mcp_servers.serpel]
url = "https://serpel.app/mcp"
```

### Sign out or remove the server

```bash
codex mcp logout serpel
codex mcp remove serpel
```

## How does the OAuth sign-in work?

Codex follows the MCP authorisation specification: OAuth 2.1 with PKCE (S256). The server answers an unauthenticated request with HTTP 401 and a `WWW-Authenticate` header that points to the discovery documents. The client registers itself, opens `/oauth/authorize` in your browser and exchanges the code at `/oauth/token`. You do not need to create a client ID or a secret.

On the consent page you sign in to Serpel if needed, choose the workspace and review the permissions. The access token gets these scopes: `mcp:read`, `projects:read`, `rankings:read`, `audit:read`, `keywords:read`, `keywords:write`, `recommendations:read`, `codebase:read`. It only works at the MCP server. The REST API rejects it. Access tokens last 1 hour. Refresh tokens last 30 days and rotate each time they are used, so you stay signed in without doing anything.

| Address | Purpose |
| --- | --- |
| `https://serpel.app/.well-known/oauth-protected-resource/mcp` | Describes the MCP server as an OAuth resource. |
| `https://serpel.app/.well-known/oauth-authorization-server` | Describes the authorisation server: endpoints, PKCE, supported grants. |
| `https://serpel.app/oauth/register` | Dynamic client registration. |
| `https://serpel.app/oauth/authorize` | The consent page in your browser. |
| `https://serpel.app/oauth/token` | Exchanges a code or a refresh token for an access token. |
| `https://serpel.app/oauth/revoke` | Revokes a token and the whole connection. |

To disconnect an app, open Settings, API, Connected apps in the dashboard. Disconnecting revokes the access and refresh tokens at once.

`codex mcp login` chooses the client registration method itself (`auto`). Serpel supports both dynamic client registration and client ID metadata documents, so the default works. You can force one for a single login with `--oauth-client-registration cimd` or `--oauth-client-registration dcr`.

## How do you connect with a bearer token instead?

Use an API token when Codex cannot open a browser, for example on a server or in CI. Create the token in the dashboard under Settings, API tokens. It needs the `mcp:read` scope, plus the scopes of the tools you want to use:

- `mcp:read`: required for every call. Without it, the server answers with HTTP 403.
- `projects:read`: `list_projects`, `get_project_overview`, `get_search_performance`, `find_keyword_opportunities`, `get_conversion_performance`.
- `rankings:read`: `get_keyword_rankings`, `get_ai_visibility`, `analyze_competitors`, and `get_job_status` for rank checks, AI checks and monitoring runs.
- `audit:read`: `get_crawl_issues`, and `get_job_status` for crawls.
- `recommendations:read`: `get_seo_recommendations`.
- `codebase:read`: `get_codebase_overview`.
- `keywords:write`: `research_keywords`.

You can restrict the token to single projects. The tools then see only those projects.

The OAuth login happens in a browser. On a machine without one, give Codex the name of an environment variable that holds the token. Codex sends its value as the bearer token and never writes it to `config.toml`.

```bash
export SERPEL_TOKEN=vsk_your_token
codex mcp add serpel --url https://serpel.app/mcp --bearer-token-env-var SERPEL_TOKEN
```

```toml
[mcp_servers.serpel]
url = "https://serpel.app/mcp"
bearer_token_env_var = "SERPEL_TOKEN"
```

## Which tools does the Serpel MCP server provide?

The server offers 13 tools. All of them check the scope, your project role and your workspace before they return data, so an agent only sees what you could see yourself. Lists hold at most 25 rows, and every result is compact JSON with a short summary sentence.

| Tool | What it does | Needs scope | Cost |
| --- | --- | --- | --- |
| `list_projects` | Lists your projects with ID, domain, market and your role. Call it first: every other tool needs a project ID from this list. | `projects:read` | Free |
| `get_project_overview` | Summarises one project: audit score and issue counts, ranking summary, AI visibility, task counts, the most important issues and next steps. Sections the token has no scope for are left out. | `projects:read` | Free |
| `get_keyword_rankings` | Shows tracked keywords with the latest and previous Google position, the change and a ranking summary. Supports `query`, `limit` and `offset`. | `rankings:read` | Free |
| `get_search_performance` | Shows clicks, impressions, click-through rate and average position from Google Search Console or Bing Webmaster Tools, compared with the previous period, plus the top queries or pages. Needs a search data connection in the dashboard. | `projects:read` | Free |
| `find_keyword_opportunities` | Finds queries on positions 4 to 20 with impressions, sorted by impressions. These are the quickest ranking wins. Needs a Search Console connection. | `projects:read` | Free |
| `get_crawl_issues` | Lists the issues of the latest completed crawl by type, sorted by severity and affected pages, with the audit score and the change since the previous crawl. | `audit:read` | Free |
| `get_ai_visibility` | Shows how often ChatGPT cites or mentions your website for your tracked prompts and how often Google shows an AI Overview that cites it, with the latest result per prompt and the sources the answers cite most. Reads stored checks and starts no new check. Supports `limit`. | `rankings:read` | Free |
| `get_seo_recommendations` | Lists prioritised recommendations with rule, impact, estimated monthly clicks, confidence, effort, keyword, page, code route, next action and evidence. By default only open and accepted ones. | `recommendations:read` | Free |
| `get_codebase_overview` | Summarises the latest snapshot uploaded with `serpel scan`: routes without title or description, routes without a live page, live pages without a route and differences between code and live site. | `codebase:read` | Free |
| `get_conversion_performance` | Shows sessions, conversions and conversion rate per landing page from PostHog, Plausible or Google Analytics 4, for the conversion events you chose in the dashboard. | `projects:read` | Free |
| `analyze_competitors` | Compares the project with its saved competitors using the stored Google results: visibility per domain, how often each competitor is ahead and the keywords where one ranks better. Runs no new searches. | `rankings:read` | Free |
| `get_job_status` | Checks a crawl, rank check, AI visibility check or monitoring run by job ID: status, progress, error and a summary of the result. | `audit:read` for crawls, `rankings:read` for the other jobs | Free |
| `research_keywords` | Looks up keyword ideas or metrics: search volume, CPC, keyword difficulty and search intent. Modes: `keyword`, `list` and `domain`. Returns at most 25 results and saves the full run in the dashboard. | `keywords:write` | Uses credits |

All tools except `research_keywords` are read-only and free. They never change your data or your website. Crawls, rank checks, AI visibility checks and monitoring runs do not start inside a tool call. You start them in the dashboard, with the [CLI](https://serpel.app/docs/cli) or through the [REST API](https://serpel.app/docs/api), and then follow them with `get_job_status`. Tools that need a data source, such as Search Console, tell the agent what to connect in the dashboard when it is missing.

In apps that can show interactive cards, such as ChatGPT and Claude, `get_keyword_rankings`, `get_crawl_issues`, `find_keyword_opportunities` and `get_ai_visibility` also show their result as a card. Every other client gets the same data as text. ChatGPT does not offer `research_keywords`.

## How do agent spending and budgets work?

`research_keywords` is the only tool that uses credits, and it runs only when every one of these conditions holds. Serpel checks them in this order:

1. The token has the `keywords:write` scope. OAuth sign-in grants it.
2. The workspace has an active Starter or Pro plan.
3. The workspace owner allowed agent spending: “Agents can spend credits” under Settings, Billing, Agents and AI apps, or `serpel agents allow`.
4. One call costs at most 50 credits, and today’s agent spending plus the call stays within the daily limit. The default limit is 500 credits per day. You can set it between 1 and 100,000 with `serpel agents daily-limit <credits>`. The day follows UTC and resets at 00:00 UTC.
5. The workspace has enough credits. Serpel uses the monthly plan allowance first and then credits you bought.

A research for 25 keyword ideas costs 12 credits, and a research of the keywords a domain ranks for costs 6 credits. Fewer results cost fewer credits. Every result states the credits charged (`credits.charged`), your balance, the remaining monthly allowance and the remaining agent budget for the day (`dailyAgentBudget`). If the agent repeats a call after a network error, it passes the same `requestId`, and the research is charged once.

| Error code | When it happens | Extra fields |
| --- | --- | --- |
| `forbidden` | The token has no `keywords:write` scope. | None |
| `plan_required` | The workspace has no Starter or Pro plan. | `pricingUrl` |
| `agent_spend_disabled` | The owner has not allowed agents to spend credits. | `settingsUrl` |
| `validation_error` | The call could cost more than 50 credits, or the input is invalid. | None |
| `daily_cap_reached` | The call would exceed the daily limit for agents. | `dailyCapCredits`, `spentTodayCredits`, `requiredCredits`, `resetsAt` |
| `insufficient_credits` | The workspace does not have enough credits. | `requiredCredits`, `availableCredits`, `nextAllowanceDate`, `pricingUrl` |

Tool results only link to the dashboard and to the [pricing page](https://serpel.app/pricing). They never link to a checkout or a top-up, so an agent cannot buy credits for you.

## Which prompts work well in Codex?

Ask in plain language. Codex starts with `list_projects` to find the project ID.

- “Use Serpel to find keywords that rank on positions 4 to 20 and propose three content changes for this repository.”
- “Check the Serpel crawl issues for my project and fix the five most severe ones in the code.”
- “Compare my tracked keywords with my competitors and write a short plan for the keywords where they are ahead.”
- “Which routes in this repository have no title or description according to Serpel’s codebase overview?”
- “Look up keyword ideas for ‘light roast coffee’ in the US. Show me the credit cost first and wait for my approval.”

The codebase overview needs a snapshot of your routes. Upload one with `serpel scan --project <id>`. The [CLI reference](https://serpel.app/docs/cli) explains the scan.

## How do you troubleshoot the connection?

| What you see | What to do |
| --- | --- |
| `codex mcp list` shows the server as not logged in | Run `codex mcp login serpel` and finish the browser sign-in. Without a credential source, Codex can connect without authentication, and Serpel then answers with HTTP 401. |
| Codex cannot use the token from `bearer_token_env_var` | Export `SERPEL_TOKEN` in the shell that starts Codex, and check that the token is valid and has the `mcp:read` scope. |
| HTTP 401, or the client reports that it needs authentication | The client has no valid token. Sign in again with OAuth, or check that your API token is correct, not expired and not revoked. |
| HTTP 403 with `insufficient_scope` | The API token has no `mcp:read` scope. Create a token that includes it. |
| A tool answers `forbidden` | The token or your project role lacks the scope the tool needs. The tool table above names the scope for each tool. |
| A tool answers `not_found` | The project or job does not exist, or your token is restricted to other projects. Call `list_projects` and use an ID from that list. |
| `get_search_performance` or `find_keyword_opportunities` ask for a connection | Connect Google Search Console or Bing Webmaster Tools for the project in the dashboard. The tool result contains the link. |
| `analyze_competitors` returns no data | It reads stored results. Run a rank check and add competitors first. |
| HTTP 429 or `rate_limited` | A token may send 120 requests per minute. Wait for the seconds in `Retry-After` or `retryAfterSeconds`. |
| HTTP 405 on a GET request | Expected. The server is stateless and only accepts POST requests with JSON-RPC messages. MCP clients handle this themselves. |

More about `codex mcp` and `config.toml` is in the [Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).