Zono Support

Work your Zono Support help desk from any AI client: read, search, answer and route support tickets, see who bought what, and get cited answers from your knowledge base. Remote server with OAuth 2.1 sign-in.

Servidor MCP hospedado

npx add-mcp 'https://zono.support/mcp'

Instala no Claude Code, Codex, Cursor e outros

Documentação

Skip to content

On this page

Endpoint

The server speaks the MCP streamable HTTP transport at a single URL. Clients that support OAuth need nothing else; others send a token in the Authorization header.

MCP endpoint

Copy

https://zono.support/mcp

Connect with OAuth

The recommended way. Your client registers itself, you sign in to Zono in the browser, pick the workspace and the scopes to grant, and approve. No token to copy or rotate.

  • Claude and ChatGPT: add a custom connector (in Claude: Settings > Connectors; in ChatGPT: Settings > Connectors) and paste https://zono.support/mcp. Connect, sign in, approve.
  • Cursor and VS Code: configure only the URL (see Client setup). The consent page opens the first time the client connects.
  • Claude Code: add the server by URL, then run /mcp and choose Authenticate.

The consent page names the app as unverified (it names itself when it registers) and shows where it will send you back, so only approve apps you are connecting yourself. Clients must use PKCE with S256, and redirect URIs must match the registered ones exactly. Discovery documents are at /.well-known/oauth-protected-resource and /.well-known/oauth-authorization-server.

Bearer tokens

For clients without OAuth, scripts and CI, send a personal access token: Authorization: Bearer <token>. Tokens are created under Account > API & MCP tokens, are scoped to one workspace, carry the scopes you tick, and are shown once. A token expires after 90 days unless you pick another lifetime (7, 30 or 365 days, or never), and we email you each time one is created. You can also give it an IP allowlist; requests from other addresses are refused. The same token also works for the REST API.

New to Zono? Start free, then create a token.

Scopes

Every tool needs one scope. OAuth connections carry the scopes approved on the consent page; tokens carry the ones ticked when they were created (the Read only and Read and write presets tick the read scopes, or all of them). Your client still lists every tool: a call outside the token's scopes returns an error result naming the missing scope, and nothing changes. Tokens made before scopes existed keep working as before: read-only tokens can call the read tools, read-write tokens every tool.

ScopeAllowsTools
tickets:readList, search and read tickets, their replies, notes and custom fields.list-tickets, get-ticket, search-tickets, list-ticket-fields, list-products, list-departments, list-team-members
tickets:writeCreate tickets, reply, add notes, assign, change status or fields, and merge tickets.reply-to-ticket, assign-ticket, update-ticket-status, update-ticket-fields, create-ticket, merge-tickets
customers:readList and read customers (team owners and admins only).list-customers, get-customer
knowledge:readSearch the help center and knowledge sources, and ask for cited answers.search-knowledge, ask-knowledge
licenses:readLook up and verify license keys and purchases.lookup-license

REST API only, no MCP tool (OAuth apps that ask for them, such as automation tools, are offered them): customers:write (change customers), conversations:read (read conversations), conversations:write (change conversations), webhooks:manage (manage webhooks).

Lifetimes and revocation

OAuth access tokens last 60 minutes and clients renew them with a refresh token, which is replaced on every use and expires after 180 days unused. Authorization codes last 10 minutes and work once. Disconnect an app under Account > API & MCP tokens > Connected apps (team owners and admins can also do it from Settings > API tokens): its access and refresh tokens stop working at once. Leaving a workspace cuts off access too. Personal access tokens last until they expire or are revoked.

Tools

Your client discovers these automatically. Parameters marked * are required.

list-ticketsReadtickets:read

List tickets in the current team that the agent can access, optionally filtered by status, assignee, priority, department or custom field values.

ParameterTypeDescription
statusstringFilter by ticket status: open, answered, on-hold, or closed.
assignee_idstringFilter to tickets assigned to a specific user ULID.
department_idstringFilter to tickets in a specific department ULID.
prioritystringFilter by priority: low, normal, high, or urgent.
limitintegerMaximum number of tickets to return (default 25, max 100).
custom_fieldsobjectFilter by custom field values keyed by field key: a value (or list of option values) to match, {"min","max"} for numbers, {"from","to"} for dates, "__empty__" for no value or "__any__" for any value.

get-ticketReadtickets:read

Fetch the full conversation thread for a single ticket by ID or number, including all replies, internal notes, SLA status and custom field values.

ParameterTypeDescription
ticket*stringTicket ULID or ticket number.

