SparrowDesk
OfficialThis server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
SparrowDesk MCP Server
A Model Context Protocol (MCP) server for SparrowDesk. Connect AI assistants like Claude to your SparrowDesk account to read and manage tickets, contacts, companies, Knowledge Base content, tags, and team data.
You sign in with OAuth, so there are no API keys to manage. The first time you connect, your MCP client opens a browser window to log in with your SparrowDesk account.
Install
The server URL is the same for every user — your account comes from the OAuth token, not the URL:
https://mcp.sparrowdesk.com/mcpClaude Code:
claude mcp add --transport http sparrowdesk https://mcp.sparrowdesk.com/mcpClaude Desktop (claude_desktop_config.json) and Cursor (~/.cursor/mcp.json) take the same block:
{
"mcpServers": {
"sparrowdesk": {
"type": "http",
"url": "https://mcp.sparrowdesk.com/mcp"
}
}
}Restart the app after saving. The SparrowDesk tools appear in the tool list, and the client opens a browser window to complete the OAuth login.
Related MCP server: relation-mcp
Permissions
Tools mirror the SparrowDesk Developer API, and each call runs under the permissions of the account you signed in with.
Knowledge Base tools need the collection and article scopes: VIEW_COLLECTIONS and MANAGE_COLLECTIONS for collections, VIEW_ARTICLES and MANAGE_ARTICLES for articles. All four are included in the MCP default scope list. Other Knowledge Base behavior can depend on further scopes or account features.
Available Tools
Tool | Description |
Account | |
| Current account information (subdomain, company, timezone, language) |
Conversations | |
| Retrieve a conversation by ID |
| List conversations with optional filters |
| Create a new conversation/ticket |
| Update subject, status, priority, assignee, team, custom fields |
| Delete a conversation |
| List conversations with their replies inlined in one call |
| List replies for a conversation |
| Add a reply or internal note |
Imports | |
| Import backdated conversations in bulk, with no notifications or workflows (returns job id) |
| Poll a conversation import job; maps each |
| Import backdated replies and notes, from agents or requesters, into up to 20 conversations |
| Poll a reply import job |
Conversation fields | |
| List ticket custom field definitions |
| Get one conversation field by ID |
| Create a custom conversation field |
| Update a conversation field |
Contacts & companies | |
| List contacts (search, email, phone, pagination) |
| Retrieve a contact by ID |
| Create a contact |
| Update a contact |
| Delete a contact |
| Bulk create contacts (returns job id) |
| Poll bulk contact job status |
| List companies |
| Retrieve a company by ID |
| Create a company |
| Update a company |
Contact fields | |
| List contact field definitions |
Members & tags | |
| List team members |
| List tags |
Knowledge Base | |
| List help centers |
| List KB collections for a help center |
| Get a collection with subcollections and articles |
| Create a KB collection |
| List articles for a help center |
| Get one article |
| Create an article (draft or publish) |
| Update an article draft / publish |
| Archive an article |
Tool Reference
Conversations
get_conversation
Fetch a single conversation by its numeric ID. Parameters: id (integer, required).
list_conversations
List conversations with optional filters, sorting, and pagination.
starting_after(string, optional) — Pagination cursorper_page(integer, optional) — Items per page, 1–100 (default: 25)status(array, optional) — Filter by status:Open,Pending,Resolved,Closedpriority(array, optional) — Filter by priority:Low,Medium,High,Urgentassigned_to_member_id(array of integers, optional) — Filter by assigned agent IDsassigned_to_team_id(array of integers, optional) — Filter by assigned team IDsbrand_id(array of integers, optional) — Filter by brand IDsrequested_by_id(integer, optional) — Filter by requestor contact IDrequested_by_company(integer, optional) — Filter by requester contact company ID (intersects withrequested_by_idwhen both are set)handled_by_ai_agent(boolean, optional) —true: only AI-assigned conversations;false: handed off to humans or not AI-assignedsearch(string, optional) — Search subject, description, replies, or conversation ID (max 250 chars; quote exact phrases)sort_by(string, optional) —created_atorupdated_at(default:created_at)sort_order(string, optional) —ascordesc(default:desc)
list_conversations_with_replies
List conversations with their replies inlined in a single call. It takes the same filters as list_conversations plus reply controls. Root pages and total_count apply to conversations only; each row carries a replies object shaped like list_conversation_replies.
starting_after(string, optional) — Cursor for conversation list paginationper_page(integer, optional) — Conversations per page, 1–20 (default: 20)replies_per_page(integer, optional) — Replies per conversation, 1–50 (default: 50)replies_sort_order(string, optional) — Reply sort bysent_at:ascordesc(default:desc)type(string, optional) — Filter replies byINTERNAL_NOTEorREPLYstatus,priority,assigned_to_member_id,assigned_to_team_id,brand_id,requested_by_id— Same conversation filters aslist_conversationshandled_by_ai_agent(boolean, optional) — Filter by whether the conversation was handled by the AI agentsearch(string, optional) — Search subject, description, replies, or conversation ID (max 250 chars; quote exact phrases)sort_by(string, optional) —created_atorupdated_at(default:created_at)sort_order(string, optional) —ascordesc(default:desc)
list_conversation_replies
List replies for a conversation, with optional filtering and pagination.
id(integer, required) — The conversation IDstarting_after(string, optional) — Pagination cursorper_page(integer, optional) — Replies per page, 1–50 (default: 50)type(string, optional) — Filter byINTERNAL_NOTEorREPLYsort_order(string, optional) —ascordesc(default:desc)
add_conversation_reply
Add a reply or internal note to a conversation.
id(integer, required) — The conversation IDreply_text(string, required) — The content of the reply messagetype(string, required) —REPLY(visible to the customer) orINTERNAL_NOTE(agents only)
create_conversation
Create a new conversation/ticket in SparrowDesk.
subject(string, required) — Conversation subjectdescription(string, required) — Opening message body (HTML)requested_by(string, required) — Email or phone number of the requesterrequested_by_firstname,requested_by_lastname(string, optional) — Applied only if the requester contact is newly createdpriority(string, optional) —Low,Medium,High, orUrgent(default:Medium)source(string, optional) —Mail,Call, orAPI(default:Call)status(string, optional) —Open,Pending,Resolved, orClosed(default:Open)brand_id(integer, optional) — Brand ID (uses the account default if omitted)assignee(string, optional) — Agent email address to assign the conversation toteam_id(integer, optional) — Team ID to assign the conversation tocreated_at(integer, optional) — Creation time in epoch seconds (default: now)resolved_at(integer, optional) — Resolution time in epoch seconds; only with statusResolved/Closed, and>= created_atskip_notifications(boolean, optional) — Suppress notifications for this creation (default:false)custom_fields(array, optional) — Array of{ internal_name, value }objects;valueis a string, or an array of option ids/names formulti_selecttags(array of strings, optional) — Tag labels to attach; missing tags are createdattachments(array, optional) —{ url, file_name?, content_type?, size?, headers? }objects; files are fetched and attached to the opening message, unfetchable ones are skipped
update_conversation
Patch an existing conversation.
id(integer, required) — Conversation IDsubject,priority,status,assignee(email),team(string) — Optional updatescustom_fields(array, optional) —{ internal_name, value }, same shape ascreate_conversation
delete_conversation
Delete a conversation. Parameters: id (integer, required).
Imports
Use these to bring in history (a migration, or demo data). Unlike create_conversation and add_conversation_reply, imports keep your timestamps, can post as the requester, and send no notifications or run any workflows or SLAs. They need the edit-all-tickets scope. Each external_id is used only once, so re-sending a batch skips the items already imported.
import_conversations
conversations(array, required, 1–100). Each item takes:subject,description_html(the opening message, from the requester),requester({ external_id?, email?, phone?, name? }; give at least one identifier),created_at: all requiredexternal_id,status,priority,resolved_at(only forResolved/Closed),assignee_email,team_id,brand_id,tags,attachments,custom_fields({ field_id, value }): optional
created_atandresolved_ataccept epoch seconds or ISO-8601 with an offset. Neither can be in the future.
Returns a job_id. Poll get_conversation_import_status (job_id) until status is completed, partial or failed. Each entry in results has the external_id, the conversation_id and a status (created, skipped or failed).
import_conversation_replies
items(array, required, 1–20):{ conversation_id, replies }, wherereplies(1–100, oldest first) have:author_type(agent|requester),author_emailorauthor_id,html_body,created_at(ISO-8601 with offset): requiredexternal_id,public(falsemakes an internal note),to,cc,bcc,attachments: optional
Each conversation is a separate API call. The tool returns one result per conversation, with its job_id (poll get_reply_import_status) or an error. If the plan's rate limit is hit, rate_limited is true and the remaining conversations are marked not_attempted, so you can resend just those.
Conversation fields
list_conversation_fields—starting_after,per_page,is_active,is_defaultget_conversation_field—idcreate_conversation_field—name,type(single_line_text|multi_line_text|dropdown|number|date|email|nested|multi_select), optionalinternal_name,description,is_mandatory_on_close,field_options(required fordropdownandmulti_select),levelsandchoices(nested fields only)update_conversation_field—idplus any ofname,description,is_active,is_mandatory_on_close,field_options(appended; an existing option returns 409)
Contacts
list_contacts
List contacts with filters. Requires the view contacts scope where the account enforces it.
Parameters: search, requested_by_email, requested_by_phone, starting_after, per_page.
get_contact
Fetch a single contact by its numeric ID. Parameters: id (integer, required).
create_contact
Create a new contact. Give either email or phone.
first_name(string, required) — Contact's first namelast_name(string, optional) — Contact's last nameemail(string, optional) — Contact's email address (required ifphoneis omitted)phone(string, optional) — Contact's phone number (required ifemailis omitted)company_ids(array of integers, optional) — IDs of the companies to associate withcustom_fields(object, optional) — Custom field key-value pairscontact_note(array, optional) — Notes{ title?, description, attachments? }to create under the contact; needs a member-bound API key
update_contact
Update an existing contact.
id(integer, required) — The contact ID to updatefirst_name(string, optional) — Contact's first namelast_name(string, optional) — Contact's last nameemail(string, optional) — Contact's email addressphone(string, optional) — Contact's phone numbercompany_ids(array of integers, optional) — IDs of the companies to associate withblocked(boolean, optional) — Whether the contact is blockedcustom_fields(object, optional) — Custom field key-value pairs
delete_contact
Delete a contact. Parameters: id (integer, required).
bulk_create_contacts and get_bulk_job_status
bulk_create_contacts accepts contacts: an array of objects with optional first_name, last_name, email, phone, company_ids, and custom_fields. The response includes a job_id. Poll get_bulk_job_status with that job_id until the job reports completed or failed.
Contact fields
list_contact_fields
Retrieve all contact fields defined in the account.
starting_after(string, optional) — Pagination cursorper_page(integer, optional) — Items per page, 1–100 (default: 25)is_active(boolean, optional) — Filter by active statusis_default(boolean, optional) — Filter default fields only
Companies
list_companies
Parameters: starting_after, per_page, domain (exact), name (exact).
get_company
Fetch a single company by its numeric ID. Parameters: id (integer, required).
create_company
Create a new company.
name(string, required) — Company namedomains(array of strings, optional) — Domains owned by the company; the first is primarydomain(string, optional) — Single-domain shorthand likeexample.com; ignored whendomainsis setaddress(string, optional) — Company addressnotes(string, optional) — Free-form notescompany_note(array, optional) — Notes{ title?, description, attachments? }to create under the company; needs a member-bound API key
update_company
Update an existing company. Give at least one field besides id.
id(integer, required) — The company ID to updatename,domains,domain,phone,address,notes— Optional updates
Knowledge Base
Call list_helpcenters first to get a help_center_id. Collections and articles are scoped per help center and brand.
Reads need VIEW_COLLECTIONS / VIEW_ARTICLES; writes need MANAGE_COLLECTIONS / MANAGE_ARTICLES.
list_helpcenters— optionalstarting_after,per_pagelist_collections—help_center_id(required); optionalstarting_after,per_page,collection_id,is_root— needsVIEW_COLLECTIONSget_collection—id— needsVIEW_COLLECTIONScreate_collection—name,help_center_id,brand_id; optionaldescription,parent_collection_id— needsMANAGE_COLLECTIONSlist_articles—help_center_id(required); optionalpublished,draft,archived,starting_after,per_page,search,collection_id— needsVIEW_ARTICLESget_article—id— needsVIEW_ARTICLEScreate_article—help_center_id,brand_id; optionaltitle,content(HTML),publish,collection_id,is_public(publish flow per the API docs) — needsMANAGE_ARTICLESupdate_article—id; optionaltitle,content,collection_id(null to remove from collection),brand_id,publish,is_public,ai_agent_enabled,ai_copilot_enabled— needsMANAGE_ARTICLESarchive_article—id— needsMANAGE_ARTICLES
Account
get_me
Retrieve current SparrowDesk account information: account ID, subdomain, domain, company name, timezone, and language. This is the account, not a user profile. Takes no parameters.
list_members
Retrieve a paginated list of all team members in the account.
starting_after(string, optional) — Pagination cursorper_page(integer, optional) — Items per page, 1–100 (default: 25)
list_tags
Parameters: starting_after, per_page, search.
Privacy Policy
This server proxies requests to the SparrowDesk API on behalf of the signed-in user. It stores no ticket, contact, or Knowledge Base content, only OAuth session state (access and refresh tokens). That state is kept encrypted in DynamoDB and deleted after 30 days without use. What the server can read or write is bounded by the permissions of the SparrowDesk account you sign in with, and SparrowDesk records every action against your user.
Data collection, storage, retention, third-party sharing, and contact details are covered in the SparrowDesk Privacy Policy. Use of SparrowDesk is governed by the Terms of Service.
Support
For questions, see developer.sparrowdesk.com/mcp or open an issue on this repository.
Local Development
See SETUP.md for running the server locally, the environment variables it reads, Docker, and how to call the deployed server with curl.
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for GLPI: tickets, ITIL, assets, knowledge base. GLPI 10/11. Not affiliated with Teclib'.
Freshdesk MCP Pack — helpdesk ticket and contact management via Freshdesk API v2.
Remote MCP server for managing Muninx tickets, messages, ticket search, and support analytics.
Notes, files, GitHub, and Drive through one MCP connection.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server for SolarWinds Service Desk (SWSD/Samanage) enabling reading and modifying tickets, comments, knowledge-base articles, and more via each user's own API token.37274 npm4MIT
- AlicenseBqualityCmaintenanceEnables to interact with Re:lation support tickets via MCP. Allows searching, updating, replying to tickets, and managing customers and internal records.116 npmMIT
- AlicenseNot gradedqualityCmaintenanceAI-powered helpdesk management via Model Context Protocol. Connect any MCP-compatible assistant to your support workspace.7 npmMIT
- AlicenseNot gradedqualityCmaintenanceMCP server to interact with Zammad ticketing system, enabling ticket search, creation, update, article addition, and user/organization/group queries via the Zammad API.6 npmMIT