Skip to main content
Glama
mcp-server-rt

mcp-server-rt

Official

mcp-server-rt

An MCP (Model Context Protocol) server that connects AI assistants to a live RT (Request Tracker) instance. Search tickets, view history, create and update tickets — all from a natural language conversation.

Features

  • Search tickets using RT's full TicketSQL query language

  • Read ticket details including full transaction history

  • Create tickets setting initial content and all ticket metadata: status, owner, requestors, due dates, custom fields, custom roles, and links

  • Update tickets reply, comment, and update tickets, with the same full field support

  • Queue and user discovery — list queues, inspect custom field definitions, look up users by name or email

  • TicketSQL grammar reference — the AI can consult the full RT 6.0.3 syntax guide before constructing complex queries

  • Queue administration — build and configure queues: lifecycles, user-defined groups and their members, custom fields, rights, and queue watchers

  • Guided queue creation — a create-queue prompt that interviews you about the workflow, recommends a configuration, confirms the plan, then builds it

Related MCP server: rt-mcp

Requirements

  • RT 6.0 or later with REST 2.0 API enabled (included by default). The lifecycle and rights tools need RT 6.0.3 or later, which is when RT added those REST 2.0 endpoints.

  • Node.js 18 or later

  • An RT authentication token

Installation

npm install -g mcp-server-rt

Or use without installing via npx mcp-server-rt.

Creating an RT Auth Token

In RT: Logged in as → Settings → Auth Tokens → Create

Give the token a name (e.g. "Claude") and copy the generated token string.

The token is associated with the user account, so all operations in RT from Claude using that token will be logged as performed by that user. So everything you do via Claude still gets logged in RT as you, including emails sent on comments and replies.

Users need to be granted the right ManageAuthTokens to see the Auth Tokens menu.


AI Client Setup

MCP is an open standard — this server works with any MCP-compatible AI client. Configuration varies by client.

Claude Desktop ✓ (tested)

Install the .mcpb extension package from the releases page. In the Claude app, go to Customize → Connectors, find RT, and enter your RT URL and auth token.

Alternatively, add manually to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "rt": {
      "type": "stdio",
      "command": "npx",
      "args": ["mcp-server-rt"],
      "env": {
        "RT_URL": "https://rt.example.com",
        "RT_TOKEN": "your-auth-token"
      }
    }
  }
}

Claude Code ✓ (tested)

Add to .mcp.json in your project root:

{
  "mcpServers": {
    "rt": {
      "type": "stdio",
      "command": "npx",
      "args": ["mcp-server-rt"],
      "env": {
        "RT_URL": "https://rt.example.com",
        "RT_TOKEN": "your-auth-token"
      }
    }
  }
}

Other MCP-compatible clients

Any client that supports MCP stdio servers should work. Consult your client's documentation for how to register a stdio MCP server with environment variables. The server entry point is mcp-server-rt (or node /path/to/dist/index.js for a local build).


Tools

Tickets, queues, and users

Tool

Description

search_tickets

Search tickets using RT's TicketSQL query language

get_ticket

Get details for a specific ticket by ID

get_ticket_history

Get transaction history (comments, replies, status changes)

get_transaction

Get full details of a single transaction, including decoded message content

get_queue

Get details about a queue by ID or name

list_queues

List all available queues

get_queue_fields

Get custom field definitions and lifecycle name for a queue

lookup_user

Search for RT users by name or email

get_current_user

Get the RT user associated with the configured auth token

get_ticketsql_grammar

Fetch the full TicketSQL grammar reference (for complex queries)

create_ticket

Create a new ticket

update_ticket

Update ticket fields (status, owner, priority, dates, watchers, links, custom fields)

add_comment

Add an internal comment (not visible to the requestor), optionally setting custom fields

add_reply

Send a reply to the requestor, optionally setting custom fields

get_ticket_attachments

List all attachments on a ticket

get_attachment

Retrieve a single attachment by ID

save_attachment

Save an attachment to a local file

Queue administration

Building and configuring queues. The lifecycle and rights tools need RT 6.0.3 or later.

Tool

Description

create_queue

Create a new queue

update_queue

Update an existing queue's settings

manage_queue_watchers

Set the members of a queue role (Cc, AdminCc, or a custom role)

list_groups

List user-defined groups with names and descriptions

get_group

Get details about a group by ID or name

create_group

Create a new user-defined group

list_group_members

List a group's members (RT returns IDs and types only)

add_group_members

Add users to a group, by user ID

remove_group_member

Remove a user from a group

create_custom_field

Create a custom field

search_custom_fields

Search existing custom fields before creating a duplicate

apply_custom_field

Apply a custom field to a queue

add_custom_field_value

Add a selectable value to a custom field

list_custom_field_applications

List the objects a custom field is applied to

remove_custom_field_application

Stop applying a custom field to an object

list_lifecycles

List lifecycles with their statuses and transitions

get_lifecycle

Get one lifecycle's full definition

create_lifecycle

Create a lifecycle, optionally cloning an existing one

update_lifecycle

Replace a lifecycle's configuration

update_lifecycle_maps

Map this lifecycle's statuses onto other lifecycles

validate_lifecycle

Check a lifecycle definition without saving it

delete_lifecycle

Delete a lifecycle no queue or catalog uses

get_available_rights

List the rights that can be granted on an object

list_rights

List the rights currently granted on an object

grant_rights

Grant rights to a user, group, or role

revoke_right

Revoke a single right

Prompts

Prompt

Description

create-queue

Interactive consultant that discovers a team's workflow, recommends a queue configuration, confirms the plan, then builds it — queue, lifecycle, groups, rights, custom fields, and watchers


Usage Examples

Example 1: Finding and triaging unowned tickets

User: "Show me active tickets in the Support queue with no owner."

Claude calls: search_tickets with query Queue = 'Support' AND Status = '__Active__' AND Owner = 'Nobody'. No fields parameter is needed — the server sends a default set that identifies each ticket, with queue and owner as names rather than ID stubs.

Result: A table of unowned active tickets with subject, requestor, and when each was last updated, ready to assign or act on.


Example 2: Reading recent correspondence on a ticket

User: "Show me the most recent reply on ticket 1234."

Claude calls: get_ticket_history to get the list of transactions, identifies the most recent Correspond entry, then calls get_transaction to fetch and decode the full message content.

Result: The decoded text of the reply, including who sent it and when.


Example 3: Creating a fully configured ticket

User: "Create a ticket in the Projects queue titled 'Update onboarding docs', assign it to alice, set the due date to next Friday, and link it to ticket 500."

Claude calls: create_ticket with Queue, Subject, Owner, Due, and RefersTo all set in a single API call.

Result: New ticket created with all fields set. Claude confirms the ticket number and a summary of what was set.


Example 4: Updating ticket status with a reply

User: "Resolve ticket 789 and let the requestor know we've pushed a fix in version 6.0.3."

Claude calls: add_reply with the message content and Status: 'resolved' to close the ticket and notify the requestor in one step.

Result: Ticket resolved, requestor notified. Claude confirms both actions completed.


Example 5: Querying with custom fields

User: "Find all open tickets in the General queue where the Category field is set to 'Bug'."

Claude calls: get_queue_fields to confirm the exact custom field name, then search_tickets with Queue = 'General' AND Status = '__Active__' AND CF.{Category} = 'Bug'.

Result: A list of matching bug tickets with subject, owner, and creation date.


How It Works

This server implements the Model Context Protocol over stdio. The AI client translates natural language requests into TicketSQL queries or RT API calls, invokes the appropriate tool, and presents the results. The server itself is a thin proxy — it passes queries directly to RT's REST 2.0 API and returns the JSON response.

For complex searches, the AI can call get_ticketsql_grammar to consult the full TicketSQL syntax reference before constructing a query.

Configuration Reference

Environment Variable

Description

RT_URL

Base URL of your RT instance (e.g. https://rt.example.com)

RT_TOKEN

RT authentication token

Development

npm install
npm run build     # compile TypeScript to dist/
npm test          # run tests
npm run dev       # watch mode

Run locally against your RT instance:

RT_URL=https://rt.example.com RT_TOKEN=your-token node dist/index.js

Compatibility

  • RT 6.0+ (REST 2.0 API)

  • Node.js 18+

Privacy

This server does not collect, store, or transmit any data to Best Practical or any third party. All communication is directly between your AI client and your own RT instance using the URL and credentials you provide. No usage data, ticket content, or credentials are sent anywhere other than your configured RT server.

See the Best Practical Privacy Policy for general information about our privacy practices.

Support

For questions and discussion, visit the Best Practical Community Forum.

To report a bug, create a ticket on our public RT instance. Note that this is a public RT instance, so the information you share will be visible to others.

Is RT mission critical for you? Commercial support for RT and this connector is available from Best Practical. Contact us at sales@bestpractical.com.

License

GPL-2.0

Available Tools

43 tools
add_commentA
Destructive

Add an internal comment to a ticket (not visible to the requestor)

Inputs: id (required), Content, TimeTaken, Attachments, +2 more.

add_custom_field_valueA
Destructive

Add one or more selectable values to a custom field (for Select, Autocomplete, etc. types). Pass a single value with Name, or multiple values with the Values array.

Inputs: id (required), Name, Values, Category, +2 more.

add_group_membersA
Destructive

Add one or more users to a group. Members are specified by user ID. Use lookup_user to find user IDs by name or email. Adding a user who is already a member has no effect.

Inputs: id (required), members (required).

add_replyA
Destructive

Send a reply (correspondence) on a ticket, visible to the requestor

Inputs: id (required), Status, Content, TimeTaken, +3 more.

apply_custom_fieldA
Destructive

Apply a custom field to a specific object or globally. The CF's LookupType determines what kind of object it can apply to (e.g. a ticket CF applies to queues). Use ObjectId 0 to apply globally. Note: applying globally removes all specific object applications.

Inputs: id (required), ObjectId (required).

create_custom_fieldA
Destructive

Create a new custom field. After creating, use apply_custom_field to apply it to specific queues or globally. Use add_custom_field_value to add values to Select-type fields.

Inputs: Name (required), Type (required), LookupType (required), Pattern, +3 more.

create_groupA
Destructive

Create a new user-defined group. After creating, use add_group_members to add users and grant_rights to give the group permissions on queues.

Inputs: Name (required), Description.

create_lifecycleA
Destructive

Create a new lifecycle. Optionally clone an existing one as a starting point. A lifecycle defines the statuses and transitions for tickets in queues that use it. After creating, use update_lifecycle to customize statuses and transitions.

Inputs: name (required), type, clone.

create_queueA
Destructive

Create a new RT queue. Returns the new queue ID and URL. After creating, use manage_queue_watchers to set up Cc/AdminCc members, grant_rights to configure permissions, and create_custom_field + apply_custom_field to add custom fields.

Inputs: Name (required), Lifecycle, Description, SLADisabled, +2 more.

create_ticketA
Destructive

Create a new ticket in RT

Inputs: Queue (required), Subject (required), Cc, Due, +21 more.

delete_lifecycleA
Destructive

Delete a lifecycle. Fails if any queue or catalog still uses it — reassign those to another lifecycle first (get_lifecycle reports them under used_by). Useful for cleaning up a lifecycle created by mistake.

Inputs: name (required).

get_attachmentA
Read-only

Retrieve a single attachment by ID. Text content is returned decoded; binary content is returned as MIME Base64. Use get_ticket_attachments or get_transaction to find attachment IDs.

Inputs: id (required).

get_available_rightsA
Read-only

Get the rights that can be granted on a queue, custom field, group, class, catalog, or globally. Returns rights grouped by category, and which categories come back depends on the object: RT's own are General, Staff and Admin, and a group offers only some of them. A queue — and the global object — also carries a Status category, holding one right for each status transition a lifecycle reserves behind a named right, so that is where a custom sign-off right appears once a lifecycle defines it. Read the categories from the response rather than assuming a fixed set.

Inputs: object_type (required), object_id.

get_current_userA
Read-only

Get the RT user account associated with the configured auth token. Use this to determine who "I" or "me" refers to when the user asks to assign tickets to themselves, find their own tickets, etc.

Inputs: no named parameters.

get_groupA
Read-only

Get details about a specific group by numeric ID

Inputs: id (required).

get_lifecycleA
Read-only

Get a lifecycle's full configuration including statuses (initial, active, inactive), allowed transitions, default statuses, and which queues/catalogs use it.

Inputs: name (required).

get_queueA
Read-only

Get details about a specific queue by ID or name

Inputs: id (required).

get_queue_fieldsA
Read-only

Get custom fields (with types and allowed values) and lifecycle name for a queue. Returns three separate groups, because RT applies custom fields to three different things: CustomFields are set on tickets in the queue (this is what you want when creating or updating a ticket), QueueCustomFields are set on the queue itself and include the queue's CurrentValues (RTIR uses these for RTIR Constituency and RTIR default WHOIS server), and TransactionCustomFields are set on individual comments and replies. When the user asks what custom fields a queue has, report all three groups and say which is which. Each field carries a ContentFormat saying how its value is rendered: "html" (send markup; a bare newline shows nothing), "plain-text-multiline" (send plain text; newlines become line breaks), "plain-text" (shown exactly as typed), "wikitext" (wiki markup), "file" (an uploaded image or attachment rather than text), "date", or "datetime" (send local time; RT reads it in the user's timezone). Check it before writing a multi-line or formatted value. Every applied field is always listed. If RT permits seeing that a field is applied but not reading the field itself, the entry carries id, Name and a DetailsUnavailable message explaining why; a QueueCustomFields entry still carries its CurrentValues too. The field is still applied to the queue either way, and a field in CustomFields can still be set on a ticket. Tell the user which fields came back without details rather than reporting them as missing.

