← API reference

MCP overview

The ziptie.ai API is available as a Model Context Protocol (MCP) server at:

https://api.ziptie.ai/mcp

This lets AI assistants (Claude, Cursor, VS Code with Copilot) call ziptie.ai API endpoints as tools within a conversation - no custom code required.

What is MCP?

MCP (Model Context Protocol) is an open standard for connecting AI assistants to external data sources and tools. When you configure an MCP server, the AI can call your tools, read the results, and use them to answer questions or take actions on your behalf.

The ziptie.ai MCP server exposes every public /v1/ endpoint as a named tool (for example, list_prompts, get_dashboard_overview, create_tag). The tool manifest is generated from the same OpenAPI spec that drives the REST API, so they are always in sync.

Transport

The ziptie.ai MCP server uses Streamable HTTP transport: a single POST https://api.ziptie.ai/mcp endpoint that accepts JSON-RPC 2.0 envelopes and returns JSON responses. Most current MCP clients support this transport natively.

Authentication

MCP requests use the same zt_live_... API tokens as the REST API, and the same entitlement rules. The workspace must have the paid API & MCP access add-on active - without it every call, including initialize, is rejected with API_ADDON_INACTIVE, and trial workspaces cannot enable the add-on. A token is either a project token, which reaches the single project it was created under, or a workspace token, which reaches every project in its workspace. Every project_id argument must be a project the token reaches, or the tool call returns PROJECT_MISMATCH. Call list_projects to find the ids. See authentication for the two kinds. Pass the token in the Authorization header:

Authorization: Bearer zt_live_<your-token>

Each MCP client has its own way to configure this header - see the per-client setup guides below.

Rotating and revoking tokens

A project token is created under Project Settings > API & MCP access with one expiry choice - 30 days, 90 days, 365 days, or never. A workspace token is created by a workspace Owner or Admin under Workspace Settings > API & MCP access with 30, 90 or 365 days and no never option, and it works only while the person who created it is still an Owner or Admin. Either way the secret is shown exactly once, at creation. There is no rotate-in-place. To replace a token you create a second one, update the client config, then revoke the first.

Revocation takes effect on the next request: every call re-checks the token against the database, so a revoked token fails with TOKEN_REVOKED from that moment on. Over /mcp that arrives as JSON-RPC -32001 at HTTP 200 with data.code set to TOKEN_REVOKED, not as a 401 - see errors. Revoked and expired tokens stay in the list with their status so you can see what was retired.

A project can hold 10 active project tokens and a workspace 10 active workspace tokens, where active means neither revoked nor past its expiry. The eleventh create returns 409 TOKEN_LIMIT_REACHED; revoking one frees the slot.

This matters for the shared config files the client guides describe. Claude Code's .mcp.json is meant to be committed, and VS Code's .vscode/mcp.json is shared with collaborators. If a token reaches either of those, or any dotfiles repo, treat it as public: revoke it and issue a replacement. A token's scope and project are fixed at creation and cannot be narrowed afterwards.

Scope ladder

The token's scope applies to MCP tool calls exactly as it does to REST calls:

A token carries exactly one of the three levels, picked at creation.

Choose the lowest level that does the job, because the assistant decides when to call a tool, not you. An admin token lets it call delete_prompt, delete_tag and delete_url against live tracked data; those are real deletes, with no confirmation step and no undo. A write token lets it call create_prompt and create_accept, each of which consumes a monitored-prompt slot from the subscription's allowance and fails with PROMPT_LIMIT_REACHED or INSUFFICIENT_CREDITS once that allowance is used up. Only monitored prompts hold a slot, so a create_prompt with monitoring_status false consumes nothing and is never refused for allowance. Use a read token for exploration and reporting, and mint a separate write or admin token only for the work that needs it.

Tools

tools/list returns 77 tools, one per public /v1/ operation, generated from the same OpenAPI spec as the REST API. Every one of them except list_projects takes project_id, and that value has to be a project the token reaches.

