FS_MCP_thin
A read-only MCP server that connects AI assistants to Freshservice Service Desk for ticket triage, asset analysis, and support history summarization.
README
FS_MCP_thin π
A powerful, read-only Model Context Protocol (MCP) server that bridges the gap between your AI assistant (like Claude) and your Freshservice Service Desk. Empower your AI with deep context to triage incidents, analyze asset distribution, and summarize support history.
β¨ Features
- π« Ticket Intelligence β Deep dive into tickets, conversations, private notes, and service request items.
- π Knowledge Integration β Search and retrieve the full content of your solution articles.
- π§ Problem Analysis β Inspect root-cause investigation records.
- π¦ Inventory Visibility β Browse and drill down into Assets (Hardware) and Software inventory.
- π€ Identity Context β Lookup Requesters and Agents, and view their specific ticket/asset history.
- β±οΈ Governance Context β Access SLA policies, business hours, and org structure as standing context.
- π¬ Canned Success β Use your curated response templates to draft high-quality replies.
- πͺΆ Token-Efficient β Responses are shaped (field-projected, HTML-stripped, compacted) before they reach the model, cutting context bloat 5-10x on list/detail calls. See Response Shaping.
π Prerequisites
- Node.js: Version 18.x or higher.
- Freshservice: An active account with API access enabled.
- API Key: Found in your Profile Settings β API Key.
π Quick Start
1. Installation
# Clone or download the repository
cd FS_MCP_thin
# Install dependencies
npm install
# Setup environment variables
cp .env.example .env
2. Configuration
The server needs exactly two environment variables. Both are required β if either is missing the server exits immediately on startup with an error.
| Variable | What it is | Where to get it |
|---|---|---|
FRESHSERVICE_DOMAIN |
Your Freshservice URL | The host in your browser, e.g. acme.freshservice.com. |
FRESHSERVICE_API_KEY |
Your personal API key | Freshservice β avatar β Profile Settings β API Key (right sidebar). |
Domain format: supply just the host (acme.freshservice.com). A full URL (https://acme.freshservice.com) also works β the client adds https:// only if no protocol is present. Do not include a trailing slash or path.
How auth works: Freshservice uses HTTP Basic auth with the API key as the username and a dummy password. The server handles this for you β you only ever supply the raw key.
Edit the .env file with your details:
FRESHSERVICE_DOMAIN=acme.freshservice.com
FRESHSERVICE_API_KEY=your_api_key_here
.envis git-ignored. Your credentials never leave your machine β see Security & Privacy.
3. Integration with Claude Desktop
Add this snippet to your claude_desktop_config.json. The env block here is an alternative to a .env file β when Claude Desktop launches the server it injects these, so you don't need both. (If both exist, the values in env take precedence.)
{
"mcpServers": {
"freshservice": {
"command": "node",
"args": ["C:\\path\\to\\FS_MCP_thin\\src\\index.js"],
"env": {
"FRESHSERVICE_DOMAIN": "acme.freshservice.com",
"FRESHSERVICE_API_KEY": "your_api_key_here"
}
}
}
}
Use the absolute path to
src/index.js. On Windows, escape backslashes (\\) as shown.
Troubleshooting credentials
| Symptom | Likely cause |
|---|---|
Server exits with FRESHSERVICE_DOMAIN and FRESHSERVICE_API_KEY ... are required |
One or both env vars are unset (typo, wrong key name, or .env not loaded). |
401 Unauthorized on every call |
API key is wrong, revoked, or copied with surrounding whitespace. |
403 Forbidden on specific tools (assets, problems, catalog) |
Your account's role or plan tier doesn't grant access to that resource β not a config bug. |
404 Not Found |
Wrong domain, or the record ID doesn't exist. |
429 Too Many Requests |
Rate limit hit. Limits are per-plan; the server surfaces the error but does not auto-retry. |
π Project Structure
FS_MCP_thin/
βββ src/
β βββ index.js # MCP server entry point β registers all tools,
β β # resources, and prompts; wires responses through shape.js
β βββ freshservice.js # FreshserviceClient β thin axios wrapper over the
β β # Freshservice v2 REST API (auth, requests, error mapping)
β βββ shape.js # Token-economy engine β projects/strips/compacts responses
β βββ shape.config.js # Declarative per-domain field/shaping rules (edit this to tune output)
β βββ index.test.js # Tests for tool registration & handler behavior
β βββ freshservice.test.js # Tests for the API client
β βββ shape.test.js # Tests for the shaping engine + config
βββ eslint.config.js # ESLint flat config (Node + Jest, recommended rules)
βββ tsconfig.json # TypeScript config for `checkJs` type-checking
βββ .env.example # Template for required environment variables
βββ .gitignore # Ignores node_modules/ and .env (credentials)
βββ package.json # Dependencies, scripts, bin entry
βββ README.md
Data flow: index.js (MCP request) β freshservice.js (API call) β shape.js + shape.config.js (trim response) β back to the AI assistant.
Where to make changes:
- Add/modify a tool, resource, or prompt β
src/index.js - Add/modify a Freshservice API call β
src/freshservice.js - Change what fields the model sees β
src/shape.config.js(no code changes needed)
π§° Available Tools
π« Tickets & Conversations
| Tool | Purpose |
|---|---|
search_tickets |
Flexible search using status, priority, or subject. |
list_open_tickets |
List open tickets (status:2) with pagination. |
get_ticket |
Curated detail view of a ticket (key fields + HTML-stripped body). |
get_ticket_conversations |
Complete thread of public and private messages. |
get_ticket_notes |
Isolates private internal notes for audit/context. |
get_service_request_items |
Views quantity and custom fields for SR items. |
π Knowledge Base & Problems
| Tool | Purpose |
|---|---|
search_kb |
Find articles by keywords. |
get_kb_article |
Retrieve the full article body (Markdown/HTML). |
list_problems |
Get a list of recent Problem records. |
get_problem |
Detailed view of a root cause investigation. |
π¦ Assets & Software
| Tool | Purpose |
|---|---|
list_assets |
Browse the CI (Configuration Item) inventory. |
get_asset |
Deep dive into a specific piece of hardware. |
list_software |
See software installations and licenses. |
?? Service Catalog & Responses
| Tool | Purpose |
|---|---|
list_service_catalog_items |
List items available in the service catalog. |
get_service_catalog_item |
Retrieve details of a specific service catalog item. |
list_canned_responses |
List canned response templates. |
π€ Identity & History
| Tool | Purpose |
|---|---|
search_requesters |
Find users by name or email. |
get_requester |
Detailed profile of a user. |
get_requester_tickets |
Historical view of all tickets for a specific user. |
get_requester_assets |
List of hardware currently assigned to a user. |
search_agents |
Find support staff members. |
get_agent / get_agent_group |
Inspect specific agents or support teams. |
π Available Resources (Standing Context)
Resources can be attached to a conversation to provide the AI with constant reference data without needing a tool call.
| URI | Content |
|---|---|
freshservice://departments |
Your organizational hierarchy. |
freshservice://ticket-fields |
The schema for custom ticket fields and their values. |
freshservice://agent-groups |
Valid routing destinations (support teams). |
freshservice://sla-policies |
Your response and resolution time targets. |
freshservice://business-hours |
Operation schedules for various teams. |
πͺ Available Prompts (Workflows)
| Prompt | Scenario |
|---|---|
triage_ticket |
Input: Ticket ID. Output: A comprehensive assessment including history, SR items, and suggested KB articles. |
summarize_ticket |
Input: Ticket ID. Output: A concise executive summary perfect for handoffs or manager reviews. |
draft_reply |
Input: Ticket ID. Output: A professional draft reply incorporating KB solutions and empathy. |
sla_check |
Input: Ticket ID. Output: An analysis of breach risk based on business hours and policies. |
π Search Syntax Reference
The search_tickets tool supports the Freshservice Filter API syntax:
- Status Codes:
2: Open,3: Pending,4: Resolved,5: Closed. - Priority Codes:
1: Low,2: Medium,3: High,4: Urgent.
Examples for AI:
"status:2 AND priority:4"β Show me urgent open tickets."created_at:>'2024-01-01'"β Show me tickets from this year."type:'Incident'"β Filter for incidents only.
πͺΆ Response Shaping (Token Economy)
Freshservice API responses are verbose β a single ticket carries 40-60 fields (many null), HTML bodies, and internal metadata the model never needs. To avoid bloating the AI's context window, tool and resource responses pass through a shaping layer before they're returned. Most are field-projected and HTML-stripped; a few (e.g. service-request items, whose custom_fields hold the request's actual answers) are compacted but deliberately kept whole.
What it does:
- Compact JSON β no pretty-print whitespace (~15-30% saving on every call).
- Field projection β list/search tools return lean summary rows (e.g. a ticket β
id, subject, status, priority, requester_id, group_id, timestamps); detail tools (get_ticket,get_asset, β¦) return a curated, richer set. - HTML stripping β descriptions, conversation bodies, and articles are converted from HTML to plain text (
descriptionβdescription_text), then truncated if very long. - Noise removal β
null/empty fields and empty custom-field entries are dropped; attachments are reduced to filenames. - Defensive fallback β if a response doesn't match the expected shape, it passes through compacted but otherwise untouched (never mangled).
Summary-then-drill-down: list tools intentionally return summaries. When the model needs everything about one record, it calls the matching get_* tool. This keeps broad queries cheap.
Tuning what the model sees
All shaping rules are declarative and live in one file β src/shape.config.js. The engine (src/shape.js) contains no per-domain logic, so adjusting output requires no code changes.
Each domain defines a list (summary) and/or detail profile:
tickets: {
container: 'tickets', // array key for list responses
item: 'ticket', // object key for single-record responses
list: { fields: ['id', 'subject', 'status', 'priority', /* β¦ */] },
detail: {
fields: ['id', 'subject', 'status', /* β¦moreβ¦ */],
text: [{ from: ['description_text', 'description'], to: 'description_text', max: 2000 }],
objects: ['custom_fields'], // kept, but null/empty entries dropped
},
}
| Profile key | Effect |
|---|---|
fields |
Whitelist of keys to keep (present + non-empty only). |
text |
Take the first available from field, strip HTML, truncate to max, store under to. |
objects |
Custom-field-style objects to keep but compact (drop null/empty). |
names |
Reduce an array of { name, β¦ } objects to an array of names (e.g. attachments). |
To add a field to a tool's output, append it to that domain's fields array. To expose more/less body text, change max. That's the whole workflow.
Note: the field names in
shape.config.jsare mapped to the Freshservice v2 API. If your instance relies on a field that isn't surfaced, add it to the relevantfieldsarray β it's a one-line change.
β‘ Performance & Reliability
The Freshservice client (src/freshservice.js) includes several measures to stay fast and resilient under real-world conditions:
- Request timeout β every request times out after 10s rather than hanging indefinitely on a stalled connection.
- Automatic retry with backoff β transient failures (
429rate limits,5xx, network/timeout errors) are retried up to 3 times with exponential backoff. A429'sRetry-Afterheader is honored when present. Non-transient errors (401,403,404) are not retried. - Caching of static data β near-static reference endpoints (departments, ticket/requester fields, SLA policies, business hours, agent groups) are cached in memory for 10 minutes, so the AI's repeated context-gathering doesn't re-hit the API. Failed lookups are never cached.
- Concurrent pagination β tools that aggregate every page (
list_canned_responses,list_service_catalog_items) fetch page 1, then pull the remaining pages in bounded-concurrency batches (per_page=100, 5 pages at a time) instead of one slow page at a time β turning ~10 sequential round-trips into 2-3 parallel batches.
These are tuned by constants at the top of
src/freshservice.js(STATIC_TTL_MS,REQUEST_TIMEOUT_MS,MAX_RETRIES).
π§ͺ Development
| Command | What it does |
|---|---|
npm start |
Run the MCP server on stdio. |
npm test |
Run the Jest test suite. |
npm run lint |
Lint with ESLint (flat config, eslint:recommended + Node/Jest globals). |
npm run lint:fix |
Lint and auto-fix where possible. |
npm run typecheck |
Type-check the JS via TypeScript in checkJs mode (no emit). |
npm run check |
Run lint + typecheck + tests together (use before committing). |
Type-checking uses TypeScript's checkJs against the application code (tsconfig.json). It catches real errors β e.g. wrong API shapes or SDK misuse β without requiring the code to be migrated to TypeScript. Test files are excluded from tsc (their Jest mocks are validated by the test runner, not the type-checker). Implicit-any is allowed, so the checker surfaces genuine type errors rather than annotation noise.
π Security & Privacy
- Read-Only: This server has NO capability to create, edit, or delete data. It is inherently safe.
- Local Only: Credentials NEVER leave your machine.
- Auditability: All API requests are standard HTTPS and appear in your Freshservice API logs.
π License
ISC License. Build with freedom.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.