Inputs: id (required).

get_ticketA
Read-only

Get detailed information about a specific ticket by its ID

Inputs: id (required), fields, subfields.

get_ticket_attachmentsA
Read-only

List all attachments on a ticket (names, MIME types, sizes, IDs)

Inputs: id (required), page, fields, per_page.

get_ticket_historyA
Read-only

Get the transaction history for a ticket. Returns a list of transactions (comments, replies, status changes, etc.). Most entries name the field changed in Field and carry its old and new values. Two kinds do not. An owner or watcher change (Type SetWatcher, AddWatcher or DelWatcher) puts a numeric user ID in OldValue and NewValue, and no tool here turns one into a name — describe the change without inventing one. A custom field change (Type CustomField) puts the field's numeric ID in Field rather than its name, which get_queue_fields maps back; its OldValue and NewValue hold the values as usual, while OldReference and NewReference are row IDs that nothing here resolves.

Inputs: id (required), page, fields, per_page.

get_ticketsql_grammarA
Read-only

Returns the TicketSQL grammar reference for RT 6.0.3. Consult this before writing any TicketSQL query — especially for Status conditions, date/time fields, custom fields, and link fields where syntax is non-obvious.

Inputs: no named parameters.

get_transactionA
Read-only

Get the full details of a single transaction including decoded message content. Use this after get_ticket_history to read the actual text of a reply or comment.

Inputs: id (required).

grant_rightsA
Destructive

Grant rights on a queue, custom field, group, class, catalog, or globally. Specify a single right with Right + (User or Group), or pass an array of grants for bulk operation. Returns 409 if a right is already granted.

Inputs: object_type (required), User, Group, Right, +2 more.

list_custom_field_applicationsA
Read-only

