Tools
MCP — agents and IDEs
Connect Claude Code, Cursor, or any MCP client to ARCNM over HTTP with a bearer token.
ARCNM ships a Model Context Protocol server, auto-generated from the REST API. MCP-speaking agents and IDEs can quote parts, inspect calculations, and read your data through typed tools — without you writing glue code.
Endpoint: https://api.arcnm.io/mcp-server/mcp (HTTP transport,
bearer-JWT protected).
Why MCP, not REST
If you're writing application code, use REST. Pick MCP when an agent is the client (Claude, Cursor, custom runtimes): it discovers tools automatically and routes arguments through structured schemas.
Authentication
The MCP server is a bearer-token protected resource. It publishes
RFC 9728 protected-resource metadata
at /.well-known/oauth-protected-resource. The verifier accepts either
credential in the Authorization: Bearer … header:
- an ARCNM API key (
ak_live_…/ak_test_…) — recommended for agents: long-lived, revocable, scoped (tried first); or - a tenant-scoped session access token (JWT, audience-pinned to
/api/v1; refresh tokens and other-audience tokens are rejected).
Mint an API key in the dashboard (Settings → API keys) and pass it as the bearer token — that's all most agents need.
Interactive clients (Claude, …) can instead sign in with OAuth when the deployment enables it: ARCNM runs a full OAuth 2.1 authorization-code flow with dynamic client registration and a consent screen where the user picks the org and the scopes to grant (read-only by default). The client receives a short-lived, org-scoped, scope-limited token — no key to copy. Either way the credential resolves to the same tenancy + scope checks.
Connect
Claude Code (CLI)
claude mcp add -t http arcnm https://api.arcnm.io/mcp-server/mcp \
--header "Authorization: Bearer $ARCNM_MCP_TOKEN"
Cursor
Add to ~/.cursor/mcp.json (or project-scoped .cursor/mcp.json):
{
"mcpServers": {
"arcnm": {
"transport": {
"type": "http",
"url": "https://api.arcnm.io/mcp-server/mcp",
"headers": { "Authorization": "Bearer ${ARCNM_MCP_TOKEN}" }
}
}
}
}
Restart Cursor; tools appear under the MCP picker.
Other clients
Any MCP-compliant HTTP client works. Point the transport at
https://api.arcnm.io/mcp-server/mcp, send the bearer header, and call
the standard tools/list method to discover the surface.
What's exposed
The surface is the public developer API and nothing else, exposed as
Tools — everything in one tools/list (a strict, deny-by-default
allow-list; an MCP tool is model-invoked, so the surface is the security
boundary):
- Reads (parts, calculations, uploads, environments, materials,
calibration) are read-only Tools (
readOnlyHint=true) — plus a read-only view of your own identity (GET /users/me,/users/me/context). Material search (materials_suggest,materials_lookup) counts as a read even though it is a POST: the query rides in the body, nothing is written. - Writes (create a part, create/run/quote a calculation, upload inputs) are Tools carrying an idempotent / destructive hint.
There are no Resources or Resource Templates — an agent-first data API is
model-invoked, which is Tool semantics, so reads and writes live in one
tools/list (matching GitHub's and Stripe's MCP servers) rather than being
split across tools/list and resources/list. Use readOnlyHint to tell a
data-fetch from a mutation.
Tool names are generated from the REST operation ids (roughly
<tag>_<operation>, e.g. calculations_get_calculation,
calculations_create_calculation). The authoritative list is whatever
tools/list returns for your token — generate it from the live server
rather than hardcoding names.
What's never exposed. Everything outside the public developer API: wallet and billing operations, plan changes, member invites/roster, API-key minting, the credential vault, SSO/SCIM, raw payment-provider webhooks, feature flags, auth/session primitives, the audit log and other admin-only endpoints, the AI and generic
/jobssurfaces, and all user identity mutations (including cross-user reads). An agent with a tenant token cannot move money, escalate access, mint credentials, read the admin plane, or rewrite the tenant — those stay human-dashboard-only by design. The environment effective-rates surface (read + edit) is likewise app-only: rate configuration is a pricing decision an agent must not make on the operator's behalf.
Scopes mirror the REST scope catalog: a
token needs parts:read to read and parts:write to create or run a
calculation. Request the minimum the agent needs.
tools/list is filtered to your token's scopes. The server returns only
the tools your credential can actually call — a parts:read key sees the
read-only tools and the identity reads, not the write tools it could only 403
on. (Scopeless first-party session tokens are unrestricted and see everything,
matching the REST gate.) So the surface an agent discovers is already
least-privilege; widen it by minting a broader-scoped key, not by working
around a missing tool.
The list is intentionally not paginated — the whole (already scope-scoped)
surface is returned in one tools/list response. The MCP cursor is optional
and we don't emit one; paging wouldn't help anyway, since a client that holds
the surface ends up holding all of it either way.
What it costs you is worth knowing, because most hosts put every tool
definition into the model's context. Two things keep it down, and one of them
is yours: the generated tools describe their arguments but not their response
shape — read response schemas from
the API reference, which publishes them once
instead of repeating them per tool — and a narrower credential is a smaller
surface, since the list is scope-filtered. A parts:read key sees about half
the tools of a full-scope one. Scope the credential to what the agent actually
does. For the cost loop, prefer the curated arcnm_* tools: those do declare
typed output and are built to be token-light.
Agent-first workflow tools
On top of the generated CRUD tools the server ships a few curated
arcnm_* tools built for an agent's cost-optimisation loop. Each returns a
concise, structured result (with an outputSchema) instead of the full
response blob, so they're cheap on context:
| Tool | What it returns |
|---|---|
arcnm_explain_cost |
Headline unit / total / setup cost and setup / cycle / unit time, the prediction band, the cost breakdown, the machine used, the material-resolution assumption, and the top cost drivers. detail="detailed" widens the driver list. |
arcnm_cost_drivers |
The top cost drivers, ranked — each with its cost, its share of the unit cost, and why it's costly. |
arcnm_cost_breakdown |
One calculation as a single rough-to-detailed hierarchy — headline → cost category → operation → feature, time and cost side by side — with a persona knob (procurement / workprep / operations / design / full) that returns just the slice that persona needs. |
arcnm_process_plan |
The ordered process plan (routing) all the way to a finished part: the machining steps, each with its process, work center and cycle time, then the post-machining chain (welding, heat treatment, surface finishing, coating) in the order it is performed — plus the plan-level setup / cycle / total time and machine(s). The work plan a work-preparation user acts on. Post-machining steps carry no cycle time: they are priced per lot, in the subcontract line. |
arcnm_compare_calculations |
The unit-cost delta between two calculations, flagging when they aren't comparable (different lot size / environment). |
arcnm_rank_calculations |
The N-way generalization of compare: ranks 2–20 calculations cheapest-unit-cost first, each with its premium over the cheapest and time beside cost, flags when they aren't like-with-like, and lists blocked / unpriced calcs last. Pick between several quotes at once. |
arcnm_compare_environments |
The parts × environments matrix of a multi-environment run — per part the unit cost in every environment and the cheapest environment (ties included); per environment the win count, basket total and median delta vs the baseline. Pass a batch_id (from a multi-environment quote/batch) or an ad-hoc calculation_ids list; all figures are server-computed, identical to the REST comparison endpoints. Up to 200 ids, and the pivoted grid may not exceed 500 cells (parts × environments). |
arcnm_optimize_lot_size |
The total-cost optimal lot size (production plus inventory holding, capped at one year of demand), the net EUR/yr saving of moving there, the Andler/EOQ cross-check, the cost-vs-quantity curve (with the per-unit-variable split), and at most two lot-size/setup directions. |
arcnm_optimization_directions |
Every optimization direction for a calculation — lot sizing, setup reduction, tolerance-cost review, material utilization, external-process benchmarking, plus the live supplier-quote gap — each tagged with its lever, confidence, and method. |
arcnm_check_quota |
This organization's remaining calculation quota for the current window — included / used / remaining, the overage rate, how overage settles (wallet = prepaid, with wallet_funded_calculations telling you how many more fit), how much of any monthly spend cap is left, and whether billing is suspended — so you can check before committing a run instead of parking a calc as blocked. |
All of these are read-only and inherit the same scopes, tenancy, and redaction as the REST API — ideal building blocks for a "cost it, find the drivers, change the design, re-cost, compare" loop driven from a CAD/agent toolchain.
Reads are tools too
Everything you need to read — a full calculation (poll
calculations_get_calculation for its status), an environment and its machine
fleet / rates, a part's revisions, the material catalogue — is a read-only
Tool in the same tools/list as the writes (look for readOnlyHint=true), so
there is no second surface to discover. There is no separate job-status tool — a
calculation carries its own status, so polling calculations_get_calculation
is the deterministic way to wait for a result.
Getting a CAD file in over MCP
An MCP client can only pass strings, so the multipart upload-and-quote /
datasets_upload_dataset tools can't carry a file. Use upload_and_quote_json
(POST /calculations/upload-and-quote-json): the same one-shot upload + quote,
but the CAD (and optional drawing / RFQ) ride as base64 (or data: URI)
strings in a JSON body. Best for small single-part STEP files — base64 inflates
~33% and rides inside the tool call, so for large assemblies use the
uploads_presign → PUT → uploads_confirm flow instead.
Finding a material
materials_lookup resolves an exact reference; on a near-miss it now returns the
closest grades in the error detail. For a fuzzy "did you mean" list that never
dead-ends — a partial code, a trade name, or a generic term like Stahl —
use materials_suggest, then pass a candidate's urn back as material_ref.
What you get back
The MCP surface is the public face of the platform, so responses carry the cost answer and the explanation a buyer needs to act — never the engine internals. Selection scoring, per-operation cycle-time math, raw extraction output, calibration parameters, and the platform machine-cost model are stripped from every response an agent receives (the first-party app keeps the full detail). Design around the result, not the derivation.
Read-only mode
A deployment can run the MCP server in read-only mode (MCP_READ_ONLY):
the write tools disappear from tools/list entirely, leaving only the read
resources and the read-only arcnm_* tools. Pair it with a read-only API key
for defence in depth when the agent only needs to read and analyse.
Tool annotations
Each tool carries MCP annotations the agent uses to decide how to call it:
openWorldHintisfalse— every tool acts on your own tenant data (a closed domain), not an open external world like web search.readOnlyHintistrueon the curatedarcnm_*analysis tools.idempotentHintisfalseforPOST/PATCH,trueforPUT.destructiveHintandidempotentHintaretrueforDELETE.
A well-behaved agent confirms with the user before calling a
destructiveHint tool.
Prompts
The tools are CRUD-shaped because they're generated from the REST API. On top
of them the server ships a small set of prompts — the task-oriented "verbs
that matter" — that walk an agent through a whole workflow using whatever tools
your token exposes. Call prompts/list to discover them:
| Prompt | What it does | Arguments |
|---|---|---|
cost_a_part |
Upload a CAD file, create + run a calculation, poll to completion, report unit / total / setup cost. | part_number, lot_size, environment |
compare_calculations |
Read two calculations and explain the cost delta and its drivers. | calculation_id_a, calculation_id_b |
compare_environments |
Price part(s) across several environments in one batch, poll the grid, and recommend the best environment per part and overall. | part_numbers_or_ids, environment_names_or_ids |
explain_cost |
Explain one calculation's cost in plain language — decomposition and drivers. | calculation_id |
find_cost_drivers |
Rank the top cost drivers for a calculation to target a redesign or re-quote. | calculation_id, top_n |
Prompts are guidance, not privilege: they describe the workflow by capability
and tell the agent to resolve exact tool names from tools/list, so they keep
working as the generated surface evolves. A prompt that ends in a write your
token can't perform simply has that final call rejected at the REST boundary.
Worked example — agent quotes a part
user: Quote this STEP file at lot size 50, on our production env.
[attaches bracket.step]
agent: <calls the parts upload-and-quote tool>
cad_file=<bytes>, part_number="BRACKET-001",
lot_size=50, costing_environment_id=<prod env id>
agent: ← { id: "9d…", status: "queued" }
agent: <polls the get-calculation resource for 9d… until status=succeeded>
agent: Unit cost at lot size 50 is €12.84 (total €642.00, setup €52.50).
The full breakdown is on the calculation's analytics blob.
The agent didn't write a line of REST glue.
Worked example — agent compares environments
user: Which of our environments makes these 3 brackets cheapest?
agent: <calls arcnm_check_quota> # a grid costs parts × envs
agent: <lists environments, resolves the 3 part revisions>
agent: <calls the batch-calculation tool>
part_revision_ids=[…,…,…],
costing_environment_ids=[<prod>, <staging>, <sub_a>]
agent: ← { batch_id: "b4…", requested: 9, enqueued: 9 }
agent: <polls arcnm_compare_environments(batch_id="b4…") until complete>
agent: Subcontractor A is cheapest for 2 of 3 parts; basket −9.8% vs
production. BRACKET-002 stays cheaper in-house (+4.1% at Sub A).
One batch call instead of nine single quotes — and the matrix (wins,
deltas, basket totals) is computed server-side, so the agent reports
the same numbers the UI shows. The compare_environments prompt walks
this flow end to end.
Rate limits & billing
MCP traffic is handled by the MCP server's own verification and is not
subject to the REST per-request quota bucket. You're billed for the
underlying billable operation (a successful calculation), not per tool
call — read-only tools and resources are free. A multi-environment
batch is one tool call but bills one calculation per
(revision × environment) cell; arcnm_check_quota first tells you
whether the grid fits.
Local development
Run a local backend and point your MCP client at
http://localhost:8000/mcp-server/mcp with a dev bearer token — an
ak_test_… API key works well locally. The MCP transport reads the
Authorization: Bearer header only (an API key or a session JWT); there
is no X-API-Key header path on the MCP server — that header is REST-only.
See also
- Authentication — bearer auth, scopes.
- API reference — the REST surface MCP wraps.
- Recipes → Quote a part — end-to-end flow.
- MCP spec — the protocol itself.