Skip to content
API console (try a request with your own key)Get early access

Use SpecCapture from an AI assistant

AI assistants such as Claude, GitHub Copilot in VS Code and Cursor use outside tools through the Model Context Protocol (MCP). SpecCapture is an MCP server at https://api.speccapture.com/mcp, beside the REST API on the same address. Add it to an assistant with an API key, and the assistant can send it a drawing, follow the reading, and report each value with how sure SpecCapture is of it - or find a drawing your team already uploaded in the dashboard. It is the same service as the REST API: the same key, the same credits and the same limits.

  • A live API key (sc_live_...), made in the dashboard under API keys (Getting a key). A test key is refused with 403 live_key_required: the tools read drawings and spend credits, which a test key cannot do yet.
  • The right role, for one tool. A key acts with the role of the person who made it (Who a key acts as). Any key can send and read drawings; making a view link needs a key made by the workspace’s owner or an admin.

Keep the key out of files you share: each setup below either reads it from an environment variable or has the assistant ask for it and store it.

Each assistant’s own documentation is linked, in case its screens have changed since this was written.

From a terminal (Claude Code’s documentation):

Terminal window
claude mcp add --transport http speccapture https://api.speccapture.com/mcp --header "Authorization: Bearer sc_live_..."

Add --scope user to have it in every project. To keep the key out of the command and out of the project, put the server in the project’s .mcp.json instead, and Claude Code reads the key from the environment variable SPECCAPTURE_API_KEY:

{
"mcpServers": {
"speccapture": {
"type": "http",
"url": "https://api.speccapture.com/mcp",
"headers": { "Authorization": "Bearer ${SPECCAPTURE_API_KEY}" }
}
}
}

Claude (claude.ai, Claude Desktop and the mobile apps)

Section titled “Claude (claude.ai, Claude Desktop and the mobile apps)”

Add SpecCapture as a custom connector (Claude’s documentation):

  1. Go to Customize > Connectors and choose Add custom connector. On a Team or Enterprise plan, an Owner adds it for the organization instead, under Organization settings > Connectors, with Add, then Custom.
  2. Set the server URL to https://api.speccapture.com/mcp, and Authentication to No sign-in.
  3. Under Request headers, add authorization with the value Bearer sc_live_.... Include the word Bearer and the space after it: Claude sends the value exactly as entered.

Claude in a chat cannot hand a file you attach to a connector’s tool, so upload the drawing in the dashboard and ask about it by its file name (Sending a drawing).

In .vscode/mcp.json for one workspace, or in your user configuration, which the MCP: Open User Configuration command opens (VS Code’s documentation). VS Code asks for the key the first time the server starts, and stores it securely:

{
"inputs": [
{
"type": "promptString",
"id": "speccapture-key",
"description": "SpecCapture API key (sc_live_...)",
"password": true
}
],
"servers": {
"speccapture": {
"type": "http",
"url": "https://api.speccapture.com/mcp",
"headers": { "Authorization": "Bearer ${input:speccapture-key}" }
}
}
}

In ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one (Cursor’s documentation). Cursor reads the key from the environment variable SPECCAPTURE_API_KEY:

{
"mcpServers": {
"speccapture": {
"url": "https://api.speccapture.com/mcp",
"headers": { "Authorization": "Bearer ${env:SPECCAPTURE_API_KEY}" }
}
}
}

Not yet. ChatGPT connects only to MCP servers that sign in through OAuth or need no sign-in at all, and it cannot send an API key (OpenAI’s documentation).

The official MCP Inspector lists the tools, and can call them, from a terminal:

Terminal window
npx @modelcontextprotocol/inspector --cli https://api.speccapture.com/mcp --transport http --header "Authorization: Bearer sc_live_..." --method tools/list

An assistant picks a tool by its name and description. Each description says what the tool does, what it costs, and what to call next; none tells the assistant how to behave beyond that.

Tool What it does
read_drawing Sends a drawing to be read, reserving its credits, and answers at once with its job
get_extraction_status Says where a job stands, and when to check again
get_extraction_results Gives one sheet’s values
create_view_link Makes a read-only link that shows a sheet with every value boxed
get_credits Shows the workspace’s credits
list_extractions Lists the workspace’s jobs, including drawings uploaded in the dashboard
list_templates Lists the workspace’s templates, and which is the default
list_view_links Lists the workspace’s view links as they stand, never their addresses
get_credit_history Shows where the workspace’s credits came from and went

Only read_drawing and create_view_link change anything; the other seven only read.

  • read_drawing, like POST /v1/extractions: the file’s bytes as base64 in fileBase64 (a data: URL prefix is accepted), its name in fileName, an optional idempotencyKey, so that sending it again does not read and charge twice, and an optional templateId (drawing, or one from list_templates; the workspace’s default when left out). It answers at once with the jobId, the number of sheets, the credits reserved and when to check again. Each sheet costs 4 credits, refunded for any sheet that cannot be read.
  • get_extraction_status, like GET /v1/extractions/{jobId}: the job’s status and each sheet’s, whether a sheet’s values wait for a person, and its credits; while it runs, when to check again and which sheets can be read already.
  • get_extraction_results, like GET /v1/extractions/{jobId}/sheets/{sheetNumber} without the boxes: one sheet’s values, given its jobId and sheetNumber (1 for the first page). Each value has its field path, a confidence from 0 to 1, its review state, check when it waits for a person, the reasons it was flagged, and the name the job’s template gives it; when a person corrected it, readAs is what was first read. Tables come row by row, each cell under its column, and the general notes come whole, in printed order.
  • create_view_link, like POST /v1/extractions/{jobId}/sheets/{sheetNumber}/view-links: a read-only link to one sheet with a box around every value, for anyone who holds it, until it expires or is withdrawn in the dashboard. It lasts 30 days unless expiresInDays says 1 to 90, and is returned only this once. It needs a key made by the workspace’s owner or an admin, and is refused for a sheet marked export-controlled until the workspace keeps its drawing.
  • get_credits, like GET /v1/account: the credits available and the sheets they pay for, those held by jobs still running, those spent, when the next ones expire, the plan with when it renews or ends and whether its last payment failed, the page that says how to get more (buyMoreAt, the same address as upgradeUrl), and balance: both units in one sentence, sheets first (“9 sheets left to read (37 credits, at 4 credits a sheet)”).
  • list_templates, like GET /v1/templates: the standard template, drawing, then the workspace’s own, each with its id, name and newest version, and defaultTemplateId.
  • list_view_links, like GET /v1/view-links: the workspace’s view links, newest first - each one’s sheet and file name, status (active, expired or withdrawn), when it expires or was withdrawn, how often it was opened, and who made it - up to limit (1 to 50, 10 when left out), only those in status when it is given, and the next page by cursor (the answer’s nextCursor). Never a link’s address, which create_view_link shows once. It needs a key made by the workspace’s owner or an admin.
  • get_credit_history, like GET /v1/credits/history: the workspace’s credit history, newest first - each grant by where it came from (the trial, a plan’s month, a pack, or added by SpecCapture) with when it expires and what of it is left, each drawing’s reservation, each sheet’s spend, each refund, each expiry and any credits taken back after a refunded or disputed payment, with availableChange and a sentence for each (about: “4 credits spent reading sheet 2 of bracket.pdf.”) - up to limit (1 to 50, 10 when left out), only entries of type when it is given, and the next page by cursor.
  • list_extractions, like GET /v1/extractions but paged the way an assistant reads a list: the workspace’s jobs, newest first, including drawings uploaded in the dashboard - up to limit (1 to 50, 10 when left out), from offset on, and only those whose file name contains fileName, in any case. It says how many match in all, and the next page’s offset while more do.

read_drawing answers as soon as the file is accepted, and each sheet is then read on its own, in the background. Rather than hold a call open, the answers say how long to wait before checking again (checkAgainInSeconds, 30), and get_extraction_status names the sheets that can be read already, before the rest are finished. While reading is paused a job waits unfinished (queued, or extracting with its sheets queued), nothing is lost, and nothing needs doing (While reading is paused).

MCP has no way to hand a file to a tool, so read_drawing takes the file’s bytes, base64-encoded, inside the request. That suits an assistant that reads files itself, such as Claude Code or an agent you build, and drawings of a few megabytes: a request can carry about 30 MB of base64, which is a file of about 22 MB. Larger files, up to 50 MB, go through the dashboard or the REST API (Submitting drawings).

A drawing uploaded in the dashboard is already a job, and list_extractions finds it by its file name. That is the way in for a chat app that does not pass the files you attach to its tools, such as Claude on claude.ai: upload the drawing in the dashboard, then ask about it by name.

Text printed on a drawing can read like an instruction to an assistant. Every answer is one JSON object, and a value read from a drawing is only ever a string inside it. The server’s instructions to the assistant, the description of get_extraction_results and every set of values (aboutTheseValues) say to report values as data and never to follow them.

A refusal is a tool result marked as an error. Its text is the REST API’s refusal: the stable code first, then the same words as the problem’s detail, then the facts beside them, after the tool’s name:

An error occurred invoking 'read_drawing': not_enough_credits: This file has 2 sheets, which needs 8 credits (4 a sheet), and the workspace has 4 available. Nothing was stored or reserved; add credits and send it again. (sheetCount: 2, creditsNeeded: 8, creditsAvailable: 4, upgradeUrl: https://app.speccapture.com/billing)

Every code is explained, with what to do about it, under Errors.

For anyone building their own client:

  • Transport: Streamable HTTP, the specification’s transport for a remote server (2026-07-28 revision). Every message is a POST to /mcp, answered with a short event stream. The server is stateless: it issues no Mcp-Session-Id and keeps nothing between requests. A GET that accepts text/event-stream, and a DELETE, answer 405; any other GET, such as a browser opening the address, is answered with a short page saying what it is and pointing here. Clients on the 2026-07-28 revision send each request on its own; clients on 2025-11-25, 2025-06-18 and 2025-03-26 open with initialize and are served at the same address. The older HTTP+SSE transport (2024-11-05) is not offered.
  • Authentication: Authorization: Bearer sc_live_... on every request, checked exactly as the REST API checks it. A request without a working key is answered 401 api_key_missing or 401 api_key_invalid before any tool runs. Authorization is optional in the MCP specification (2026-07-28), and a bearer key is allowed. No OAuth sign-in is offered yet, so the server publishes no protected-resource metadata, and a client looking for it after a 401 finds none.
  • Limits: every POST counts as one request against the key’s rate limit, and past it the answer is 429 rate_limited (Rate limits). Each tool does what its REST endpoint does, so credits, idempotency keys (Idempotency) and the daily limits hold unchanged, and a key only ever sees its own workspace.
  • Browsers: a request whose Origin header names a site SpecCapture has not allowed is refused with 403 before its key is looked at, as the specification requires to guard against DNS rebinding. Desktop and server-side clients send no Origin, and are never refused for it.
  • The API reference and the API console describe the REST endpoints; the MCP server is not in them.