makepartsnow
Developers & AI agents

Order parts from code, or let your agent do it.

Everything you can do on the website works for AI agents and code: upload a file, configure it, see prices and ship dates for every speed, and order. Pick the way you want to connect.

Use it in a chat app

Add Make Parts Now to your AI app and ask for a quote. Quotes don't need an account. Nothing is charged in the chat: you get a link to review the order and pay on makepartsnow.com. Each file gets random ids that stay in your chat. Where the app tells us who you are (ChatGPT) or runs on your computer, they work only for you. Claude doesn't, so there they work like a private link, and only the answer to the upload itself shows a picture of the part. Deleting a file needs the delete token from that upload, unless the file is in your signed-in account.

Claude

In Settings, open Connectors, choose Add custom connector, and paste this URL. Ask for a quote, then drop your CAD file into the upload box that appears in the chat.

https://makepartsnow.com/mcp/assistant
ChatGPT

In Settings, under Apps & Connectors, add a custom connector with this URL. Custom connectors need developer mode turned on. Attach your CAD file to the message and ask for a quote.

https://makepartsnow.com/mcp/assistant
Cursor

Install the Make Parts Now plugin from Cursor Directory, or add this MCP server. Ask the agent to quote a CAD file in your project; it uploads the file itself.

https://makepartsnow.com/mcp/assistant?client=cursor
Gemini CLI

Install our extension, then ask for a quote or run /make-parts-now:quote ./bracket.step 25. Gemini uploads the file itself after you confirm the command.

gemini extensions install https://github.com/makepartsnow/makepartsnow-gemini
Hermes Agent

Install our plugin from the Hermes plugin catalog: hermes plugins install make-parts-now, then hermes plugins enable make-parts-now. It adds the server and our quoting skill. Hermes can upload a CAD file from your computer itself, or give you an upload link. Without the plugin, add this to ~/.hermes/config.yaml and run hermes mcp test makepartsnow:

mcp_servers:
  makepartsnow:
    url: "https://makepartsnow.com/mcp/assistant?client=hermes"
    tools:
      exclude: [get_order_status]
OpenClaw

Install our plugin from ClawHub and approve what it adds (one skill and one MCP server, no code), then start a new session. If the install stops asking for capability consent, add --accept-capabilities. OpenClaw can upload a CAD file from your computer itself, or give you an upload link.

openclaw plugins install clawhub:@makepartsnow/make-parts-now

Try “Quote 25 of this bracket in black nylon,” “Change that to 50 pieces,” “I'll take Standard, send me the checkout link,” or “Where is my order?” One part per quote; STL, STEP, 3MF or OBJ up to 95 MB.

Checking an order needs your Make Parts Now account: Claude, ChatGPT, Cursor and Gemini CLI ask you to sign in when you ask. Hermes and OpenClaw connect without an account and point you to your orders page; OpenClaw can add a signed-in connection, see the plugin's README. See how we handle your files in the privacy policy.

Tools in chat apps:
get_manufacturing_optionscreate_upload_linkanalyze_partquote_partupdate_quotecreate_checkout_linkget_order_statusdelete_uploaded_part

Connect a coding agent or MCP client

Coding tools and agents that work on their own use our full MCP server (Streamable HTTP). It can do everything the REST API can, so it needs a signed-in account. Chat apps use the simpler /mcp/assistant above instead: it quotes without an account, and paying always happens on our website.

https://makepartsnow.com/mcp

Sign in with your website account (OAuth)

Add the server, and your client opens a sign-in page. The agent acts for your account and creates payment links you approve.

Claude Code

claude mcp add --transport http makepartsnow https://makepartsnow.com/mcp

Cursor

Add to Cursor in one click, or add "makepartsnow": { "url": "https://makepartsnow.com/mcp" } under mcpServers in .cursor/mcp.json.

VS Code

Add "makepartsnow": { "type": "http", "url": "https://makepartsnow.com/mcp" } under servers in .vscode/mcp.json.

Or use an agent account key

For an agent with no person behind it, create an agent account and send its key as a Bearer token. The agent can then pay in USDC itself.

{
  "mcpServers": {
    "makepartsnow": {
      "url": "https://makepartsnow.com/mcp",
      "headers": { "Authorization": "Bearer mpn_agent_..." }
    }
  }
}
Tools:
get_capabilitiescreate_agent_accountget_accountupdate_accountupload_partget_upload_urlget_partcreate_quoteget_quotelist_quotesupdate_quotediscard_quotecreate_checkout_linkpay_with_cryptoget_orderlist_ordersset_refund_preferencerequest_order_cancellation

