rootly-mcp-server 1.0.0__tar.gz → 2.0.1__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.
Files changed (30) hide show
  1. rootly_mcp_server-2.0.1/.github/workflows/pypi-release.yml +33 -0
  2. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/.gitignore +15 -1
  3. rootly_mcp_server-2.0.1/.semaphore/deploy.yml +55 -0
  4. rootly_mcp_server-2.0.1/.semaphore/semaphore.yml +45 -0
  5. rootly_mcp_server-2.0.1/.semaphore/update-task-definition.sh +43 -0
  6. rootly_mcp_server-2.0.1/CLAUDE.md +68 -0
  7. rootly_mcp_server-2.0.1/Dockerfile +28 -0
  8. rootly_mcp_server-2.0.1/PKG-INFO +225 -0
  9. rootly_mcp_server-2.0.1/README.md +200 -0
  10. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/pyproject.toml +12 -16
  11. rootly_mcp_server-2.0.1/rootly_fastmcp_server.py +148 -0
  12. rootly_mcp_server-2.0.1/rootly_fastmcp_server_routemap.py +210 -0
  13. rootly_mcp_server-2.0.1/rootly_openapi_loader.py +96 -0
  14. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/src/rootly_mcp_server/__init__.py +1 -1
  15. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/src/rootly_mcp_server/__main__.py +78 -10
  16. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/src/rootly_mcp_server/client.py +40 -26
  17. rootly_mcp_server-2.0.1/src/rootly_mcp_server/routemap_server.py +206 -0
  18. rootly_mcp_server-2.0.1/src/rootly_mcp_server/server.py +525 -0
  19. rootly_mcp_server-2.0.1/src/rootly_mcp_server/test_client.py +148 -0
  20. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/uv.lock +164 -13
  21. rootly_mcp_server-1.0.0/PKG-INFO +0 -128
  22. rootly_mcp_server-1.0.0/README.md +0 -104
  23. rootly_mcp_server-1.0.0/src/rootly_mcp_server/data/swagger.json +0 -1
  24. rootly_mcp_server-1.0.0/src/rootly_mcp_server/server.py +0 -451
  25. rootly_mcp_server-1.0.0/src/rootly_mcp_server/test_client.py +0 -67
  26. rootly_mcp_server-1.0.0/swagger.json +0 -1
  27. rootly_mcp_server-1.0.0/test_mcp_client.py +0 -106
  28. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/LICENSE +0 -0
  29. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/rootly-mcp-server-demo.gif +0 -0
  30. {rootly_mcp_server-1.0.0 → rootly_mcp_server-2.0.1}/src/rootly_mcp_server/data/__init__.py +0 -0