List which objects a custom field is currently applied to, including whether it is applied globally.

Inputs: id (required), page, per_page.

list_group_membersA
Read-only

List the members of a group. RT returns only an id and a type (user or group) per member — this collection ignores a fields parameter, so names cannot be requested. get_group returns the same membership already resolved: a user member carries its username as its id, a group member its numeric id. Use get_group when the user needs members named rather than listed as bare ids.

Inputs: id (required), page, users, groups, +2 more.

list_groupsA
Read-only

List user-defined groups. Returns group names, descriptions, and IDs. Use this to check for existing groups before creating new ones.

Inputs: fields.

list_lifecyclesA
Read-only

List all available lifecycles. Each lifecycle defines the statuses and transitions for tickets in queues that use it.

Inputs: type.

list_queuesB
Read-only

List all available queues

Inputs: fields.

list_rightsA
Read-only

List rights currently granted on a queue, custom field, group, class, catalog, or globally. Can filter by user or group.

Inputs: object_type (required), page, user, group, +2 more.

lookup_userB
Read-only

Search for RT users by name or email address

Inputs: query (required), page, fields, per_page.

manage_queue_watchersA
Destructive

Set the members of a queue role (Cc, AdminCc, or a multi-value custom role). Pass the complete member list — it replaces existing members. Members can be usernames, email addresses, or user/group IDs. To add a group by name, prefix it with "group:" (e.g. "group:Facilities Managers"); a bare name is looked up as a user and fails. Only user-defined groups resolve this way — not system groups like Everyone, and not role groups. Single-value custom roles (like Owner) cannot have queue-level members. A member that cannot be resolved is skipped and reported in the returned messages while the call still succeeds, so confirm every member you passed was actually added — see PARTIAL UPDATES.

Inputs: id (required), Cc, AdminCc, CustomRoles.

remove_custom_field_applicationA
Destructive

Remove a custom field from a specific object or remove its global application. Use ObjectId 0 to remove the global application.

Inputs: id (required), ObjectId (required).

remove_group_memberB
Destructive

Remove a user from a group

Inputs: id (required), member_id (required).

revoke_rightA
Destructive

Revoke a right from a user or group on a queue, custom field, group, class, catalog, or globally. The principal goes in the URL path here rather than a request body, and RT resolves a name there only for a user: a group has to be given as its numeric ID, and a group name answers 404 even though grant_rights resolves that same name. RT answers 404 for a right that was never granted too, so a group name passed here looks like nothing to revoke rather than a bad parameter. Use get_group or list_groups to get the ID.

Inputs: Right (required), object_type (required), User, Group, +1 more.

save_attachmentA
Read-only

Save an attachment to a local file. The MCP server writes the file directly, so this works on any platform. If path is a directory, the original filename is used.

Inputs: id (required), path (required).

search_custom_fieldsA
Read-only

Search for existing custom fields. Use this before creating new ones to avoid duplicates. Search by Name, Type, LookupType, or any combination. Returns matching custom fields with their IDs, types, and descriptions.

Inputs: Name, Type, page, fields, +2 more.

search_ticketsA
Read-only

Search for tickets using RT's TicketSQL query language. TicketSQL has non-obvious syntax — consult get_ticketsql_grammar before writing any query involving Status, date conditions, custom fields, or special values. Key syntax notes: Status has meta-values Active and Inactive that match all active/inactive statuses across lifecycles (e.g. Status = 'Active' rather than Status = 'open'). Basic examples: "Queue = 'General' AND Owner = 'Nobody'", "Subject LIKE 'login'". A useful default field set is sent automatically, with Queue and Owner expanded to names, so pass fields or subfields only when the context calls for a different set.

Inputs: query (required), page, order, fields, +3 more.

update_lifecycleA
Destructive

