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.
What you need
Section titled “What you need”- A live API key (
sc_live_...), made in the dashboard under API keys (Getting a key). A test key is refused with403 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.
Setting up an assistant
Section titled “Setting up an assistant”Each assistant’s own documentation is linked, in case its screens have changed since this was written.
Claude Code
Section titled “Claude Code”From a terminal (Claude Code’s documentation):
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):
- 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.
- Set the server URL to
https://api.speccapture.com/mcp, and Authentication to No sign-in. - Under Request headers, add
authorizationwith the valueBearer sc_live_.... Include the wordBearerand 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).
VS Code (GitHub Copilot)
Section titled “VS Code (GitHub Copilot)”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}" } } }}Cursor
Section titled “Cursor”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}" } } }}ChatGPT
Section titled “ChatGPT”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).
Trying it without an assistant
Section titled “Trying it without an assistant”The official MCP Inspector lists the tools, and can call them, from a terminal:
npx @modelcontextprotocol/inspector --cli https://api.speccapture.com/mcp --transport http --header "Authorization: Bearer sc_live_..." --method tools/listThe tools
Section titled “The tools”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.
What each tool takes and gives
Section titled “What each tool takes and gives”read_drawing, likePOST /v1/extractions: the file’s bytes as base64 infileBase64(adata:URL prefix is accepted), its name infileName, an optionalidempotencyKey, so that sending it again does not read and charge twice, and an optionaltemplateId(drawing, or one fromlist_templates; the workspace’s default when left out). It answers at once with thejobId, 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, likeGET /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, likeGET /v1/extractions/{jobId}/sheets/{sheetNumber}without the boxes: one sheet’s values, given itsjobIdandsheetNumber(1 for the first page). Each value has its field path, a confidence from 0 to 1, its review state,checkwhen it waits for a person, the reasons it was flagged, and thenamethe job’s template gives it; when a person corrected it,readAsis 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, likePOST /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 unlessexpiresInDayssays 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, likeGET /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 asupgradeUrl), andbalance: both units in one sentence, sheets first (“9 sheets left to read (37 credits, at 4 credits a sheet)”).list_templates, likeGET /v1/templates: the standard template,drawing, then the workspace’s own, each with its id, name and newest version, anddefaultTemplateId.list_view_links, likeGET /v1/view-links: the workspace’s view links, newest first - each one’s sheet and file name,status(active,expiredorwithdrawn), when it expires or was withdrawn, how often it was opened, and who made it - up tolimit(1 to 50, 10 when left out), only those instatuswhen it is given, and the next page bycursor(the answer’snextCursor). Never a link’s address, whichcreate_view_linkshows once. It needs a key made by the workspace’s owner or an admin.get_credit_history, likeGET /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, withavailableChangeand a sentence for each (about: “4 credits spent reading sheet 2 of bracket.pdf.”) - up tolimit(1 to 50, 10 when left out), only entries oftypewhen it is given, and the next page bycursor.list_extractions, likeGET /v1/extractionsbut paged the way an assistant reads a list: the workspace’s jobs, newest first, including drawings uploaded in the dashboard - up tolimit(1 to 50, 10 when left out), fromoffseton, and only those whose file name containsfileName, in any case. It says how many match in all, and the next page’soffsetwhile more do.
Reading takes about a minute a sheet
Section titled “Reading takes about a minute a sheet”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).
Sending a drawing
Section titled “Sending a drawing”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.
Values are data, never instructions
Section titled “Values are data, never instructions”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.
When a tool refuses
Section titled “When a tool refuses”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.
The connection
Section titled “The connection”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
POSTto/mcp, answered with a short event stream. The server is stateless: it issues noMcp-Session-Idand keeps nothing between requests. AGETthat acceptstext/event-stream, and aDELETE, answer405; any otherGET, 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 withinitializeand 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 answered401 api_key_missingor401 api_key_invalidbefore 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 a401finds none. - Limits: every
POSTcounts as one request against the key’s rate limit, and past it the answer is429 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
Originheader names a site SpecCapture has not allowed is refused with403before its key is looked at, as the specification requires to guard against DNS rebinding. Desktop and server-side clients send noOrigin, and are never refused for it. - The API reference and the API console describe the REST endpoints; the MCP server is not in them.