Working a ticket
Change, snooze, reopen, merge, split and link tickets, and read a ticket's stored summary.
These tools cover what an agent does to a ticket after reading it: change its fields, put it aside until later, bring it back, combine two tickets into one, move messages into a new ticket, record how tickets relate, and read the summary the helpdesk has already written.
| Tool | What it does | Role needed | Changes data? |
|---|---|---|---|
update_ticket | Changes status, priority, assignee, team or tags | editor | destructive |
snooze_ticket | Hides a live ticket from the queue until a time | editor | adds |
unsnooze_ticket | Brings a snoozed ticket back into the queue now | editor | adds |
reopen_ticket | Reopens a solved or closed ticket | editor | destructive |
merge_tickets | Previews, then merges one ticket into another | editor | destructive |
split_ticket | Moves messages off a ticket into a new ticket | editor | destructive |
link_tickets | Links another ticket as parent, child or related | editor | adds |
list_ticket_links | Lists a ticket's parent, children and related tickets | viewer | read-only |
unlink_tickets | Removes one link | editor | destructive |
get_ticket_summary | Reads the ticket's stored summary | viewer | read-only |
Source: _TOOLS in services/runtime/src/runtime/mcp/tools.py and the
handler named after each tool (_update_ticket, _snooze_ticket, and so on).
update_ticket sends the client no read-only or destructive hint. Its entry
describes what the handler does: it overwrites values.
What every write here returns
Except update_ticket, each write answers with the ticket in a short form: id,
reference, subject, status, priority, assignee_id, customer_id,
snooze_until, reopened_at, merged_into_id, legal_next_states and
updated_at. For the whole ticket, call get_ticket.
The subject was written by a customer, so it comes back wrapped as
{"untrusted_text": ...}. See Limits for what that wrapper does
and does not do.
A ticket you cannot see, or one that does not exist, gets the same "not found" answer.
Source: _compact_ticket, _COMPACT_TICKET_KEYS and _assert_ticket_reachable
in services/runtime/src/runtime/mcp/tools.py.
update_ticket
- Inputs:
ticket_idis required. Any ofstatus,priority,assignee_id,team_idandtagsmay be given. statusis one ofclosed,on_hold,open,pending,solvedorspam. It must be a legal move from the ticket's current status. A refusal names the legal targets, so the assistant can pick one and try again.tagsreplaces the whole tag list. It does not add to it.- Returns the updated ticket as the HTTP route returns it, unwrapped. This is one of the older tools that does not wrap customer text.
Source: _update_ticket in services/runtime/src/runtime/mcp/tools.py.
snooze_ticket and unsnooze_ticket
snooze_tickettakesticket_idand exactly one ofuntilorduration_minutes. Giving both, or neither, is refused.untilmust be an ISO-8601 date-time with a UTC offset, for example2026-10-21T09:00:00+00:00, and in the future.duration_minutesruns from 1 to 525,600 (one year).unsnooze_ticketon a ticket that is not snoozed leaves it alone, so calling it twice is safe.
Source: _snooze_ticket, _unsnooze_ticket, _optional_instant and
_SNOOZE_MINUTES_MAX in services/runtime/src/runtime/mcp/tools.py.
reopen_ticket
Takes ticket_id. Works on a solved or closed ticket, and its SLA timers start
again.
merge_tickets: preview first, then confirm
A merge cannot be undone, so it always takes two calls.
- Preview. Call with
source_ticket_idandtarget_ticket_idand noconfirmation_token. Nothing changes. The answer haspreview: true, both tickets (the source with itsmessage_count), anywarnings, aconfirmation_tokenand itsexpires_at. - Confirm. Call again with the same two ids and that
confirmation_token. The source is merged into the target, and the answer hasmerged: trueand both tickets.
Warnings name two situations worth a second look: different_customers (the two
tickets belong to different customers) and target_not_live (the target is not
open, pending or on_hold).
The token:
- lasts 10 minutes;
- works only for the same person, the same workspace and the same pair of tickets, in the same direction;
- is refused with a message telling the assistant to preview again, whether it is expired, altered or for a different merge.
The token goes to the assistant app, not to you. It stops an accidental or mistyped merge. It does not prove that a person looked at the preview. Keep your app's own approval prompt switched on for this tool.
Source: _merge_tickets, _merge_preview, _issue_merge_token,
_verify_merge_token and _MERGE_TOKEN_TTL in
services/runtime/src/runtime/mcp/tools.py.
split_ticket
- Inputs:
ticket_id, and exactly one ofevent_ids(a list of 1 to 500 message ids) orfrom_event_id(that message and every later one).subject(1 to 200 characters) names the new ticket. - Returns
moved,new_ticketandsource_ticket. - Cannot be undone.
Source: _split_ticket and _SPLIT_EVENT_IDS_MAX in
services/runtime/src/runtime/mcp/tools.py.
link_tickets, list_ticket_links and unlink_tickets
link_ticketstakesticket_id,linked_ticket_idandrelation.relationisparent,childorrelated, and says what the other ticket is to this one.list_ticket_linkstakesticket_idand an optionallimit(1 to 200, default 50).unlink_ticketstakesticket_idand thelink_idthatlist_ticket_linksreturned.- All three return the ticket's links:
parent,childrenandrelated. Each linked ticket'ssubjectis wrapped as untrusted text.
Source: _link_tickets, _list_ticket_links, _unlink_tickets and
_links_view in services/runtime/src/runtime/mcp/tools.py.
get_ticket_summary
- Reads the summary the helpdesk has already stored. It never generates one.
When none is stored,
statussays it is unavailable. - Returns
ticket_id,status,bullets,summary_text,generated_at,staleandsource_version. summary_textand each bullet are wrapped as untrusted text, because a summary repeats what the customer wrote.staletrue means the ticket has changed since the summary was written.
Source: _get_ticket_summary and SummaryField in
services/runtime/src/runtime/mcp/tools.py.
Size limits
snooze_ticket, reopen_ticket, merge_tickets and split_ticket answer in at
most 8 KB. The change is already saved when the answer is measured, so an answer
that does not fit is shortened, never turned into an error. See
Limits.