Area Tools
Project list_projects, get_project
Prompts list_prompts, get_prompt, get_prompt_ugc_evidence, create_prompt, create_prompts_bulk, update_prompt, delete_prompt
Prompt performance list_prompt_performance, get_prompts_summary
Prompt checks list_checks, list_check_answers, list_prompt_checks, get_prompt_check, get_prompt_check_latest
Prompt suggestions get_prompt_suggestions, create_accept, create_dismiss
Tags list_tags, create_tag, update_tag, delete_tag
URLs list_urls, get_url, create_url, update_url, delete_url
Dashboard get_dashboard_overview, get_llm_trends, get_ugc_impact, get_ugc_platform_sources
Brand aliases list_brand_aliases
Competitors list_competitors, get_competitors_citations, get_competitors_mentions, get_competitors_sources, get_competitors_trends, get_competitor_brand_facts, get_serp, get_competitors_bing_organic
Competitor drill-downs list_competitor_mention_prompts, list_competitor_citation_prompts, list_competitor_citation_urls, list_competitor_source_prompts, list_competitor_serp_prompts, list_competitor_serp_urls, list_competitor_bing_organic_prompts, list_competitor_bing_organic_urls
Competitor tags list_competitor_tags, create_competitor_tag, update_competitor_tag, delete_competitor_tag, list_competitor_tag_members, create_competitor_tag_members, delete_competitor_tag_member
UGC Impact get_topic_clusters, get_topics, get_sources, get_ugc_attributes, get_ugc_voices
Search Console get_gsc_trends, list_gsc_pages, list_gsc_queries
Website list_website_pages, get_website_page
Brand facts list_brand_facts, create_brand_fact, update_brand_fact, delete_brand_fact
Answer accuracy get_answer_accuracy_summary, list_answer_accuracy_problems, get_answer_accuracy_problem, list_answer_accuracy_problem_answers, dismiss_answer_accuracy_problem, undismiss_answer_accuracy_problem
Limits get_limits

55 of those are read, 14 are write, and 8 are admin: the 6 deletes and the 2 brand-fact writes.

list_prompt_performance and get_prompts_summary read the app's Prompts table and its summary card: each prompt's AI Score, its change over the window and every engine's answer at its latest check. The eight drill-down tools list the prompts and pages behind one row of a competitor ranking, over the same window, engines and prompt filters as that row, so their counts add up to the row's count. Each read returns applied, the window and the engines the numbers cover, so an assistant can say exactly what it measured.

list_projects is the one to call first: it returns the projects the token reaches, each with its id, name, country, language, check cadence, the engines enabled for that project and freshness, one page at a time (limit, offset, and sort as name:asc, name:desc, created_at:asc or created_at:desc). Pass an id to get_project next. Every other tool is scoped to a project but describes none of it, so get_project is what lets an assistant say which domains and brands are tracked, which engines are being checked, and whether the numbers it is about to read are fresh. Re-list rather than caching ids: the list follows the token's access at the moment of the call.

With a workspace token the flow is the same for every client project: list_projects, then any other tool once per project_id from the list. A project the token does not reach answers -32002 PROJECT_MISMATCH, and if the reach check cannot be made the call answers -32000 SERVICE_UNAVAILABLE, which is safe to retry. Each tools/call costs one unit whichever project it names, against the workspace token's own per-minute limit (120) and the shared workspace limits.

What is deliberately absent matters as much as what is there. There is no project create, update or delete, so an assistant can read a project's configuration but cannot change or destroy it. There are no workspace, billing, subscription, notification, export or content-brief tools. There is no way to trigger a check on demand: checks run on the project's own schedule, and these tools only read what those runs produced. There is also no get_tag - fetch a single tag by passing its name to the q filter on list_tags. list_competitors reads the tracked-competitor roster, the brands and domains carrying at least one competitor tag, and the competitor tag tools change it. Hiding a brand or domain stays an in-app action; the competitor rankings leave the hidden rows out by default and return them with filter=hidden.

Rate limits

Each tools/call costs one unit in each of the per-token (60/min) and per-workspace (600/min, 50000/day) buckets, the same as one /v1/ request. The unit is charged when the call reaches /mcp; the /v1/ request the tool runs internally is not charged again. A call refused before it dispatches, such as an unknown tool or a scope refusal, still costs its unit, as a REST 4xx does. initialize and tools/list are exempt. See rate limits.

Errors

A failed tool call still returns HTTP 200. The failure lives inside the JSON-RPC envelope, as an error object whose data field carries the underlying API envelope:

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32002,
    "message": "Token scope does not cover 'admin'",
    "data": {"code": "INSUFFICIENT_SCOPE", "error": "Token scope does not cover 'admin'"}
  }
}
JSON-RPC code Meaning
-32001 Unauthorized - token missing, malformed, expired, or revoked
-32002 Forbidden - scope too low, or project_id is a project the token does not reach
-32003 Rate limited
-32004 Payment required - API & MCP access add-on off, a payment not confirmed, a closed workspace, a read-only subscription (SUBSCRIPTION_READ_ONLY) or a plan cap reached (PROMPT_LIMIT_REACHED, INSUFFICIENT_CREDITS)
-32005 Not found, including PROJECT_NOT_FOUND
-32006 Maintenance - a declared maintenance window is in progress. Retry after data.retry_after_seconds; nothing is broken
-32009 Conflict - a duplicate, idempotency-key reuse, an already-resolved suggestion, or a Search Console connection that must be reconnected (GSC_REAUTH_REQUIRED)
-32602 Invalid params - missing required argument, or a rejected filter value
-32601 Unknown tool name or unknown JSON-RPC method
-32000 Server error - an upstream fault, an unreachable dependency or an internal error

