Skip to content

MCP

Kiku runs an MCP server, so an MCP client such as Claude Code can read tickets and work them. The client signs in with an access token, acts as the agent who made it, and can do only what the token’s scopes allow.

Create an access token

Each agent makes their own, in Settings → Access tokens:

  1. Click New token and name it after the client that will use it.
  2. Choose its scopes. A new token offers Read alone.
  3. Copy the token and the MCP endpoint. Kiku shows the token once and keeps only a fingerprint.
ScopeWhat the client may do
ReadList tickets, read a whole thread and its attachments, list agents, ticket types and companies.
WriteSet status, type, company and assignee; manage and link todos; post and edit internal notes; save drafts; raise a ticket by hand.
ReplyEmail a public reply to the Contact, signed with your footer; resend a reply that failed.
AdminCreate, rename and delete types, areas and outcomes. Offered to admins only.

Everything the client writes appears in the thread under your name, exactly as if you had done it in the desk. Revoke a token from the same page; the client is refused from its next request.

Connect a client

The endpoint is /api/mcp on your APP_URL, over Streamable HTTP. Send the token as a bearer token.

Claude Code:

Terminal window
claude mcp add --transport http kiku https://desk.example.com/api/mcp \
--header "Authorization: Bearer kiku_…"

Clients configured with JSON, such as Cursor:

{
"mcpServers": {
"kiku": {
"url": "https://desk.example.com/api/mcp",
"headers": { "Authorization": "Bearer kiku_…" }
}
}
}

Tools

ToolScope
list_tickets, get_ticket, get_attachment, list_agents, list_ticket_types, list_companiesRead
set_ticket_status, set_ticket_priority, set_ticket_type, set_ticket_area, set_ticket_outcome, set_ticket_company, set_ticket_assigneeWrite
add_todo, set_todo_text, set_todo_done, delete_todo, link_todo, refresh_ticket_linksWrite
add_internal_note, edit_internal_note, create_ticket, save_reply_draft, delete_reply_draftWrite
set_ticket_context, set_company_contextWrite
add_ticket_reference, remove_ticket_referenceWrite
send_reply, retry_messageReply
create_ticket_type, update_ticket_type, delete_ticket_typeAdmin

Message bodies go in as plain text; a blank line starts a new paragraph. In an internal note, <@agentId> mentions that agent and notifies them, as a mention in the desk does, and <#1234> references ticket 1234, as # in the desk does. send_reply, add_internal_note and create_ticket take files as base64, up to the usual attachment size. get_attachment returns text files as text and anything else as base64. edit_internal_note replaces the body of a note the token’s agent wrote; its files stay and new ones are added.

get_ticket returns the ticket’s context and its company’s context as Markdown. set_ticket_context and set_company_context replace one of them with new Markdown; the company one is reached through a ticket filed under it. Both keep the existing attachments, and a save that crosses another edit fails with who saved in between.

get_ticket also lists the ticket’s references and the tickets it is referencedBy. add_ticket_reference references another ticket by hand, as the desk’s References tab does, and both tickets record it in their thread. remove_ticket_reference removes only a reference added by hand (manual: true); one a note makes goes when the note is edited to drop its <#number>.

save_reply_draft puts a reply or note in your own composer on the ticket, where you read it and send it from the desk. It is the way to let a client write replies without the Reply scope.

send_reply goes to the requester, with every participant in Cc. A client can neither add a recipient nor change the requester; both stay in the desk, so a message in a thread cannot talk a client into mailing someone new.

What it does not do

  • No ticket summary. A summary is model-authored and never an input to anything, a client included.
  • No unread changes. A client reading a ticket does not mark it read for you.
  • No admin settings beyond categories. Companies, Contact forms, agents and settings stay in the desk. Types, areas and outcomes are the exception, under the Admin scope.
  • No OAuth. Hosted connectors that require an OAuth sign-in cannot connect yet. Use a client that sends a header.

Security

A token is as powerful as you are within its scopes, so treat it like a password. Ticket text is written by Contacts, and a message can carry instructions aimed at the client’s model. Give a token Reply only when the client should be able to mail customers without you reading first, and Admin only for the session that rebuilds your categories: deleting one clears it on every ticket that carries it.

Requests that carry a browser Origin header are refused, so a web page cannot use a token it learns. A token stops working when its agent leaves the organization or is deactivated. While an organization is locked, writes are refused and reads still work.

The decision and its trade-offs are recorded in ADR 0018: An MCP client works tickets as an agent.