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.
- mcp_freshservice-2.0.0/.gitignore +174 -0
- mcp_freshservice-2.0.0/CHANGELOG.md +67 -0
- mcp_freshservice-2.0.0/LICENSE +22 -0
- mcp_freshservice-2.0.0/PKG-INFO +193 -0
- mcp_freshservice-2.0.0/README.md +165 -0
- mcp_freshservice-2.0.0/pyproject.toml +72 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/__init__.py +16 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/__main__.py +3 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/client.py +308 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/config.py +48 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/server.py +135 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/__init__.py +17 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/_common.py +542 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/_registry.py +102 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/agents.py +144 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/assets.py +213 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/changes.py +226 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/groups.py +176 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/organisation.py +269 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/problems.py +269 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/requesters.py +164 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/service_catalog.py +92 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/solutions.py +330 -0
- mcp_freshservice-2.0.0/src/mcp_freshservice/tools/tickets.py +398 -0
- mcp_freshservice-2.0.0/tests/conftest.py +57 -0
- mcp_freshservice-2.0.0/tests/test_live_check.py +197 -0
- 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).
|