Branch on error.data.code, not on the JSON-RPC number and not on the HTTP status. Several distinct API codes share one JSON-RPC number: -32004, for one, means "the workspace owner has something to pay for or renew", and data.code says what. A code with no row of its own in the mapping table follows the HTTP status it carries on /v1/ (a 404 is -32005, a 409 is -32009, and so on), so a new code still arrives in the right family.

Every failure reaches you as a JSON-RPC error. Four checks run in front of the router and can refuse a call before the tool executes - maintenance, then authentication, then entitlement, then rate limiting - and all four reply with HTTP 200 and a JSON-RPC error member, exactly as the router does. There is no condition on this endpoint that answers with a 401, 402, 403, 429 or 503, so a client that branches on the HTTP status will not see any of them.

The four are the only errors you can receive without your tool having run:

Refused by error.code data.code
Maintenance window -32006 MAINTENANCE_MODE
Authentication -32001 MISSING_AUTH_HEADER, INVALID_AUTH_FORMAT, TOKEN_INVALID, TOKEN_REVOKED, TOKEN_EXPIRED
Entitlement -32004 PAYMENT_REQUIRED, API_ADDON_INACTIVE, ENTITLEMENT_DENIED
Rate limiting -32003 RATE_LIMITED

They are listed in the order they run, and the first one to refuse is the one you hear from. A call with no token that would also have been rate limited comes back -32001, not -32003; during a maintenance window it comes back -32006 whatever else is wrong with it.

Authentication and entitlement

A missing, malformed, revoked, expired or unknown token is -32001:

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32001,
    "message": "API token has been revoked",
    "data": {"code": "TOKEN_REVOKED", "error": "API token has been revoked"}
  }
}

An entitlement refusal - the API & MCP access add-on switched off, a first payment not yet confirmed, a closed workspace, or API access not enabled for the workspace - has the same shape at -32004. Read data.code to tell them apart: -32001 means fix the token, -32004 means the workspace owner has something to resolve in billing settings, and neither is worth retrying until they do.

A workspace whose paid period has ended but which is still open is read-only rather than refused. Every read tool keeps working, and every write tool (create_*, update_*, delete_*) returns -32004 with data.code SUBSCRIPTION_READ_ONLY. That refusal comes from the tool's own /v1/ call, after the four checks below, so initialize, tools/list and the read tools are unaffected. get_project reports the state ahead of a write as write_access: false. A workspace in dunning keeps full access while it is inside its paid period.

If the subscription check itself cannot be made, the call is refused with -32000 and data.code SERVICE_UNAVAILABLE. That answer is not cached, so retry after a short wait.

Neither carries a header, and neither adds keys to data beyond code and error. id is echoed from your request, or null when the body carried none.

Rate limits

A tools/call that exceeds any bucket is refused with -32003, at HTTP 200, before the tool runs:

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32003,
    "message": "Rate limit exceeded",
    "data": {
      "code": "RATE_LIMITED",
      "error": "Rate limit exceeded",
      "retry_after_seconds": 37
    }
  }
}

Maintenance windows

While a maintenance window is declared, every /mcp call is refused. The reply is still HTTP 200 with a JSON-RPC error, deliberately: a transport-level 503 handed to an agent tends to become a confident wrong answer for its user, while a typed error with a retry hint becomes a correct one.

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32006,
    "message": "Service is under maintenance",
    "data": {
      "code": "MAINTENANCE_MODE",
      "error": "Service is under maintenance",
      "reason": "Scheduled database upgrade",
      "ends_at": "2026-08-07T03:00:00+00:00",
      "retry_after_seconds": 1800
    }
  }
}

This is the case the "branch on error.data.code" rule is worth most: an agent that reads the JSON-RPC number as a generic server error reports a broken API to its user, when the correct behaviour is to wait and retry once.

Client setup guides

Supported methods

JSON-RPC method Description
initialize Handshake; returns server info and capability flags
tools/list Returns the full tool manifest
tools/call Calls one tool by name with arguments

Nothing else is implemented. initialize advertises capabilities as {"tools": {}} and nothing more, so resources, prompts, notifications, sampling, roots, completion, and logging are all absent, as is SSE. If your client expects to read MCP resources or fetch server-side prompt templates, it will find none here.