rootly-mcp-server 0.0.5__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
- rootly_mcp_server/client.py +18 -2
- rootly_mcp_server/server.py +48 -14
- {rootly_mcp_server-0.0.5.dist-info → rootly_mcp_server-1.0.0.dist-info}/METADATA +27 -2
- {rootly_mcp_server-0.0.5.dist-info → rootly_mcp_server-1.0.0.dist-info}/RECORD +7 -7
- {rootly_mcp_server-0.0.5.dist-info → rootly_mcp_server-1.0.0.dist-info}/WHEEL +0 -0
- {rootly_mcp_server-0.0.5.dist-info → rootly_mcp_server-1.0.0.dist-info}/entry_points.txt +0 -0
- {rootly_mcp_server-0.0.5.dist-info → rootly_mcp_server-1.0.0.dist-info}/licenses/LICENSE +0 -0
rootly_mcp_server/client.py
CHANGED
|
@@ -24,7 +24,7 @@ class RootlyClient:
|
|
|
24
24
|
raise ValueError("ROOTLY_API_TOKEN environment variable is not set")
|
|
25
25
|
return api_token
|
|
26
26
|
|
|
27
|
-
def make_request(self, method: str, path: str, query_params: Optional[Dict[str, Any]] = None, json_data: Optional[Dict[str, Any]] = None) -> str:
|
|
27
|
+
def make_request(self, method: str, path: str, query_params: Optional[Dict[str, Any]] = None, json_data: Optional[Dict[str, Any]] = None, json_api_type: Optional[str] = None) -> str:
|
|
28
28
|
"""
|
|
29
29
|
Make an authenticated request to the Rootly API.
|
|
30
30
|
|
|
@@ -33,16 +33,32 @@ class RootlyClient:
|
|
|
33
33
|
path: The API path.
|
|
34
34
|
query_params: Query parameters for the request.
|
|
35
35
|
json_data: JSON data for the request body.
|
|
36
|
+
json_api_type: If set, use JSON-API format and this type value.
|
|
36
37
|
|
|
37
38
|
Returns:
|
|
38
39
|
The API response as a JSON string.
|
|
39
40
|
"""
|
|
41
|
+
# Default headers
|
|
40
42
|
headers = {
|
|
41
43
|
"Authorization": f"Bearer {self._api_token}",
|
|
42
44
|
"Content-Type": "application/json",
|
|
43
45
|
"Accept": "application/json"
|
|
44
46
|
}
|
|
45
|
-
|
|
47
|
+
|
|
48
|
+
# If JSON-API, update headers and wrap payload
|
|
49
|
+
if json_api_type and method.upper() in ["POST", "PUT", "PATCH"]:
|
|
50
|
+
headers["Content-Type"] = "application/vnd.api+json"
|
|
51
|
+
headers["Accept"] = "application/vnd.api+json"
|
|
52
|
+
if json_data:
|
|
53
|
+
json_data = {
|
|
54
|
+
"data": {
|
|
55
|
+
"type": json_api_type,
|
|
56
|
+
"attributes": json_data
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else:
|
|
60
|
+
json_data = None
|
|
61
|
+
|
|
46
62
|
# Ensure path starts with a slash
|
|
47
63
|
if not path.startswith("/"):
|
|
48
64
|
path = f"/{path}"
|
rootly_mcp_server/server.py
CHANGED
|
@@ -55,7 +55,40 @@ class RootlyMCPServer(FastMCP):
|
|
|
55
55
|
# Set default allowed paths if none provided
|
|
56
56
|
self.allowed_paths = allowed_paths or [
|
|
57
57
|
"/incidents",
|
|
58
|
-
"/incidents/{incident_id}/alerts"
|
|
58
|
+
"/incidents/{incident_id}/alerts",
|
|
59
|
+
"/alerts",
|
|
60
|
+
"/alerts/{alert_id}",
|
|
61
|
+
"/severities",
|
|
62
|
+
"/severities/{severity_id}",
|
|
63
|
+
"/teams",
|
|
64
|
+
"/teams/{team_id}",
|
|
65
|
+
"/services",
|
|
66
|
+
"/services/{service_id}",
|
|
67
|
+
"/functionalities",
|
|
68
|
+
"/functionalities/{functionality_id}",
|
|
69
|
+
# Incident types
|
|
70
|
+
"/incident_types",
|
|
71
|
+
"/incident_types/{incident_type_id}",
|
|
72
|
+
# Action items (all, by id, by incident)
|
|
73
|
+
"/incident_action_items",
|
|
74
|
+
"/incident_action_items/{incident_action_item_id}",
|
|
75
|
+
"/incidents/{incident_id}/action_items",
|
|
76
|
+
# Workflows
|
|
77
|
+
"/workflows",
|
|
78
|
+
"/workflows/{workflow_id}",
|
|
79
|
+
# Workflow runs
|
|
80
|
+
"/workflow_runs",
|
|
81
|
+
"/workflow_runs/{workflow_run_id}",
|
|
82
|
+
# Environments
|
|
83
|
+
"/environments",
|
|
84
|
+
"/environments/{environment_id}",
|
|
85
|
+
# Users
|
|
86
|
+
"/users",
|
|
87
|
+
"/users/{user_id}",
|
|
88
|
+
"/users/me",
|
|
89
|
+
# Status pages
|
|
90
|
+
"/status_pages",
|
|
91
|
+
"/status_pages/{status_page_id}"
|
|
59
92
|
]
|
|
60
93
|
# Add /v1 prefix to paths if not present
|
|
61
94
|
self.allowed_paths = [
|
|
@@ -357,7 +390,7 @@ class RootlyMCPServer(FastMCP):
|
|
|
357
390
|
path: The API path.
|
|
358
391
|
method: The HTTP method.
|
|
359
392
|
operation: The Swagger operation object.
|
|
360
|
-
**
|
|
393
|
+
**v: The parameters for the request.
|
|
361
394
|
|
|
362
395
|
Returns:
|
|
363
396
|
The API response as a JSON string.
|
|
@@ -379,38 +412,39 @@ class RootlyMCPServer(FastMCP):
|
|
|
379
412
|
body_params = {}
|
|
380
413
|
|
|
381
414
|
if method.lower() == "get":
|
|
382
|
-
# For GET requests, all remaining parameters are query parameters
|
|
383
415
|
query_params = kwargs
|
|
384
|
-
|
|
385
|
-
# Add default pagination for incident-related endpoints
|
|
386
416
|
if "incidents" in path and method.lower() == "get":
|
|
387
|
-
# Check if pagination parameters are already specified
|
|
388
417
|
has_pagination = any(param.startswith("page[") for param in query_params.keys())
|
|
389
|
-
|
|
390
|
-
# If no pagination parameters are specified, add default page size
|
|
391
418
|
if not has_pagination:
|
|
392
419
|
query_params["page[size]"] = self.default_page_size
|
|
393
420
|
logger.debug(f"Added default pagination (page[size]={self.default_page_size}) for incidents endpoint: {path}")
|
|
394
421
|
else:
|
|
395
|
-
# For other methods, check which parameters are query parameters
|
|
396
422
|
for param in operation.get("parameters", []):
|
|
397
423
|
param_name = param.get("name")
|
|
398
424
|
param_in = param.get("in")
|
|
399
|
-
|
|
400
425
|
if param_in == "query" and param_name in kwargs:
|
|
401
426
|
query_params[param_name] = kwargs.pop(param_name)
|
|
402
|
-
|
|
403
|
-
# All remaining parameters go in the request body
|
|
404
427
|
body_params = kwargs
|
|
405
428
|
|
|
406
|
-
# Make the API request
|
|
407
429
|
try:
|
|
430
|
+
json_api_type = None
|
|
431
|
+
if method.lower() in ["post", "put", "patch"]:
|
|
432
|
+
segments = [seg for seg in actual_path.split("/") if seg and not seg.startswith(":") and not seg.startswith("{")]
|
|
433
|
+
if segments:
|
|
434
|
+
if segments[-1].startswith("by_") or segments[-1].endswith("_id") or segments[-1].startswith("id") or segments[-1].startswith("{id"):
|
|
435
|
+
if len(segments) > 1:
|
|
436
|
+
json_api_type = segments[-2]
|
|
437
|
+
else:
|
|
438
|
+
json_api_type = segments[-1]
|
|
439
|
+
|
|
408
440
|
response = self.client.make_request(
|
|
409
441
|
method=method.upper(),
|
|
410
442
|
path=actual_path,
|
|
411
443
|
query_params=query_params if query_params else None,
|
|
412
|
-
json_data=body_params if body_params else None
|
|
444
|
+
json_data=body_params if body_params else None,
|
|
445
|
+
json_api_type=json_api_type
|
|
413
446
|
)
|
|
447
|
+
# Do not include kwargs or payload in the output, just return the response
|
|
414
448
|
return response
|
|
415
449
|
except Exception as e:
|
|
416
450
|
logger.error(f"Error calling Rootly API: {e}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rootly-mcp-server
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: A Model Context Protocol server for Rootly APIs using OpenAPI spec
|
|
5
5
|
Project-URL: Homepage, https://github.com/Rootly-AI-Labs/Rootly-MCP-server
|
|
6
6
|
Project-URL: Issues, https://github.com/Rootly-AI-Labs/Rootly-MCP-server/issues
|
|
@@ -22,7 +22,6 @@ Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
|
22
22
|
Requires-Dist: isort>=5.0.0; extra == 'dev'
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
|
|
25
|
-
|
|
26
25
|
# Rootly MCP Server
|
|
27
26
|
|
|
28
27
|
An MCP server for [Rootly API](https://docs.rootly.com/api-reference/overview) that you can plug into your favorite MCP-compatible editors like Cursor, Windsurf, and Claude. Resolve production incidents in under a minute without leaving your IDE.
|
|
@@ -101,3 +100,29 @@ This project is a prototype and not intended for production use. If you have fea
|
|
|
101
100
|
This project was developed by the [Rootly AI Labs](https://labs.rootly.ai/). The AI Labs is building the future of system reliability and operational excellence. We operate as an open-source incubator, sharing ideas, experimenting, and rapidly prototyping. We're committed to ensuring our research benefits the entire community.
|
|
102
101
|

|
|
103
102
|
|
|
103
|
+
## Developer Setup & Troubleshooting
|
|
104
|
+
|
|
105
|
+
### 1. Install dependencies with `uv`
|
|
106
|
+
This project uses [`uv`](https://github.com/astral-sh/uv) for fast dependency management. To install all dependencies from your `pyproject.toml`:
|
|
107
|
+
```bash
|
|
108
|
+
uv pip install .
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 2. Using a virtual environment
|
|
112
|
+
It is recommended to use a virtual environment for development:
|
|
113
|
+
```bash
|
|
114
|
+
uv venv .venv
|
|
115
|
+
source .venv/bin/activate
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. Running the test client
|
|
119
|
+
To run the test client and verify your setup:
|
|
120
|
+
```bash
|
|
121
|
+
python test_mcp_client.py
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 5. General tips
|
|
125
|
+
- Always activate your virtual environment before running scripts.
|
|
126
|
+
- If you add new dependencies, use `uv pip install <package>` to keep your environment up to date.
|
|
127
|
+
- If you encounter issues, check your Python version and ensure it matches the project's requirements.
|
|
128
|
+
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
rootly_mcp_server/__init__.py,sha256=n-YajkwxYg0eoVvtYfYTY6slaktHTYvQbasg15HwGKo,628
|
|
2
2
|
rootly_mcp_server/__main__.py,sha256=yVbn4s2WGDy7ASbcLULMi2ro4Qt6WgVZbHVD0p0ibrs,4311
|
|
3
|
-
rootly_mcp_server/client.py,sha256=
|
|
4
|
-
rootly_mcp_server/server.py,sha256=
|
|
3
|
+
rootly_mcp_server/client.py,sha256=bUi_2WJl_w4kAAyuD18Mu0O_EPJ1VrvqxQAkPWQQKc0,4521
|
|
4
|
+
rootly_mcp_server/server.py,sha256=sq8kksmDY_4DpSGVVQoTi6yNBZFA5TWmtqLMUhbeM7Y,17656
|
|
5
5
|
rootly_mcp_server/test_client.py,sha256=xFQ4cfUpD6qs-aLidy56B3nnV38EFvUe_eBHOqZOC9o,2191
|
|
6
6
|
rootly_mcp_server/data/__init__.py,sha256=fO8a0bQnRVEoRMHKvhFzj10bhoaw7VsI51czc2MsUm4,143
|
|
7
7
|
rootly_mcp_server/data/swagger.json,sha256=8Ag4COTnS3WSC6vBaa2Q7hq3RxIQ8fGrmwsnNSnPheA,2046619
|
|
8
|
-
rootly_mcp_server-0.0.
|
|
9
|
-
rootly_mcp_server-0.0.
|
|
10
|
-
rootly_mcp_server-0.0.
|
|
11
|
-
rootly_mcp_server-0.0.
|
|
12
|
-
rootly_mcp_server-0.0.
|
|
8
|
+
rootly_mcp_server-1.0.0.dist-info/METADATA,sha256=6M05t9v0v2WT_eTHqCI4cqCBEOC9_WjIV8SweLPbZYE,4883
|
|
9
|
+
rootly_mcp_server-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
rootly_mcp_server-1.0.0.dist-info/entry_points.txt,sha256=NE33b8VgigVPGBkboyo6pvN1Vz35HZtLybxMO4Q03PI,70
|
|
11
|
+
rootly_mcp_server-1.0.0.dist-info/licenses/LICENSE,sha256=c9w9ZZGl14r54tsP40oaq5adTVX_HMNHozPIH2ymzmw,11341
|
|
12
|
+
rootly_mcp_server-1.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|