rootly-mcp-server 2.0.0__py3-none-any.whl → 2.0.2__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/__main__.py +1 -1
- rootly_mcp_server/routemap_server.py +206 -0
- {rootly_mcp_server-2.0.0.dist-info → rootly_mcp_server-2.0.2.dist-info}/METADATA +67 -36
- {rootly_mcp_server-2.0.0.dist-info → rootly_mcp_server-2.0.2.dist-info}/RECORD +7 -6
- {rootly_mcp_server-2.0.0.dist-info → rootly_mcp_server-2.0.2.dist-info}/WHEEL +0 -0
- {rootly_mcp_server-2.0.0.dist-info → rootly_mcp_server-2.0.2.dist-info}/entry_points.txt +0 -0
- {rootly_mcp_server-2.0.0.dist-info → rootly_mcp_server-2.0.2.dist-info}/licenses/LICENSE +0 -0
rootly_mcp_server/__main__.py
CHANGED
|
@@ -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,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
|
{
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
rootly_mcp_server/__init__.py,sha256=H3Dd4Od-PEff8VdbMgnblS6cCEBCb9XqYdI_-wmtQqk,628
|
|
2
|
-
rootly_mcp_server/__main__.py,sha256=
|
|
2
|
+
rootly_mcp_server/__main__.py,sha256=yOBEaQWEMZvsC7zT5no7yo1ISIvfeq7NlIPflBMoAFI,6447
|
|
3
3
|
rootly_mcp_server/client.py,sha256=05TsHVJ3WtLH0k4R19Yzwwx4xcmjCKH6hS3uKcTMwRA,4678
|
|
4
|
+
rootly_mcp_server/routemap_server.py,sha256=SloHu4ZTaFBusoIlhM2h7jfB8kFtMQrT3M_n7JAekug,6101
|
|
4
5
|
rootly_mcp_server/server.py,sha256=2paE39caYRVuQG4yWEEOqZewbvpFREmf-J01lPQ5elw,19756
|
|
5
6
|
rootly_mcp_server/test_client.py,sha256=8p1aJHrEt_Tj2NuJzTnTHw-ZeW816P99fJi5bhPidyc,5119
|
|
6
7
|
rootly_mcp_server/data/__init__.py,sha256=fO8a0bQnRVEoRMHKvhFzj10bhoaw7VsI51czc2MsUm4,143
|
|
7
|
-
rootly_mcp_server-2.0.
|
|
8
|
-
rootly_mcp_server-2.0.
|
|
9
|
-
rootly_mcp_server-2.0.
|
|
10
|
-
rootly_mcp_server-2.0.
|
|
11
|
-
rootly_mcp_server-2.0.
|
|
8
|
+
rootly_mcp_server-2.0.2.dist-info/METADATA,sha256=gVQHYX9Z8KlzftzQZluRXsJ45K3kEkzxkxTpyHSdyCM,6141
|
|
9
|
+
rootly_mcp_server-2.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
10
|
+
rootly_mcp_server-2.0.2.dist-info/entry_points.txt,sha256=NE33b8VgigVPGBkboyo6pvN1Vz35HZtLybxMO4Q03PI,70
|
|
11
|
+
rootly_mcp_server-2.0.2.dist-info/licenses/LICENSE,sha256=c9w9ZZGl14r54tsP40oaq5adTVX_HMNHozPIH2ymzmw,11341
|
|
12
|
+
rootly_mcp_server-2.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|