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:

The endpoint
POST https://app.artifacts.md/mcp
  • POST only. The server is stateless and tools-only — no sessions, no server-initiated messages. GET and DELETE return 405; a client that skips the optional SSE stream loses nothing.
  • JSON responses. Every tool call returns a single application/json reply — no stream to parse.
  • Protocol version. The server advertises 2025-11-25 on initialize and 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:

Per-request bearer auth
Authorization: Bearer tix_...

Two ways to get a key for protected tools:

  • No signup: POST /agent/identity returns 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.

Register, create, and read back through MCP
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
claude mcp add --transport http artifacts https://app.artifacts.md/mcp \
  --header "Authorization: Bearer $ARTIFACTS_API_KEY"

Cursor, and any mcp.json-style client

.cursor/mcp.json (same shape for most clients)
{
  "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.

ToolAccessScopeWhat it does
request_agent_accesswritepublicCreate a 15-minute exact-board request; required idempotency_key recovers its dormant secret.
poll_agent_accessreadrequest secretPoll privately; approval activates that same secret as the board key.
inspect_agent_accessreadagents:approveInspect one request under exact-board approval authority.
approve_agent_accesswriteagents:approveApprove or narrow requested scopes and duration; required idempotency_key makes exact replay safe.
deny_agent_accesswriteagents:approveDeny one pending request with a required idempotency_key and no credential activation.
get_billingreadusage:readRead the canonical plan, capacity, usage, and human billing link.
list_boardsreadboards:readList owned boards; sandbox keys cannot enumerate accounts.
create_boardwriteboards:writeCreate an owned or anonymous public-link board with a required idempotency_key.
list_templatesreadboards:readList visible global and workspace templates.
get_templatereadboards:readRead one frozen template snapshot and version.
save_templatewriteboards:adminSnapshot an organization board as a workspace template.
import_templatewriteboards:adminCreate workspace template version 1 from a strict snapshot.
publish_templatewriteboards:adminPublish the next immutable workspace-template version.
get_boardreadboards:read tickets:readFetch schema by board plus optional owner_type/owner_id; owned locators require both owner fields.
board_schema_from_promptreadboards:writeGenerate a validated board blueprint without creating it.
apply_board_schemawriteboards:adminApply 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_ticketwritetickets:writeCreate a ticket using real schema keys and a required idempotency_key.
list_ticketsreadtickets:readFilter tickets by status, tag, type, assignee, text, or readiness.
search_ticketsreadtickets:readSearch accessible tickets through the REST search contract.
ready_workreadtickets:readList unblocked, non-terminal work an agent can pick up.
get_ticketreadtickets:readFetch one ticket by key, id, or number.
update_ticketwritetickets:writePatch only changed fields and incrementally update tags.
move_ticketwritetickets:writeMove a ticket between columns and optionally set status.
claim_ticketwritetickets:writeTake or release a lease so agents do not collide.
add_dependencywritetickets:writeAdd one normalized Ticket dependency edge; exact repeats converge.
remove_dependencywritetickets:writeRemove one normalized Ticket dependency edge; an absent edge is a no-op.
add_commentwritecomments:writePost a root ticket or board comment, idempotent on clientKey.
request_approvalwritetickets:write boards:writeRequest an explicit Reviewer approval for one ticket or board.
reply_commentwritecomments:writeReply under a root comment at depth one.
list_commentsreadcomments:readRead roots, replies, and reaction aggregates.
resolve_commentwritecomments:writeResolve a root thread and optionally pin its reply.
reactwritecomments:writeAdd an idempotent emoji reaction.
unreactwritecomments:writeRemove 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, and tickets:write. It has no admin, attachment, usage, or cross-board authority. The new key minted after claim also adds boards:admin, attachment read/write, and usage:read.
  • Reuse the original Idempotency-Key after an interrupted registration. A different request body under the same key is refused; it never silently creates a second operation.
  • 401 means the credential is absent or invalid; 403 means the requested tool exceeds its scope; 429 means 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:

Inspect the live server
npx @modelcontextprotocol/inspector --cli \
  https://app.artifacts.md/mcp --transport http --method tools/list

Discovery 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.