mcp-freshservice 2.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. mcp_freshservice-2.0.0/.gitignore +174 -0
  2. mcp_freshservice-2.0.0/CHANGELOG.md +67 -0
  3. mcp_freshservice-2.0.0/LICENSE +22 -0
  4. mcp_freshservice-2.0.0/PKG-INFO +193 -0
  5. mcp_freshservice-2.0.0/README.md +165 -0
  6. mcp_freshservice-2.0.0/pyproject.toml +72 -0
  7. mcp_freshservice-2.0.0/src/mcp_freshservice/__init__.py +16 -0
  8. mcp_freshservice-2.0.0/src/mcp_freshservice/__main__.py +3 -0
  9. mcp_freshservice-2.0.0/src/mcp_freshservice/client.py +308 -0
  10. mcp_freshservice-2.0.0/src/mcp_freshservice/config.py +48 -0
  11. mcp_freshservice-2.0.0/src/mcp_freshservice/server.py +135 -0
  12. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/__init__.py +17 -0
  13. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/_common.py +542 -0
  14. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/_registry.py +102 -0
  15. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/agents.py +144 -0
  16. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/assets.py +213 -0
  17. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/changes.py +226 -0
  18. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/groups.py +176 -0
  19. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/organisation.py +269 -0
  20. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/problems.py +269 -0
  21. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/requesters.py +164 -0
  22. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/service_catalog.py +92 -0
  23. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/solutions.py +330 -0
  24. mcp_freshservice-2.0.0/src/mcp_freshservice/tools/tickets.py +398 -0
  25. mcp_freshservice-2.0.0/tests/conftest.py +57 -0
  26. mcp_freshservice-2.0.0/tests/test_live_check.py +197 -0
  27. mcp_freshservice-2.0.0/tests/test_tools.py +559 -0
