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:
- Click New token and name it after the client that will use it.
- Choose its scopes. A new token offers Read alone.
- Copy the token and the MCP endpoint. Kiku shows the token once and keeps only a fingerprint.
| Scope | What the client may do |
|---|---|
| Read | List tickets, read a whole thread and its attachments, list agents, ticket types and companies. |
| Write | Set status, type, company and assignee; manage and link todos; post and edit internal notes; save drafts; raise a ticket by hand. |
| Reply | Email a public reply to the Contact, signed with your footer; resend a reply that failed. |
| Admin | Create, 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:
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
| Tool | Scope |
|---|---|
list_tickets, get_ticket, get_attachment, list_agents, list_ticket_types, list_companies | Read |
set_ticket_status, set_ticket_priority, set_ticket_type, set_ticket_area, set_ticket_outcome, set_ticket_company, set_ticket_assignee | Write |
add_todo, set_todo_text, set_todo_done, delete_todo, link_todo, refresh_ticket_links | Write |
add_internal_note, edit_internal_note, create_ticket, save_reply_draft, delete_reply_draft | Write |
set_ticket_context, set_company_context | Write |
add_ticket_reference, remove_ticket_reference | Write |
send_reply, retry_message | Reply |
create_ticket_type, update_ticket_type, delete_ticket_type | Admin |
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.