rootly-mcp-server 2.3.8__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.
Files changed (85) hide show
  1. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/CHANGELOG.md +19 -0
  2. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/Dockerfile +7 -0
  3. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/PKG-INFO +95 -38
  4. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/README.md +94 -37
  5. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/pyproject.toml +1 -1
  6. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/__main__.py +56 -3
  7. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/server.py +106 -47
  8. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/server_defaults.py +130 -27
  9. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/spec_transform.py +7 -6
  10. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/incidents.py +112 -0
  11. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/resources.py +1 -1
  12. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/transport.py +79 -22
  13. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/integration/local/test_tool_allowlists.py +6 -1
  14. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/integration/remote/test_essential.py +7 -4
  15. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_main_transport.py +152 -0
  16. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_server.py +54 -4
  17. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_server_defaults_module.py +32 -0
  18. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_tools.py +71 -0
  19. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_transport_module.py +51 -11
  20. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/uv.lock +76 -76
  21. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.dockerignore +0 -0
  22. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.gitattributes +0 -0
  23. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.github/dependabot.yml +0 -0
  24. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.github/openapi-audit-remote-baseline.json +0 -0
  25. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.github/workflows/ci.yml +0 -0
  26. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.github/workflows/dependency-review.yml +0 -0
  27. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.github/workflows/openapi-audit.yml +0 -0
  28. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.github/workflows/pypi-release.yml +0 -0
  29. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.gitignore +0 -0
  30. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.mcp.json +0 -0
  31. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.semaphore/deploy-staging.yml +0 -0
  32. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.semaphore/deploy.yml +0 -0
  33. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.semaphore/semaphore.yml +0 -0
  34. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/.semaphore/update-task-definition.sh +0 -0
  35. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/CONTRIBUTING.md +0 -0
  36. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/LICENSE +0 -0
  37. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/examples/skills/README.md +0 -0
  38. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/gemini-extension.json +0 -0
  39. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/rootly-mcp-server-demo.gif +0 -0
  40. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/rootly_openapi.json +0 -0
  41. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/scripts/audit_openapi.py +0 -0
  42. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/scripts/setup-hooks.sh +0 -0
  43. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/server.json +0 -0
  44. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/__init__.py +0 -0
  45. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/audit.py +0 -0
  46. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/client.py +0 -0
  47. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/code_mode.py +0 -0
  48. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/data/__init__.py +0 -0
  49. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/exceptions.py +0 -0
  50. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/legacy_server.py +0 -0
  51. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/mcp_error.py +0 -0
  52. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/monitoring.py +0 -0
  53. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/och_client.py +0 -0
  54. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/pagination.py +0 -0
  55. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/payload_stripping.py +0 -0
  56. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/security.py +0 -0
  57. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/smart_utils.py +0 -0
  58. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/__init__.py +0 -0
  59. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/alerts.py +0 -0
  60. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/tools/oncall.py +0 -0
  61. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/utils.py +0 -0
  62. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/src/rootly_mcp_server/validators.py +0 -0
  63. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/README.md +0 -0
  64. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/conftest.py +0 -0
  65. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/integration/local/test_basic.py +0 -0
  66. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/integration/local/test_smart_tools.py +0 -0
  67. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/test_client.py +0 -0
  68. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_alert_stripping.py +0 -0
  69. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_alert_tools.py +0 -0
  70. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_authentication.py +0 -0
  71. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_code_mode_module.py +0 -0
  72. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_exceptions.py +0 -0
  73. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_http_headers.py +0 -0
  74. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_legacy_server_module.py +0 -0
  75. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_mcp_error_module.py +0 -0
  76. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_och_client.py +0 -0
  77. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_handoff.py +0 -0
  78. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_metrics.py +0 -0
  79. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_new_tools.py +0 -0
  80. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_oncall_severity_normalization.py +0 -0
  81. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_payload_stripping_module.py +0 -0
  82. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_security.py +0 -0
  83. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_smart_utils.py +0 -0
  84. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_utils.py +0 -0
  85. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.9}/tests/unit/test_validators.py +0 -0
@@ -5,6 +5,25 @@ 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
+
8
27
  ## [2.3.8] - Released 2026-05-19
9
28
 
10
29
  ### Security
@@ -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.8
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
@@ -65,7 +65,21 @@ Use the hosted MCP server. No local installation required.
65
65
 
66
66
  ### General Remote Setup
67
67
 
68
- Default remote config (HTTP streamable):
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
- **Streamable HTTP**
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
- ```bash
130
- claude mcp add rootly-codemode --transport http https://mcp.rootly.com/mcp-codemode \
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
- SSE (alternative):
137
+ **With API Token:**
135
138
 
136
139
  ```bash
137
- claude mcp add --transport sse rootly-sse https://mcp.rootly.com/sse \
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
- > **Note:** The `--transport http` flag ensures HTTP streamable transport is used instead of auto-falling back to SSE.
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
- Both hosted and self-hosted deployments expose the same curated tool surface by default, including the default write-enabled tools. To restrict that surface to read-only tools, start the server with `--no-enable-write-tools` or set `ROOTLY_MCP_ENABLE_WRITE_TOOLS=false`.
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
- With 150+ tools available, you may want to configure focused subsets for optimal AI agent performance. Use `ROOTLY_MCP_ENABLED_TOOLS` to activate specific workflows:
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="listIncidents,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"
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="listIncidents,search_incidents,collect_incidents,listTeams,listServices,listSchedules,get_oncall_shift_metrics,get_shift_incidents,listDashboards,getDashboard,listAlerts,listHeartbeats,listPulses,getCurrentUser,list_endpoints"
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": "listIncidents,getIncident,createIncident,find_related_incidents,suggest_solutions..."
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 server configuration exposes **150+ tools**.
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
- Default remote config (HTTP streamable):
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
- **Streamable HTTP**
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
- ```bash
86
- claude mcp add rootly-codemode --transport http https://mcp.rootly.com/mcp-codemode \
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
- SSE (alternative):
93
+ **With API Token:**
91
94
 
92
95
  ```bash
93
- claude mcp add --transport sse rootly-sse https://mcp.rootly.com/sse \
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
- > **Note:** The `--transport http` flag ensures HTTP streamable transport is used instead of auto-falling back to SSE.
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
- Both hosted and self-hosted deployments expose the same curated tool surface by default, including the default write-enabled tools. To restrict that surface to read-only tools, start the server with `--no-enable-write-tools` or set `ROOTLY_MCP_ENABLE_WRITE_TOOLS=false`.
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
- With 150+ tools available, you may want to configure focused subsets for optimal AI agent performance. Use `ROOTLY_MCP_ENABLED_TOOLS` to activate specific workflows:
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="listIncidents,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"
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="listIncidents,search_incidents,collect_incidents,listTeams,listServices,listSchedules,get_oncall_shift_metrics,get_shift_incidents,listDashboards,getDashboard,listAlerts,listHeartbeats,listPulses,getCurrentUser,list_endpoints"
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": "listIncidents,getIncident,createIncident,find_related_incidents,suggest_solutions..."
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 server configuration exposes **150+ tools**.
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.8"
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"
@@ -7,12 +7,13 @@ This module provides the main entry point for the Rootly MCP Server.
7
7
 
8
8
  import argparse
9
9
  import asyncio
10
+ import importlib
10
11
  import logging
11
12
  import os
12
13
  import sys
13
14
  from contextlib import AsyncExitStack, asynccontextmanager
14
15
  from pathlib import Path
15
- from typing import Literal, cast
16
+ from typing import Any, Literal, cast
16
17
 
17
18
  from .code_mode import (
18
19
  code_mode_enabled_from_env,
@@ -24,6 +25,7 @@ from .exceptions import RootlyConfigurationError, RootlyMCPError
24
25
  from .security import validate_api_token
25
26
  from .server import create_rootly_mcp_server, get_hosted_auth_middleware
26
27
  from .server_defaults import enabled_tools_from_env, write_tools_enabled_from_env
28
+ from .transport import get_hosted_authenticated_user
27
29
 
28
30
  TransportName = Literal["stdio", "sse", "streamable-http", "both"]
29
31
  TRANSPORT_ALIASES: dict[str, TransportName] = {
@@ -77,6 +79,52 @@ def streamable_http_stateless_enabled(*, hosted: bool, fastmcp_stateless_http: b
77
79
  return hosted
78
80
 
79
81
 
82
+ def maybe_enable_mcpcat_tracking(server, project_id: str | None, logger: logging.Logger) -> None:
83
+ """Enable MCPcat tracking when configured and available.
84
+
85
+ The Python MCPcat package is currently deployed separately from the core
86
+ server dependency set, so we load it lazily and only when a project ID is
87
+ configured. This keeps the base server behavior unchanged for self-hosted
88
+ users and local development environments that do not install MCPcat.
89
+ """
90
+ if not project_id:
91
+ return
92
+
93
+ try:
94
+ mcpcat = importlib.import_module("mcpcat")
95
+ mcpcat_types = importlib.import_module("mcpcat.types")
96
+ except ImportError:
97
+ logger.warning(
98
+ "ROOTLY_MCPCAT_PROJECT_ID is set but mcpcat is not installed; skipping MCPcat tracking"
99
+ )
100
+ return
101
+
102
+ try:
103
+ options = mcpcat_types.MCPCatOptions(
104
+ identify=build_mcpcat_identify_callback(mcpcat_types.UserIdentity),
105
+ )
106
+ mcpcat.track(server, project_id, options)
107
+ except Exception:
108
+ logger.warning("MCPcat tracking could not be enabled; skipping", exc_info=True)
109
+
110
+
111
+ def build_mcpcat_identify_callback(user_identity_cls: type[Any]):
112
+ """Build a lightweight MCPcat identify callback from hosted auth context."""
113
+
114
+ def identify(_request: dict[str, Any], _context: Any) -> Any:
115
+ user = get_hosted_authenticated_user()
116
+ if not user:
117
+ return None
118
+
119
+ return user_identity_cls(
120
+ user_id=user["id"],
121
+ user_name=(user.get("full_name_with_team") or user.get("name") or user.get("email")),
122
+ user_data=None,
123
+ )
124
+
125
+ return identify
126
+
127
+
80
128
  def parse_args():
81
129
  """Parse command-line arguments."""
82
130
  parser = argparse.ArgumentParser(description="Start the Rootly MCP server for API integration.")
@@ -217,7 +265,7 @@ def get_server():
217
265
  base_url = os.getenv("ROOTLY_BASE_URL")
218
266
  transport = normalize_transport_or_default(os.getenv("ROOTLY_TRANSPORT", "stdio"))
219
267
  enable_write_tools = write_tools_enabled_from_env(default=True)
220
- enabled_tools = enabled_tools_from_env()
268
+ enabled_tools = enabled_tools_from_env(hosted=hosted)
221
269
 
222
270
  # Parse allowed paths from environment variable
223
271
  allowed_paths = None
@@ -419,7 +467,7 @@ def main():
419
467
  enabled_tools = (
420
468
  {tool.strip() for tool in args.enabled_tools.split(",") if tool.strip()}
421
469
  if args.enabled_tools
422
- else enabled_tools_from_env()
470
+ else enabled_tools_from_env(hosted=hosted_mode)
423
471
  )
424
472
 
425
473
  logger.info(f"Initializing server with name: {args.name}")
@@ -434,6 +482,7 @@ def main():
434
482
  if args.code_mode_path
435
483
  else code_mode_path_from_env()
436
484
  )
485
+ mcpcat_project_id = os.getenv("ROOTLY_MCPCAT_PROJECT_ID")
437
486
  server = create_rootly_mcp_server(
438
487
  swagger_path=args.swagger_path,
439
488
  name=args.name,
@@ -471,6 +520,10 @@ def main():
471
520
  )
472
521
  logger.info("Code Mode enabled at path: %s", code_mode_path)
473
522
 
523
+ maybe_enable_mcpcat_tracking(server, mcpcat_project_id, logger)
524
+ if code_mode_server is not None:
525
+ maybe_enable_mcpcat_tracking(code_mode_server, mcpcat_project_id, logger)
526
+
474
527
  logger.info(f"Running server with transport: {normalized_transport}...")
475
528
  direct_streamable_stateless_http = streamable_http_stateless_enabled(
476
529
  hosted=hosted_mode,