# MCP server

Source: https://webagent-docs-staging.lookover.ai/mcp

> The hosted webagent MCP endpoint. URL, transport, authentication and error statuses.

webagent runs a hosted [MCP](https://modelcontextprotocol.io) server. An MCP client such as Claude Code or Codex CLI connects to it and gets tools that open cloud browsers, run goals in them, scrape pages and run skills. You install nothing on your machine.

> **Note: API address**
>
> The default API address is `https://api.us.webagent.lookover.ai`, so the MCP URL is `https://api.us.webagent.lookover.ai/mcp`. If your organization was given another API address, use that one. The shell example below uses the variable `API_URL`: set it with `export API_URL=https://api.us.webagent.lookover.ai`, and set `WEBAGENT_API_KEY` to your API key.

## At a glance [#at-a-glance]

| | |
|---|---|
| URL | `https://api.us.webagent.lookover.ai/mcp` (the API address, then `/mcp`) |
| Transport | Streamable HTTP, `POST` only |
| State | Stateless. No MCP session id, no server-sent stream |
| Replies | A single JSON body per request |
| Authentication | An API key, as `Authorization: Bearer <key>` or `x-api-key: <key>` |
| Server name | `webagent` |
| Server version | `0.1.0` |
| Tools | 15 fixed tools, plus one `skill_<name>` tool per skill. See [Tools](/mcp/tools) |

## Connect a client [#connect-a-client]

Create an API key in the dashboard, then add the server to your client. Each client has its own install line:

- [Claude Code](/qa-testing/claude-code)
- [Codex CLI](/qa-testing/codex)

Any other client that supports Streamable HTTP and custom headers works the same way. Point it at `https://api.us.webagent.lookover.ai/mcp` and send the key in the `Authorization` header.

## Transport [#transport]

The endpoint accepts `POST` only. A `GET` or `DELETE` returns `405` with an `Allow: POST` header and the error code `method_not_allowed`. The server keeps no state between requests, so a client sends `initialize`, `tools/list` and `tools/call` as separate `POST` requests and needs no session header.

The request must send `Content-Type: application/json` and an `Accept` header that lists both `application/json` and `text/event-stream`. Without them the server answers `415` or `406`. The server replies with plain JSON, never an event stream.

A raw call looks like this:

```bash title="List the tools"
curl -s $API_URL/mcp \
  -H "Authorization: Bearer $WEBAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

The reply is one JSON body. Trimmed:

```json
{
  "result": {
    "tools": [
      { "name": "create_session", "description": "...", "inputSchema": { "type": "object", "properties": { "...": "..." } } },
      { "name": "run_task", "description": "...", "inputSchema": { "...": "..." } }
    ]
  },
  "jsonrpc": "2.0",
  "id": 1
}
```

## Authentication [#authentication]

Use an API key from the dashboard. Keys look like `wa_us_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`. The key decides the organization, the project and the role of every call, so tools run with the same limits as the REST API.

Send the key in one of two headers:

```http
Authorization: Bearer wa_us_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

```http
x-api-key: wa_us_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

A key belongs to one region. The region is the part after `wa_`.

## Errors [#errors]

Problems with the connection itself are HTTP errors. The body is `{ "error": { "code", "message" } }`, except for 406 and 415, which the MCP transport answers with a JSON-RPC error.

| Status | `error.code` | When |
|---|---|---|
| 401 | `unauthorized` | No key, or a key that is not valid |
| 421 | `wrong_region` | The key belongs to another region than this API. `error.details.region` names it |
| 429 | `rate_limited` | More than 600 requests in a minute for this key (the default). `Retry-After` says how many seconds to wait |
| 405 | `method_not_allowed` | `GET` or `DELETE` on `/mcp` |
| 406 | none | The `Accept` header does not list both `application/json` and `text/event-stream` |
| 415 | none | The `Content-Type` is not `application/json` |

The rate limit counts every request to the API for the key, REST and MCP together. One MCP message is one request. The limit may change.

A tool that fails is not an HTTP error. The call returns normally, with `isError: true` and the error as text (`[code] message`) and in `structuredContent.error`. A test that ran and failed is not an error at all: `isError` is set only when a test could not run. See [Tools](/mcp/tools#results-and-errors).

## Tools [#tools]

Every `tools/list` call returns the 15 fixed tools, then one tool for each skill your project can see. A skill named `smoke-uat` appears as `skill_smoke_uat`. Dashes in the skill name become underscores. The list is built on each call, so a skill you add shows up on the next `tools/list`. Your client may need to reload its tool list to see it.

The server also sends a short instruction text on `initialize`. It names the tool families: browser sessions, quick actions (scrape, screenshot, pdf, crawl) and skill runs. It also tells the agent how to test a page: call `smoke_test` for a pass/fail verdict, then `get_report` while the verdict is `running`. It says that a failed test is a result and `isError` is set only when the test could not run, and that `run_task` is for an open-ended goal and checks no assertions.

To test a page or a flow, start with [`smoke_test`](/mcp/tools#smoke_test). It makes one call, records the session and returns a report. [`get_report`](/mcp/tools#get_report) reads the report of a run or a task. [`run_task`](/mcp/tools#run_task) is for exploring.

Next: [the tool reference](/mcp/tools), and [how limits apply](/concepts/limits).
