Reference

MCP server

A live, remote MCP server at app.artifacts.md/mcp — Streamable HTTP, stateless, authenticated with the same key as the REST API. Point any MCP-capable agent at it and the board becomes 22 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?

Send the same bearer key you would use against the REST API on every request:

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

Two ways to get a key:

  • No signup: POST /agent/identity returns a sandbox board and a key scoped to that one board — 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. Tool calls run under the wrapped REST route's scope checks: 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 TIX_API_KEY=$(printf '%s' "$REGISTRATION" | jq -r '.credential.api_key')
SLUG=$(printf '%s' "$REGISTRATION" | jq -r '.board.slug')

mcp_call () {
  curl -fsS https://app.artifacts.md/mcp \
    -H "authorization: Bearer $TIX_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" '{jsonrpc:"2.0",id:1,method:"tools/call",params:{name:"create_ticket",arguments:{board:$board,title:"Verify the MCP connection"}}}')"
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 $TIX_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 22 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.

ToolAccessScopeWhat it does
list_boardsreadboards:readList owned boards; sandbox keys cannot enumerate accounts.
create_boardwriteboards:writeCreate an owned or anonymous public-link board.
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:readFetch columns, ticket types, and field definitions; call this first.
board_schema_from_promptreadboards:writeGenerate a validated board blueprint without creating it.
create_ticketwritetickets:writeCreate a ticket using the board's real schema keys.
list_ticketsreadtickets:readFilter tickets by status, tag, type, assignee, text, or readiness.
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_commentwritetickets:write boards:writePost a root ticket or board comment, idempotent on clientKey.
reply_commentwritetickets:write boards:writeReply under a root comment at depth one.
list_commentsreadtickets:read boards:readRead roots, replies, and reaction aggregates.
resolve_commentwritetickets:write boards:writeResolve a root thread and optionally pin its reply.
reactwritetickets:write boards:writeAdd an idempotent emoji reaction.
unreactwritetickets:write boards:writeRemove a reaction; absent reactions are a no-op.

Comment tools inherit their parent's scope — reading a thread needs read on its ticket or board; writing, reacting, or resolving needs write on it.

Limits & recovery

  • The anonymous sandbox is free, requires no card, expires after 14 days, and is limited to one board with boards:read, boards:write, tickets:read, and tickets:write. It has no admin, attachment, or cross-board authority.
  • 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.
  • Durable ownership, identity binding, broader scopes, legal acceptance, and any future billing require the human claim flow. The board is promoted in place; the agent cannot approve its own claim.

Contract reviewed: August 7, 2026. The generated Markdown mirror and tool-name parity are checked during the production build. Live verification is performed after deployment and recorded separately.

One core, three surfaces

The MCP layer adds zero board logic. Every tool is a thin wrapper that re-issues the call through the same /v1 REST route the tix CLI uses — auth, scope enforcement, idempotency, and rate limits are the REST layer's, verbatim. MCP, CLI, and REST cannot drift, because they are the same code path.

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 full endpoint surface behind these tools is in the API & MCP reference.