Skip to content

Bug get_ticket_by_id fails with pydantic validation error (expected string, got dict) #30

Description

@pmoisontech

Description

The get_ticket_by_id tool fails with a pydantic validation error when
called with a valid ticket ID. The Freshservice API call succeeds and
returns the ticket payload correctly, but the tool's return-type
validation rejects the response because it expects a string while the
API returns a JSON object.

Steps to reproduce

  1. Call get_ticket_by_id with any valid ticket_id (e.g. 12031).

Expected behavior

The tool returns the full ticket payload, including standard fields
(subject, description, status, priority, requester, responder, dates,
etc.), custom fields, and the dedicated Resolution Note field.

Actual behavior

The tool returns:

Error executing tool get_ticket_by_id: 1 validation error for get_ticket_by_idOutput
result
Input should be a valid string [type=string_type, input_value={'ticket': {'planned_star...v>', 'attachments': []}}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.13/v/string_type

The raw API response is visible inside the error message, which
confirms that the upstream HTTP call to Freshservice succeeds —
only the output validation in the MCP wrapper fails.

Impact

  • No single ticket can be fetched by ID through the MCP.
  • The dedicated Resolution Note field becomes effectively
    unreachable, since it is not exposed by list_all_ticket_conversation
    either. This blocks any use case relying on resolution data
    (post-mortems, KB seeding, reporting on closed tickets).
  • Custom fields, SLA escalation flags and planned dates on individual
    tickets are also inaccessible.

Suggested fix

Align the get_ticket_by_id output schema with the actual Freshservice
v2 response shape — a JSON object with a top-level ticket key — by
either:

  • changing the declared return type from str to dict (or a typed
    Pydantic model mirroring the ticket schema), or
  • serializing the dict to JSON string before returning, if the string
    contract must be preserved for downstream compatibility.

The same pattern should be reviewed on any sibling tool returning a
single record (e.g. get_agent, get_requester_id) to make sure the
fix is consistent.

Environment

  • Freshservice MCP server: ?
  • Pydantic: 2.13
  • Freshservice region / domain: EU (*.freshservice.com)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions