rootly-mcp-server 2.3.7__tar.gz → 2.3.9__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.3.7 → rootly_mcp_server-2.3.9}/.github/workflows/dependency-review.yml +1 -1
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.gitignore +1 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/CHANGELOG.md +55 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/Dockerfile +7 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/PKG-INFO +97 -40
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/README.md +94 -37
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/pyproject.toml +3 -3
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/__main__.py +56 -3
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/server.py +156 -58
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/server_defaults.py +130 -27
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/spec_transform.py +7 -6
- rootly_mcp_server-2.3.9/src/rootly_mcp_server/tools/alerts.py +87 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/incidents.py +112 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/oncall.py +280 -310
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/resources.py +1 -1
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/transport.py +157 -1
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/utils.py +31 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/integration/local/test_tool_allowlists.py +6 -1
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/integration/remote/test_essential.py +7 -4
- rootly_mcp_server-2.3.9/tests/unit/test_alert_tools.py +135 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_main_transport.py +152 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_handoff.py +364 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_server.py +54 -4
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_server_defaults_module.py +32 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_tools.py +71 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_transport_module.py +175 -11
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/uv.lock +86 -86
- rootly_mcp_server-2.3.7/src/rootly_mcp_server/tools/alerts.py +0 -105
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.dockerignore +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.gitattributes +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.github/dependabot.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.github/openapi-audit-remote-baseline.json +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.github/workflows/ci.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.github/workflows/openapi-audit.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.github/workflows/pypi-release.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.mcp.json +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.semaphore/deploy-staging.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.semaphore/deploy.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.semaphore/semaphore.yml +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/.semaphore/update-task-definition.sh +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/CONTRIBUTING.md +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/LICENSE +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/examples/skills/README.md +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/gemini-extension.json +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/rootly-mcp-server-demo.gif +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/rootly_openapi.json +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/scripts/audit_openapi.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/scripts/setup-hooks.sh +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/server.json +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/__init__.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/audit.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/client.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/code_mode.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/data/__init__.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/exceptions.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/legacy_server.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/mcp_error.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/monitoring.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/och_client.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/pagination.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/payload_stripping.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/security.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/smart_utils.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/__init__.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/validators.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/README.md +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/conftest.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/integration/local/test_basic.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/integration/local/test_smart_tools.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/test_client.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_alert_stripping.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_authentication.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_code_mode_module.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_exceptions.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_http_headers.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_legacy_server_module.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_mcp_error_module.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_och_client.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_metrics.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_new_tools.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_severity_normalization.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_payload_stripping_module.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_security.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_smart_utils.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_utils.py +0 -0
- {rootly_mcp_server-2.3.7 → rootly_mcp_server-2.3.9}/tests/unit/test_validators.py +0 -0
|
@@ -5,6 +5,61 @@ All notable changes to the Rootly MCP Server will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.3.9] - Released 2026-05-21
|
|
9
|
+
|
|
10
|
+
### Performance
|
|
11
|
+
|
|
12
|
+
- **Hosted Default Tool Surface Slimmed**: Default hosted deployments now expose a curated core profile of 55 high-usage tools instead of the full 200+ tool surface, improving MCP client tool-discovery performance while preserving a broad self-hosted default
|
|
13
|
+
- **Hosted and Self-Hosted Defaults Split**: Hosted/serverless instances now default to the slim allowlist, while local and self-hosted deployments continue to expose the full tool catalog unless explicitly overridden
|
|
14
|
+
|
|
15
|
+
### Configuration
|
|
16
|
+
|
|
17
|
+
- **Hosted Allowlist Override Behavior**: `ROOTLY_MCP_ENABLED_TOOLS` now cleanly overrides the hosted default profile when operators want a narrower or broader remote tool surface
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
|
|
21
|
+
- **README Deployment Guidance Updated**: Documented the new hosted-versus-self-hosted tool defaults, the hosted override behavior, and the current approximate tool counts for each mode
|
|
22
|
+
|
|
23
|
+
### Dependencies
|
|
24
|
+
|
|
25
|
+
- **Lockfile Sync**: Regenerated `uv.lock` so the lockfile matches the current pinned versions in `pyproject.toml`, including `requests==2.34.0` and `pydantic==2.13.4`
|
|
26
|
+
|
|
27
|
+
## [2.3.8] - Released 2026-05-19
|
|
28
|
+
|
|
29
|
+
### Security
|
|
30
|
+
|
|
31
|
+
- **Bearer Auth Enforcement on Hosted Transports**: Required Bearer authentication on MCP transport paths in hosted mode so unauthenticated requests are rejected before any tool dispatch
|
|
32
|
+
- **Upstream Token Validation**: Validated Bearer tokens against the upstream Rootly API before granting MCP access, surfacing malformed or expired credentials at the edge with clearer errors
|
|
33
|
+
- **Dependency Advisories**: Bumped `urllib3` (≥2.7.0), `python-multipart` (≥0.0.27), and `pip` (≥26.1) to resolve five open Dependabot advisories (urllib3 CVE-2026-44431/44432, python-multipart CVE-2026-42561, pip CVE-2026-6357/3219)
|
|
34
|
+
|
|
35
|
+
### Performance
|
|
36
|
+
|
|
37
|
+
- **`get_alert_by_short_id` Now O(1)**: Replaced the up-to-20-page sequential scan with a single direct `GET /v1/alerts/{short_id}` point lookup. P95 spikes of 41s on this tool collapse to ~200ms; not-found responses no longer cost 10+ seconds; workspaces with >2,000 alerts no longer silently fail
|
|
38
|
+
- **`get_oncall_handoff_summary` Fan-Out Parallelized**: Replaced sequential per-schedule shift and incident fetches with `asyncio.gather` capped by a `Semaphore(10)`. Worst-case p95 of ~15s on populated workspaces drops to ~1–2s
|
|
39
|
+
- **Lookup-Maps Helper Parallelized**: `_fetch_users_and_schedules_maps` (used by `list_shifts`, `check_responder_availability`, `check_oncall_health_risk`, `create_override_recommendation`, `find_related_incidents`) now runs the three independent resource fetches concurrently with intra-resource page fan-out. Cold-cache worst case drops from ~15s to ~1s — meaningfully more impactful since v2.3.7 made sessions stateless and the in-memory cache is repaid more often
|
|
40
|
+
- **Shared `_fetch_all_pages` Helper Across Five Shift Tools**: `list_shifts`, `get_oncall_schedule_summary`, `check_responder_availability`, `create_override_recommendation`, and `check_oncall_health_risk` now all route through the same paginated, concurrency-capped helper instead of duplicating sequential pagination loops. Each tool saves 2–5s worst case under load
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- **`get_oncall_shift_metrics` Silent Data Loss**: The function previously fetched only page 1 of schedules and teams (no pagination loop), causing team-id filtering to silently drop schedules whose teams lived past page 1. Now uses the shared paginated, cached helper so all schedules are considered
|
|
45
|
+
- **OAuth Authorization Server Discovery**: Derived the OAuth authorization server URL from the API base URL so discovery works against staging and self-hosted Rootly instances
|
|
46
|
+
- **OAuth Protected Resource Metadata**: Removed `scopes_supported` from the protected resource metadata, advertised only the granular scopes the resource actually accepts, and included resource-specific scopes for clients that key off them
|
|
47
|
+
- **Pagination Resilience**: `asyncio.gather` callsites that fan out pages now use `return_exceptions=True` with an `isinstance(_, BaseException)` guard so a single transient httpx error on one page no longer aborts the entire handler
|
|
48
|
+
- **Missing `total_pages` Metadata Fallback**: When upstream omits `meta.total_pages`, the helper now falls back to fetching up to `max_pages` (preserving the legacy "keep going until a short page" semantics) instead of silently truncating to page 1
|
|
49
|
+
|
|
50
|
+
### Dependencies
|
|
51
|
+
|
|
52
|
+
- **Routine Refresh**: Pulled in the latest minor and patch dependency updates from Dependabot
|
|
53
|
+
- **CI Action Bump**: Updated `actions/dependency-review-action` from 4.9.0 to 5.0.0
|
|
54
|
+
|
|
55
|
+
### Repo
|
|
56
|
+
|
|
57
|
+
- **`.claude/` Ignored**: Stopped tracking transient `.claude/worktrees/` directories and added `.claude/` to `.gitignore` so local Claude Code state no longer pollutes diffs
|
|
58
|
+
|
|
59
|
+
### Testing
|
|
60
|
+
|
|
61
|
+
- New unit tests for the parallelized fan-out paths, the missing-`total_pages` fallback, exception-tolerance in `asyncio.gather`, the `get_oncall_shift_metrics` pagination regression, and the direct-GET path for `get_alert_by_short_id`
|
|
62
|
+
|
|
8
63
|
## [2.3.7] - Released 2026-05-08
|
|
9
64
|
|
|
10
65
|
### Features
|
|
@@ -18,6 +18,13 @@ COPY . .
|
|
|
18
18
|
# Install the package and its dependencies
|
|
19
19
|
RUN uv pip install --system --no-cache-dir -e .
|
|
20
20
|
|
|
21
|
+
# Install MCPcat for hosted telemetry without changing the repo dependency graph.
|
|
22
|
+
# MCPcat's current package metadata pins an older Pydantic range, but the SDK
|
|
23
|
+
# imports successfully with our runtime pin, so we restore the server's pinned
|
|
24
|
+
# version after installation.
|
|
25
|
+
RUN uv pip install --system --no-cache-dir mcpcat==0.1.14 \
|
|
26
|
+
&& uv pip install --system --no-cache-dir pydantic==2.13.4
|
|
27
|
+
|
|
21
28
|
# Create non-root user
|
|
22
29
|
RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
|
|
23
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rootly-mcp-server
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.9
|
|
4
4
|
Summary: Secure Model Context Protocol server for Rootly APIs with AI SRE capabilities, comprehensive error handling, and input validation
|
|
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
|
|
@@ -27,11 +27,11 @@ Requires-Dist: cryptography>=46.0.7
|
|
|
27
27
|
Requires-Dist: fastmcp[code-mode]==3.2.4
|
|
28
28
|
Requires-Dist: httpx==0.28.1
|
|
29
29
|
Requires-Dist: numpy>=1.24.0
|
|
30
|
-
Requires-Dist: pydantic==2.13.
|
|
30
|
+
Requires-Dist: pydantic==2.13.4
|
|
31
31
|
Requires-Dist: pygments>=2.20.0
|
|
32
32
|
Requires-Dist: python-dotenv>=1.2.2
|
|
33
33
|
Requires-Dist: python-multipart>=0.0.26
|
|
34
|
-
Requires-Dist: requests==2.
|
|
34
|
+
Requires-Dist: requests==2.34.0
|
|
35
35
|
Requires-Dist: scikit-learn>=1.3.0
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: bandit>=1.7.0; extra == 'dev'
|
|
@@ -65,7 +65,21 @@ Use the hosted MCP server. No local installation required.
|
|
|
65
65
|
|
|
66
66
|
### General Remote Setup
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
**With OAuth2 (recommended):**
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"rootly": {
|
|
74
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Your MCP client handles OAuth2 login automatically — a browser window opens for you to authenticate with Rootly. No API token needed.
|
|
81
|
+
|
|
82
|
+
**With API Token:**
|
|
69
83
|
|
|
70
84
|
```json
|
|
71
85
|
{
|
|
@@ -86,10 +100,7 @@ SSE (alternative):
|
|
|
86
100
|
{
|
|
87
101
|
"mcpServers": {
|
|
88
102
|
"rootly": {
|
|
89
|
-
"url": "https://mcp.rootly.com/sse"
|
|
90
|
-
"headers": {
|
|
91
|
-
"Authorization": "Bearer YOUR_ROOTLY_API_TOKEN"
|
|
92
|
-
}
|
|
103
|
+
"url": "https://mcp.rootly.com/sse"
|
|
93
104
|
}
|
|
94
105
|
}
|
|
95
106
|
}
|
|
@@ -101,10 +112,7 @@ Code Mode:
|
|
|
101
112
|
{
|
|
102
113
|
"mcpServers": {
|
|
103
114
|
"rootly": {
|
|
104
|
-
"url": "https://mcp.rootly.com/mcp-codemode"
|
|
105
|
-
"headers": {
|
|
106
|
-
"Authorization": "Bearer YOUR_ROOTLY_API_TOKEN"
|
|
107
|
-
}
|
|
115
|
+
"url": "https://mcp.rootly.com/mcp-codemode"
|
|
108
116
|
}
|
|
109
117
|
}
|
|
110
118
|
}
|
|
@@ -117,47 +125,35 @@ Code Mode:
|
|
|
117
125
|
|
|
118
126
|
<br>
|
|
119
127
|
|
|
120
|
-
**
|
|
128
|
+
**With OAuth2 (recommended):**
|
|
121
129
|
|
|
122
130
|
```bash
|
|
123
|
-
claude mcp add --transport http rootly https://mcp.rootly.com/mcp
|
|
124
|
-
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Code Mode:
|
|
131
|
+
claude mcp add --transport http rootly https://mcp.rootly.com/mcp
|
|
128
132
|
|
|
129
|
-
|
|
130
|
-
claude mcp add
|
|
131
|
-
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
|
|
133
|
+
# Code Mode:
|
|
134
|
+
claude mcp add --transport http rootly-codemode https://mcp.rootly.com/mcp-codemode
|
|
132
135
|
```
|
|
133
136
|
|
|
134
|
-
|
|
137
|
+
**With API Token:**
|
|
135
138
|
|
|
136
139
|
```bash
|
|
137
|
-
claude mcp add --transport
|
|
140
|
+
claude mcp add --transport http rootly https://mcp.rootly.com/mcp \
|
|
138
141
|
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
|
|
139
142
|
```
|
|
140
143
|
|
|
141
|
-
**Manual Configuration**
|
|
142
|
-
|
|
143
|
-
Create `.mcp.json` in your project root:
|
|
144
|
+
**Manual Configuration** — Create `.mcp.json` in your project root:
|
|
144
145
|
|
|
145
146
|
```json
|
|
146
147
|
{
|
|
147
148
|
"mcpServers": {
|
|
148
149
|
"rootly": {
|
|
149
150
|
"type": "http",
|
|
150
|
-
"url": "https://mcp.rootly.com/mcp"
|
|
151
|
-
"headers": {
|
|
152
|
-
"Authorization": "Bearer YOUR_ROOTLY_API_TOKEN"
|
|
153
|
-
}
|
|
151
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
154
152
|
}
|
|
155
153
|
}
|
|
156
154
|
}
|
|
157
155
|
```
|
|
158
156
|
|
|
159
|
-
Restart Claude Code after updating the config.
|
|
160
|
-
|
|
161
157
|
</details>
|
|
162
158
|
|
|
163
159
|
<details>
|
|
@@ -196,6 +192,20 @@ Or configure manually in `~/.gemini/settings.json`:
|
|
|
196
192
|
|
|
197
193
|
Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
198
194
|
|
|
195
|
+
**With OAuth2 (recommended):**
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"mcpServers": {
|
|
200
|
+
"rootly": {
|
|
201
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**With API Token:**
|
|
208
|
+
|
|
199
209
|
```json
|
|
200
210
|
{
|
|
201
211
|
"mcpServers": {
|
|
@@ -218,6 +228,20 @@ Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
|
218
228
|
|
|
219
229
|
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
220
230
|
|
|
231
|
+
**With OAuth2 (recommended):**
|
|
232
|
+
|
|
233
|
+
```json
|
|
234
|
+
{
|
|
235
|
+
"mcpServers": {
|
|
236
|
+
"rootly": {
|
|
237
|
+
"serverUrl": "https://mcp.rootly.com/mcp"
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**With API Token:**
|
|
244
|
+
|
|
221
245
|
```json
|
|
222
246
|
{
|
|
223
247
|
"mcpServers": {
|
|
@@ -240,6 +264,15 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
240
264
|
|
|
241
265
|
Add to `~/.codex/config.toml`:
|
|
242
266
|
|
|
267
|
+
**With OAuth2 (recommended):**
|
|
268
|
+
|
|
269
|
+
```toml
|
|
270
|
+
[mcp_servers.rootly]
|
|
271
|
+
url = "https://mcp.rootly.com/mcp"
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**With API Token:**
|
|
275
|
+
|
|
243
276
|
```toml
|
|
244
277
|
[mcp_servers.rootly]
|
|
245
278
|
url = "https://mcp.rootly.com/mcp"
|
|
@@ -253,9 +286,23 @@ bearer_token_env_var = "ROOTLY_API_TOKEN"
|
|
|
253
286
|
|
|
254
287
|
<br>
|
|
255
288
|
|
|
289
|
+
**With OAuth2 (recommended):**
|
|
290
|
+
|
|
256
291
|
Add to `claude_desktop_config.json`:
|
|
257
292
|
|
|
258
|
-
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"mcpServers": {
|
|
296
|
+
"rootly": {
|
|
297
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Claude Desktop handles OAuth2 login automatically.
|
|
304
|
+
|
|
305
|
+
**With API Token (via mcp-remote):**
|
|
259
306
|
|
|
260
307
|
```json
|
|
261
308
|
{
|
|
@@ -350,7 +397,14 @@ Choose one transport per server process:
|
|
|
350
397
|
- **SSE** endpoint path: `/sse`
|
|
351
398
|
- **Code Mode (experimental)** endpoint path: `/mcp-codemode` in hosted dual-transport mode
|
|
352
399
|
|
|
353
|
-
|
|
400
|
+
Hosted and self-hosted deployments now have different defaults:
|
|
401
|
+
|
|
402
|
+
- Hosted defaults to a slim core profile of about 50-60 high-usage tools for better MCP client performance.
|
|
403
|
+
- Self-hosted keeps the full tool surface by default.
|
|
404
|
+
|
|
405
|
+
To restrict either deployment to read-only tools, start the server with `--no-enable-write-tools` or set `ROOTLY_MCP_ENABLE_WRITE_TOOLS=false`.
|
|
406
|
+
|
|
407
|
+
To override the hosted default core profile, set `ROOTLY_MCP_ENABLED_TOOLS` (or pass `--enabled-tools`) with a comma-separated allowlist of exact tool names. When that variable is set, it fully replaces the default hosted selection.
|
|
354
408
|
|
|
355
409
|
To expose only a specific subset of MCP tools on a self-hosted deployment, set `ROOTLY_MCP_ENABLED_TOOLS` (or pass `--enabled-tools`) with a comma-separated allowlist of exact tool names, for example `list_incidents,getIncident,get_server_version`.
|
|
356
410
|
|
|
@@ -418,13 +472,13 @@ docker run -p 8000:8000 \
|
|
|
418
472
|
|
|
419
473
|
## Workflow-Focused Tool Subsets
|
|
420
474
|
|
|
421
|
-
|
|
475
|
+
The full self-hosted surface exposes 200+ tools, while hosted defaults to a slim core profile. If you want even tighter workflow-specific subsets, use `ROOTLY_MCP_ENABLED_TOOLS`:
|
|
422
476
|
|
|
423
477
|
### 🚨 Incident Response (25 tools)
|
|
424
478
|
*Essential tools for emergency responders and incident commanders*
|
|
425
479
|
|
|
426
480
|
```bash
|
|
427
|
-
ROOTLY_MCP_ENABLED_TOOLS="
|
|
481
|
+
ROOTLY_MCP_ENABLED_TOOLS="list_incidents,getIncident,createIncident,updateIncident,search_incidents,find_related_incidents,suggest_solutions,createIncidentActionItem,listIncidentActionItems,updateIncidentFormFieldSelection,listTeams,getCurrentUser,listServices,listSeverities,getAlert,listAlerts,updateAlert,listEscalationPolicies,getEscalationPolicy,listOnCallRoles,listSchedules,getScheduleShifts,get_oncall_handoff_summary,get_shift_incidents,list_endpoints"
|
|
428
482
|
```
|
|
429
483
|
|
|
430
484
|
### 📅 On-Call Management (35 tools)
|
|
@@ -452,7 +506,7 @@ ROOTLY_MCP_ENABLED_TOOLS="getIncident,updateIncident,find_related_incidents,sugg
|
|
|
452
506
|
*For leadership and metrics teams (read-only focus)*
|
|
453
507
|
|
|
454
508
|
```bash
|
|
455
|
-
ROOTLY_MCP_ENABLED_TOOLS="
|
|
509
|
+
ROOTLY_MCP_ENABLED_TOOLS="list_incidents,search_incidents,collect_incidents,listTeams,listServices,listSchedules,get_oncall_shift_metrics,get_shift_incidents,listDashboards,getDashboard,listAlerts,listHeartbeats,listPulses,getCurrentUser,list_endpoints"
|
|
456
510
|
```
|
|
457
511
|
|
|
458
512
|
### Multiple MCP Instances for Different Teams
|
|
@@ -466,7 +520,7 @@ You can run multiple MCP instances with different tool subsets:
|
|
|
466
520
|
"command": "uvx", "args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
|
|
467
521
|
"env": {
|
|
468
522
|
"ROOTLY_API_TOKEN": "<token>",
|
|
469
|
-
"ROOTLY_MCP_ENABLED_TOOLS": "
|
|
523
|
+
"ROOTLY_MCP_ENABLED_TOOLS": "list_incidents,getIncident,createIncident,find_related_incidents,suggest_solutions..."
|
|
470
524
|
}
|
|
471
525
|
},
|
|
472
526
|
"rootly-oncall-management": {
|
|
@@ -514,7 +568,10 @@ You can run multiple MCP instances with different tool subsets:
|
|
|
514
568
|
|
|
515
569
|
## Supported Tools
|
|
516
570
|
|
|
517
|
-
The default
|
|
571
|
+
The default tool surface depends on deployment mode:
|
|
572
|
+
|
|
573
|
+
- Hosted default: about **56 tools**
|
|
574
|
+
- Self-hosted default: about **218 tools**
|
|
518
575
|
|
|
519
576
|
### Custom Agentic Tools
|
|
520
577
|
|
|
@@ -610,7 +667,7 @@ listIncidentActionItems
|
|
|
610
667
|
listIncidentAlerts
|
|
611
668
|
listIncidentFormFieldSelections
|
|
612
669
|
listIncident_Types
|
|
613
|
-
listIncidents
|
|
670
|
+
listIncidents (deprecated alias — use `list_incidents`)
|
|
614
671
|
listOnCallRoles
|
|
615
672
|
listOnCallShadows
|
|
616
673
|
listOverrideShifts
|
|
@@ -21,7 +21,21 @@ Use the hosted MCP server. No local installation required.
|
|
|
21
21
|
|
|
22
22
|
### General Remote Setup
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
**With OAuth2 (recommended):**
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"rootly": {
|
|
30
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Your MCP client handles OAuth2 login automatically — a browser window opens for you to authenticate with Rootly. No API token needed.
|
|
37
|
+
|
|
38
|
+
**With API Token:**
|
|
25
39
|
|
|
26
40
|
```json
|
|
27
41
|
{
|
|
@@ -42,10 +56,7 @@ SSE (alternative):
|
|
|
42
56
|
{
|
|
43
57
|
"mcpServers": {
|
|
44
58
|
"rootly": {
|
|
45
|
-
"url": "https://mcp.rootly.com/sse"
|
|
46
|
-
"headers": {
|
|
47
|
-
"Authorization": "Bearer YOUR_ROOTLY_API_TOKEN"
|
|
48
|
-
}
|
|
59
|
+
"url": "https://mcp.rootly.com/sse"
|
|
49
60
|
}
|
|
50
61
|
}
|
|
51
62
|
}
|
|
@@ -57,10 +68,7 @@ Code Mode:
|
|
|
57
68
|
{
|
|
58
69
|
"mcpServers": {
|
|
59
70
|
"rootly": {
|
|
60
|
-
"url": "https://mcp.rootly.com/mcp-codemode"
|
|
61
|
-
"headers": {
|
|
62
|
-
"Authorization": "Bearer YOUR_ROOTLY_API_TOKEN"
|
|
63
|
-
}
|
|
71
|
+
"url": "https://mcp.rootly.com/mcp-codemode"
|
|
64
72
|
}
|
|
65
73
|
}
|
|
66
74
|
}
|
|
@@ -73,47 +81,35 @@ Code Mode:
|
|
|
73
81
|
|
|
74
82
|
<br>
|
|
75
83
|
|
|
76
|
-
**
|
|
84
|
+
**With OAuth2 (recommended):**
|
|
77
85
|
|
|
78
86
|
```bash
|
|
79
|
-
claude mcp add --transport http rootly https://mcp.rootly.com/mcp
|
|
80
|
-
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Code Mode:
|
|
87
|
+
claude mcp add --transport http rootly https://mcp.rootly.com/mcp
|
|
84
88
|
|
|
85
|
-
|
|
86
|
-
claude mcp add
|
|
87
|
-
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
|
|
89
|
+
# Code Mode:
|
|
90
|
+
claude mcp add --transport http rootly-codemode https://mcp.rootly.com/mcp-codemode
|
|
88
91
|
```
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
**With API Token:**
|
|
91
94
|
|
|
92
95
|
```bash
|
|
93
|
-
claude mcp add --transport
|
|
96
|
+
claude mcp add --transport http rootly https://mcp.rootly.com/mcp \
|
|
94
97
|
--header "Authorization: Bearer YOUR_ROOTLY_API_TOKEN"
|
|
95
98
|
```
|
|
96
99
|
|
|
97
|
-
**Manual Configuration**
|
|
98
|
-
|
|
99
|
-
Create `.mcp.json` in your project root:
|
|
100
|
+
**Manual Configuration** — Create `.mcp.json` in your project root:
|
|
100
101
|
|
|
101
102
|
```json
|
|
102
103
|
{
|
|
103
104
|
"mcpServers": {
|
|
104
105
|
"rootly": {
|
|
105
106
|
"type": "http",
|
|
106
|
-
"url": "https://mcp.rootly.com/mcp"
|
|
107
|
-
"headers": {
|
|
108
|
-
"Authorization": "Bearer YOUR_ROOTLY_API_TOKEN"
|
|
109
|
-
}
|
|
107
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
110
108
|
}
|
|
111
109
|
}
|
|
112
110
|
}
|
|
113
111
|
```
|
|
114
112
|
|
|
115
|
-
Restart Claude Code after updating the config.
|
|
116
|
-
|
|
117
113
|
</details>
|
|
118
114
|
|
|
119
115
|
<details>
|
|
@@ -152,6 +148,20 @@ Or configure manually in `~/.gemini/settings.json`:
|
|
|
152
148
|
|
|
153
149
|
Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
154
150
|
|
|
151
|
+
**With OAuth2 (recommended):**
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"mcpServers": {
|
|
156
|
+
"rootly": {
|
|
157
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**With API Token:**
|
|
164
|
+
|
|
155
165
|
```json
|
|
156
166
|
{
|
|
157
167
|
"mcpServers": {
|
|
@@ -174,6 +184,20 @@ Add to `.cursor/mcp.json` or `~/.cursor/mcp.json`:
|
|
|
174
184
|
|
|
175
185
|
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
176
186
|
|
|
187
|
+
**With OAuth2 (recommended):**
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"mcpServers": {
|
|
192
|
+
"rootly": {
|
|
193
|
+
"serverUrl": "https://mcp.rootly.com/mcp"
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**With API Token:**
|
|
200
|
+
|
|
177
201
|
```json
|
|
178
202
|
{
|
|
179
203
|
"mcpServers": {
|
|
@@ -196,6 +220,15 @@ Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
|
196
220
|
|
|
197
221
|
Add to `~/.codex/config.toml`:
|
|
198
222
|
|
|
223
|
+
**With OAuth2 (recommended):**
|
|
224
|
+
|
|
225
|
+
```toml
|
|
226
|
+
[mcp_servers.rootly]
|
|
227
|
+
url = "https://mcp.rootly.com/mcp"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**With API Token:**
|
|
231
|
+
|
|
199
232
|
```toml
|
|
200
233
|
[mcp_servers.rootly]
|
|
201
234
|
url = "https://mcp.rootly.com/mcp"
|
|
@@ -209,9 +242,23 @@ bearer_token_env_var = "ROOTLY_API_TOKEN"
|
|
|
209
242
|
|
|
210
243
|
<br>
|
|
211
244
|
|
|
245
|
+
**With OAuth2 (recommended):**
|
|
246
|
+
|
|
212
247
|
Add to `claude_desktop_config.json`:
|
|
213
248
|
|
|
214
|
-
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"mcpServers": {
|
|
252
|
+
"rootly": {
|
|
253
|
+
"url": "https://mcp.rootly.com/mcp"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Claude Desktop handles OAuth2 login automatically.
|
|
260
|
+
|
|
261
|
+
**With API Token (via mcp-remote):**
|
|
215
262
|
|
|
216
263
|
```json
|
|
217
264
|
{
|
|
@@ -306,7 +353,14 @@ Choose one transport per server process:
|
|
|
306
353
|
- **SSE** endpoint path: `/sse`
|
|
307
354
|
- **Code Mode (experimental)** endpoint path: `/mcp-codemode` in hosted dual-transport mode
|
|
308
355
|
|
|
309
|
-
|
|
356
|
+
Hosted and self-hosted deployments now have different defaults:
|
|
357
|
+
|
|
358
|
+
- Hosted defaults to a slim core profile of about 50-60 high-usage tools for better MCP client performance.
|
|
359
|
+
- Self-hosted keeps the full tool surface by default.
|
|
360
|
+
|
|
361
|
+
To restrict either deployment to read-only tools, start the server with `--no-enable-write-tools` or set `ROOTLY_MCP_ENABLE_WRITE_TOOLS=false`.
|
|
362
|
+
|
|
363
|
+
To override the hosted default core profile, set `ROOTLY_MCP_ENABLED_TOOLS` (or pass `--enabled-tools`) with a comma-separated allowlist of exact tool names. When that variable is set, it fully replaces the default hosted selection.
|
|
310
364
|
|
|
311
365
|
To expose only a specific subset of MCP tools on a self-hosted deployment, set `ROOTLY_MCP_ENABLED_TOOLS` (or pass `--enabled-tools`) with a comma-separated allowlist of exact tool names, for example `list_incidents,getIncident,get_server_version`.
|
|
312
366
|
|
|
@@ -374,13 +428,13 @@ docker run -p 8000:8000 \
|
|
|
374
428
|
|
|
375
429
|
## Workflow-Focused Tool Subsets
|
|
376
430
|
|
|
377
|
-
|
|
431
|
+
The full self-hosted surface exposes 200+ tools, while hosted defaults to a slim core profile. If you want even tighter workflow-specific subsets, use `ROOTLY_MCP_ENABLED_TOOLS`:
|
|
378
432
|
|
|
379
433
|
### 🚨 Incident Response (25 tools)
|
|
380
434
|
*Essential tools for emergency responders and incident commanders*
|
|
381
435
|
|
|
382
436
|
```bash
|
|
383
|
-
ROOTLY_MCP_ENABLED_TOOLS="
|
|
437
|
+
ROOTLY_MCP_ENABLED_TOOLS="list_incidents,getIncident,createIncident,updateIncident,search_incidents,find_related_incidents,suggest_solutions,createIncidentActionItem,listIncidentActionItems,updateIncidentFormFieldSelection,listTeams,getCurrentUser,listServices,listSeverities,getAlert,listAlerts,updateAlert,listEscalationPolicies,getEscalationPolicy,listOnCallRoles,listSchedules,getScheduleShifts,get_oncall_handoff_summary,get_shift_incidents,list_endpoints"
|
|
384
438
|
```
|
|
385
439
|
|
|
386
440
|
### 📅 On-Call Management (35 tools)
|
|
@@ -408,7 +462,7 @@ ROOTLY_MCP_ENABLED_TOOLS="getIncident,updateIncident,find_related_incidents,sugg
|
|
|
408
462
|
*For leadership and metrics teams (read-only focus)*
|
|
409
463
|
|
|
410
464
|
```bash
|
|
411
|
-
ROOTLY_MCP_ENABLED_TOOLS="
|
|
465
|
+
ROOTLY_MCP_ENABLED_TOOLS="list_incidents,search_incidents,collect_incidents,listTeams,listServices,listSchedules,get_oncall_shift_metrics,get_shift_incidents,listDashboards,getDashboard,listAlerts,listHeartbeats,listPulses,getCurrentUser,list_endpoints"
|
|
412
466
|
```
|
|
413
467
|
|
|
414
468
|
### Multiple MCP Instances for Different Teams
|
|
@@ -422,7 +476,7 @@ You can run multiple MCP instances with different tool subsets:
|
|
|
422
476
|
"command": "uvx", "args": ["--from", "rootly-mcp-server", "rootly-mcp-server"],
|
|
423
477
|
"env": {
|
|
424
478
|
"ROOTLY_API_TOKEN": "<token>",
|
|
425
|
-
"ROOTLY_MCP_ENABLED_TOOLS": "
|
|
479
|
+
"ROOTLY_MCP_ENABLED_TOOLS": "list_incidents,getIncident,createIncident,find_related_incidents,suggest_solutions..."
|
|
426
480
|
}
|
|
427
481
|
},
|
|
428
482
|
"rootly-oncall-management": {
|
|
@@ -470,7 +524,10 @@ You can run multiple MCP instances with different tool subsets:
|
|
|
470
524
|
|
|
471
525
|
## Supported Tools
|
|
472
526
|
|
|
473
|
-
The default
|
|
527
|
+
The default tool surface depends on deployment mode:
|
|
528
|
+
|
|
529
|
+
- Hosted default: about **56 tools**
|
|
530
|
+
- Self-hosted default: about **218 tools**
|
|
474
531
|
|
|
475
532
|
### Custom Agentic Tools
|
|
476
533
|
|
|
@@ -566,7 +623,7 @@ listIncidentActionItems
|
|
|
566
623
|
listIncidentAlerts
|
|
567
624
|
listIncidentFormFieldSelections
|
|
568
625
|
listIncident_Types
|
|
569
|
-
listIncidents
|
|
626
|
+
listIncidents (deprecated alias — use `list_incidents`)
|
|
570
627
|
listOnCallRoles
|
|
571
628
|
listOnCallShadows
|
|
572
629
|
listOverrideShifts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "rootly-mcp-server"
|
|
3
|
-
version = "2.3.
|
|
3
|
+
version = "2.3.9"
|
|
4
4
|
description = "Secure Model Context Protocol server for Rootly APIs with AI SRE capabilities, comprehensive error handling, and input validation"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -42,9 +42,9 @@ dependencies = [
|
|
|
42
42
|
"python-multipart>=0.0.26", # Override vulnerable transitive python-multipart (CVE-2026-40347)
|
|
43
43
|
"cryptography>=46.0.7", # Override vulnerable transitive cryptography
|
|
44
44
|
"Pygments>=2.20.0", # Override vulnerable transitive Pygments
|
|
45
|
-
"requests==2.
|
|
45
|
+
"requests==2.34.0", # Pin to patched version
|
|
46
46
|
"httpx==0.28.1", # Pin to specific version
|
|
47
|
-
"pydantic==2.13.
|
|
47
|
+
"pydantic==2.13.4", # Pin to specific version
|
|
48
48
|
"brotli>=1.2.0", # For Brotli compression support in httpx
|
|
49
49
|
"scikit-learn>=1.3.0", # For text similarity and ML utilities
|
|
50
50
|
"numpy>=1.24.0", # For numerical operations
|