Every tool returns structuredContent. create_quote, get_quote and update_quote declare a typed outputSchema (QuoteView), the same quote the REST API returns and the OpenAPI spec describes.

/mcp and /api/agent/v1 change additively within v1: new tools, endpoints and optional fields can appear, and nothing is removed or renamed.

Listed in the official MCP Registry as com.makepartsnow/manufacturing and on Smithery.

No MCP setup? Install our agent skill. It teaches Claude Code, Codex, Cursor, Gemini CLI and other coding agents to export your CAD, quote it, compare quantities and open checkout through the REST API below.

npx skills add makepartsnow/skills

Build on the REST API

Base URL https://makepartsnow.com/api/agent/v1, authenticated with your agent key as a Bearer token. Full reference in the interactive docs. Agents pay one of two ways:

Option A · Payment link

The agent builds the quote and gets a Stripe Checkout link. A person pays by card. Best for assistants working for someone.

Option B · USDC, no human

The agent creates its own account and pays in USDC on Base using the x402 protocol. Orders are placed fully autonomously.

1. Create an agent account

No human sign-up needed. The key is shown once.

curl -X POST https://makepartsnow.com/api/agent/v1/accounts \
  -H 'content-type: application/json' \
  -d '{"name":"PartsBot","email":"[email protected]","accept_terms":true,
       "ship_to":{"name":"Receiving","line1":"100 Main St","city":"Austin",
                  "state":"TX","postal_code":"78701","country":"US"}}'

# => {"account_id":"agt_...","api_key":"mpn_agent_...","webhook_secret":"..."}

2. Upload a part

Send the file as multipart, a public https URL, or base64. Every upload must confirm the file has no controlled data (policy).

curl -X POST https://makepartsnow.com/api/agent/v1/uploads \
  -H "Authorization: Bearer $MPN_KEY" \
  -F [email protected] -F no_controlled_data=true

curl "https://makepartsnow.com/api/agent/v1/parts/prt_...?wait=20" -H "Authorization: Bearer $MPN_KEY"
# waits up to 20 s (max 30) for "status": "ready" or "failed"; poll again while it is still pending.
# Once ready, the response lists capable_processes

3. Quote it

Valid ids for processes, materials, colors, finishes, and services come from GET /api/agent/v1/capabilities.

curl -X POST https://makepartsnow.com/api/agent/v1/quotes \
  -H "Authorization: Bearer $MPN_KEY" -H 'content-type: application/json' \
  -H 'Idempotency-Key: 7f1c...' \
  -d '{"items":[{"part_id":"prt_...","quantity":20,
        "config":{"units":"mm","process":"sls","material":"sls_pa12",
                  "finishes":["sls_black_dye"],
                  "services":[{"id":"heat_set_inserts","count":4,"size":"M3"}]}}],
       "speed":"fast"}'

The response includes per-part prices, a tiers list with the price, ship date and arrival date for each speed, shipping options, totals, design warnings on each item (items[].pricing.warnings), next_steps written for agents, and share_url, the quote's page for a person to see. If an option is wrong, ready is false and blocking names the field and the allowed values.

4a. Send a payment link

curl -X POST https://makepartsnow.com/api/agent/v1/quotes/qt_.../checkout -H "Authorization: Bearer $MPN_KEY"
# => {"checkout_url":"https://checkout.stripe.com/...","expires_at":...}

4b. Or pay in USDC (x402)

Call /pay. You get HTTP 402 with x402 payment requirements (exact USDC amount, network, and pay-to address) in the body and the PAYMENT-REQUIRED header. Sign the payment with any x402 client and retry with PAYMENT-SIGNATURE. Account credit is applied first. If credit covers the whole total, you get HTTP 409 with credit_confirmation_required and a credit_confirmation token instead, and nothing is charged. Call /pay?confirm_credit=<token> to place the order.

# pip install "x402[evm,httpx]" eth-account
from eth_account import Account
from x402 import x402Client
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm.exact.register import register_exact_evm_client

client = x402Client()
register_exact_evm_client(client, Account.from_key(PRIVATE_KEY))
client.set_spend_controls({"max_amount_per_payment": "$1500"})  # the library refuses over $1 by default

async with x402HttpxClient(client, base_url="https://makepartsnow.com") as c:
    r = await c.post("/api/agent/v1/quotes/qt_.../pay",
                     headers={"Authorization": f"Bearer {MPN_KEY}"})
    print(r.json()["order"])

Webhooks

Set callback_url on your account and we POST these events for your parts, quotes and orders, signed with your webhook secret:

part.analyzedquote.readyquote.needs_revieworder.paidorder.status_changedorder.shippedorder.delayedorder.canceledorder.refunded
{"event": "order.shipped", "data": {...}, "id": "evt_123", "created": 1760000000}
X-MPN-Signature: t=1760000000,v1=<hex HMAC-SHA256(secret, "t." + raw_body)>

Any answer other than 2xx is a failure. We retry up to 5 times, after 10 s, 60 s, 5 min, 15 min and 1 h. A retry keeps the same id, so dedupe on it.

Check the signature against the raw body and accept the request when any v1 matches. For 24 hours after you rotate the secret the header carries two, v1=<previous>,v1=<new>, so your receiver can switch without missing events.

import hashlib, hmac, time

def verify(secret: str, header: str, raw_body: bytes, tolerance: int = 300) -> bool:
    # X-MPN-Signature holds two v1 values during a secret rotation: accept any that matches.
    fields = [p.split("=", 1) for p in header.split(",") if "=" in p]
    ts = next((v for k, v in fields if k == "t"), "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > tolerance:
        return False
    mac = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return any(k == "v1" and hmac.compare_digest(v, mac) for k, v in fields)
const crypto = require("node:crypto");

// rawBody: the request body as a Buffer, before any JSON parsing. Accepts any v1 (two during a secret rotation).
function verify(secret, header, rawBody, toleranceS = 300) {
  const fields = header.split(",").map((p) => p.split("="));
  const ts = (fields.find(([k]) => k === "t") || [])[1] || "";
  if (!/^[0-9]+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > toleranceS) return false;
  const mac = crypto.createHmac("sha256", secret).update(ts + ".").update(rawBody).digest();
  return fields.some(([k, v]) => k === "v1" && /^[0-9a-f]{64}$/.test(v) && crypto.timingSafeEqual(Buffer.from(v, "hex"), mac));
}

Rotate the secret (the new one is shown once, and the account email is told, at most once a day), send a webhook.test event, see your deliveries from the last 30 days, and send one again with the same id:

curl -X POST https://makepartsnow.com/api/agent/v1/account/webhook-secret/rotate -H "Authorization: Bearer $MPN_KEY"
# => {"webhook_secret":"...","previous_valid_until":"...","note":"..."}

curl -X POST https://makepartsnow.com/api/agent/v1/account/webhooks/test -H "Authorization: Bearer $MPN_KEY"
curl "https://makepartsnow.com/api/agent/v1/account/webhooks/deliveries?limit=20" -H "Authorization: Bearer $MPN_KEY"
# => {"deliveries":[{"id":"evt_123","event":"webhook.test","status":"delivered","response_status":200,...}],...}
curl -X POST https://makepartsnow.com/api/agent/v1/account/webhooks/deliveries/evt_123/redeliver -H "Authorization: Bearer $MPN_KEY"

Errors

Errors are JSON with a stable code to branch on, plus retry_after_s when you should wait. MCP tool errors read Error executing tool <name>: <status>: <CODE>: <message>. Every response has an X-Request-Id header, also in error bodies as request_id; quote it when you report a problem. Codes are only ever added:

{"message": "Too many open quotes (limit 50). Discard quotes you no longer need, or order them.",
 "next_steps": ["List your open quotes: GET /quotes?status=open (MCP: list_quotes).", "..."],
 "error": true, "status": 429, "code": "OPEN_QUOTE_LIMIT", "request_id": "3f2c0a1e-..."}
INVALID_ARGUMENTINVALID_CONFIGAUTH_REQUIREDPAYMENT_REQUIREDFORBIDDENSPENDING_LIMITNOT_FOUNDCONFLICTQUOTE_CLOSEDQUOTE_NOT_READYCREDIT_CONFIRMATION_REQUIREDIDEMPOTENCY_IN_PROGRESSEXPIREDFILE_TOO_LARGEUNSUPPORTED_FILE_TYPERATE_LIMITEDOPEN_QUOTE_LIMITUPLOAD_QUOTASERVICE_UNAVAILABLEAGENTS_PAUSEDINTERNAL_ERROR

Limits and rules