reply-to-ticketWritetickets:write

Post a reply to a ticket as the authenticated agent. Set is_internal=true for staff-only notes.

ParameterTypeDescription
ticket*stringTicket ULID or ticket number to reply to.
message*stringReply body (plain text or HTML). HTML is preserved.
is_internalbooleanWhen true, the reply becomes a staff-only internal note (default: false).
close_ticketbooleanWhen true, close the ticket after posting the reply (default: false).

assign-ticketWritetickets:write

Assign a ticket to a team member, or unassign it by passing assignee_id=null.

ParameterTypeDescription
ticket*stringTicket ULID or ticket number.
assignee_idstringUser ULID to assign the ticket to. Omit or send null to unassign.

update-ticket-statusWritetickets:write

Change a ticket status (open, answered, on-hold, closed). Closing needs every required custom field filled in; pass missing values in custom_fields, keyed by field key.

ParameterTypeDescription
ticket*stringTicket ULID or ticket number.
status*stringNew ticket status: open, answered, on-hold, or closed.
custom_fieldsobjectOptional custom field values to save with the status change, keyed by field key, e.g. {"order_number": "1001"}. Use list-ticket-fields for keys, types and options.

update-ticket-fieldsWritetickets:write

Set custom field values on an existing ticket. Values are keyed by field key (see list-ticket-fields); null or an empty value clears an optional field.

ParameterTypeDescription
ticket*stringTicket ULID or ticket number.
custom_fields*objectCustom field values keyed by field key, e.g. {"order_number": "1001", "category": "bug"}. Multi-select values are arrays of option values, dates are YYYY-MM-DD. Only fields that apply to the ticket's department and product are accepted.

create-ticketWritetickets:write

Create a new ticket on behalf of a customer. The customer and product must already exist in the team. Custom field values are keyed by field key (see list-ticket-fields).

ParameterTypeDescription
customer_id*stringCustomer ULID the ticket is created for.
subject*stringTicket subject line.
description*stringInitial ticket body / description.
product_id*integerProduct ID the ticket relates to.
prioritystringOptional priority: low, normal, high, urgent.
department_idstringOptional department ULID to route the ticket to.
custom_fieldsobjectOptional custom field values keyed by field key, e.g. {"order_number": "1001", "category": "bug"}. Use list-ticket-fields for keys, types and options; multi-select values are arrays of option values, dates are YYYY-MM-DD.

search-ticketsReadtickets:read

Full-text search across ticket subject, description, and customer name. Honors per-agent access rules.

ParameterTypeDescription
query*stringSearch term to match against subject, description, customer name, and customer email.
statusstringOptional status filter.
limitintegerMaximum results to return (default 20, max 50).

list-customersReadcustomers:read

List or search customers belonging to the current team. Team admins and owners only, as in the dashboard.

ParameterTypeDescription
searchstringOptional substring to match against customer name or email (case-insensitive; % and _ match literally).
limitintegerMaximum customers to return (default 25, max 100).

get-customerReadcustomers:read

Fetch one customer by ID or email, with their ticket count and most recent tickets. Team admins and owners only, as in the dashboard. Use lookup-license for their purchases.

ParameterTypeDescription
customer*stringCustomer ULID or email address.

search-knowledgeReadknowledge:read

Search the team knowledge (help articles, saved replies, snippets, resolved tickets, websites, files) with the team's AI Knowledge settings. Returns ranked passages with scores and citations.

ParameterTypeDescription
query*stringWhat to look up.
ticketstringOptional ticket ID or number to search in the context of (its product, department and channel).
product_idstringOptional product ID to scope the search to.
limitintegerMaximum passages to return (1-20, default from settings).

ask-knowledgeReadknowledge:read

