# VATBuild MCP Server

VATBuild is a UK construction VAT reclaim platform built on HMRC Notice 708. This MCP server lets any AI assistant classify invoice line items, manage VAT projects, and route reclaim decisions — all without leaving the chat interface.

**Endpoint:** `POST https://vatbuild.com/mcp` (JSON-RPC 2.0, Streamable HTTP)
**Protocol:** Model Context Protocol (MCP), stateless transport

---

## Getting started

You need a free VATBuild account and an API key before calling the authenticated tools.

**Option A — OAuth 2.1 with PKCE (recommended for directory-listed agents)**

VATBuild supports OAuth 2.1 with PKCE via standard discovery endpoints. MCP clients that support RFC 9728 (including Claude desktop) auto-discover these and drive the PKCE flow without manual key management:

```
GET https://vatbuild.com/.well-known/oauth-authorization-server
GET https://vatbuild.com/.well-known/oauth-protected-resource
```

See the client integration guides for the full PKCE parameter reference:
[claude-integration.md](../claude-integration.md#oauth--pkce-alternative) · [chatgpt-integration.md](../chatgpt-integration.md#oauth-21-pkce--user-delegated-auth) · [gemini-integration.md](../gemini-integration.md#oauth--pkce-alternative)

**Option B — Bearer API key (web dashboard or CLI)**

Sign up at [vatbuild.com](https://vatbuild.com), go to **Settings → API Keys**, create a key, and paste it into your client config. Keys have the format `vb_live_<64 hex characters>` and are shown only once.

**Option C — Device-code flow via MCP (bootstrap without a browser)**

`create_account` and `authenticate_account` are public tools (no key required) and implement a secure email-verified device-code consent flow:

1. Call `create_account` — VATBuild sends a **confirmation email**. No API key is returned and no account is created until the user clicks the link.
2. Once the user confirms their email, call `authenticate_account` with the same address — returns a `user_code` and `request_id`.
3. Display the `user_code` to the user and ask them to check their email and click "Approve API access" (the approval page shows the same code for verification).
4. Poll `poll_authentication` every 3–5 seconds — once the user approves, it returns `{ status: "ready", key_retrieval_url }`.
5. Give the user `key_retrieval_url` to open in their browser — the page shows the API key and config snippet. Never pass the key as a tool argument.

> **Note for MCP session clients (Claude Desktop, ChatGPT connector):** Session clients can complete the `initialize` handshake without credentials and call `check_line_item` with no key. Auth is enforced per-tool: calling a gated tool without a valid Bearer token returns HTTP 401 with `WWW-Authenticate: Bearer resource_metadata=…` (RFC 9728), triggering OAuth discovery. Claude Desktop handles this automatically by opening a browser for the PKCE consent flow. Option C (device-code flow) is also available for clients that cannot use OAuth.

---

## All tools

| Tool | Auth | Description |
|---|---|---|
| `check_line_item` | Public | Classify a single invoice line against HMRC Notice 708 — stateless, no persistence |
| `create_account` | Public | Start account registration — sends a confirmation email; no key is returned until the user confirms and completes the device-code flow |
| `authenticate_account` | Public | Start the device-code consent flow for an existing account — returns a user_code and request_id; key is delivered via poll_authentication after user approval |
| `check_account_status` | Bearer key | Return account status — verification, plan, and pending actions |
| `set_up_project` | Bearer key | Create a new VAT project with a scheme and building details |
| `list_projects` | Bearer key | List all projects in the authenticated user's organisation |
| `assess_project_eligibility` | Bearer key | Run an HMRC Notice 708 eligibility check before uploading invoices |
| `list_invoices` | Bearer key | List invoice documents and their extraction status for a project |
| `list_line_items` | Bearer key | Retrieve paginated invoice line items for a project |
| `route_line_item` | Bearer key | Classify and persist a VAT routing decision to a project |
| `answer_vat_complex_question` | Bearer key | Submit an answer to a pending complex-VAT question (ESM, supply-and-install, etc.) |
| `reclassify_companion_items` | Bearer key | Re-route sibling items on an invoice after a complex-VAT answer |
| `submit_invoice_data` | Bearer key | Upload invoice image or document data for AI extraction and classification |

For full input/output schemas for every tool, see [mcp-tool-reference.md](../mcp-tool-reference.md).

### Project scope — one project per VAT regime

A VATBuild project always represents a **single VAT regime**. All invoices within a project are assessed under the same rules. When a build spans more than one regime — for example, a barn conversion (`self_build_431c`) that also includes constructing a new separate dwelling annexe (`self_build_431nb`) — each regime requires its own project, and suppliers must issue separate invoices for work covering each element.

VATBuild has two built-in helpers for this: the **project setup wizard** in the web app identifies multi-regime builds during profiling and prompts the user to create separate projects; and the **VAT Actions workflow** on each project surfaces action items guiding the user to contact suppliers and request split invoices. See the [`set_up_project` section of mcp-tool-reference.md](../mcp-tool-reference.md#set_up_project-requires-auth) for full guidance and worked examples.

---

## API key scopes

A VATBuild API key grants access to tools within its granted scopes:

- `projects:read` — read project data, line items, invoices, and eligibility
- `projects:write` — create and update projects
- `line_items:write` — route line items, answer VAT questions, re-classify companion items, and submit invoice data
- `jobs:read` — poll extraction job status via the REST API (`GET /api/v1/jobs/{jobId}`)
- `invoices:write` — submit invoice data (`submit_invoice_data`) and lock/manage invoices via the REST API. Use this for upload-only keys that should not grant manual line-item override access.

`check_line_item`, `create_account`, `authenticate_account`, `poll_authentication`, and `check_account_status` are publicly accessible without any key. All other tools require authentication: calling a gated tool without a valid Bearer token returns **HTTP 401** with `WWW-Authenticate: Bearer resource_metadata=…` (RFC 9728). OAuth-capable clients (Claude Desktop, ChatGPT) use this 401 to trigger automatic discovery and drive the PKCE browser flow — no agent intervention needed.

> **Note for MCP session clients:** Session clients can complete the `initialize` handshake without credentials and call `check_line_item` with no key. Auth is enforced per-tool: calling a gated tool without a valid Bearer token returns HTTP 401 + `WWW-Authenticate`, triggering OAuth discovery. Claude Desktop handles this automatically by opening a browser for the PKCE consent flow. A Bearer token is needed only to use the project tools.

---

## Step 1 — Configure Claude Desktop

Open (or create) your Claude Desktop MCP configuration file:

| OS | Path |
|---|---|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |

Add the VATBuild server to the `mcpServers` object:

```json
{
  "mcpServers": {
    "vatbuild": {
      "type": "http",
      "url": "https://vatbuild.com/mcp",
      "headers": {
        "Authorization": "Bearer vb_live_<your-64-hex-key>"
      }
    }
  }
}
```

If you already have other MCP servers configured, merge the `"vatbuild"` entry into the existing `mcpServers` object — do not replace the whole file.

A ready-to-paste template is in [claude-config.json](claude-config.json). Replace `<YOUR_VATBUILD_API_KEY>` with your actual key.

## Step 2 — Restart Claude Desktop

Quit and relaunch Claude Desktop. The VATBuild tools should appear in the tool list (look for the hammer icon or "Add from MCP" in the composer).

## Step 3 — Add the system prompt

For best results, add the VATBuild system prompt to your Claude project or conversation instructions. Download your personalised copy from **Settings → API Keys → System Prompts** inside your VATBuild account.

## Step 4 — Test the connection

Ask Claude:

> "Use the VATBuild check_line_item tool to classify this line: structural brickwork, £5,000 net, £0 VAT, labour supply type, on a self_build_431nb new build."

Claude should call `check_line_item` and return the classification with the HMRC rule explanation.

---

## Other MCP clients

The endpoint is `POST https://vatbuild.com/mcp` (JSON-RPC 2.0, Streamable HTTP transport). `/sse` is a path alias for the same Streamable HTTP transport — `POST https://vatbuild.com/sse` behaves identically to `/mcp`. Note that `GET /sse` returns **405 Method Not Allowed**; `/sse` does **not** implement the legacy HTTP+SSE transport. MCP clients must be configured with `"type": "streamableHttp"` (or the equivalent for their SDK), not `"type": "sse"`.

**Generic JSON config (any MCP-compatible client):**

```json
{
  "endpoint": "https://vatbuild.com/mcp",
  "transport": "streamable-http",
  "auth": {
    "type": "bearer",
    "token": "vb_live_<your-64-hex-key>"
  }
}
```

**CLI / curl — quick test without a client:**

```bash
curl -X POST https://vatbuild.com/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "check_line_item",
      "arguments": {
        "context": {
          "projectType": "new_build",
          "newDwelling": "yes",
          "buildingType": "detached house",
          "claimantRoute": "self_build_431nb"
        },
        "item": {
          "lineText": "Structural brickwork",
          "netAmount": "5000.00",
          "vatCharged": "0.00",
          "supplyType": "labour",
          "identifierName": null,
          "vatComplexTypeHint": null,
          "esmStatus": null,
          "relation": null,
          "confirmedAnswer": null,
          "esmInvoiceCtx": false,
          "saiInvoiceCtx": false
        }
      }
    }
  }'
```

`check_line_item` is public — no `Authorization` header needed for this test. Add `-H "Authorization: Bearer vb_live_..."` for authenticated tools.

**Origin policy:** The `/mcp` endpoint is intended for server-to-server requests and CLI agents. Requests without an `Origin` header (all server and CLI clients) are allowed. Browser-origin requests from a domain not listed in the server's `APP_ORIGIN` config are rejected with `403 Forbidden` — use the REST API (`POST /api/v1/check-line-item`) from browser clients instead.

---

## Rate limits

| Endpoint | Limit |
|---|---|
| `POST /mcp` — all tools, unauthenticated (by IP) | 200 requests/min |
| `POST /mcp` — all tools, authenticated (per user — userId or API key) | 60 requests/min |
| `route_line_item`, `answer_vat_complex_question`, `reclassify_companion_items` | 10 requests/min per API key |
| `create_account`, `authenticate_account` | 3 requests/hour per IP |
| `check_line_item` — unauthenticated callers and `free`/`self_build` plan users | **5 calls per 24 hours** (per IP for anonymous; per API key for authenticated) — `full_monthly`, `full_annual`, and `pro` plans exempt |
| `POST /oauth/token` | 60 requests/min per `client_id` (IP fallback for requests with no identity) |
| `GET /oauth/authorize` | 30 requests/min per authenticated user (IP fallback for unauthenticated visits) |
| `POST /oauth/register` (DCR) | 20 requests per 15 min per IP |

All 429 responses include a `Retry-After` header. When the daily cap is reached, the response body contains `{ ok: false, error: "daily_limit_reached", retryAfterSecs }`. See [mcp-tool-reference.md](../mcp-tool-reference.md#check_line_item-public-no-auth-required) for full detail.

---

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| Tools don't appear in Claude | Config file not found or JSON is invalid | Validate the JSON at jsonlint.com and check the file path |
| `401 Unauthorized` | API key missing or invalid | Check the `Authorization: Bearer ...` header value |
| `403 Forbidden` | Browser-origin request blocked | Use a non-browser client; MCP is server-to-server only |
| `429 Too Many Requests` | Rate limit exceeded | Wait for `Retry-After` seconds before retrying |
| `503 Service Unavailable` | Server still initialising on cold start | Retry in 5 seconds |
| `401 Unauthorized` on a gated tool call | Bearer token missing or revoked | OAuth clients re-trigger discovery automatically; for API-key users, check Settings → API Keys on vatbuild.com |

---

## Third-party registry listings (Smithery, MCP.run, etc.)

VATBuild may appear in external MCP directories such as [Smithery](https://smithery.ai) and [MCP.run](https://mcp.run). Those hosted listings are managed outside this repository. If a directory snippet shows an `mcpServers` block **without** `"type": "http"`, it is using the old pre-1.0 format and will fail on current Claude Desktop builds.

The correct Claude-targeting block is:

```json
{
  "mcpServers": {
    "vatbuild": {
      "type": "http",
      "url": "https://vatbuild.com/mcp",
      "headers": {
        "Authorization": "Bearer <YOUR_VATBUILD_API_KEY>"
      }
    }
  }
}
```

**Key requirement:** `"type": "http"` must be present at the server level. Omitting it causes Claude Desktop to silently skip the server on startup.

To update an external listing:

1. **Smithery** — open the VATBuild entry in the Smithery dashboard, edit the "Claude config" snippet, and ensure `"type": "http"` is present inside the `vatbuild` object.
2. **MCP.run** — open the VATBuild connector page, select "Edit", and verify the config block matches the template above.
3. **Any other directory** — apply the same check: every `mcpServers` entry targeting a remote HTTP server must carry `"type": "http"`.

The canonical template for external listings is the file [`claude-config.json`](claude-config.json) in this directory. Always copy from there to keep external listings in sync.

---

## See also

- [Agent workflow guide](../agent-workflow-guide.md) — consolidated 12-step end-to-end workflow from check_line_item to report, with user-confirmation boundary and decision tree
- [Full tool reference](../mcp-tool-reference.md) — per-tool input/output schemas, error codes, and field descriptions
- System prompts — download personalised copies from **Settings → API Keys → System Prompts** inside your VATBuild account
- [ChatGPT connection guide](../chatgpt-integration.md) — OAuth-based setup for ChatGPT Custom Connectors
- [OpenAPI spec](../openapi.yaml) — REST API OpenAPI 3.1 spec (`POST /api/v1/check-line-item` companion endpoint)
