MCP server

The Model Context Protocol server lets an AI assistant work with Contents.team directly: open a claim, add photos, check progress and read the priced inventory.
The tool list, with each tool's input schema, is also published as mcp.json.

Endpoint and authentication

  • Streamable HTTP at https://contents.team/api/mcp.
  • Authenticate with an org API key as a bearer token, exactly as for the REST API. Each tool needs the scopes listed below, so give an assistant's key only what you want it to do. A ctk_test_ key is a safe place to start.
  • OAuth access tokens (cto_) work too. A request without a valid credential gets a 401 whose WWW-Authenticate header points at /.well-known/oauth-protected-resource/api/mcp, so OAuth-capable clients find the authorization server on their own.
  • The server is stateless: every call is a plain POST with JSON back, and there are no sessions to keep alive.
  • The tools call the same operations as the REST API, with the same scopes, limits, ids, cents and basis points. A test key's add_photos uses the fixture pipeline; send X-Contents-Test-Mode: live-ai on the connection to use the real one, as on REST.
  • export_report waits up to 20 seconds for the file. If it is not ready by then, call it again with the returned exportId.

Tools

ToolWhat it doesScopes
list_claimsList the organization's claims, newest first, with item counts and approved RCV in cents. Filter by externalRef (your own id) or updatedSince; page with cursor.claims:read
create_claimOpen a claim with the insured, loss address, loss type and date of loss, and your own externalRef. Returns the claim and its clm_ id. Pass a fresh idempotencyKey for each new claim and reuse it when retrying, so a retry never opens a second claim.claims:write
add_photosAdd up to 10 photos to a claim by public https URL, optionally filed by room name. Each photo is analyzed and its items drafted and priced; poll get_claim_status for progress. Pass a fresh idempotencyKey for each batch and reuse it when retrying, so a retry never adds the photos twice.photos:write
get_claim_statusHow far a claim has got: photos received, queued, analyzing, analyzed and failed; items drafted, awaiting review, approved and rejected; approved RCV, ACV and payment totals in cents.claims:read
get_inventoryThe claim's line items: room, description, quantity, condition, status, unit cost in cents, and each line's RCV, depreciation (basis points and cents) and ACV. priced and needsReview say what still needs a person. Filter by status, needsReview, priced or room; page with cursor.items:read
export_reportGenerate the XactContents-format XLSX (default), the PDF report or a photo ZIP for a claim. Waits up to 20 seconds and returns the download link when ready; otherwise call again with the returned exportId. Pass a fresh idempotencyKey for each new export and reuse it when retrying, so a retry never starts a second export.exports:write
get_replacementsThe replacement finder's offers for one item from its latest search, best first: title, retailer, price in cents, link and image, with proposed marking the finder's pick. Each has an rpl_ id for accept_replacement.items:read
update_itemEdit one item the way the app does: name, model, quantity, unitCostCents (integer cents; null removes the price), priceSource, priceSourceUrl, roomId, condition, estimatedAgeYears, notes. Returns the item, revalued. An item still being priced is refused (item_locked). Pass a fresh idempotencyKey for each edit and reuse it when retrying.items:write
approve_itemsApprove up to 1000 items of a claim, as bulk approval in the app does; only approved items count toward totals and exports. Reports each id as approved, alreadyApproved, locked (still being priced), skipped (with a reason, e.g. unpriced) or notFound. Pass a fresh idempotencyKey for each approval and reuse it when retrying.items:write
accept_replacementPrice an item from one of its offers (an rpl_ id from get_replacements) and approve it in one step, as accepting in the app does. The price and quantity come from the offer; if the listing unit count is unclear the call asks you to confirm a quantity (quantity plus quantityConfirmed: true). Pass a fresh idempotencyKey and reuse it when retrying.items:write
add_itemAdd an item the AI missed, as manual add in the app does: name, optional model, quantity (default 1), unitCostCents (integer cents; omit to add it unpriced), roomId, condition, estimatedAgeYears, notes. Returns the new item. idempotencyKey is required: send a fresh one per item and reuse it when retrying, so a retry never adds (and bills) a second item.items:write
delete_itemRemove one item from the inventory, as delete in the app does. To keep a record that an item was ruled out, use reject_items instead. Pass a fresh idempotencyKey and reuse it when retrying.items:write
unapprove_itemsSend up to 1000 approved items of a claim back to review, as bulk unapprove in the app does. Pass a fresh idempotencyKey and reuse it when retrying.items:write
reject_itemsRule out up to 100 items of a claim (not part of the loss, a duplicate), as rejecting in the app does; rejected items stay on the claim but never count toward totals or exports. Pass a fresh idempotencyKey and reuse it when retrying.items:write

Retries

create_claim, add_photos and export_report take an optional idempotencyKey argument, the MCP form of the REST Idempotency-Key header with the same rules: 1 to 255 visible ASCII characters, kept for 24 hours. Send a new key for each action and the same key when retrying it, and a retry returns the first result instead of making a second claim, batch of photos or export. The same key with different arguments, or on another tool, is a tool error with code idempotency_key_reused; a retry while the first call is still running is idempotency_request_in_progress, so wait a moment and retry. A call that fails frees its key.

Connect a client

Each snippet reads the key from the CONTENTS_API_KEY environment variable. Keep the key out of shared config files and repositories.

Claude Code

Shell
claude mcp add --transport http contents-team https://contents.team/api/mcp \
  --header "Authorization: Bearer $CONTENTS_API_KEY"

Then ask Claude Code to create a test claim called JOB-1042 and show me its inventory. Run claude mcp list to check the connection.

Cursor

~/.cursor/mcp.json
{
  "mcpServers": {
    "contents-team": {
      "url": "https://contents.team/api/mcp",
      "headers": { "Authorization": "Bearer ${env:CONTENTS_API_KEY}" }
    }
  }
}

Claude Desktop

Claude Desktop starts local servers from its config file, so it reaches a remote server with bearer auth through the mcp-remote bridge. Add this to claude_desktop_config.json and restart the app.

claude_desktop_config.json
{
  "mcpServers": {
    "contents-team": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote", "https://contents.team/api/mcp",
        "--header", "Authorization:Bearer ${CONTENTS_API_KEY}"
      ],
      "env": { "CONTENTS_API_KEY": "ctk_test_..." }
    }
  }
}

Custom connectors on claude.ai and ChatGPT sign in with OAuth rather than a key. They work through OAuth apps, which are in preview; see Authentication.

ChatGPT and the OpenAI API

From your own code, the OpenAI Responses API connects to remote MCP servers and passes the key in a header:

Python
from openai import OpenAI
import os

client = OpenAI()
response = client.responses.create(
    model="gpt-5",
    tools=[{
        "type": "mcp",
        "server_label": "contents_team",
        "server_url": "https://contents.team/api/mcp",
        "headers": {"Authorization": f"Bearer {os.environ['CONTENTS_API_KEY']}"},
        "require_approval": "never",
    }],
    input="List my five newest claims and how many items each has.",
)
print(response.output_text)

Good habits

  • Give each assistant its own key, so you can see its activity and revoke it alone.
  • Leave approval on for the write tools (create_claim, add_photos, export_report, add_item, update_item, delete_item, approve_items, unapprove_items, reject_items and accept_replacement) in clients that ask before calling a tool.
  • An assistant drafts, a person approves. Give a key items:write only when a person signs off on what the assistant approves; without it, items still need a reviewer in Contents.team.
NextAPI referenceEvery endpoint, parameter and response, generated from the OpenAPI document.