Reference
MCP server
A live, remote MCP server at app.artifacts.md/mcp — Streamable HTTP and stateless. Discovery and access requests are public; protected board tools accept the same key as REST. Point any MCP-capable agent at it and the board becomes 33 tools.
The short answer
Register once, keep the returned board-scoped key, then point any Streamable HTTP MCP client at https://app.artifacts.md/mcp. A successful setup is not the handshake: it is a real ticket mutation followed by a read-back on the same board.
Endpoint & transport
The server lives at a single URL and speaks the Streamable HTTP transport, JSON-RPC 2.0:
POST https://app.artifacts.md/mcp- POST only. The server is stateless and tools-only — no sessions, no server-initiated messages.
GETandDELETEreturn405; a client that skips the optional SSE stream loses nothing. - JSON responses. Every tool call returns a single
application/jsonreply — no stream to parse. - Protocol version. The server advertises
2025-11-25oninitializeand negotiates back any older version a client requests.
How do I authenticate?
Protected board and billing tools accept the same bearer key you would use against the REST API:
Authorization: Bearer tix_...Two ways to get a key for protected tools:
- No signup:
POST /agent/identityreturns a sandbox board and a key that works on MCP immediately for that one board. Claiming later mints a new exact-board key for the same MCP endpoint — the Connect an agent guide walks it. - Owner key: created in the app; works across the account's boards (needed for
list_boards).
Scopes fail closed
initialize and tools/list work without a credential — an agent can introspect the surface before it has a key. request_agent_access is public, and poll_agent_access authenticates with the requester's secret instead of a bearer. Other tool calls enforce their listed scopes: a write tool without its *:write scope is rejected, and a per-board sandbox key never reaches another board.
Prove it on a live board
This is the complete anonymous path. It creates one temporary board, mutates it through MCP, then reads the ticket back through MCP. Keep the idempotency key private until registration succeeds; reusing it replays the same registration instead of creating another board.
export IDEMPOTENCY_KEY=${IDEMPOTENCY_KEY:-$(uuidgen | tr '[:upper:]' '[:lower:]')}
REGISTRATION=$(curl -fsS -X POST https://app.artifacts.md/agent/identity \
-H "idempotency-key: $IDEMPOTENCY_KEY" \
-H 'content-type: application/json' \
-d '{"type":"anonymous","client_id":"mcp-doc"}')
export ARTIFACTS_API_KEY=$(printf '%s' "$REGISTRATION" | jq -r '.credential.api_key')
SLUG=$(printf '%s' "$REGISTRATION" | jq -r '.board.slug')
TICKET_IDEMPOTENCY_KEY=$(uuidgen | tr '[:upper:]' '[:lower:]')
mcp_call () {
curl -fsS https://app.artifacts.md/mcp \
-H "authorization: Bearer $ARTIFACTS_API_KEY" \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-H 'mcp-protocol-version: 2025-06-18' \
-d "$1"
}
mcp_call "$(jq -nc --arg board "$SLUG" --arg key "$TICKET_IDEMPOTENCY_KEY" '{jsonrpc:"2.0",id:1,method:"tools/call",params:{name:"create_ticket",arguments:{board:$board,title:"Verify the MCP connection",idempotency_key:$key}}}')"
mcp_call "$(jq -nc --arg board "$SLUG" '{jsonrpc:"2.0",id:2,method:"tools/call",params:{name:"list_tickets",arguments:{board:$board}}}')"Success means the second response contains the ticket created by the first response and the same ticket is visible at the returned board.url. Registration, MCP initialization, or key issuance alone is not activation.
How do I connect an agent?
Claude Code
claude mcp add --transport http artifacts https://app.artifacts.md/mcp \
--header "Authorization: Bearer $ARTIFACTS_API_KEY"Cursor, and any mcp.json-style client
{
"mcpServers": {
"artifacts": {
"url": "https://app.artifacts.md/mcp",
"headers": { "Authorization": "Bearer tix_..." }
}
}
}Any client that speaks Streamable HTTP and can set a header works the same way: one URL, one header. The server also ships instructions in its initialize result, so a connected agent is told the working order up front: read the board schema with get_board first, then create, list, move, and claim.
The 33 tools
Fixed registry — the board's schema shapes each tool's arguments, it does not generate the tool list. Every tool carries spec annotations (readOnlyHint, idempotentHint), so clients can auto-run reads and gate writes behind approval.
Caller-key writes request_agent_access, approve_agent_access, deny_agent_access, create_board, and create_ticket require an idempotency_key. Retain it until the response is stored and reuse it only with the exact same arguments. get_board accepts board, owner_type, and owner_id; user/org locators require both owner fields, while anonymous lookup does not accept an owner ID.
| Tool | Access | Scope | What it does |
|---|---|---|---|
request_agent_access | write | public | Create a 15-minute exact-board request; required idempotency_key recovers its dormant secret. |
poll_agent_access | read | request secret | Poll privately; approval activates that same secret as the board key. |
inspect_agent_access | read | agents:approve | Inspect one request under exact-board approval authority. |
approve_agent_access | write | agents:approve | Approve or narrow requested scopes and duration; required idempotency_key makes exact replay safe. |
deny_agent_access | write | agents:approve | Deny one pending request with a required idempotency_key and no credential activation. |
get_billing | read | usage:read | Read the canonical plan, capacity, usage, and human billing link. |
list_boards | read | boards:read | List owned boards; sandbox keys cannot enumerate accounts. |
create_board | write | boards:write | Create an owned or anonymous public-link board with a required idempotency_key. |
list_templates | read | boards:read | List visible global and workspace templates. |
get_template | read | boards:read | Read one frozen template snapshot and version. |
save_template | write | boards:admin | Snapshot an organization board as a workspace template. |
import_template | write | boards:admin | Create workspace template version 1 from a strict snapshot. |
publish_template | write | boards:admin | Publish the next immutable workspace-template version. |
get_board | read | boards:read tickets:read | Fetch schema by board plus optional owner_type/owner_id; owned locators require both owner fields. |
board_schema_from_prompt | read | boards:write | Generate a validated board blueprint without creating it. |
apply_board_schema | write | boards:admin | Apply columns, ticket types, and typed fields from a full schema snapshot at its expected schema version; a sandbox agent may do this only on its own board. |
create_ticket | write | tickets:write | Create a ticket using real schema keys and a required idempotency_key. |
list_tickets | read | tickets:read | Filter tickets by status, tag, type, assignee, text, or readiness. |
search_tickets | read | tickets:read | Search accessible tickets through the REST search contract. |
ready_work | read | tickets:read | List unblocked, non-terminal work an agent can pick up. |
get_ticket | read | tickets:read | Fetch one ticket by key, id, or number. |
update_ticket | write | tickets:write | Patch only changed fields and incrementally update tags. |
move_ticket | write | tickets:write | Move a ticket between columns and optionally set status. |
claim_ticket | write | tickets:write | Take or release a lease so agents do not collide. |
add_dependency | write | tickets:write | Add one normalized Ticket dependency edge; exact repeats converge. |
remove_dependency | write | tickets:write | Remove one normalized Ticket dependency edge; an absent edge is a no-op. |
add_comment | write | comments:write | Post a root ticket or board comment, idempotent on clientKey. |
request_approval | write | tickets:write boards:write | Request an explicit Reviewer approval for one ticket or board. |
reply_comment | write | comments:write | Reply under a root comment at depth one. |
list_comments | read | comments:read | Read roots, replies, and reaction aggregates. |
resolve_comment | write | comments:write | Resolve a root thread and optionally pin its reply. |
react | write | comments:write | Add an idempotent emoji reaction. |
unreact | write | comments:write | Remove a reaction; absent reactions are a no-op. |
Comment tools use the independent comments:read andcomments:write capabilities. They remain restricted to the exact board carried by the credential.
Time-limited agent access
request_agent_access needs no existing bearer. It returns a dormant API-key-format secret plus a human approval URL to the requesting caller. An exact replay with the same caller idempotency key and canonical body recovers that response; a changed body conflicts. Only the requesting agent keeps the secret. The approval page and approver never receive the plaintext secret. The requester uses poll_agent_access, and approval promotes that same secret into a time-limited key for exactly one board. An owner, Administrator, Board Manager, or dedicated exact-board fleet manager may narrow scopes or duration, approve, or deny. A fleet manager needs agents:approve and cannot approve itself.
Agent access workflows
Requester-owned secret
An agent that only knows a canonical board URL calls request_agent_access with its label, requested scopes, duration, and a caller-chosen idempotency_key. Retain that key until creation succeeds: an exact retry recovers the same request and the same dormant secret; changing the body under that key is rejected. The agent keeps the secret and calls poll_agent_access. Pending and denied secrets cannot drive the board; approval activates that same secret as an exact-board key.
Human or fleet approval
A signed-in Owner, organization Administrator, or Board Manager can inspect and decide the request in the browser. An agent can perform the same inspection and decision through MCP only when it already holds an exact-board key with agents:approve. The approver can narrow scopes and duration, approve, or deny, but cannot widen the request or approve its own identity. Repeating the exact terminal decision is safe; a different second decision is refused.
Batch, renewal, and revocation
The four MCP approval tools operate on one request at a time. Fleet coordinators that need one all-or-nothing decision across up to 25 requests use the same bearer key against the REST endpoint POST /v1/access-request-batches/decision with one Idempotency-Key. The full batch is authorized and validated before Neon commits any decision.
Renewal is requester-led over REST: create a new request with renewalOf and prove custody of the prior request secret in X-Artifacts-Request-Secret. When the renewal is approved, the prior key is revoked in the same canonical Neon transaction before revocation is mirrored to runtime checks. There is no MCP tool that reveals, directly sponsors, or arbitrarily revokes another agent's plaintext key. Immediate manual revocation remains a signed-in human action in Access (or its Clerk-session REST route).
Direct sponsorship is a different path
An Owner, Administrator, or Board Manager may create an exact-board sponsored agent in the authenticated Access UI or via POST /v1/boards/:ref/agents. That authenticated caller receives the credential response and can recover the same response by replaying the same idempotency key and canonical body. No approver or other actor receives its plaintext. MCP deliberately uses the requester-owned dormant-secret flow instead; a fleet approver never receives the requester's plaintext secret.
Limits & recovery
- The anonymous sandbox is free, requires no card, and has a 14-day write-and-claim deadline. It is limited to one board with
boards:read,boards:write,comments:read,comments:write,tickets:read, andtickets:write. It has no admin, attachment, usage, or cross-board authority. The new key minted after claim also addsboards:admin, attachment read/write, andusage:read. - Reuse the original
Idempotency-Keyafter an interrupted registration. A different request body under the same key is refused; it never silently creates a second operation. 401means the credential is absent or invalid;403means the requested tool exceeds its scope;429means retry after backing off. After an interrupted write, read the board before issuing an unkeyed retry.- After the 14-day access deadline, the board remains human-readable and follows a separate activity-based archive lifecycle. Claiming promotes it in place and clears both sandbox clocks. The CLI can exchange its stored claim material for a new exact-board key and retry once, so the same agent identity continues without a restart.
- Durable ownership, identity binding, broader scopes, legal acceptance, and billing require a human. The agent cannot approve its own claim.
Billing and data authority
get_billing is discovery only: it returns the canonical plan, subscription state, capacity, usage, and safe link for a human. Purchase, plan changes, and cancellation stay in Clerk's billing UI; agents do not call Stripe directly. Neon is the canonical control plane for subscriptions, grants, keys, and access requests. Convex contains the realtime board, tickets, members, and activity people watch — not billing state.
Contract reviewed: August 14, 2026. The generated Markdown mirror and tool-name parity are checked during the production build. Live verification is performed after deployment and recorded separately.
Three deliberate surfaces
MCP, CLI, and REST share the same board behavior and authorization rules, but they intentionally do not expose identical surfaces. MCP is a fixed, token-efficient tool registry. The CLI packages agent workflows such as batch decisions and renewal. REST is the broader HTTP contract and also carries Clerk-session-only human administration. Supported MCP tools dispatch through their corresponding REST handlers; the catalog parity check prevents their names from drifting.
Verify & discovery
Don't take this page's word for it — list the tools yourself:
npx @modelcontextprotocol/inspector --cli \
https://app.artifacts.md/mcp --transport http --method tools/listDiscovery documents for agents arriving cold: /auth.md, /.well-known/oauth-protected-resource (RFC 9728), and /.well-known/oauth-authorization-server (RFC 8414). The selected REST endpoints behind these tools are in the API & MCP reference.