Key types and tool access

Create a key via POST /space/:id/keys (see Keys docs) and hand its raw value to the MCP client. modeller and creator exist specifically to scope down what an assistant can do; read/write also work but are broader than most MCP use cases need.

keyTypeCan do via MCP
readList/read models and content. No write tools succeed.
writeFull read/write on both models and content. No delete tool exists for any key type — see below.
modellerList/read/create/update models. Cannot touch content at all.
creatorList/read models (to know what to author against), create/update content. Cannot create/update models.
Why there is no delete tool

Deleting a model or content item is a deliberately irreversible, high-blast-radius action, so it's excluded from the MCP tool surface entirely — delete_model/delete_content are simply never registered in tools/list, for any key type, including write. Deletion is still available over plain REST (DELETE /models/:id, DELETE /content/:id) for callers who need it.

POST
/mcp
MCP Streamable HTTP endpoint

Speaks the MCP Streamable HTTP transport in stateless mode — every request is handled independently (no session id, no server-side connection state), so a client sends a normal JSON-RPC 2.0 body per request. GET/DELETE /mcp return 405 since there is no session/SSE stream to resume.

Headers

HeaderNotes
X-Contently-KeyRequired. An Authorization Bearer token is not accepted on this route.
Content-Typeapplication/json
AcceptRequired by the MCP Streamable HTTP spec: must include both application/json and text/event-stream, or the request is rejected with 406 before any auth/tool logic runs.

Example: tools/list request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}

Example: tools/call request (a creator key creating content)

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "create_content",
    "arguments": {
      "modelId": 1,
      "title": "Hello world",
      "status": "draft",
      "data": {
        "body": "First post"
      }
    }
  }
}

Example: denied call (same key calling create_model)

{
  "content": [
    {
      "type": "text",
      "text": "This API key does not permit write access to model"
    }
  ],
  "isError": true
}

A permission denial is a normal MCP tool result with isError: true, not an HTTP error — the JSON-RPC call itself still succeeds.

Available tools
ToolResource / action
list_modelsmodel / read
get_modelmodel / read
create_modelmodel / write
update_modelmodel / write
validate_model_datamodel / read
validate_model_changemodel / read
list_model_contentmodel / read
list_contentcontent / read
get_contentcontent / read
get_resolved_contentcontent / read
get_content_referencescontent / read
create_contentcontent / write
update_contentcontent / write
Connecting Claude Code

Either a one-line CLI command (personal scope), or a project-shared .mcp.json committed to the repo — both need the raw key in an env var, never hardcoded.

CLI (personal scope)

claude mcp add --transport http contently https://your-host/mcp --header "X-Contently-Key: ${CONTENTLY_MCP_KEY}"

.mcp.json (project-shared, committed to the repo)

{
  "mcpServers": {
    "contently": {
      "type": "http",
      "url": "https://your-host/mcp",
      "headers": {
        "X-Contently-Key": "${CONTENTLY_MCP_KEY}"
      }
    }
  }
}

Claude Code expands ${VAR} from the shell environment at connect time — export CONTENTLY_MCP_KEY before launching Claude Code.

Connecting GitHub Copilot in VS Code

Add a workspace .vscode/mcp.json (or use the Command Palette → "MCP: Open User Configuration" for a user-level config). Use an inputs entry so VS Code prompts for the key once and stores it in its secret storage, instead of writing it into the file.

.vscode/mcp.json

{
  "servers": {
    "contently": {
      "type": "http",
      "url": "https://your-host/mcp",
      "headers": {
        "X-Contently-Key": "${input:contently_mcp_key}"
      }
    }
  },
  "inputs": [
    {
      "id": "contently_mcp_key",
      "type": "promptString",
      "description": "Contently MCP API key (modeller or creator)",
      "password": true
    }
  ]
}

Point your-host at wherever the app is actually deployed (see the README's BASE_PATH note) — and prefer a modeller or creator key over a write key here, since the whole point of these key types is to scope down what the assistant can do.