Ask a question and get an answer grounded in the team knowledge, with [S#] citations, a confidence score and whether a human should handle it.

ParameterTypeDescription
query*stringThe question to answer.
ticketstringOptional ticket ID or number to answer in the context of.
product_idstringOptional product ID to scope the answer to.

list-ticket-fieldsReadtickets:read

List the team's active custom ticket fields with their keys, types, options and whether they are required, for use with create-ticket and list-tickets.

No parameters.

list-productsReadtickets:read

List or search the team's products, with the product_id that create-ticket and the knowledge tools take.

ParameterTypeDescription
searchstringOptional substring to match against the product name (case-insensitive; % and _ match literally).
include_inactivebooleanInclude inactive products (default false).
limitintegerMaximum products to return (default 50, max 100).

list-departmentsReadtickets:read

List the team's active departments, with the department_id that create-ticket and list-tickets take.

No parameters.

list-team-membersReadtickets:read

List or search the team's members with their role, for the assignee_id that assign-ticket and list-tickets take. "me" marks the signed-in user.

ParameterTypeDescription
searchstringOptional substring to match against the member's name or email (case-insensitive).

merge-ticketsWritetickets:write

Merge a duplicate ticket (source) into another ticket (target) of the same customer. The target receives the source's replies, notes, attachments and tags; the source is closed and linked to the target, and future customer messages to it land on the target. Tickets of different customers cannot be merged.

ParameterTypeDescription
source*stringTicket ULID or number of the duplicate ticket to merge (it will be closed).
target*stringTicket ULID or number of the ticket to merge into (it stays open). Must belong to the same customer as the source.
notify_customerbooleanTell the source ticket's customer where their request went. Defaults to false.
notestringOptional internal note added to both tickets.

lookup-licenseReadlicenses:read

Look up licenses and purchases: pass a ticket (ID or number) for its requester's storefront card (stored licenses, purchases found by email and a refund flag), or a license_key (team admins and owners only) for the stored license with that key and its customer. Keys come back masked to their last four characters.

ParameterTypeDescription
ticketstringTicket ULID or ticket number: returns its requester's licenses and purchases. Pass this or license_key, not both.
license_keystringA license key or purchase code to find among the team's stored licenses (team admins and owners only). Pass this or ticket, not both.

Permission model

Tools run as the user who connected the app or issued the token, scoped to one workspace. They inherit that user's role and department and product access, so the AI sees and changes only the tickets you could in the dashboard; scopes narrow that further, never widen it. Customer listing is limited to team owners and admins, as in the dashboard. Leaving the workspace, disconnecting the app or revoking the token cuts off access immediately.

Rate limits

60 requests per minute per token (or per connected app) and 300 per workspace; the tighter limit applies. The per-workspace limit stops many tokens on one workspace from crowding out others. Over the limit, requests get a 429 with Retry-After.

Audit trail

Every tool call is logged after it runs, with the tool, the user, the token or connected app, its outcome (including calls refused for a missing scope) and its latency. Creating and revoking tokens, and connecting and disconnecting apps, are logged too. Team owners see these entries in the workspace activity log.

Client setup

OAuth first; with a bearer token, replace <YOUR_TOKEN> with your token.

Claude Code

Run this once in your terminal, then type /mcp in Claude Code and choose Authenticate: your browser opens the Zono sign-in and consent page. With a token instead, add the Authorization header.

OAuth Bearer token

Copy

claude mcp add --transport http zono-support https://zono.support/mcp

Claude Desktop

Easiest: Settings > Connectors > Add custom connector, then paste the endpoint. To configure it by file instead, Claude Desktop starts local servers from claude_desktop_config.json, so it reaches Zono through the mcp-remote bridge (needs Node.js for npx); mcp-remote opens the consent page itself. The bearer variant passes the header through an env var because some clients do not escape spaces in args.

OAuth Bearer token

Copy

{
    "mcpServers": {
        "zono-support": {
            "command": "npx",
            "args": [
                "-y",
                "mcp-remote",
                "https://zono.support/mcp"
            ]
        }
    }
}

Cursor

Add the server to ~/.cursor/mcp.json (or .cursor/mcp.json in a project) with only the URL. The first time it connects, Cursor asks you to log in and opens the consent page. With a token instead, add the headers block.

OAuth Bearer token

Copy

{
    "mcpServers": {
        "zono-support": {
            "url": "https://zono.support/mcp"
        }
    }
}

VS Code

Add the server to .vscode/mcp.json (or your user settings) with only the URL. VS Code asks you to sign in when it first starts the server.

.vscode/mcp.json

Copy

{
    "servers": {
        "zono-support": {
            "type": "http",
            "url": "https://zono.support/mcp"
        }
    }
}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Zono Support MCP server","description":"Reference for the Zono Support MCP server: connect Claude Code, Claude Desktop or Cursor to your helpdesk by signing in with OAuth or with a workspace-scoped bearer token, read-only or read-write tools for tickets, customers and knowledge, the permission model, rate limits and audit trail.","url":"https://zono.support/developers/mcp"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://zono.support"},{"@type":"ListItem","position":2,"name":"Developers","item":"https://zono.support/developers"},{"@type":"ListItem","position":3,"name":"MCP server","item":"https://zono.support/developers/mcp"}]}