@@ -0,0 +1,174 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # Ruff stuff:
171
+ .ruff_cache/
172
+
173
+ # PyPI configuration file
174
+ .pypirc
@@ -0,0 +1,67 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0
4
+
5
+ Published as **`mcp-freshservice`** (was `freshservice-mcp`); run it with `uvx mcp-freshservice`.
6
+
7
+ ### Fixed
8
+ - `get_ticket_by_id` returned a pydantic output-validation error instead of the ticket.
9
+ Single-record tools now return their `{"ticket": {...}}` payload with a proper output schema, and
10
+ `include=` (conversations, requester, stats, …) is supported.
11
+ - Tools that returned an error *string* from a `dict`-typed function and the `${…}` typo in
12
+ those messages. Every failure is now a tool error with Freshservice's description and field errors.
13
+ - `send_ticket_reply` no longer sends a made-up `from_email` that Freshservice rejected with 400.
14
+ - Wrong ticket source IDs (Chat was 7, is 4) and missing ones (Chatbot, Workplace, Alerts, MS Teams, …).
15
+ - Change approvals used paths that don't exist (`approval_groups`, `approval_chain`, `resend_approval`);
16
+ they now use `approval-groups`, `approval-chain-rule` and `approvals/{id}/remind`.
17
+ - Docs/examples that treated `:<` as strict (e.g. `status:<6` for "not closed" changes). `:>`/`:<` are inclusive,
18
+ confirmed against a live account, so "not closed" is `status:<5`.
19
+ - Knowledge-base search and folder listings return a short `snippet` instead of every article's full HTML and
20
+ text body (Freshservice sends full bodies for all 30 results, which is large enough for clients to truncate);
21
+ pass `include_body=true` for the full text or read one article with `get_solution_article`.
22
+ - Change `query` and `view` can't be combined (the API rejects it); the server says so up front.
23
+ - Filter syntax checked against the official docs: `:>`/`:<` are documented as inclusive; query length limit
24
+ (512) enforced locally; filter endpoints no longer send `per_page` (fixed 30); page caps (40) for
25
+ requester/agent filters; queries are percent-encoded as in the docs; departments/locations/asset-search/
26
+ release filters describe only their documented fields. Releases take the documented `filter_name` values
27
+ only (there is no free-form release query).
28
+ - `filter_requesters` now quotes its query like the other filters (the API requires it); all filters use one code path.
29
+
30
+ ### Added
31
+ - Ticket, change, problem and release time entries, tasks and notes; ticket approvals,
32
+ child tickets, restore, activities, ticket sources.
33
+ - Problems, releases, assets and asset types, departments, locations, vendors, roles, service catalog
34
+ search, solution search and sub-folders, requester-group member removal, agent/requester deactivate and
35
+ reactivate.
36
+ - Attachments on replies, notes and tickets; `private` flag on notes; `group_id` /
37
+ `responder_id` on `create_ticket`.
38
+ - `FRESHSERVICE_WORKSPACE_ID` default workspace, `FRESHSERVICE_READ_ONLY`,
39
+ `FRESHSERVICE_TOOLSETS`, streamable-HTTP/SSE transports, `--version`.
40
+ - Read-only / destructive / idempotent annotations on every tool, titles, typed and described parameters.
41
+
42
+ ### Changed (breaking)
43
+ - **Only a core set of 76 tools is enabled by default** (tickets, ticket time entries, requesters, agents,
44
+ groups, solutions, service catalog). Everything else is opt-in: `--toolsets default,changes,assets` or
45
+ `--toolsets all`; `--list-toolsets` shows the options. Notes, tasks, time entries and approvals for each
46
+ record type are separate toolsets (e.g. `change_notes`).
47
+ - Requires `mcp>=1.30,<2` (MCP SDK v1 line); still Python 3.13+.
48
+ - Package/module renamed `freshservice_mcp` → `mcp_freshservice`; console script `mcp-freshservice`.
49
+ - `server.py` split into `client.py`, `config.py` and `tools/<area>.py`.
50
+ - Renamed tools: `get_requester_id` → `get_requester`, `getAgentGroupById` → `get_agent_group`,
51
+ `get_requester_groups_by_id` → `get_requester_group`, `get_products_by_id` → `get_product`,
52
+ `get_change_tasks` → `list_change_tasks`, `update_approval_chain_rule_change` →
53
+ `update_change_approval_chain_rule`.
54
+ - Renamed parameters: generic `id` arguments are now explicit (`product_id`, `requester_group_id`,
55
+ `canned_response_id`, `workspace_id`, `folder_id`, `category_id`); `get_list_of_solution_folder` takes
56
+ `category_id` and `get_list_of_solution_article` takes `folder_id`.
57
+ - `update_agent`, `update_requester`, `update_group` and `update_*_task` take a fields object; `update_product`
58
+ and `update_solution_category` no longer require every field.
59
+ - `list_canned_response_folder` now lists the responses *in* a folder (`/canned_response_folders/{id}/canned_responses`).
60
+ - List tools return the API's own wrapper once (`{"tickets": [...]}`, not nested twice) plus
61
+ `pagination: {page, per_page, next_page, has_more}`; `current_page`/`prev_page` are gone.
62
+ `list_service_items` returns one page instead of fetching every page; `filter_agents` returns one page.
63
+ - `send_ticket_reply` takes lists for `cc_emails`/`bcc_emails` (JSON strings are no longer parsed).
64
+ - `get_requested_items` no longer pre-fetches the ticket to check its type; the API's own error is returned.
65
+ - Failures raise tool errors rather than returning `{"error": ...}` dictionaries or strings.
66
+ - Removed `smithery.yaml` and the Smithery-generated `Dockerfile` (distribution is via PyPI/`uvx`).
67
+ - Dropped the `build` runtime dependency and the live-API script `tests/test-fs-mcp.py` (replaced by offline tests).
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 effy
4
+ Copyright (c) 2026 Angel Pandey
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.5
2
+ Name: mcp-freshservice
3
+ Version: 2.0.0
4
+ Summary: A Model Context Protocol (MCP) server for the Freshservice ITSM API v2
5
+ Project-URL: Homepage, https://github.com/angel-pandey/mcp-freshservice
6
+ Project-URL: Repository, https://github.com/angel-pandey/mcp-freshservice
7
+ Project-URL: Issues, https://github.com/angel-pandey/mcp-freshservice/issues
8
+ Project-URL: Freshservice API, https://api.freshservice.com/
9
+ Author: Angel Pandey, Gopi Krishnan, Maanaesh Swamy, Vijay Ragunath
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: freshservice,helpdesk,itsm,llm,mcp,model-context-protocol
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: System :: Systems Administration
22
+ Requires-Python: >=3.13
23
+ Requires-Dist: httpx<1,>=0.28.1
24
+ Requires-Dist: mcp[cli]<2,>=1.30.0
25
+ Requires-Dist: pydantic<3,>=2.11
26
+ Requires-Dist: python-dotenv>=1.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # mcp-freshservice
30
+
31
+ A [Model Context Protocol](https://modelcontextprotocol.io/) server for the
32
+ [Freshservice REST API v2](https://api.freshservice.com/). It lets an AI assistant work with tickets,
33
+ changes, problems, releases, assets, requesters, agents, groups, the service catalog and the knowledge
34
+ base.
35
+
36
+ > Forked from [effytech/freshservice_mcp](https://github.com/effytech/freshservice_mcp) and reworked for
37
+ > v2 (see [CHANGELOG.md](CHANGELOG.md) for breaking changes).
38
+
39
+ ## Quick start
40
+
41
+ You need a Freshservice API key (Profile Settings → API key) and your domain.
42
+
43
+ ```bash
44
+ uvx mcp-freshservice --version
45
+ ```
46
+
47
+ Claude Desktop / any MCP client (`claude_desktop_config.json`):
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "freshservice": {
53
+ "command": "uvx",
54
+ "args": ["mcp-freshservice"],
55
+ "env": {
56
+ "FRESHSERVICE_DOMAIN": "yourcompany.freshservice.com",
57
+ "FRESHSERVICE_APIKEY": "<your-api-key>"
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ Claude Code: `claude mcp add freshservice -e FRESHSERVICE_DOMAIN=yourcompany.freshservice.com -e FRESHSERVICE_APIKEY=... -- uvx mcp-freshservice`
65
+
66
+ ## Configuration
67
+
68
+ | Variable | Required | Description |
69
+ |---|---|---|
70
+ | `FRESHSERVICE_DOMAIN` | yes | `yourcompany.freshservice.com` (a bare `yourcompany` also works) |
71
+ | `FRESHSERVICE_APIKEY` | yes | API key of the agent the server acts as. Permissions follow that agent |
72
+ | `FRESHSERVICE_WORKSPACE_ID` | no | Default `workspace_id` for calls on multi-workspace accounts. A tool's own `workspace_id` argument wins |
73
+ | `FRESHSERVICE_READ_ONLY` | no | `1` exposes only read-only tools |
74
+ | `FRESHSERVICE_TOOLSETS` | no | Which toolsets to expose: names, `default` (the core set, used when unset) and/or `all`. See [Choosing tools](#choosing-tools) |
75
+ | `FRESHSERVICE_TIMEOUT` | no | HTTP timeout in seconds (default 30) |
76
+ | `MCP_TRANSPORT`, `MCP_HOST`, `MCP_PORT` | no | `stdio` (default), `streamable-http` or `sse` |
77
+
78
+ The same switches exist as flags: `--read-only`, `--toolsets tickets,solutions`, `--transport`.
79
+
80
+ ### Choosing tools
81
+
82
+ The server can expose 204 tools (full list in [TOOLS.md](TOOLS.md)), but some clients cap the tools per agent
83
+ (for example 128) and models choose better from a shorter list. So **by default only a 76-tool core set is
84
+ enabled**; everything else is opt-in by toolset.
85
+
86
+ ```bash
87
+ uvx mcp-freshservice --list-toolsets # see what's available
88
+ uvx mcp-freshservice --toolsets default,changes,assets # core set + changes + assets
89
+ uvx mcp-freshservice --toolsets all # everything
90
+ uvx mcp-freshservice --toolsets tickets,solutions --read-only
91
+ ```
92
+
93
+ The same works with `FRESHSERVICE_TOOLSETS=default,changes` in the client's `env`. A list of plain names is
94
+ exact (only those toolsets); add `default` to keep the core set.
95
+
96
+ | Toolset | Default | Tools | Covers |
97
+ |---|:-:|---:|---|
98
+ | `tickets` | yes | 17 | tickets, replies and notes (with attachments), conversations, child tickets, requested items |
99
+ | `ticket_time_entries` | yes | 5 | time logged on tickets |
100
+ | `ticket_tasks` | | 5 | ticket tasks |
101
+ | `ticket_approvals` | | 9 | service-request approval groups and approvals |
102
+ | `requesters` | yes | 9 | requesters, fields, reactivate, convert to agent |
103
+ | `agents` | yes | 9 | agents, fields, roles |
104
+ | `groups` | yes | 13 | agent groups, requester groups and membership |
105
+ | `solutions` | yes | 18 | knowledge-base categories, folders, articles, search |
106
+ | `service_catalog` | yes | 5 | browse/search items, place service requests |
107
+ | `changes` | | 9 | change requests and planning fields |
108
+ | `change_notes`, `change_tasks`, `change_time_entries` | | 5 each | notes, tasks, time entries on changes |
109
+ | `change_approvals` | | 9 | change approval groups, chains, approvals |
110
+ | `problems`, `releases` | | 8, 7 | problem and release records |
111
+ | `problem_*`, `release_*` (`notes`, `tasks`, `time_entries`) | | 5 each | notes, tasks, time entries |
112
+ | `assets` | | 16 | assets, asset types, canned responses |
113
+ | `organisation` | | 20 | workspaces, departments, locations, vendors, products |
114
+
115
+ Every tool is annotated read-only / destructive so clients can auto-approve safely.
116
+
117
+ ## Conventions
118
+
119
+ - **Single records** come back as Freshservice returns them: `{"ticket": {...}}`.
120
+ - **Lists** return one page plus `pagination: {page, per_page, next_page, has_more}`. `per_page` is at most 100.
121
+ - **Errors** are real MCP tool errors (`isError: true`) carrying Freshservice's message and field errors,
122
+ with hints for 401/403/404/429.
123
+ - **Filtering**: see [Query syntax](#query-syntax).
124
+ - **Numeric codes**: ticket status 2 Open, 3 Pending, 4 Resolved, 5 Closed; priority 1 Low … 4 Urgent;
125
+ source 1 Email, 2 Portal, 3 Phone, 4 Chat … (see `list_ticket_sources` for the full list).
126
+ - **Attachments**: `send_ticket_reply`, `create_ticket_note`, `create_ticket` and
127
+ `update_ticket_conversation` accept local file paths (max 15 files / 40 MB).
128
+
129
+ Example prompts: "Show ticket 12031 with its conversations and resolution notes", "How much time was
130
+ logged on ticket 8?", "List open P1 incidents unassigned for a day", "Search the KB for printer setup".
131
+
132
+ ## Query syntax
133
+
134
+ `filter_tickets`, `filter_changes`, `filter_requesters`, `filter_agents` and the `query` / `filter` / `search`
135
+ arguments of the list tools use Freshservice's query language. Freshservice requires the whole query to be
136
+ **enclosed in a pair of double quotes** (without them the API answers `500`), so the server adds them for you;
137
+ you can pass `status:3` or `"status:3"` and get the same request.
138
+
139
+ | Rule | Example |
140
+ |---|---|
141
+ | Fields are snake_case and case-sensitive (custom fields by API name) | `status:3` |
142
+ | Numbers bare, strings and dates in **single** quotes | `tag:'vip'`, `planned_start_date:>'2025-07-14'` |
143
+ | `AND`, `OR` and parentheses | `(group_id:12 OR group_id:15) AND status:3` |
144
+ | `:>` / `:<` are **inclusive** (>= and <=), confirmed on a live account | `status:<5` means status 5 or lower |
145
+ | `null` finds empty values | `agent_id:null` |
146
+ | Starts-with (requesters and agents only) | `~[first_name\|last_name]:'ad'` |
147
+ | Max 512 characters (checked locally); filter results are 30 per page | |
148
+
149
+ Changes: `"status:3"` awaiting approval, `"approval_status:1"` approved,
150
+ `"approval_status:1 AND status:<5"` approved and not closed (status 6 is Closed, and `:<` includes its boundary, so `<6` would include closed changes), `"status:3 AND priority:1"`. `approval_status`
151
+ is 0 Requested, 1 Approved, 2 Rejected, 3 Not requested. A change `view` and `query` cannot be combined.
152
+
153
+ Not every endpoint supports every field: departments and locations filter on `name` only; asset `search`
154
+ takes one field (`name`, `asset_tag`, `serial_number`, ...); releases only have predefined `filter_name`
155
+ values. The per-tool descriptions list the supported fields. Filtered requester/agent pages are capped at 40;
156
+ changes to users can take a few minutes to be indexed.
157
+
158
+ ## Running remotely
159
+
160
+ ```bash
161
+ MCP_TRANSPORT=streamable-http MCP_PORT=8000 uvx mcp-freshservice
162
+ ```
163
+
164
+ The server is stateless over streamable HTTP and serves `/mcp`. It has **no authentication of its own**:
165
+ run it behind a gateway/reverse proxy that authenticates callers, because everyone who can reach it acts
166
+ with the configured API key.
167
+
168
+ ## Development
169
+
170
+ ```bash
171
+ uv sync
172
+ uv run pytest # offline, mocks the Freshservice API
173
+ uv run ruff check .
174
+ ```
175
+
176
+ To check the server against a real Freshservice account (read-only by default; never prints your key):
177
+
178
+ ```bash
179
+ uv run python scripts/live_check.py
180
+ ```
181
+
182
+ When you point an MCP client at a local checkout with `uvx --from <folder> mcp-freshservice`, uvx reuses a
183
+ cached build and will not notice your code changes (`--refresh` does not help). Add `--no-cache` to the uvx
184
+ arguments while developing, e.g. `"args": ["--no-cache", "--from", "G:/path/to/mcp-freshservice", "mcp-freshservice"]`.
185
+
186
+ Tests call tools through FastMCP's real `call_tool` path against a mocked API, so output-schema problems
187
+ (like the old `get_ticket_by_id` failure) are caught without credentials. Each tool module lives in
188
+ `src/mcp_freshservice/tools/`; add tools with `@ts.tool(title, kind)` and they are registered, filtered and
189
+ annotated automatically.
190
+
191
+ ## License
192
+
193
+ MIT, see [LICENSE](LICENSE).
@@ -0,0 +1,165 @@
1
+ # mcp-freshservice
2
+
3
+ A [Model Context Protocol](https://modelcontextprotocol.io/) server for the
4
+ [Freshservice REST API v2](https://api.freshservice.com/). It lets an AI assistant work with tickets,
5
+ changes, problems, releases, assets, requesters, agents, groups, the service catalog and the knowledge
6
+ base.
7
+
8
+ > Forked from [effytech/freshservice_mcp](https://github.com/effytech/freshservice_mcp) and reworked for
9
+ > v2 (see [CHANGELOG.md](CHANGELOG.md) for breaking changes).
10
+
11
+ ## Quick start
12
+
13
+ You need a Freshservice API key (Profile Settings → API key) and your domain.
14
+
15
+ ```bash
16
+ uvx mcp-freshservice --version
17
+ ```
18
+
19
+ Claude Desktop / any MCP client (`claude_desktop_config.json`):
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "freshservice": {
25
+ "command": "uvx",
26
+ "args": ["mcp-freshservice"],
27
+ "env": {
28
+ "FRESHSERVICE_DOMAIN": "yourcompany.freshservice.com",
29
+ "FRESHSERVICE_APIKEY": "<your-api-key>"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ Claude Code: `claude mcp add freshservice -e FRESHSERVICE_DOMAIN=yourcompany.freshservice.com -e FRESHSERVICE_APIKEY=... -- uvx mcp-freshservice`
37
+
38
+ ## Configuration
39
+
40
+ | Variable | Required | Description |
41
+ |---|---|---|
42
+ | `FRESHSERVICE_DOMAIN` | yes | `yourcompany.freshservice.com` (a bare `yourcompany` also works) |
43
+ | `FRESHSERVICE_APIKEY` | yes | API key of the agent the server acts as. Permissions follow that agent |
44
+ | `FRESHSERVICE_WORKSPACE_ID` | no | Default `workspace_id` for calls on multi-workspace accounts. A tool's own `workspace_id` argument wins |
45
+ | `FRESHSERVICE_READ_ONLY` | no | `1` exposes only read-only tools |
46
+ | `FRESHSERVICE_TOOLSETS` | no | Which toolsets to expose: names, `default` (the core set, used when unset) and/or `all`. See [Choosing tools](#choosing-tools) |
47
+ | `FRESHSERVICE_TIMEOUT` | no | HTTP timeout in seconds (default 30) |
48
+ | `MCP_TRANSPORT`, `MCP_HOST`, `MCP_PORT` | no | `stdio` (default), `streamable-http` or `sse` |
49
+
50
+ The same switches exist as flags: `--read-only`, `--toolsets tickets,solutions`, `--transport`.
51
+
52
+ ### Choosing tools
53
+
54
+ The server can expose 204 tools (full list in [TOOLS.md](TOOLS.md)), but some clients cap the tools per agent
55
+ (for example 128) and models choose better from a shorter list. So **by default only a 76-tool core set is
56
+ enabled**; everything else is opt-in by toolset.
57
+
58
+ ```bash
59
+ uvx mcp-freshservice --list-toolsets # see what's available
60
+ uvx mcp-freshservice --toolsets default,changes,assets # core set + changes + assets
61
+ uvx mcp-freshservice --toolsets all # everything
62
+ uvx mcp-freshservice --toolsets tickets,solutions --read-only
63
+ ```
64
+
65
+ The same works with `FRESHSERVICE_TOOLSETS=default,changes` in the client's `env`. A list of plain names is
66
+ exact (only those toolsets); add `default` to keep the core set.
67
+
68
+ | Toolset | Default | Tools | Covers |
69
+ |---|:-:|---:|---|
70
+ | `tickets` | yes | 17 | tickets, replies and notes (with attachments), conversations, child tickets, requested items |
71
+ | `ticket_time_entries` | yes | 5 | time logged on tickets |
72
+ | `ticket_tasks` | | 5 | ticket tasks |
73
+ | `ticket_approvals` | | 9 | service-request approval groups and approvals |
74
+ | `requesters` | yes | 9 | requesters, fields, reactivate, convert to agent |
75
+ | `agents` | yes | 9 | agents, fields, roles |
76
+ | `groups` | yes | 13 | agent groups, requester groups and membership |
77
+ | `solutions` | yes | 18 | knowledge-base categories, folders, articles, search |
78
+ | `service_catalog` | yes | 5 | browse/search items, place service requests |
79
+ | `changes` | | 9 | change requests and planning fields |
80
+ | `change_notes`, `change_tasks`, `change_time_entries` | | 5 each | notes, tasks, time entries on changes |
81
+ | `change_approvals` | | 9 | change approval groups, chains, approvals |
82
+ | `problems`, `releases` | | 8, 7 | problem and release records |
83
+ | `problem_*`, `release_*` (`notes`, `tasks`, `time_entries`) | | 5 each | notes, tasks, time entries |
84
+ | `assets` | | 16 | assets, asset types, canned responses |
85
+ | `organisation` | | 20 | workspaces, departments, locations, vendors, products |
86
+
87
+ Every tool is annotated read-only / destructive so clients can auto-approve safely.
88
+
89
+ ## Conventions
90
+
91
+ - **Single records** come back as Freshservice returns them: `{"ticket": {...}}`.
92
+ - **Lists** return one page plus `pagination: {page, per_page, next_page, has_more}`. `per_page` is at most 100.
93
+ - **Errors** are real MCP tool errors (`isError: true`) carrying Freshservice's message and field errors,
94
+ with hints for 401/403/404/429.
95
+ - **Filtering**: see [Query syntax](#query-syntax).
96
+ - **Numeric codes**: ticket status 2 Open, 3 Pending, 4 Resolved, 5 Closed; priority 1 Low … 4 Urgent;
97
+ source 1 Email, 2 Portal, 3 Phone, 4 Chat … (see `list_ticket_sources` for the full list).
98
+ - **Attachments**: `send_ticket_reply`, `create_ticket_note`, `create_ticket` and
99
+ `update_ticket_conversation` accept local file paths (max 15 files / 40 MB).
100
+
101
+ Example prompts: "Show ticket 12031 with its conversations and resolution notes", "How much time was
102
+ logged on ticket 8?", "List open P1 incidents unassigned for a day", "Search the KB for printer setup".
103
+
104
+ ## Query syntax
105
+
106
+ `filter_tickets`, `filter_changes`, `filter_requesters`, `filter_agents` and the `query` / `filter` / `search`
107
+ arguments of the list tools use Freshservice's query language. Freshservice requires the whole query to be
108
+ **enclosed in a pair of double quotes** (without them the API answers `500`), so the server adds them for you;
109
+ you can pass `status:3` or `"status:3"` and get the same request.
110
+
111
+ | Rule | Example |
112
+ |---|---|
113
+ | Fields are snake_case and case-sensitive (custom fields by API name) | `status:3` |
114
+ | Numbers bare, strings and dates in **single** quotes | `tag:'vip'`, `planned_start_date:>'2025-07-14'` |
115
+ | `AND`, `OR` and parentheses | `(group_id:12 OR group_id:15) AND status:3` |
116
+ | `:>` / `:<` are **inclusive** (>= and <=), confirmed on a live account | `status:<5` means status 5 or lower |
117
+ | `null` finds empty values | `agent_id:null` |
118
+ | Starts-with (requesters and agents only) | `~[first_name\|last_name]:'ad'` |
119
+ | Max 512 characters (checked locally); filter results are 30 per page | |
120
+
121
+ Changes: `"status:3"` awaiting approval, `"approval_status:1"` approved,
122
+ `"approval_status:1 AND status:<5"` approved and not closed (status 6 is Closed, and `:<` includes its boundary, so `<6` would include closed changes), `"status:3 AND priority:1"`. `approval_status`
123
+ is 0 Requested, 1 Approved, 2 Rejected, 3 Not requested. A change `view` and `query` cannot be combined.
124
+
125
+ Not every endpoint supports every field: departments and locations filter on `name` only; asset `search`
126
+ takes one field (`name`, `asset_tag`, `serial_number`, ...); releases only have predefined `filter_name`
127
+ values. The per-tool descriptions list the supported fields. Filtered requester/agent pages are capped at 40;
128
+ changes to users can take a few minutes to be indexed.
129
+
130
+ ## Running remotely
131
+
132
+ ```bash
133
+ MCP_TRANSPORT=streamable-http MCP_PORT=8000 uvx mcp-freshservice
134
+ ```
135
+
136
+ The server is stateless over streamable HTTP and serves `/mcp`. It has **no authentication of its own**:
137
+ run it behind a gateway/reverse proxy that authenticates callers, because everyone who can reach it acts
138
+ with the configured API key.
139
+
140
+ ## Development
141
+
142
+ ```bash
143
+ uv sync
144
+ uv run pytest # offline, mocks the Freshservice API
145
+ uv run ruff check .
146
+ ```
147
+
148
+ To check the server against a real Freshservice account (read-only by default; never prints your key):
149
+
150
+ ```bash
151
+ uv run python scripts/live_check.py
152
+ ```
153
+
154
+ When you point an MCP client at a local checkout with `uvx --from <folder> mcp-freshservice`, uvx reuses a
155
+ cached build and will not notice your code changes (`--refresh` does not help). Add `--no-cache` to the uvx
156
+ arguments while developing, e.g. `"args": ["--no-cache", "--from", "G:/path/to/mcp-freshservice", "mcp-freshservice"]`.
157
+
158
+ Tests call tools through FastMCP's real `call_tool` path against a mocked API, so output-schema problems
159
+ (like the old `get_ticket_by_id` failure) are caught without credentials. Each tool module lives in
160
+ `src/mcp_freshservice/tools/`; add tools with `@ts.tool(title, kind)` and they are registered, filtered and
161
+ annotated automatically.
162
+
163
+ ## License
164
+
165
+ MIT, see [LICENSE](LICENSE).