@@ -0,0 +1,33 @@
1
+ name: Publish Python 🐍 distribution 📦 to PyPI on tag
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - '*'
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout code
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: '3.12'
19
+
20
+ - name: Install uv and build tools
21
+ run: |
22
+ pip install build twine
23
+
24
+ - name: Build package
25
+ run: |
26
+ python -m build
27
+
28
+ - name: Publish to PyPI
29
+ env:
30
+ TWINE_USERNAME: __token__
31
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
32
+ run: |
33
+ twine upload dist/*
@@ -77,6 +77,7 @@ target/
77
77
 
78
78
  # Jupyter Notebook
79
79
  .ipynb_checkpoints
80
+ *.ipynb
80
81
 
81
82
  # IPython
82
83
  profile_default/
@@ -173,4 +174,17 @@ cython_debug/
173
174
  # PyPI configuration file
174
175
  .pypirc
175
176
 
176
- .cursor
177
+ # IDE/Editor files
178
+ .cursor
179
+ .vscode/
180
+ *.swp
181
+ *.swo
182
+ *~
183
+
184
+ # MCP Server specific
185
+ # Downloaded swagger.json files (auto-fetched from URL)
186
+ swagger.json
187
+
188
+ # Test outputs and temporary files
189
+ test_output/
190
+ *.tmp
@@ -0,0 +1,55 @@
1
+ version: v1.0
2
+ name: Build and Deploy
3
+
4
+ queue:
5
+ name: Deployment Queue
6
+ scope: project
7
+
8
+ agent:
9
+ machine:
10
+ type: r1-standard-4
11
+ os_image: ubuntu2204
12
+
13
+ blocks:
14
+ - name: 'Deploy'
15
+ dependencies: []
16
+ task:
17
+ secrets:
18
+ - name: 'AWS Credentials'
19
+ prologue:
20
+ commands:
21
+ - export AWS_PROFILE=production
22
+ - export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
23
+ - aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com
24
+ jobs:
25
+ - name: Deploy
26
+ commands:
27
+ - checkout
28
+ - |
29
+ export TASK_FAMILY=rootly-mcp-server
30
+ export CONTAINER_NAME=mcp
31
+ export IMAGE=657716690934.dkr.ecr.us-east-1.amazonaws.com/rootly/mcp:${SEMAPHORE_GIT_SHA}
32
+ NEW_TASK_DEFINITION_ARN=$(./.semaphore/update-task-definition.sh)
33
+
34
+ aws ecs update-service \
35
+ --cluster rootly-web \
36
+ --service rootly-mcp-server \
37
+ --task-definition "$NEW_TASK_DEFINITION_ARN" \
38
+ --deployment-configuration "deploymentCircuitBreaker={enable=true,rollback=true},maximumPercent=200,minimumHealthyPercent=100" \
39
+ --force-new-deployment >/dev/null
40
+
41
+ echo "Waiting for service to stabilize at the new revision..."
42
+
43
+ # Wait for the service to stabilize for up to 10 minutes
44
+ for i in {1..40}; do
45
+ if aws ecs describe-services --cluster rootly-web --service rootly-mcp-server --output json | jq -e \
46
+ '.services | map(select((.deployments | length) != 1 or .runningCount != .desiredCount)) | length == 0' >/dev/null; then
47
+ break
48
+ fi
49
+ sleep 15
50
+ done
51
+
52
+ if [ $i -eq 40 ]; then
53
+ echo "Service failed to stabilize after 10 minutes"
54
+ exit 1
55
+ fi
@@ -0,0 +1,45 @@
1
+ version: v1.0
2
+ name: Build and Deploy
3
+
4
+ queue:
5
+ name: Build Queue
6
+ scope: project
7
+
8
+ auto_cancel:
9
+ queued:
10
+ when: 'true'
11
+
12
+ agent:
13
+ machine:
14
+ type: r1-standard-4
15
+ os_image: ubuntu2204
16
+
17
+ blocks:
18
+ - name: 'Build'
19
+ dependencies: []
20
+ task:
21
+ secrets:
22
+ - name: 'AWS Credentials'
23
+ prologue:
24
+ commands:
25
+ - export AWS_PROFILE=production
26
+ - export AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
27
+ - aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com
28
+ jobs:
29
+ - name: Build
30
+ commands:
31
+ - checkout
32
+ - export BUILDKIT_PROGRESS=plain
33
+ - |
34
+ docker build --push \
35
+ -t 657716690934.dkr.ecr.us-east-1.amazonaws.com/rootly/mcp:${SEMAPHORE_GIT_SHA} \
36
+ -t 657716690934.dkr.ecr.us-east-1.amazonaws.com/rootly/mcp:latest \
37
+ -t 657716690934.dkr.ecr.us-east-1.amazonaws.com/rootly/mcp:production .
38
+
39
+ promotions:
40
+ - name: Deploy
41
+ pipeline_file: deploy.yml
42
+ deployment_target: production
43
+
44
+ auto_promote:
45
+ when: branch = 'main' AND result = 'passed'
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ # Updates a task definition with a new container image
6
+ # Returns the new task definition ARN
7
+ #
8
+ # Required environment variables:
9
+ # TASK_FAMILY - Task definition family
10
+ # CONTAINER_NAME - Container name to update
11
+ # IMAGE - New container image to deploy
12
+
13
+ if [ -z "$TASK_FAMILY" ] || [ -z "$CONTAINER_NAME" ] || [ -z "$IMAGE" ]; then
14
+ echo "Error: TASK_FAMILY, CONTAINER_NAME, and IMAGE environment variables are required"
15
+ exit 1
16
+ fi
17
+
18
+ TASK_DEFINITION="$(aws ecs describe-task-definition --task-definition=$TASK_FAMILY | jq '.taskDefinition')"
19
+
20
+ # Remove fields that can't be used in register-task-definition
21
+ TASK_DEFINITION="$(jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)' <<< "$TASK_DEFINITION")"
22
+
23
+ # Find the index of the specified container
24
+ CONTAINER_INDEX="$(jq --arg NAME "$CONTAINER_NAME" '.containerDefinitions | map(.name) | index($NAME)' <<< "$TASK_DEFINITION")"
25
+
26
+ if [ "$CONTAINER_INDEX" = "null" ]; then
27
+ echo "Error: Container '$CONTAINER_NAME' not found in task definition"
28
+ exit 1
29
+ fi
30
+
31
+ # Update the container image
32
+ NEW_TASK_DEFINITION="$(jq --arg INDEX "$CONTAINER_INDEX" --arg IMAGE "$IMAGE" '.containerDefinitions[$INDEX | tonumber].image = $IMAGE' <<< "$TASK_DEFINITION")"
33
+
34
+ # Register the new task definition
35
+ NEW_TASK_DEFINITION_ARN="$(aws ecs register-task-definition --cli-input-json "$NEW_TASK_DEFINITION" --output text --query 'taskDefinition.taskDefinitionArn')"
36
+
37
+ echo "$TASK_DEFINITION" > task-definition.json
38
+ echo "$NEW_TASK_DEFINITION" > new-task-definition.json
39
+
40
+ echo "Applying update:" >&2
41
+ diff -u task-definition.json new-task-definition.json >&2 || :
42
+
43
+ echo "$NEW_TASK_DEFINITION_ARN"
@@ -0,0 +1,68 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Development Commands
6
+
7
+ ### Environment Setup
8
+ ```bash
9
+ # Install dependencies using uv
10
+ uv pip install .
11
+
12
+ # Create and activate virtual environment
13
+ uv venv .venv
14
+ source .venv/bin/activate
15
+ ```
16
+
17
+ ### Testing and Quality
18
+ ```bash
19
+ # Run test client to verify setup
20
+ python test_mcp_client.py
21
+
22
+ # Linting and type checking (if you add dev dependencies)
23
+ ruff check src/
24
+ pyright src/
25
+ ```
26
+
27
+ ### Package Building
28
+ ```bash
29
+ # Build the package
30
+ uv build
31
+ ```
32
+
33
+ ## Architecture Overview
34
+
35
+ This is an MCP (Model Context Protocol) server that provides AI agents access to the Rootly API for incident management. The project uses Python 3.12+ with `uv` for dependency management.
36
+
37
+ ### Core Components
38
+
39
+ - **`server.py`**: Main MCP server implementation (`RootlyMCPServer` class)
40
+ - Dynamically generates MCP tools from Rootly's OpenAPI/Swagger specification
41
+ - Filters available endpoints via `allowed_paths` configuration for security and context management
42
+ - Implements automatic pagination (default 10 items) for incident endpoints
43
+ - Uses FastMCP framework with ERROR log level to prevent UI noise
44
+
45
+ - **`client.py`**: Rootly API client (`RootlyClient` class)
46
+ - Handles authentication via `ROOTLY_API_TOKEN` environment variable
47
+ - Supports both JSON and JSON-API formats depending on endpoint requirements
48
+ - Base URL defaults to `https://api.rootly.com`
49
+ - Auto-prefixes paths with `/v1` if not present
50
+
51
+ - **`data/swagger.json`**: Cached OpenAPI specification
52
+ - Falls back to downloading from `https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json`
53
+ - Server searches local directories before downloading
54
+
55
+ ### Key Design Patterns
56
+
57
+ - **Dynamic Tool Generation**: Tools are created at runtime based on Swagger spec rather than hardcoded
58
+ - **Path Whitelisting**: Only specific endpoints in `allowed_paths` are exposed to prevent context overflow and maintain security
59
+ - **JSON-API Support**: Automatically wraps request bodies in JSON-API format for create/update operations
60
+ - **Error Resilience**: Comprehensive error handling with structured JSON error responses
61
+
62
+ ### Configuration
63
+
64
+ The `allowed_paths` array in `server.py:56-92` controls which Rootly API endpoints are available. Modify this list to expose additional endpoints. Paths should be specified without the `/v1` prefix.
65
+
66
+ ### Environment Variables
67
+
68
+ - `ROOTLY_API_TOKEN`: Required authentication token for Rootly API access
@@ -0,0 +1,28 @@
1
+ # Use Python 3.12 slim image as base
2
+ FROM python:3.12-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Install system dependencies
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ gcc curl ca-certificates \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # Install uv
13
+ RUN pip install --no-cache-dir uv
14
+
15
+ # Copy the entire project first for installation
16
+ COPY . .
17
+
18
+ # Install the package and its dependencies
19
+ RUN uv pip install --system --no-cache-dir -e .
20
+
21
+ # Expose the port the app runs on
22
+ EXPOSE 8000
23
+
24
+ # Set environment variables
25
+ ENV PYTHONUNBUFFERED=1
26
+
27
+ # Run the application
28
+ CMD ["rootly-mcp-server", "--transport", "sse", "--log-level", "INFO", "--host", "0.0.0.0", "--port", "8000", "--hosted"]
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: rootly-mcp-server
3
+ Version: 2.0.1
4
+ Summary: A Model Context Protocol server for Rootly APIs using OpenAPI spec
5
+ Project-URL: Homepage, https://github.com/Rootly-AI-Labs/Rootly-MCP-server
6
+ Project-URL: Issues, https://github.com/Rootly-AI-Labs/Rootly-MCP-server/issues
7
+ Author-email: Rootly AI Labs <support@rootly.com>
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE
10
+ Keywords: automation,incidents,llm,mcp,rootly
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Software Development :: Build Tools
16
+ Requires-Python: >=3.12
17
+ Requires-Dist: fastmcp==2.4.0
18
+ Requires-Dist: httpx>=0.24.0
19
+ Requires-Dist: pydantic>=2.0.0
20
+ Requires-Dist: requests>=2.28.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: black>=23.0.0; extra == 'dev'
23
+ Requires-Dist: isort>=5.0.0; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Rootly MCP Server
27
+
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
+
30
+ [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=rootly&config=eyJjb21tYW5kIjoibnB4IC15IG1jcC1yZW1vdGUgaHR0cHM6Ly9tY3Aucm9vdGx5LmNvbS9zc2UgLS1oZWFkZXIgQXV0aG9yaXphdGlvbjoke1JPT1RMWV9BVVRIX0hFQURFUn0iLCJlbnYiOnsiUk9PVExZX0FVVEhfSEVBREVSIjoiQmVhcmVyIDxZT1VSX1JPT1RMWV9BUElfVE9LRU4%2BIn19)
31
+
32
+ ![Demo GIF](rootly-mcp-server-demo.gif)
33
+
34
+ ## Prerequisites
35
+
36
+ - Python 3.12 or higher
37
+ - `uv` package manager
38
+ ```bash
39
+ curl -LsSf https://astral.sh/uv/install.sh | sh
40
+ ```
41
+ - [Rootly API token](https://docs.rootly.com/api-reference/overview#how-to-generate-an-api-key%3F)
42
+
43
+ ## Installation
44
+
45
+ Install via our [PyPi package](https://pypi.org/project/rootly-mcp-server/) or by cloning this repository.
46
+
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
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "rootly": {
77
+ "command": "uvx",
78
+ "args": [
79
+ "--from",
80
+ "rootly-mcp-server",
81
+ "rootly-mcp-server",
82
+ ],
83
+ "env": {
84
+ "ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ To customize `allowed_paths` and access additional Rootly API paths, clone the repository and use this configuration:
92
+
93
+ ```json
94
+ {
95
+ "mcpServers": {
96
+ "rootly": {
97
+ "command": "uv",
98
+ "args": [
99
+ "run",
100
+ "--directory",
101
+ "/path/to/rootly-mcp-server",
102
+ "rootly-mcp-server"
103
+ ],
104
+ "env": {
105
+ "ROOTLY_API_TOKEN": "<YOUR_ROOTLY_API_TOKEN>"
106
+ }
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ## Features
113
+
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
117
+
118
+ ### Whitelisted Endpoints
119
+
120
+ By default, the following Rootly API endpoints are exposed to the AI agent (see `allowed_paths` in `src/rootly_mcp_server/server.py`):
121
+
122
+ ```
123
+ /v1/incidents
124
+ /v1/incidents/{incident_id}/alerts
125
+ /v1/alerts
126
+ /v1/alerts/{alert_id}
127
+ /v1/severities
128
+ /v1/severities/{severity_id}
129
+ /v1/teams
130
+ /v1/teams/{team_id}
131
+ /v1/services
132
+ /v1/services/{service_id}
133
+ /v1/functionalities
134
+ /v1/functionalities/{functionality_id}
135
+ /v1/incident_types
136
+ /v1/incident_types/{incident_type_id}
137
+ /v1/incident_action_items
138
+ /v1/incident_action_items/{incident_action_item_id}
139
+ /v1/incidents/{incident_id}/action_items
140
+ /v1/workflows
141
+ /v1/workflows/{workflow_id}
142
+ /v1/workflow_runs
143
+ /v1/workflow_runs/{workflow_run_id}
144
+ /v1/environments
145
+ /v1/environments/{environment_id}
146
+ /v1/users
147
+ /v1/users/{user_id}
148
+ /v1/users/me
149
+ /v1/status_pages
150
+ /v1/status_pages/{status_page_id}
151
+ ```
152
+
153
+ ### Why Path Limiting?
154
+
155
+ We limit exposed API paths for two key reasons:
156
+
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
159
+
160
+ To expose additional paths, modify the `allowed_paths` variable in `src/rootly_mcp_server/server.py`.
161
+
162
+ ## About Rootly AI Labs
163
+
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.
165
+ ![Rootly AI logo](https://github.com/Rootly-AI-Labs/EventOrOutage/raw/main/rootly-ai.png)
166
+
167
+ ## Developer Setup & Troubleshooting
168
+
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
174
+
175
+ Create and activate a virtual environment:
176
+
177
+ ```bash
178
+ uv venv .venv
179
+ source .venv/bin/activate # Always activate before running scripts
180
+ ```
181
+
182
+ ### 2. Install Dependencies
183
+
184
+ Install all project dependencies:
185
+
186
+ ```bash
187
+ uv pip install .
188
+ ```
189
+
190
+ To add new dependencies during development:
191
+ ```bash
192
+ uv pip install <package>
193
+ ```
194
+
195
+ ### 3. Verify Installation
196
+
197
+ Run the test client to ensure everything is configured correctly:
198
+
199
+ ```bash
200
+ python test_mcp_client.py
201
+ ```
202
+
203
+ ### Connect to Hosted MCP Server
204
+
205
+ Alternatively, connect directly to our hosted MCP server:
206
+
207
+ ```json
208
+ {
209
+ "mcpServers": {
210
+ "rootly": {
211
+ "command": "npx",
212
+ "args": [
213
+ "-y",
214
+ "mcp-remote",
215
+ "https://mcp.rootly.com/sse",
216
+ "--header",
217
+ "Authorization:${ROOTLY_AUTH_HEADER}"
218
+ ],
219
+ "env": {
220
+ "ROOTLY_AUTH_HEADER": "Bearer <YOUR_ROOTLY_API_TOKEN>"
221
+ }
222
+ }
223
+ }
224
+ }
225
+ ```