FieldstubDocs › MCP

The Fieldstub MCP server

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.

Last updated 2026-08-30 · Read as markdown

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:

FieldValue
Namecom.fieldstub/fieldstub
Transportstreamable-http
URLhttps://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 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#

ToolWhat it does
list_projectsProcore projects on your company
project_capabilityWhether a project can take a Change Event, or only a daily log. Read this before approving
list_ticketsTickets, filterable by status and project
get_ticketOne ticket plus routing: where every line will land
create_ticketRecord extra work. Safe: nothing reaches Procore
approve_ticketWrites to Procore. Marked destructive. Takes destination on a project with no Financials
reject_ticketClose a ticket without writing
search_cost_codesFind a cost code on a project
create_budget_codeCreate a budget code the project lacks
create_capture_linkA 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.

Put a code on one job and see what comes back.

Fieldstub turns a phone and a QR code into a signed Change Event in Procore. The field needs no login and no seat.

Start free