rootly-mcp-server 2.0.0__tar.gz → 2.0.2__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.
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/PKG-INFO +67 -36
- rootly_mcp_server-2.0.2/README.md +200 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/pyproject.toml +3 -3
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/src/rootly_mcp_server/__main__.py +1 -1
- rootly_mcp_server-2.0.2/src/rootly_mcp_server/routemap_server.py +206 -0
- rootly_mcp_server-2.0.0/README.md +0 -169
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/.github/workflows/pypi-release.yml +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/.gitignore +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/.semaphore/deploy.yml +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/.semaphore/semaphore.yml +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/.semaphore/update-task-definition.sh +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/CLAUDE.md +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/Dockerfile +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/LICENSE +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/rootly-mcp-server-demo.gif +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/rootly_fastmcp_server.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/rootly_fastmcp_server_routemap.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/rootly_openapi_loader.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/src/rootly_mcp_server/__init__.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/src/rootly_mcp_server/client.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/src/rootly_mcp_server/data/__init__.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/src/rootly_mcp_server/server.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/src/rootly_mcp_server/test_client.py +0 -0
- {rootly_mcp_server-2.0.0 → rootly_mcp_server-2.0.2}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rootly-mcp-server
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
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
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
15
|
Classifier: Topic :: Software Development :: Build Tools
|
|
16
16
|
Requires-Python: >=3.12
|
|
17
|
-
Requires-Dist: fastmcp==2.
|
|
17
|
+
Requires-Dist: fastmcp==2.10.5
|
|
18
18
|
Requires-Dist: httpx>=0.24.0
|
|
19
19
|
Requires-Dist: pydantic>=2.0.0
|
|
20
20
|
Requires-Dist: requests>=2.28.0
|
|
@@ -25,7 +25,7 @@ Description-Content-Type: text/markdown
|
|
|
25
25
|
|
|
26
26
|
# Rootly MCP Server
|
|
27
27
|
|
|
28
|
-
An MCP server for [Rootly API](https://docs.rootly.com/api-reference/overview) that
|
|
28
|
+
An MCP server for the [Rootly API](https://docs.rootly.com/api-reference/overview) that integrates seamlessly with MCP-compatible editors like Cursor, Windsurf, and Claude. Resolve production incidents in under a minute without leaving your IDE.
|
|
29
29
|
|
|
30
30
|
[](https://cursor.com/install-mcp?name=rootly&config=eyJjb21tYW5kIjoibnB4IC15IG1jcC1yZW1vdGUgaHR0cHM6Ly9tY3Aucm9vdGx5LmNvbS9zc2UgLS1oZWFkZXIgQXV0aG9yaXphdGlvbjoke1JPT1RMWV9BVVRIX0hFQURFUn0iLCJlbnYiOnsiUk9PVExZX0FVVEhfSEVBREVSIjoiQmVhcmVyIDxZT1VSX1JPT1RMWV9BUElfVE9LRU4%2BIn19)
|
|
31
31
|
|
|
@@ -40,18 +40,46 @@ An MCP server for [Rootly API](https://docs.rootly.com/api-reference/overview) t
|
|
|
40
40
|
```
|
|
41
41
|
- [Rootly API token](https://docs.rootly.com/api-reference/overview#how-to-generate-an-api-key%3F)
|
|
42
42
|
|
|
43
|
-
##
|
|
43
|
+
## Installation
|
|
44
44
|
|
|
45
|
-
Install
|
|
45
|
+
Install via our [PyPi package](https://pypi.org/project/rootly-mcp-server/) or by cloning this repository.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Configure your MCP-compatible editor (tested with Cursor and Windsurf) with the following:
|
|
48
|
+
|
|
49
|
+
### With uv
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"rootly": {
|
|
55
|
+
"command": "uv",
|
|
56
|
+
"args": [
|
|
57
|
+
"tool",
|
|
58
|
+
"run",
|
|
59
|
+
"--from",
|
|
60
|
+
"rootly-mcp-server",
|
|
61
|
+
"rootly-mcp-server",
|
|
62
|
+
],
|
|
63
|
+
"env": {
|
|
64
|
+
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### With uv-tool-uvx
|
|
48
72
|
|
|
49
73
|
```json
|
|
50
74
|
{
|
|
51
75
|
"mcpServers": {
|
|
52
76
|
"rootly": {
|
|
53
77
|
"command": "uvx",
|
|
54
|
-
"args": [
|
|
78
|
+
"args": [
|
|
79
|
+
"--from",
|
|
80
|
+
"rootly-mcp-server",
|
|
81
|
+
"rootly-mcp-server",
|
|
82
|
+
],
|
|
55
83
|
"env": {
|
|
56
84
|
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
57
85
|
}
|
|
@@ -60,7 +88,7 @@ To set it up in your favorite MCP-compatible editor (we tested it with Cursor an
|
|
|
60
88
|
}
|
|
61
89
|
```
|
|
62
90
|
|
|
63
|
-
|
|
91
|
+
To customize `allowed_paths` and access additional Rootly API paths, clone the repository and use this configuration:
|
|
64
92
|
|
|
65
93
|
```json
|
|
66
94
|
{
|
|
@@ -83,11 +111,9 @@ If you want to customize `allowed_paths` to access more Rootly API paths, clone
|
|
|
83
111
|
|
|
84
112
|
## Features
|
|
85
113
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
-
|
|
89
|
-
- Default pagination (10 items) for incident endpoints to prevent context window overflow
|
|
90
|
-
- Limits the number of API paths exposed to the AI agent
|
|
114
|
+
- **Dynamic Tool Generation**: Automatically creates MCP resources from Rootly's OpenAPI (Swagger) specification
|
|
115
|
+
- **Smart Pagination**: Defaults to 10 items per request for incident endpoints to prevent context window overflow
|
|
116
|
+
- **API Filtering**: Limits exposed API endpoints for security and performance
|
|
91
117
|
|
|
92
118
|
### Whitelisted Endpoints
|
|
93
119
|
|
|
@@ -124,54 +150,59 @@ By default, the following Rootly API endpoints are exposed to the AI agent (see
|
|
|
124
150
|
/v1/status_pages/{status_page_id}
|
|
125
151
|
```
|
|
126
152
|
|
|
127
|
-
|
|
153
|
+
### Why Path Limiting?
|
|
154
|
+
|
|
155
|
+
We limit exposed API paths for two key reasons:
|
|
128
156
|
|
|
129
|
-
|
|
130
|
-
|
|
157
|
+
1. **Context Management**: Rootly's comprehensive API can overwhelm AI agents, affecting their ability to perform simple tasks effectively
|
|
158
|
+
2. **Security**: Control which information and actions are accessible through the MCP server
|
|
131
159
|
|
|
132
|
-
|
|
160
|
+
To expose additional paths, modify the `allowed_paths` variable in `src/rootly_mcp_server/server.py`.
|
|
133
161
|
|
|
134
|
-
## About
|
|
162
|
+
## About Rootly AI Labs
|
|
135
163
|
|
|
136
|
-
This project was developed by
|
|
164
|
+
This project was developed by [Rootly AI Labs](https://labs.rootly.ai/), where we're building the future of system reliability and operational excellence. As an open-source incubator, we share ideas, experiment, and rapidly prototype solutions that benefit the entire community.
|
|
137
165
|

|
|
138
166
|
|
|
139
167
|
## Developer Setup & Troubleshooting
|
|
140
168
|
|
|
141
|
-
###
|
|
169
|
+
### Prerequisites
|
|
170
|
+
- Python 3.12 or higher
|
|
171
|
+
- [`uv`](https://github.com/astral-sh/uv) for dependency management
|
|
172
|
+
|
|
173
|
+
### 1. Set Up Virtual Environment
|
|
142
174
|
|
|
143
|
-
|
|
175
|
+
Create and activate a virtual environment:
|
|
144
176
|
|
|
145
177
|
```bash
|
|
146
|
-
uv
|
|
178
|
+
uv venv .venv
|
|
179
|
+
source .venv/bin/activate # Always activate before running scripts
|
|
147
180
|
```
|
|
148
181
|
|
|
149
|
-
### 2.
|
|
182
|
+
### 2. Install Dependencies
|
|
150
183
|
|
|
151
|
-
|
|
184
|
+
Install all project dependencies:
|
|
152
185
|
|
|
153
186
|
```bash
|
|
154
|
-
uv
|
|
155
|
-
source .venv/bin/activate
|
|
187
|
+
uv pip install .
|
|
156
188
|
```
|
|
157
189
|
|
|
158
|
-
|
|
190
|
+
To add new dependencies during development:
|
|
191
|
+
```bash
|
|
192
|
+
uv pip install <package>
|
|
193
|
+
```
|
|
159
194
|
|
|
160
|
-
|
|
195
|
+
### 3. Verify Installation
|
|
196
|
+
|
|
197
|
+
Run the test client to ensure everything is configured correctly:
|
|
161
198
|
|
|
162
199
|
```bash
|
|
163
200
|
python test_mcp_client.py
|
|
164
201
|
```
|
|
165
202
|
|
|
166
|
-
###
|
|
167
|
-
|
|
168
|
-
- Always activate your virtual environment before running scripts.
|
|
169
|
-
- If you add new dependencies, use `uv pip install <package>` to keep your environment up to date.
|
|
170
|
-
- If you encounter issues, check your Python version and ensure it matches the project's requirements.
|
|
171
|
-
|
|
172
|
-
### 6. Connecting to Our MCP Server
|
|
203
|
+
### Connect to Hosted MCP Server
|
|
173
204
|
|
|
174
|
-
|
|
205
|
+
Alternatively, connect directly to our hosted MCP server:
|
|
175
206
|
|
|
176
207
|
```json
|
|
177
208
|
{
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Rootly MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP server for the [Rootly API](https://docs.rootly.com/api-reference/overview) that integrates seamlessly with MCP-compatible editors like Cursor, Windsurf, and Claude. Resolve production incidents in under a minute without leaving your IDE.
|
|
4
|
+
|
|
5
|
+
[](https://cursor.com/install-mcp?name=rootly&config=eyJjb21tYW5kIjoibnB4IC15IG1jcC1yZW1vdGUgaHR0cHM6Ly9tY3Aucm9vdGx5LmNvbS9zc2UgLS1oZWFkZXIgQXV0aG9yaXphdGlvbjoke1JPT1RMWV9BVVRIX0hFQURFUn0iLCJlbnYiOnsiUk9PVExZX0FVVEhfSEVBREVSIjoiQmVhcmVyIDxZT1VSX1JPT1RMWV9BUElfVE9LRU4%2BIn19)
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- Python 3.12 or higher
|
|
12
|
+
- `uv` package manager
|
|
13
|
+
```bash
|
|
14
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
15
|
+
```
|
|
16
|
+
- [Rootly API token](https://docs.rootly.com/api-reference/overview#how-to-generate-an-api-key%3F)
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
Install via our [PyPi package](https://pypi.org/project/rootly-mcp-server/) or by cloning this repository.
|
|
21
|
+
|
|
22
|
+
Configure your MCP-compatible editor (tested with Cursor and Windsurf) with the following:
|
|
23
|
+
|
|
24
|
+
### With uv
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"rootly": {
|
|
30
|
+
"command": "uv",
|
|
31
|
+
"args": [
|
|
32
|
+
"tool",
|
|
33
|
+
"run",
|
|
34
|
+
"--from",
|
|
35
|
+
"rootly-mcp-server",
|
|
36
|
+
"rootly-mcp-server",
|
|
37
|
+
],
|
|
38
|
+
"env": {
|
|
39
|
+
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### With uv-tool-uvx
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"mcpServers": {
|
|
51
|
+
"rootly": {
|
|
52
|
+
"command": "uvx",
|
|
53
|
+
"args": [
|
|
54
|
+
"--from",
|
|
55
|
+
"rootly-mcp-server",
|
|
56
|
+
"rootly-mcp-server",
|
|
57
|
+
],
|
|
58
|
+
"env": {
|
|
59
|
+
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
To customize `allowed_paths` and access additional Rootly API paths, clone the repository and use this configuration:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"rootly": {
|
|
72
|
+
"command": "uv",
|
|
73
|
+
"args": [
|
|
74
|
+
"run",
|
|
75
|
+
"--directory",
|
|
76
|
+
"/path/to/rootly-mcp-server",
|
|
77
|
+
"rootly-mcp-server"
|
|
78
|
+
],
|
|
79
|
+
"env": {
|
|
80
|
+
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Features
|
|
88
|
+
|
|
89
|
+
- **Dynamic Tool Generation**: Automatically creates MCP resources from Rootly's OpenAPI (Swagger) specification
|
|
90
|
+
- **Smart Pagination**: Defaults to 10 items per request for incident endpoints to prevent context window overflow
|
|
91
|
+
- **API Filtering**: Limits exposed API endpoints for security and performance
|
|
92
|
+
|
|
93
|
+
### Whitelisted Endpoints
|
|
94
|
+
|
|
95
|
+
By default, the following Rootly API endpoints are exposed to the AI agent (see `allowed_paths` in `src/rootly_mcp_server/server.py`):
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
/v1/incidents
|
|
99
|
+
/v1/incidents/{incident_id}/alerts
|
|
100
|
+
/v1/alerts
|
|
101
|
+
/v1/alerts/{alert_id}
|
|
102
|
+
/v1/severities
|
|
103
|
+
/v1/severities/{severity_id}
|
|
104
|
+
/v1/teams
|
|
105
|
+
/v1/teams/{team_id}
|
|
106
|
+
/v1/services
|
|
107
|
+
/v1/services/{service_id}
|
|
108
|
+
/v1/functionalities
|
|
109
|
+
/v1/functionalities/{functionality_id}
|
|
110
|
+
/v1/incident_types
|
|
111
|
+
/v1/incident_types/{incident_type_id}
|
|
112
|
+
/v1/incident_action_items
|
|
113
|
+
/v1/incident_action_items/{incident_action_item_id}
|
|
114
|
+
/v1/incidents/{incident_id}/action_items
|
|
115
|
+
/v1/workflows
|
|
116
|
+
/v1/workflows/{workflow_id}
|
|
117
|
+
/v1/workflow_runs
|
|
118
|
+
/v1/workflow_runs/{workflow_run_id}
|
|
119
|
+
/v1/environments
|
|
120
|
+
/v1/environments/{environment_id}
|
|
121
|
+
/v1/users
|
|
122
|
+
/v1/users/{user_id}
|
|
123
|
+
/v1/users/me
|
|
124
|
+
/v1/status_pages
|
|
125
|
+
/v1/status_pages/{status_page_id}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Why Path Limiting?
|
|
129
|
+
|
|
130
|
+
We limit exposed API paths for two key reasons:
|
|
131
|
+
|
|
132
|
+
1. **Context Management**: Rootly's comprehensive API can overwhelm AI agents, affecting their ability to perform simple tasks effectively
|
|
133
|
+
2. **Security**: Control which information and actions are accessible through the MCP server
|
|
134
|
+
|
|
135
|
+
To expose additional paths, modify the `allowed_paths` variable in `src/rootly_mcp_server/server.py`.
|
|
136
|
+
|
|
137
|
+
## About Rootly AI Labs
|
|
138
|
+
|
|
139
|
+
This project was developed by [Rootly AI Labs](https://labs.rootly.ai/), where we're building the future of system reliability and operational excellence. As an open-source incubator, we share ideas, experiment, and rapidly prototype solutions that benefit the entire community.
|
|
140
|
+

|
|
141
|
+
|
|
142
|
+
## Developer Setup & Troubleshooting
|
|
143
|
+
|
|
144
|
+
### Prerequisites
|
|
145
|
+
- Python 3.12 or higher
|
|
146
|
+
- [`uv`](https://github.com/astral-sh/uv) for dependency management
|
|
147
|
+
|
|
148
|
+
### 1. Set Up Virtual Environment
|
|
149
|
+
|
|
150
|
+
Create and activate a virtual environment:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
uv venv .venv
|
|
154
|
+
source .venv/bin/activate # Always activate before running scripts
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 2. Install Dependencies
|
|
158
|
+
|
|
159
|
+
Install all project dependencies:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
uv pip install .
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
To add new dependencies during development:
|
|
166
|
+
```bash
|
|
167
|
+
uv pip install <package>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 3. Verify Installation
|
|
171
|
+
|
|
172
|
+
Run the test client to ensure everything is configured correctly:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
python test_mcp_client.py
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Connect to Hosted MCP Server
|
|
179
|
+
|
|
180
|
+
Alternatively, connect directly to our hosted MCP server:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"mcpServers": {
|
|
185
|
+
"rootly": {
|
|
186
|
+
"command": "npx",
|
|
187
|
+
"args": [
|
|
188
|
+
"-y",
|
|
189
|
+
"mcp-remote",
|
|
190
|
+
"https://mcp.rootly.com/sse",
|
|
191
|
+
"--header",
|
|
192
|
+
"Authorization:${ROOTLY_AUTH_HEADER}"
|
|
193
|
+
],
|
|
194
|
+
"env": {
|
|
195
|
+
"ROOTLY_AUTH_HEADER": "Bearer <YOUR_ROOTLY_API_TOKEN>"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "rootly-mcp-server"
|
|
3
|
-
version = "2.0.
|
|
3
|
+
version = "2.0.2"
|
|
4
4
|
description = "A Model Context Protocol server for Rootly APIs using OpenAPI spec"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -16,9 +16,9 @@ classifiers = [
|
|
|
16
16
|
"Programming Language :: Python :: 3.12",
|
|
17
17
|
]
|
|
18
18
|
dependencies = [
|
|
19
|
-
# Pinned to 2.
|
|
19
|
+
# Pinned to 2.10.5 to avoid unexpected breaking changes - to upgrade, just bump the pinned version here
|
|
20
20
|
# and run `uv sync` to update the lockfile.
|
|
21
|
-
"fastmcp==2.
|
|
21
|
+
"fastmcp==2.10.5",
|
|
22
22
|
"requests>=2.28.0", # For API calls
|
|
23
23
|
"httpx>=0.24.0", # For async HTTP client
|
|
24
24
|
"pydantic>=2.0.0", # For data validation
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Rootly FastMCP Server (RouteMap Version)
|
|
4
|
+
|
|
5
|
+
Alternative implementation using FastMCP's RouteMap system for filtering
|
|
6
|
+
instead of pre-filtering the OpenAPI spec.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import httpx
|
|
10
|
+
from fastmcp import FastMCP
|
|
11
|
+
from fastmcp.server.openapi import RouteMap, MCPType
|
|
12
|
+
import os
|
|
13
|
+
import logging
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Optional, List
|
|
17
|
+
|
|
18
|
+
# Import the shared OpenAPI loader
|
|
19
|
+
sys.path.append(str(Path(__file__).parent.parent.parent))
|
|
20
|
+
from rootly_openapi_loader import load_rootly_openapi_spec
|
|
21
|
+
|
|
22
|
+
# Configure logging
|
|
23
|
+
logging.basicConfig(level=logging.INFO)
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
def create_rootly_mcp_server(
|
|
27
|
+
swagger_path: Optional[str] = None,
|
|
28
|
+
name: str = "Rootly API Server (RouteMap Filtered)",
|
|
29
|
+
allowed_paths: Optional[List[str]] = None,
|
|
30
|
+
hosted: bool = False,
|
|
31
|
+
base_url: Optional[str] = None,
|
|
32
|
+
):
|
|
33
|
+
"""Create and configure the Rootly MCP server using RouteMap filtering."""
|
|
34
|
+
|
|
35
|
+
# Get Rootly API token from environment
|
|
36
|
+
ROOTLY_API_TOKEN = os.getenv("ROOTLY_API_TOKEN")
|
|
37
|
+
if not ROOTLY_API_TOKEN:
|
|
38
|
+
raise ValueError("ROOTLY_API_TOKEN environment variable is required")
|
|
39
|
+
|
|
40
|
+
logger.info("Creating authenticated HTTP client...")
|
|
41
|
+
# Create authenticated HTTP client
|
|
42
|
+
client = httpx.AsyncClient(
|
|
43
|
+
base_url=base_url or "https://api.rootly.com",
|
|
44
|
+
headers={
|
|
45
|
+
"Authorization": f"Bearer {ROOTLY_API_TOKEN}",
|
|
46
|
+
"Content-Type": "application/vnd.api+json",
|
|
47
|
+
"User-Agent": "Rootly-FastMCP-Server/1.0"
|
|
48
|
+
},
|
|
49
|
+
timeout=30.0
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
logger.info("Loading OpenAPI specification...")
|
|
53
|
+
# Load OpenAPI spec with smart fallback logic
|
|
54
|
+
openapi_spec = load_rootly_openapi_spec()
|
|
55
|
+
logger.info("✅ Successfully loaded OpenAPI specification")
|
|
56
|
+
|
|
57
|
+
logger.info("Fixing OpenAPI spec for FastMCP compatibility...")
|
|
58
|
+
# Fix array types for FastMCP compatibility
|
|
59
|
+
def fix_array_types(obj):
|
|
60
|
+
if isinstance(obj, dict):
|
|
61
|
+
keys_to_process = list(obj.keys())
|
|
62
|
+
for key in keys_to_process:
|
|
63
|
+
value = obj[key]
|
|
64
|
+
if key == 'type' and isinstance(value, list):
|
|
65
|
+
non_null_types = [t for t in value if t != 'null']
|
|
66
|
+
if len(non_null_types) >= 1:
|
|
67
|
+
obj[key] = non_null_types[0]
|
|
68
|
+
obj['nullable'] = True
|
|
69
|
+
else:
|
|
70
|
+
fix_array_types(value)
|
|
71
|
+
elif isinstance(obj, list):
|
|
72
|
+
for item in obj:
|
|
73
|
+
fix_array_types(item)
|
|
74
|
+
|
|
75
|
+
fix_array_types(openapi_spec)
|
|
76
|
+
logger.info("✅ Fixed OpenAPI spec compatibility issues")
|
|
77
|
+
|
|
78
|
+
logger.info("Creating FastMCP server with RouteMap filtering...")
|
|
79
|
+
|
|
80
|
+
# Define custom route maps for filtering specific endpoints
|
|
81
|
+
route_maps = [
|
|
82
|
+
# Core incident management
|
|
83
|
+
RouteMap(
|
|
84
|
+
pattern=r"^/v1/incidents$",
|
|
85
|
+
mcp_type=MCPType.TOOL
|
|
86
|
+
),
|
|
87
|
+
RouteMap(
|
|
88
|
+
pattern=r"^/v1/incidents/\{incident_id\}/alerts$",
|
|
89
|
+
mcp_type=MCPType.TOOL
|
|
90
|
+
),
|
|
91
|
+
RouteMap(
|
|
92
|
+
pattern=r"^/v1/incidents/\{incident_id\}/action_items$",
|
|
93
|
+
mcp_type=MCPType.TOOL
|
|
94
|
+
),
|
|
95
|
+
|
|
96
|
+
# Alert management
|
|
97
|
+
RouteMap(
|
|
98
|
+
pattern=r"^/v1/alerts$",
|
|
99
|
+
mcp_type=MCPType.TOOL
|
|
100
|
+
),
|
|
101
|
+
RouteMap(
|
|
102
|
+
pattern=r"^/v1/alerts/\{id\}$",
|
|
103
|
+
mcp_type=MCPType.TOOL
|
|
104
|
+
),
|
|
105
|
+
|
|
106
|
+
# Configuration entities
|
|
107
|
+
RouteMap(
|
|
108
|
+
pattern=r"^/v1/severities(\{id\})?$",
|
|
109
|
+
mcp_type=MCPType.TOOL
|
|
110
|
+
),
|
|
111
|
+
RouteMap(
|
|
112
|
+
pattern=r"^/v1/incident_types(\{id\})?$",
|
|
113
|
+
mcp_type=MCPType.TOOL
|
|
114
|
+
),
|
|
115
|
+
RouteMap(
|
|
116
|
+
pattern=r"^/v1/functionalities(\{id\})?$",
|
|
117
|
+
mcp_type=MCPType.TOOL
|
|
118
|
+
),
|
|
119
|
+
|
|
120
|
+
# Organization
|
|
121
|
+
RouteMap(
|
|
122
|
+
pattern=r"^/v1/teams(\{id\})?$",
|
|
123
|
+
mcp_type=MCPType.TOOL
|
|
124
|
+
),
|
|
125
|
+
RouteMap(
|
|
126
|
+
pattern=r"^/v1/users(\{id\}|/me)?$",
|
|
127
|
+
mcp_type=MCPType.TOOL
|
|
128
|
+
),
|
|
129
|
+
|
|
130
|
+
# Infrastructure
|
|
131
|
+
RouteMap(
|
|
132
|
+
pattern=r"^/v1/services(\{id\})?$",
|
|
133
|
+
mcp_type=MCPType.TOOL
|
|
134
|
+
),
|
|
135
|
+
RouteMap(
|
|
136
|
+
pattern=r"^/v1/environments(\{id\})?$",
|
|
137
|
+
mcp_type=MCPType.TOOL
|
|
138
|
+
),
|
|
139
|
+
|
|
140
|
+
# Action items
|
|
141
|
+
RouteMap(
|
|
142
|
+
pattern=r"^/v1/incident_action_items(\{id\})?$",
|
|
143
|
+
mcp_type=MCPType.TOOL
|
|
144
|
+
),
|
|
145
|
+
|
|
146
|
+
# Workflows
|
|
147
|
+
RouteMap(
|
|
148
|
+
pattern=r"^/v1/workflows(\{id\})?$",
|
|
149
|
+
mcp_type=MCPType.TOOL
|
|
150
|
+
),
|
|
151
|
+
RouteMap(
|
|
152
|
+
pattern=r"^/v1/workflow_runs(\{id\})?$",
|
|
153
|
+
mcp_type=MCPType.TOOL
|
|
154
|
+
),
|
|
155
|
+
|
|
156
|
+
# Status pages
|
|
157
|
+
RouteMap(
|
|
158
|
+
pattern=r"^/v1/status_pages(\{id\})?$",
|
|
159
|
+
mcp_type=MCPType.TOOL
|
|
160
|
+
),
|
|
161
|
+
|
|
162
|
+
# Exclude everything else
|
|
163
|
+
RouteMap(
|
|
164
|
+
pattern=r".*",
|
|
165
|
+
mcp_type=MCPType.EXCLUDE
|
|
166
|
+
)
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
# Create MCP server with custom route maps
|
|
170
|
+
mcp = FastMCP.from_openapi(
|
|
171
|
+
openapi_spec=openapi_spec,
|
|
172
|
+
client=client,
|
|
173
|
+
name=name,
|
|
174
|
+
timeout=30.0,
|
|
175
|
+
tags={"rootly", "incident-management", "evaluation"},
|
|
176
|
+
route_maps=route_maps
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
logger.info(f"✅ Created MCP server with RouteMap filtering successfully")
|
|
180
|
+
logger.info("🚀 Selected Rootly API endpoints are now available as MCP tools")
|
|
181
|
+
|
|
182
|
+
return mcp
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def main():
|
|
188
|
+
"""Main entry point."""
|
|
189
|
+
try:
|
|
190
|
+
logger.info("🚀 Starting Rootly FastMCP Server (RouteMap Version)...")
|
|
191
|
+
mcp = create_rootly_mcp_server()
|
|
192
|
+
|
|
193
|
+
logger.info("🌐 Server starting on stdio transport...")
|
|
194
|
+
logger.info("Ready for MCP client connections!")
|
|
195
|
+
|
|
196
|
+
# Run the MCP server
|
|
197
|
+
mcp.run()
|
|
198
|
+
|
|
199
|
+
except KeyboardInterrupt:
|
|
200
|
+
logger.info("🛑 Server stopped by user")
|
|
201
|
+
except Exception as e:
|
|
202
|
+
logger.error(f"❌ Server error: {e}")
|
|
203
|
+
raise
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__":
|
|
206
|
+
main()
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
# Rootly MCP Server
|
|
2
|
-
|
|
3
|
-
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.
|
|
4
|
-
|
|
5
|
-
[](https://cursor.com/install-mcp?name=rootly&config=eyJjb21tYW5kIjoibnB4IC15IG1jcC1yZW1vdGUgaHR0cHM6Ly9tY3Aucm9vdGx5LmNvbS9zc2UgLS1oZWFkZXIgQXV0aG9yaXphdGlvbjoke1JPT1RMWV9BVVRIX0hFQURFUn0iLCJlbnYiOnsiUk9PVExZX0FVVEhfSEVBREVSIjoiQmVhcmVyIDxZT1VSX1JPT1RMWV9BUElfVE9LRU4%2BIn19)
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
## Prerequisites
|
|
10
|
-
|
|
11
|
-
- Python 3.12 or higher
|
|
12
|
-
- `uv` package manager
|
|
13
|
-
```bash
|
|
14
|
-
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
15
|
-
```
|
|
16
|
-
- [Rootly API token](https://docs.rootly.com/api-reference/overview#how-to-generate-an-api-key%3F)
|
|
17
|
-
|
|
18
|
-
## Run it in your IDE
|
|
19
|
-
|
|
20
|
-
Install with our [PyPi package](https://pypi.org/project/rootly-mcp-server/) or by cloning this repo.
|
|
21
|
-
|
|
22
|
-
To set it up in your favorite MCP-compatible editor (we tested it with Cursor and Windsurf), here is the config :
|
|
23
|
-
|
|
24
|
-
```json
|
|
25
|
-
{
|
|
26
|
-
"mcpServers": {
|
|
27
|
-
"rootly": {
|
|
28
|
-
"command": "uvx",
|
|
29
|
-
"args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
|
|
30
|
-
"env": {
|
|
31
|
-
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
If you want to customize `allowed_paths` to access more Rootly API paths, clone the package and use this config.
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"mcpServers": {
|
|
43
|
-
"rootly": {
|
|
44
|
-
"command": "uv",
|
|
45
|
-
"args": [
|
|
46
|
-
"run",
|
|
47
|
-
"--directory",
|
|
48
|
-
"/path/to/rootly-mcp-server",
|
|
49
|
-
"rootly-mcp-server"
|
|
50
|
-
],
|
|
51
|
-
"env": {
|
|
52
|
-
"ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Features
|
|
60
|
-
|
|
61
|
-
This server dynamically generates MCP resources based on Rootly's OpenAPI (Swagger) specification:
|
|
62
|
-
|
|
63
|
-
- Dynamically generated MCP tools based on Rootly's OpenAPI specification
|
|
64
|
-
- Default pagination (10 items) for incident endpoints to prevent context window overflow
|
|
65
|
-
- Limits the number of API paths exposed to the AI agent
|
|
66
|
-
|
|
67
|
-
### Whitelisted Endpoints
|
|
68
|
-
|
|
69
|
-
By default, the following Rootly API endpoints are exposed to the AI agent (see `allowed_paths` in `src/rootly_mcp_server/server.py`):
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
/v1/incidents
|
|
73
|
-
/v1/incidents/{incident_id}/alerts
|
|
74
|
-
/v1/alerts
|
|
75
|
-
/v1/alerts/{alert_id}
|
|
76
|
-
/v1/severities
|
|
77
|
-
/v1/severities/{severity_id}
|
|
78
|
-
/v1/teams
|
|
79
|
-
/v1/teams/{team_id}
|
|
80
|
-
/v1/services
|
|
81
|
-
/v1/services/{service_id}
|
|
82
|
-
/v1/functionalities
|
|
83
|
-
/v1/functionalities/{functionality_id}
|
|
84
|
-
/v1/incident_types
|
|
85
|
-
/v1/incident_types/{incident_type_id}
|
|
86
|
-
/v1/incident_action_items
|
|
87
|
-
/v1/incident_action_items/{incident_action_item_id}
|
|
88
|
-
/v1/incidents/{incident_id}/action_items
|
|
89
|
-
/v1/workflows
|
|
90
|
-
/v1/workflows/{workflow_id}
|
|
91
|
-
/v1/workflow_runs
|
|
92
|
-
/v1/workflow_runs/{workflow_run_id}
|
|
93
|
-
/v1/environments
|
|
94
|
-
/v1/environments/{environment_id}
|
|
95
|
-
/v1/users
|
|
96
|
-
/v1/users/{user_id}
|
|
97
|
-
/v1/users/me
|
|
98
|
-
/v1/status_pages
|
|
99
|
-
/v1/status_pages/{status_page_id}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
We limited the number of API paths exposed for 2 reasons:
|
|
103
|
-
|
|
104
|
-
- Context size: because [Rootly's API](https://docs.rootly.com/api-reference/overview) is very rich in paths, AI agents can get overwhelmed and not perform simple actions properly.
|
|
105
|
-
- Security: if you want to limit the type of information or actions that users can access through the MCP server
|
|
106
|
-
|
|
107
|
-
If you want to make more paths available, edit the variable `allowed_paths` in `src/rootly_mcp_server/server.py`.
|
|
108
|
-
|
|
109
|
-
## About the Rootly AI Labs
|
|
110
|
-
|
|
111
|
-
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.
|
|
112
|
-

|
|
113
|
-
|
|
114
|
-
## Developer Setup & Troubleshooting
|
|
115
|
-
|
|
116
|
-
### 1. Install dependencies with `uv`
|
|
117
|
-
|
|
118
|
-
This project uses [`uv`](https://github.com/astral-sh/uv) for fast dependency management. To install all dependencies from your `pyproject.toml`:
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
uv pip install .
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### 2. Using a virtual environment
|
|
125
|
-
|
|
126
|
-
It is recommended to use a virtual environment for development:
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
uv venv .venv
|
|
130
|
-
source .venv/bin/activate
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### 3. Running the test client
|
|
134
|
-
|
|
135
|
-
To run the test client and verify your setup:
|
|
136
|
-
|
|
137
|
-
```bash
|
|
138
|
-
python test_mcp_client.py
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### 5. General tips
|
|
142
|
-
|
|
143
|
-
- Always activate your virtual environment before running scripts.
|
|
144
|
-
- If you add new dependencies, use `uv pip install <package>` to keep your environment up to date.
|
|
145
|
-
- If you encounter issues, check your Python version and ensure it matches the project's requirements.
|
|
146
|
-
|
|
147
|
-
### 6. Connecting to Our MCP Server
|
|
148
|
-
|
|
149
|
-
You can configure your client to connect directly to our hosted MCP server:
|
|
150
|
-
|
|
151
|
-
```json
|
|
152
|
-
{
|
|
153
|
-
"mcpServers": {
|
|
154
|
-
"rootly": {
|
|
155
|
-
"command": "npx",
|
|
156
|
-
"args": [
|
|
157
|
-
"-y",
|
|
158
|
-
"mcp-remote",
|
|
159
|
-
"https://mcp.rootly.com/sse",
|
|
160
|
-
"--header",
|
|
161
|
-
"Authorization:${ROOTLY_AUTH_HEADER}"
|
|
162
|
-
],
|
|
163
|
-
"env": {
|
|
164
|
-
"ROOTLY_AUTH_HEADER": "Bearer <YOUR_ROOTLY_API_TOKEN>"
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|