# The Fieldstub MCP server

> Connect an AI assistant to Fieldstub over MCP. Ten tools for capturing extra work and filing it into Procore, with approval deliberately fenced off.

Source: https://fieldstub.com/docs/mcp/  ·  Updated 2026-08-30

Fieldstub speaks the Model Context Protocol, so an assistant can turn a description of what happened on site into a structured ticket, and see exactly where the money would land in Procore before anyone approves it.

Endpoint: `https://app.fieldstub.com/mcp`. Authentication is the same API key as the REST API, sent as a bearer token.

It is listed in the official MCP registry as `com.fieldstub/fieldstub`, so a client that reads the registry can find it without being told the URL.

## Connecting

Create a key at **/keys** in the review queue, then point your client at the endpoint with an `Authorization` header.

In Claude Code that is one line:

```
claude mcp add --transport http fieldstub https://app.fieldstub.com/mcp \
  --header "Authorization: Bearer fs_live_..."
```

Anywhere that takes a config file:

```
{
  "mcpServers": {
    "fieldstub": {
      "url": "https://app.fieldstub.com/mcp",
      "headers": { "Authorization": "Bearer fs_live_..." }
    }
  }
}
```

Streamable HTTP, stateless. No session to establish and nothing to keep alive: one POST, one response. Protocol versions `2025-11-25` and earlier are supported, which is what clients speak today.

> OAuth is not supported yet, so a client that only does the OAuth discovery flow will not connect. Bearer keys work everywhere a custom header can be set. Saying this plainly rather than letting you find out.

## Finding it

The server is published in the official [Model Context Protocol registry](https://registry.modelcontextprotocol.io):

| Field | Value |
|---|---|
| Name | `com.fieldstub/fieldstub` |
| Transport | `streamable-http` |
| URL | `https://app.fieldstub.com/mcp` |

The namespace is verified by domain ownership rather than a username, so `com.fieldstub/*` can only be published by somebody who controls fieldstub.com. The proof is public at [/.well-known/mcp-registry-auth](https://fieldstub.com/.well-known/mcp-registry-auth) if you want to check rather than take our word for it.

> Being in the registry gets an agent the address, not an account. The endpoint needs a bearer key, which needs a Fieldstub account, which needs the general contractor to have installed Fieldstub in their Procore. Discovery and access are separate problems and only one of them is solved by a listing.

## The tools

| Tool | What it does |
|---|---|
| `list_projects` | Procore projects on your company |
| `project_capability` | Whether a project can take a Change Event, or only a daily log. **Read this before approving** |
| `list_tickets` | Tickets, filterable by status and project |
| `get_ticket` | One ticket plus **routing**: where every line will land |
| `create_ticket` | Record extra work. Safe: nothing reaches Procore |
| `approve_ticket` | **Writes to Procore.** Marked destructive. Takes `destination` on a project with no Financials |
| `reject_ticket` | Close a ticket without writing |
| `search_cost_codes` | Find a cost code on a project |
| `create_budget_code` | Create a budget code the project lacks |
| `create_capture_link` | A no-login URL for the field |

## Two destinations, and the agent has to pick

Change Events live inside Procore's Project Financials. On a project without it there is no Change Events tool and no change event to write, so `approve_ticket` fails rather than improvising:

```
no_change_events: This project has no Change Events tool ...
Approve with destination "daily_log" to file the record to the Procore
daily log instead. That is a diary entry: it carries the description,
hours and who signed, it bills nothing, and it cannot carry the photos.
```

Call `project_capability` first on a project you have not seen:

```
{ "change_events": false, "daily_log": true, "destination": "daily_log" }
```

> The error is the design. An agent that silently downgraded a change event to a diary entry would be reporting success for something that files no money, and the person reading the summary would have no way to tell. Making it fail once, loudly, is cheaper than that.

`destination` is an enum of exactly two values and neither is a way around routing. On a project that *does* have Financials, `requireExact` is still on and an unconfirmed line is still refused.

## What we did about the obvious risk

An agent with a tool that writes into someone's construction financials is a bad idea handled carelessly. Four things, all of them enforced by the server rather than requested in a prompt.

**Approval is marked destructive.** `approve_ticket` carries `destructiveHint`, so clients that ask before destructive calls will ask. The reads are marked read-only so they do not.

**There is no way to accept a blank budget code.** The REST API has `allow_unrouted` for the case where somebody knowingly files a cost to the blank code. That parameter **does not exist on the MCP tool**, and passing it does nothing. It lives in the web review queue, where a person makes that call.

**A merely plausible match is refused too.** This is the subtle one. A line with no cost code still resolves to *a* code of the right cost type: real, plausible, and quite possibly wrong. A reviewer sees that flagged on screen and catches it. Nobody is on screen when an agent calls, so over MCP those lines are refused and must be placed explicitly with `routes`.

**Every response carries a `review_url`.** The moment an agent should stop and hand off, it already has the link to send a person to.

> The server tells the model all of this in its instructions before a single tool runs, so the rules arrive with the connection rather than depending on how someone worded a prompt.

## What a good flow looks like

1. Someone describes the extra work, in a message, a voice note, or a thread.
2. The assistant calls `create_ticket`. Nothing has touched Procore.
3. It calls `get_ticket` and reads `routing`.
4. It shows a person the total and the budget code each line will hit.
5. On an explicit yes, it calls `approve_ticket`. If a line is not on a confirmed code, the call is refused and it either supplies `routes` or sends the person to `review_url`.

Steps 1 to 4 are where the value is. Step 5 is the one to be careful with, and it is fine to decide your assistant never does it.

## Why it is a wrapper, not a second product

Every tool is one call into the same service layer the web review queue and the REST API use. There is one implementation of approving a ticket, so the MCP path cannot quietly develop different rules from the screen a project manager uses.

The one deliberate difference is the direction that makes it stricter, never looser: MCP always demands confirmed budget codes.

## Questions

### Which MCP protocol version does it support?

2025-11-25 and earlier. Revision 2026-07-28 removes sessions and the initialize handshake and adds required Mcp-Method and Mcp-Name headers; the server is stateless already, so that upgrade is additive once clients start asking for it.

### Does it support OAuth?

Not yet. Authentication is a bearer API key from /keys, which works with any client that lets you set a header. OAuth 2.1 with protected resource metadata is what the spec wants for remote servers and is on the list.

### Can an agent approve a ticket on its own?

Technically yes, and we would rather it did not. The tool is marked destructive so clients prompt, it refuses any line not on a confirmed budget code, and it cannot accept the blank code at all. Creating and reviewing tickets is the part worth automating.

### What stops one customer's agent seeing another customer's tickets?

The API key resolves to exactly one Procore company and every call is scoped to it. A ticket belonging to another company reads as though it does not exist.

### Is there a stdio version for local use?

No. The server is remote because the data is, and a local process would still need the same key to reach it.

## Related

- https://fieldstub.com/docs/api.md
- https://fieldstub.com/docs/procore-budget-codes.md

---

Fieldstub captures extra construction work from people with no Procore seat and files it into Procore as a Change Event. https://fieldstub.com/
