Label ticket enums server-side so clients never guess the scale
A webhook consumer read priority 4 off a ticket and called it 'Low (4)' in a posted note — inverting Freshservice's scale (4=Urgent). Add *_label companions (priority, status, impact, urgency) to every ticket returned by get_ticket and list_tickets; status labels resolve through the live instance status list, so custom statuses label correctly too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -204,6 +204,33 @@ def _open_status_ids() -> list[int]:
|
|||||||
return [c["id"] for c in _status_choices() if c.get("id") is not None and not _is_terminal(c)]
|
return [c["id"] for c in _status_choices() if c.get("id") is not None and not _is_terminal(c)]
|
||||||
|
|
||||||
|
|
||||||
|
# Impact/urgency are fixed 1-3 scales in Freshservice (priority is fixed 1-4).
|
||||||
|
IMPACT_URGENCY = {1: "Low", 2: "Medium", 3: "High"}
|
||||||
|
|
||||||
|
|
||||||
|
def _label_ticket(t: Any) -> Any:
|
||||||
|
"""Add *_label fields next to a ticket's numeric enums (priority, status,
|
||||||
|
impact, urgency) so no consumer ever guesses the scale. A weak model once
|
||||||
|
read priority 4 and called it "Low (4)" — Urgent — in a customer-visible
|
||||||
|
note; labels in the data remove that entire error class."""
|
||||||
|
if not isinstance(t, dict):
|
||||||
|
return t
|
||||||
|
p = t.get("priority")
|
||||||
|
if p in TICKET_PRIORITY:
|
||||||
|
t["priority_label"] = TICKET_PRIORITY[p]
|
||||||
|
for field in ("impact", "urgency"):
|
||||||
|
v = t.get(field)
|
||||||
|
if v in IMPACT_URGENCY:
|
||||||
|
t[f"{field}_label"] = IMPACT_URGENCY[v]
|
||||||
|
s = t.get("status")
|
||||||
|
if isinstance(s, int) and "status_name" not in t:
|
||||||
|
label = next((c.get("value") for c in _status_choices() if c.get("id") == s),
|
||||||
|
None) or TICKET_STATUS.get(s)
|
||||||
|
if label:
|
||||||
|
t["status_label"] = label
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
# --- Tickets ---------------------------------------------------------------
|
# --- Tickets ---------------------------------------------------------------
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def list_tickets(query: str | None = None, unresolved: bool = False,
|
def list_tickets(query: str | None = None, unresolved: bool = False,
|
||||||
@@ -247,11 +274,16 @@ def list_tickets(query: str | None = None, unresolved: bool = False,
|
|||||||
if query:
|
if query:
|
||||||
params = {"query": f'"{query}"', "workspace_id": workspace_id,
|
params = {"query": f'"{query}"', "workspace_id": workspace_id,
|
||||||
"page": page, "per_page": min(per_page, 100)}
|
"page": page, "per_page": min(per_page, 100)}
|
||||||
return _out(_request("GET", "/tickets/filter", params=params))
|
res = _request("GET", "/tickets/filter", params=params)
|
||||||
params = {"updated_since": updated_since, "order_by": order_by,
|
else:
|
||||||
"order_type": order_type, "workspace_id": workspace_id,
|
params = {"updated_since": updated_since, "order_by": order_by,
|
||||||
"page": page, "per_page": min(per_page, 100)}
|
"order_type": order_type, "workspace_id": workspace_id,
|
||||||
return _out(_request("GET", "/tickets", params=params))
|
"page": page, "per_page": min(per_page, 100)}
|
||||||
|
res = _request("GET", "/tickets", params=params)
|
||||||
|
if res.get("ok"):
|
||||||
|
for t in res["data"].get("tickets", []):
|
||||||
|
_label_ticket(t)
|
||||||
|
return _out(res)
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
@@ -271,9 +303,15 @@ def list_ticket_statuses() -> str:
|
|||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
def get_ticket(ticket_id: int, include: str | None = None) -> str:
|
def get_ticket(ticket_id: int, include: str | None = None) -> str:
|
||||||
"""Get a ticket by id. `include` e.g. "conversations,requester,stats"."""
|
"""Get a ticket by id. `include` e.g. "conversations,requester,stats".
|
||||||
|
Numeric enums come back with companion *_label fields (priority_label,
|
||||||
|
status_label, impact_label, urgency_label) — use those names, never guess
|
||||||
|
the scale (priority 4 is Urgent, not low)."""
|
||||||
params = {"include": include} if include else None
|
params = {"include": include} if include else None
|
||||||
return _out(_request("GET", f"/tickets/{ticket_id}", params=params))
|
res = _request("GET", f"/tickets/{ticket_id}", params=params)
|
||||||
|
if res.get("ok"):
|
||||||
|
_label_ticket(res["data"].get("ticket"))
|
||||||
|
return _out(res)
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
|
|||||||
Reference in New Issue
Block a user