rootly-mcp-server 2.0.0__py3-none-any.whl → 2.0.1__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.
@@ -12,7 +12,7 @@ import sys
12
12
  from pathlib import Path
13
13
  from typing import Optional, List
14
14
 
15
- from rootly_mcp_server.server import create_rootly_mcp_server
15
+ from .routemap_server import create_rootly_mcp_server
16
16
 
17
17
 
18
18
  def parse_args():
@@ -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.0
3
+ Version: 2.0.1
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
@@ -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 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.
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
  [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](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
- ## Run it in your IDE
43
+ ## Installation
44
44
 
45
- Install with our [PyPi package](https://pypi.org/project/rootly-mcp-server/) or by cloning this repo.
45
+ Install via our [PyPi package](https://pypi.org/project/rootly-mcp-server/) or by cloning this repository.
46
46
 
47
- To set it up in your favorite MCP-compatible editor (we tested it with Cursor and Windsurf), here is the config :
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": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
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
- If you want to customize `allowed_paths` to access more Rootly API paths, clone the package and use this config.
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
- This server dynamically generates MCP resources based on Rootly's OpenAPI (Swagger) specification:
87
-
88
- - Dynamically generated MCP tools based on Rootly's OpenAPI specification
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
- We limited the number of API paths exposed for 2 reasons:
153
+ ### Why Path Limiting?
154
+
155
+ We limit exposed API paths for two key reasons:
128
156
 
129
- - 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.
130
- - Security: if you want to limit the type of information or actions that users can access through the MCP server
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
- If you want to make more paths available, edit the variable `allowed_paths` in `src/rootly_mcp_server/server.py`.
160
+ To expose additional paths, modify the `allowed_paths` variable in `src/rootly_mcp_server/server.py`.
133
161
 
134
- ## About the Rootly AI Labs
162
+ ## About Rootly AI Labs
135
163
 
136
- 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.
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
  ![Rootly AI logo](https://github.com/Rootly-AI-Labs/EventOrOutage/raw/main/rootly-ai.png)
138
166
 
139
167
  ## Developer Setup & Troubleshooting
140
168
 
141
- ### 1. Install dependencies with `uv`
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
- This project uses [`uv`](https://github.com/astral-sh/uv) for fast dependency management. To install all dependencies from your `pyproject.toml`:
175
+ Create and activate a virtual environment:
144
176
 
145
177
  ```bash
146
- uv pip install .
178
+ uv venv .venv
179
+ source .venv/bin/activate # Always activate before running scripts
147
180
  ```
148
181
 
149
- ### 2. Using a virtual environment
182
+ ### 2. Install Dependencies
150
183
 
151
- It is recommended to use a virtual environment for development:
184
+ Install all project dependencies:
152
185
 
153
186
  ```bash
154
- uv venv .venv
155
- source .venv/bin/activate
187
+ uv pip install .
156
188
  ```
157
189
 
158
- ### 3. Running the test client
190
+ To add new dependencies during development:
191
+ ```bash
192
+ uv pip install <package>
193
+ ```
159
194
 
160
- To run the test client and verify your setup:
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
- ### 5. General tips
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
- You can configure your client to connect directly to our hosted MCP server:
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=57YiODNe__-s_JSlfQIc5zSnJ4oWo7PTEU_dVr2L5gE,6455
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.0.dist-info/METADATA,sha256=74MSyB_onB347uVI81W8lBgzgzJKEAR1sMqYWpGWTYk,6120
8
- rootly_mcp_server-2.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
9
- rootly_mcp_server-2.0.0.dist-info/entry_points.txt,sha256=NE33b8VgigVPGBkboyo6pvN1Vz35HZtLybxMO4Q03PI,70
10
- rootly_mcp_server-2.0.0.dist-info/licenses/LICENSE,sha256=c9w9ZZGl14r54tsP40oaq5adTVX_HMNHozPIH2ymzmw,11341
11
- rootly_mcp_server-2.0.0.dist-info/RECORD,,
8
+ rootly_mcp_server-2.0.1.dist-info/METADATA,sha256=SNQJLqa2_tBEV3ZRycB8NgnDt6jaw5UvuW1zMbI_R-A,6140
9
+ rootly_mcp_server-2.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
+ rootly_mcp_server-2.0.1.dist-info/entry_points.txt,sha256=NE33b8VgigVPGBkboyo6pvN1Vz35HZtLybxMO4Q03PI,70
11
+ rootly_mcp_server-2.0.1.dist-info/licenses/LICENSE,sha256=c9w9ZZGl14r54tsP40oaq5adTVX_HMNHozPIH2ymzmw,11341
12
+ rootly_mcp_server-2.0.1.dist-info/RECORD,,