Update a lifecycle's configuration. Pass the full lifecycle definition including initial, active, inactive status arrays, transitions, rights, actions, and defaults. This REPLACES the stored configuration — any key you omit is dropped, including keys inherited from a create_lifecycle clone. RT fills in a missing defaults.on_create from the first initial status, and falls back to ModifyTicket — DeleteTicket for deleted — where rights are missing, but it does that in memory as it loads the config: neither key reappears in get_lifecycle, so one absent there is a working default rather than damage to repair. Omitted actions, colors, status_metadata and transition_metadata are simply lost. Cloning "default" inherits a full set of metadata, so omitting those two keys here silently strips the descriptions from every status. Use get_lifecycle first to get the current config, then modify and send the whole thing back. The lifecycle is validated before saving; any warning fails the update with a 400.

Inputs: name (required), active, colors, rights, +7 more.

update_lifecycle_mapsA
Destructive

Update the status mappings between this lifecycle and other lifecycles. Maps define how statuses translate when tickets move between queues with different lifecycles. Format: {"lifecycle_a -> lifecycle_b": {"status_in_a": "status_in_b", ...}}

Inputs: maps (required), name (required).

update_queueA
Destructive

Update an existing queue's settings (name, description, lifecycle, email addresses, etc.). To manage watchers (Cc, AdminCc), use manage_queue_watchers instead. Each field is applied independently and the call succeeds even when some of them fail, so check the returned messages for every change you asked for — see PARTIAL UPDATES.

Inputs: id (required), Name, Disabled, Lifecycle, +4 more.

update_ticketA
Destructive

Update an existing ticket. Pass each property to change as a top-level parameter (e.g. Due, Status, Owner) — do NOT use a nested "fields" object. Links are changed only with the Add/Delete fields below: a bare relation name such as RefersTo, Parent or Children is refused, because RT would treat it as the complete list for that relation and silently remove every other link of the type.

Inputs: id (required), Cc, Due, Told, +25 more.

validate_lifecycleA
Read-only

Check a lifecycle definition without saving it. Takes the same payload as update_lifecycle and reports whether RT would accept it, with a warning for each problem found (unknown statuses, malformed transitions or actions, and so on). Use this to dry-run a custom lifecycle before writing it, since update_lifecycle rejects the whole payload if anything is wrong. RT checks only the payload sent: it never reads the lifecycle the name refers to, which is why the name need not exist yet and why it does nothing but label the warnings. So send a complete definition rather than the part being changed — transitions on their own report every status in them as nonexistent, including statuses the named lifecycle already has. Read the current definition with get_lifecycle, change it, and validate the whole thing.

Inputs: name (required), active, colors, rights, +7 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 43 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action, and close pairs like list_group_members vs get_group and get_ticket_history vs get_transaction are explicitly differentiated in their descriptions. Even with 43 tools, the annotations make the intended selection clear without true overlap.

    Naming Consistency4/5

    The vast majority of tools follow a clear verb_noun pattern such as get_, list_, create_, update_, add_, and remove_. Minor singular/plural inconsistencies like grant_rights vs revoke_right and add_group_members vs remove_group_member prevent a perfect score.

    Tool Count2/5

    43 tools is a very large surface for a single server, spanning tickets, queues, groups, lifecycles, rights, and custom fields. Even though each tool appears purposeful, the count is well beyond the typical well-scoped MCP toolset and creates significant selection burden for agents.

    Completeness3/5

    Ticket, queue, lifecycle, and rights workflows are covered thoroughly, including create/read/update operations. However, group and custom field management lack update/delete operations, and user management is limited to lookup and current-user, leaving notable gaps in the administrative lifecycle.

    Maintenance

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      B
      quality
      B
      maintenance
      An MCP server that exposes the Tickiti helpdesk API to AI assistants, enabling ticket management and helpdesk operations via natural language.
      11
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for Request Tracker REST2 API, enabling ticket, queue, user, and asset management via natural language.
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      MCP server that exposes the i-net HelpDesk Ticket Web-API as tools for AI agents, enabling ticket search, reading, creation, and actions like replying, closing, and escalating, with attachment support.
      8
      MIT