rootly-mcp-server 2.3.8__tar.gz → 2.3.16__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 (89) hide show
  1. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.github/workflows/ci.yml +19 -19
  2. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.github/workflows/openapi-audit.yml +6 -6
  3. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.github/workflows/pypi-release.yml +3 -3
  4. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/CHANGELOG.md +137 -0
  5. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/CONTRIBUTING.md +10 -6
  6. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/Dockerfile +10 -2
  7. rootly_mcp_server-2.3.16/Makefile +87 -0
  8. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/PKG-INFO +245 -163
  9. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/README.md +230 -155
  10. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/examples/skills/README.md +2 -2
  11. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/pyproject.toml +18 -11
  12. rootly_mcp_server-2.3.16/scripts/setup-hooks.sh +39 -0
  13. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/server.json +1 -1
  14. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/__main__.py +358 -46
  15. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/code_mode.py +1 -1
  16. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/server.py +337 -95
  17. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/server_defaults.py +207 -27
  18. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/spec_transform.py +61 -15
  19. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/tools/alerts.py +16 -2
  20. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/tools/incidents.py +248 -125
  21. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/tools/oncall.py +37 -17
  22. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/tools/resources.py +1 -1
  23. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/transport.py +319 -35
  24. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/utils.py +2 -0
  25. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/integration/local/test_tool_allowlists.py +11 -2
  26. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/integration/remote/test_essential.py +15 -12
  27. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_alert_stripping.py +23 -5
  28. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_alert_tools.py +29 -0
  29. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_code_mode_module.py +1 -1
  30. rootly_mcp_server-2.3.16/tests/unit/test_main_transport.py +643 -0
  31. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_server.py +388 -107
  32. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_server_defaults_module.py +45 -2
  33. rootly_mcp_server-2.3.16/tests/unit/test_snakecase_tools.py +171 -0
  34. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_tools.py +427 -120
  35. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_transport_module.py +326 -12
  36. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/uv.lock +305 -247
  37. rootly_mcp_server-2.3.8/scripts/setup-hooks.sh +0 -66
  38. rootly_mcp_server-2.3.8/src/rootly_mcp_server/pagination.py +0 -98
  39. rootly_mcp_server-2.3.8/tests/unit/test_main_transport.py +0 -193
  40. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.dockerignore +0 -0
  41. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.gitattributes +0 -0
  42. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.github/dependabot.yml +0 -0
  43. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.github/openapi-audit-remote-baseline.json +0 -0
  44. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.github/workflows/dependency-review.yml +0 -0
  45. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.gitignore +0 -0
  46. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.mcp.json +0 -0
  47. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.semaphore/deploy-staging.yml +0 -0
  48. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.semaphore/deploy.yml +0 -0
  49. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.semaphore/semaphore.yml +0 -0
  50. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/.semaphore/update-task-definition.sh +0 -0
  51. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/LICENSE +0 -0
  52. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/gemini-extension.json +0 -0
  53. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/rootly-mcp-server-demo.gif +0 -0
  54. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/rootly_openapi.json +0 -0
  55. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/scripts/audit_openapi.py +0 -0
  56. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/__init__.py +0 -0
  57. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/audit.py +0 -0
  58. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/client.py +0 -0
  59. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/data/__init__.py +0 -0
  60. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/exceptions.py +0 -0
  61. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/legacy_server.py +0 -0
  62. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/mcp_error.py +0 -0
  63. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/monitoring.py +0 -0
  64. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/och_client.py +0 -0
  65. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/payload_stripping.py +0 -0
  66. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/security.py +0 -0
  67. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/smart_utils.py +0 -0
  68. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/tools/__init__.py +0 -0
  69. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/src/rootly_mcp_server/validators.py +0 -0
  70. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/README.md +0 -0
  71. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/conftest.py +0 -0
  72. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/integration/local/test_basic.py +0 -0
  73. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/integration/local/test_smart_tools.py +0 -0
  74. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/test_client.py +0 -0
  75. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_authentication.py +0 -0
  76. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_exceptions.py +0 -0
  77. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_http_headers.py +0 -0
  78. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_legacy_server_module.py +0 -0
  79. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_mcp_error_module.py +0 -0
  80. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_och_client.py +0 -0
  81. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_oncall_handoff.py +0 -0
  82. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_oncall_metrics.py +0 -0
  83. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_oncall_new_tools.py +0 -0
  84. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_oncall_severity_normalization.py +0 -0
  85. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_payload_stripping_module.py +0 -0
  86. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_security.py +0 -0
  87. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_smart_utils.py +0 -0
  88. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_utils.py +0 -0
  89. {rootly_mcp_server-2.3.8 → rootly_mcp_server-2.3.16}/tests/unit/test_validators.py +0 -0
@@ -15,16 +15,16 @@ concurrency:
15
15
 
16
16
  jobs:
17
17
  quality:
18
- name: Quality (Python 3.12)
18
+ name: Quality (Python 3.13)
19
19
  runs-on: ubuntu-latest
20
20
  steps:
21
21
  - name: Checkout code
22
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
22
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
23
23
 
24
24
  - name: Set up Python
25
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
25
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
26
26
  with:
27
- python-version: "3.12"
27
+ python-version: "3.13"
28
28
 
29
29
  - name: Install uv
30
30
  uses: astral-sh/setup-uv@7eb50e6e20e1e2009087999ba91242e80253875f # v7
@@ -53,10 +53,10 @@ jobs:
53
53
 
54
54
  steps:
55
55
  - name: Checkout code
56
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
56
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
57
57
 
58
58
  - name: Set up Python ${{ matrix.python-version }}
59
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
59
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
60
60
  with:
61
61
  python-version: ${{ matrix.python-version }}
62
62
 
@@ -70,14 +70,14 @@ jobs:
70
70
  run: uv run pytest tests/unit/ --cov=src/rootly_mcp_server --cov-report=xml
71
71
 
72
72
  - name: Run local integration tests
73
- if: matrix.python-version == '3.12'
73
+ if: matrix.python-version == '3.13'
74
74
  env:
75
75
  ROOTLY_API_TOKEN: ${{ secrets.ROOTLY_API_TOKEN }}
76
76
  run: uv run pytest tests/integration/local/ -x
77
77
 
78
78
  - name: Upload coverage to Codecov
79
- if: matrix.python-version == '3.12'
80
- uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v5
79
+ if: matrix.python-version == '3.13'
80
+ uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v5
81
81
  with:
82
82
  file: ./coverage.xml
83
83
  flags: unittests
@@ -87,15 +87,15 @@ jobs:
87
87
  name: Container Tests
88
88
  runs-on: ubuntu-latest
89
89
  needs: test
90
- if: ${{ github.repository == 'Rootly-AI-Labs/rootly-mcp-server' }}
90
+ if: ${{ github.repository == 'rootlyhq/rootly-mcp-server' }}
91
91
  steps:
92
92
  - name: Checkout code
93
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
93
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
94
94
 
95
95
  - name: Set up Python
96
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
96
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
97
97
  with:
98
- python-version: "3.12"
98
+ python-version: "3.13"
99
99
 
100
100
  - name: Install uv
101
101
  uses: astral-sh/setup-uv@7eb50e6e20e1e2009087999ba91242e80253875f # v7
@@ -135,12 +135,12 @@ jobs:
135
135
  runs-on: ubuntu-latest
136
136
  steps:
137
137
  - name: Checkout code
138
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
138
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
139
139
 
140
140
  - name: Set up Python
141
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
141
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
142
142
  with:
143
- python-version: "3.12"
143
+ python-version: "3.13"
144
144
 
145
145
  - name: Install uv
146
146
  uses: astral-sh/setup-uv@7eb50e6e20e1e2009087999ba91242e80253875f # v7
@@ -161,12 +161,12 @@ jobs:
161
161
  needs: [quality, test, security]
162
162
  steps:
163
163
  - name: Checkout code
164
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
164
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
165
165
 
166
166
  - name: Set up Python
167
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
167
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
168
168
  with:
169
- python-version: "3.12"
169
+ python-version: "3.13"
170
170
 
171
171
  - name: Install uv
172
172
  uses: astral-sh/setup-uv@7eb50e6e20e1e2009087999ba91242e80253875f # v7
@@ -36,12 +36,12 @@ jobs:
36
36
  runs-on: ubuntu-latest
37
37
  steps:
38
38
  - name: Checkout code
39
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
39
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
40
40
 
41
41
  - name: Set up Python
42
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
42
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
43
43
  with:
44
- python-version: "3.12"
44
+ python-version: "3.13"
45
45
 
46
46
  - name: Install uv
47
47
  uses: astral-sh/setup-uv@7eb50e6e20e1e2009087999ba91242e80253875f # v7
@@ -58,12 +58,12 @@ jobs:
58
58
  if: ${{ github.event_name != 'pull_request' }}
59
59
  steps:
60
60
  - name: Checkout code
61
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
61
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
62
62
 
63
63
  - name: Set up Python
64
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
64
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
65
65
  with:
66
- python-version: "3.12"
66
+ python-version: "3.13"
67
67
 
68
68
  - name: Install uv
69
69
  uses: astral-sh/setup-uv@7eb50e6e20e1e2009087999ba91242e80253875f # v7
@@ -13,12 +13,12 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
15
  - name: Checkout code
16
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
16
+ uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
17
17
 
18
18
  - name: Set up Python
19
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
19
+ uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
20
20
  with:
21
- python-version: '3.12'
21
+ python-version: '3.13'
22
22
 
23
23
  - name: Install uv and build tools
24
24
  run: |
@@ -5,6 +5,143 @@ 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.16] - Released 2026-07-23
9
+
10
+ ### Added
11
+
12
+ - **Meeting Recordings & Transcripts**: Added read-only tools `get_meeting_recording`, `list_meeting_recordings`, and `list_all_meeting_recordings` so agents can read call transcripts (the `meeting_transcript` / `meeting_transcript_formatted` data). Call `get_meeting_recording` with `include=transcript` for the full transcript. Refreshed the bundled `data/swagger.json` from source to pick up these endpoints
13
+
14
+ ### Fixed
15
+
16
+ - **Incident Tool Hardening (follow-ups)**: A cluster of robustness fixes for the incident tools. Consolidated the incident-reference error taxonomy into one helper so `update_incident`, `find_related_incidents`, and `suggest_solutions` now report an unknown sequential number as `not_found` and a bad reference as `validation_error` (matching `get_incident`) instead of a generic error. Incident-reference resolution now rejects path-altering `"direct"` references (e.g. `../../…`, embedded slashes/whitespace) so a reference can't redirect the request to a different endpoint. Incident summarization tolerates a present-but-null `attributes` field instead of raising. `update_incident` now normalizes `summary` like `create_incident` (a whitespace-only summary is treated as no field). `search_incidents` multi-page mode now flags truncated results with `meta.partial`/`meta.error` instead of silently returning a partial set as complete. `list_incidents` and `search_incidents` append actionable guidance (use filters / `collect_incidents`) when a deep-page request fails with a client error. Removed the unused, uncapped `pagination.py` helpers
17
+ - **Sequential Incident Lookups (400 Bad Request)**: Resolving an incident by its human-readable number (e.g. `57597`, `#57597`, `INC-57597`) no longer walks the entire incident list to find a match. The old approach binary-searched pages sorted by `-created_at`, and its first probe requested a high `page[number]` that the API rejects with a 400 once an account has enough incidents — so sequential lookups failed regardless of the number passed while UUIDs kept working. `get_incident` (and every other tool that accepts an incident reference) now resolves the number with a single direct `filter[sequential_id]` request. Also made the `INC-` prefix case-insensitive so lowercase `inc-57597` resolves correctly, and capped `suggest_solutions`' page size at the API maximum (100, was 150)
18
+ - **Alert Payload Returned on Detail Lookups**: Single-alert lookups now return the full alert payload, including custom fields. Alert responses were stripped to a whitelist of essential attributes to keep payloads small, but this also dropped the raw `data` payload — where custom fields such as runbook links live (the same data shown under the Rootly UI's alert "payload" tab). The strip now applies only to list/search responses; single-resource detail lookups (`GET /v1/alerts/{id}`) preserve their full attribute set, while relationships are still collapsed to counts and sideloaded `included` data is dropped to keep responses bounded. The curated `get_alert_by_short_id` tool also passes through `data`, `alert_field_values`, and `labels` (plus `external_url` and `updated_at`). Verified end-to-end against a live alert
19
+
20
+ ### Security
21
+
22
+ - **Dependency Bumps to Resolve Dependabot Alerts**: Raised direct override constraints in `pyproject.toml` (and regenerated `uv.lock`) to pull patched versions of vulnerable transitive dependencies, resolving all 16 open Dependabot alerts:
23
+ - `starlette` 0.52.1 → 1.3.1 (GHSA-82w8-qh3p-5jfq, -jp82-jpqv-5vv3, -wqp7-x3pw-xc5r, -x746-7m8f-x49c — DoS, SSRF)
24
+ - `cryptography` 46.0.7 → 49.0.0 (GHSA-537c-gmf6-5ccf — bundled OpenSSL)
25
+ - `python-multipart` 0.0.28 → 0.0.32 (CVE-2026-40347, GHSA-v9pg-7xvm-68hf, -6jv3-5f52-599m, -vffw-93wf-4j4q — DoS / parameter smuggling)
26
+ - `pyjwt` 2.12.1 → 2.13.0 (GHSA-xgmm-8j9v-c9wx, -993g-76c3-p5m4, -w7vc-732c-9m39, -jq35-7prp-9v3f, -fhv5-28vv-h8m8 — token forgery / DoS)
27
+ - `msgpack` 1.1.2 → 1.2.1 (GHSA-6v7p-g79w-8964 — out-of-bounds read)
28
+ - `authlib` 1.7.0 → 1.7.2 (GHSA-w8p2-r796-3vmq — OAuth open redirect)
29
+ - **Follow-up Dependency Bumps**: Raised override constraints for newly disclosed vulnerabilities in transitive dependencies (`uv.lock` regenerated):
30
+ - `mcp` 1.26.0 → 1.28.1 (CVE-2026-52870, CVE-2026-52869, CVE-2026-59950)
31
+ - `joserfc` 1.6.4 → 1.7.4 (PYSEC-2026-2528, PYSEC-2026-2530)
32
+ - `idna` 3.10 → 3.18 (PYSEC-2026-215)
33
+ - `click` 8.1.8 → 8.4.2 (PYSEC-2026-2132)
34
+
35
+ ### Testing
36
+
37
+ - Added coverage for detail-lookup payload preservation, list-response stripping (unchanged), and the `get_alert_by_short_id` payload/custom-field pass-through
38
+
39
+ ## [2.3.14] - Released 2026-06-05
40
+
41
+ ### Features
42
+
43
+ - **`list_incident_roles` Tool**: Added a curated `list_incident_roles(incident_id)` tool that returns role assignments for an incident (Commander, Postmortem Owner, Scribe, etc.) as a flat table with role metadata and the assigned user. Wraps `GET /v1/incidents/{id}?include=roles` and flattens the JSON:API `included` array so callers don't have to walk the relationships graph. Included in the default hosted tool surface
44
+
45
+ ### Fixed
46
+
47
+ - **Misnamed Tool Argument Normalization**: Added argument normalization middleware to recover from common LLM/client parameter mistakes before Pydantic validation runs. This now remaps `from`/`to` to `from_date`/`to_date` for `list_shifts`, remaps `max_tokens` to `max_results` for `search_incidents`, and coerces list-shaped schedule/shift identifiers into the CSV form expected by the current tool schemas
48
+
49
+ ### Testing
50
+
51
+ - Expanded snake_case and argument-normalization coverage for alias handling, CSV coercion, and misnamed-argument recovery paths
52
+ - Added coverage for `list_incident_roles` happy path, unassigned roles, sequential reference resolution, and validation errors
53
+
54
+ ## [2.3.13] - Released 2026-06-01
55
+
56
+ ### Features
57
+
58
+ - **OAuth Authorization Server Metadata**: Hosted MCP deployments now serve RFC 8414 authorization server metadata so OAuth-capable clients can discover Rootly's authorization endpoints directly from the MCP server
59
+ - **Safe Write Surface Expanded**: The default write-allowed surface now exposes a broader set of non-destructive tools for alerts, alert events, alert routes, alert sources, custom forms, form fields, workflow runs, status page templates, and related resources when write tools are enabled
60
+
61
+ ### Fixed
62
+
63
+ - **Snake Case Tool Names**: OpenAPI-generated MCP tools are now normalized to `snake_case`, with a compatibility bridge for legacy camelCase callers, so tool discovery and invocation are more predictable across MCP clients
64
+ - **ASGI Response Double-Send Guard**: Hosted auth middleware now suppresses orphaned or duplicate body frames after a response is already dropped or completed, preventing duplicate ASGI response behavior in production
65
+ - **OAuth Scope Compatibility**: Protected resource metadata now advertises a single coarse `all` scope instead of many granular scopes, improving compatibility with MCP clients that fail to forward fine-grained scopes through dynamic client registration
66
+
67
+ ### Infrastructure
68
+
69
+ - **Docker Base Updated**: The container image now builds on `python:3.13-slim`
70
+
71
+ ### Testing
72
+
73
+ - Added focused coverage for snake_case normalization and the camelCase alias bridge
74
+ - Added/updated hosted and server allowlist coverage for the expanded write surface
75
+
76
+ ## [2.3.12] - Released 2026-05-28
77
+
78
+ ### Fixed
79
+
80
+ - **Unfilled Path Templates**: When a tool was called with a missing or misnamed path argument (e.g. `schedule_id` instead of `id`), FastMCP left the literal `{id}` placeholder in the URL and the encoded `%7Bid%7D` was sent upstream, producing a misleading 404 "Not found or unauthorized". The transport layer now detects unfilled placeholders in the URL path and raises a `RootlyValidationError` naming the missing parameter before any upstream call
81
+ - **Deprecated Alert Routing Endpoint**: Tenants with Advanced Alert Routing enabled were repeatedly hitting 403s on `/v1/alert_routing_rules`. The replacement `listAlertRoutes` / `getAlertRoute` operations are now exposed in the default allowlist, and 403 responses with the Advanced Alert Routing message are annotated with a structured `_use_tool` field pointing models at the correct replacement
82
+ - **Schedule Shift Date Range Cap**: `getScheduleShifts` and `listShifts` callers regularly hit opaque 422 errors after sending `from`/`to` windows larger than the upstream cap (1 month and 2 months respectively). A pre-flight check now parses the dates and rejects oversized windows client-side with a clear chunking recommendation. `/v1/override_shifts/*` paths are excluded
83
+ - **Phantom `listIncidents` Tool**: `canonicalize_tool_names()` only expanded legacy → canonical aliases, so an allowlist mentioning `list_incidents` (the canonical name) stripped the curated `listIncidents` proxy. Alias expansion is now bidirectional, keeping both names exposed together during the deprecation window
84
+ - **Missing `createSchedule` In Hosted Slim Profile**: The `/schedules` POST endpoint was already write-allowed, but the operationId wasn't included in the slim hosted tool profile. Added so models can actually create schedules when write tools are enabled
85
+ - **Param-Name Discoverability**: Production logs showed models repeatedly guessing wrong on parameter names that were unobvious from tool descriptions. Tool descriptions now explicitly name the canonical argument shape for `getIncident` (`incident_id`, not `id`), the `max_results <= 10` cap on `search_incidents`, the `user_ids` (not `emails`) contract on `check_responder_availability`, and the plural `schedule_ids` argument on `get_oncall_schedule_summary`
86
+
87
+ ### Testing
88
+
89
+ - Added focused transport coverage for unfilled-path-template rejection, shift date-range pre-flight (with override-shift lookalike exclusions), alert-routing 403 annotation, and false-positive guards on query-string braces and similar lookalike paths
90
+ - Extended `canonicalize_tool_names` coverage for both directions of the legacy/canonical pair
91
+
92
+ ## [2.3.11] - Released 2026-05-27
93
+
94
+ ### Features
95
+
96
+ - **Hosted Full Tool Surface by Default**: Hosted MCP deployments now expose the full tool surface by default again, so remote clients no longer miss create/update workflows that were absent from the slimmer hosted profile
97
+ - **Hosted Slim Profile Selector**: Added a slimmer hosted profile of about 70 high-usage tools that clients can opt into with `?tool_profile=slim`, `X-Rootly-Tool-Profile: slim`, or the `ROOTLY_MCP_HOSTED_TOOL_PROFILE` server setting
98
+
99
+ ### Configuration
100
+
101
+ - **Profile Override Precedence**: `ROOTLY_MCP_ENABLED_TOOLS` remains the highest-precedence override, so operators can still replace either hosted profile with an exact custom allowlist when needed
102
+
103
+ ### Documentation
104
+
105
+ - **Hosted Profile Guidance**: Updated the README to document full-vs-slim hosted usage options, server-wide profile defaults, and exact allowlist overrides
106
+
107
+ ### Dependencies
108
+
109
+ - **Lockfile Sync**: Regenerated `uv.lock` so the lockfile matches the current pinned package versions in `pyproject.toml`, including `fastmcp==3.3.1` and `requests==2.34.2`
110
+
111
+ ### Testing
112
+
113
+ - **Hosted Routing Coverage**: Added coverage for hosted profile resolution, profiled streamable HTTP routing, explicit allowlist bypass behavior, and unknown profile fallback handling
114
+
115
+ ## [2.3.10] - Released 2026-05-26
116
+
117
+ ### Fixed
118
+
119
+ - **Blank Query Param Forwarding**: The MCP transport now drops empty string, whitespace-only, and empty collection query parameters before forwarding requests upstream, preventing optional blank filters from corrupting pagination or other serialized query values
120
+ - **Alerts Pagination Corruption Guard**: Hardened the shared request path used by OpenAPI-generated tools so requests that include blank optional filters no longer risk serializing `page[size]` incorrectly when valid pagination values are provided
121
+
122
+ ### Testing
123
+
124
+ - Added focused transport regression coverage for dropping blank query params in both direct parameter transforms and rebuilt outbound request URLs
125
+
126
+ ## [2.3.9] - Released 2026-05-21
127
+
128
+ ### Performance
129
+
130
+ - **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
131
+ - **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
132
+
133
+ ### Configuration
134
+
135
+ - **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
136
+
137
+ ### Documentation
138
+
139
+ - **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
140
+
141
+ ### Dependencies
142
+
143
+ - **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`
144
+
8
145
  ## [2.3.8] - Released 2026-05-19
9
146
 
10
147
  ### Security
@@ -39,19 +39,23 @@ uv pip install <package>
39
39
 
40
40
  ### 3. Set Up Git Hooks (Recommended)
41
41
 
42
- Install pre-commit hooks to automatically run linting and tests before commits:
42
+ Install pre-commit hooks to automatically run the quality gate before commits:
43
43
 
44
44
  ```bash
45
- ./scripts/setup-hooks.sh
45
+ make hooks # or: ./scripts/setup-hooks.sh
46
46
  ```
47
47
 
48
- This ensures code quality by running:
49
- - Ruff linting
50
- - Pyright type checking
51
- - Unit tests
48
+ The hook runs `make check` (lint, format check, type checks, unit tests) —
49
+ the same gate CI enforces.
52
50
 
53
51
  ### 4. Verify Installation
54
52
 
55
53
  The server should now be ready to use with your MCP-compatible editor.
56
54
 
57
55
  Additional testing tools are available in the `tests/` directory.
56
+
57
+ ## Common Tasks
58
+
59
+ The `Makefile` wraps the toolchain; run `make help` to list every target.
60
+ Common ones: `make check` (pre-push gate), `make test`, and `make fetch-spec`
61
+ to refresh the bundled OpenAPI spec from source.
@@ -1,5 +1,5 @@
1
- # Use Python 3.12 slim image as base
2
- FROM python:3.12-slim
1
+ # Use Python 3.13 slim image as base
2
+ FROM python:3.13-slim
3
3
 
4
4
  # Set working directory
5
5
  WORKDIR /app
@@ -18,6 +18,14 @@ COPY . .
18
18
  # Install the package and its dependencies
19
19
  RUN uv pip install --system --no-cache-dir -e .
20
20
 
21
+ # Install AgentCat (formerly MCPcat) for hosted telemetry without changing the
22
+ # repo dependency graph. The [community] extra provides FastMCP support, which
23
+ # this server relies on. AgentCat's package metadata pins an older Pydantic
24
+ # range, but the SDK imports successfully with our runtime pin, so we restore
25
+ # the server's pinned version after installation.
26
+ RUN uv pip install --system --no-cache-dir "agentcat[community]==1.0.1" \
27
+ && uv pip install --system --no-cache-dir pydantic==2.13.4
28
+
21
29
  # Create non-root user
22
30
  RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app
23
31
 
@@ -0,0 +1,87 @@
1
+ .DEFAULT_GOAL := help
2
+
3
+ PYTHON_VERSION := 3.12
4
+ SPEC_URL := https://rootly-heroku.s3.amazonaws.com/swagger/v1/swagger.json
5
+ SPEC_PATH := src/rootly_mcp_server/data/swagger.json
6
+ PKG := src/rootly_mcp_server
7
+ UV := uv run --python $(PYTHON_VERSION)
8
+
9
+ IMAGE := rootly-mcp-server
10
+
11
+ .PHONY: help install build run \
12
+ test test-unit test-integration \
13
+ lint format format-check typecheck security \
14
+ fetch-spec audit-spec \
15
+ docker-build docker-test \
16
+ check ci hooks clean
17
+
18
+ help: ## Show available targets
19
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
20
+ | awk 'BEGIN{FS=":.*?## "}{printf " \033[36m%-16s\033[0m %s\n", $$1, $$2}'
21
+
22
+ install: ## Install dependencies and the pinned Python via uv
23
+ uv sync --dev --python $(PYTHON_VERSION)
24
+
25
+ build: ## Build the sdist and wheel
26
+ uv build
27
+
28
+ run: ## Run the MCP server locally (needs ROOTLY_API_TOKEN)
29
+ $(UV) rootly-mcp-server
30
+
31
+ # --- tests ---
32
+ test: ## Run the full test suite (with coverage)
33
+ $(UV) pytest
34
+
35
+ test-unit: ## Run unit tests only
36
+ $(UV) pytest tests/unit/
37
+
38
+ test-integration: ## Run local integration tests (needs ROOTLY_API_TOKEN)
39
+ $(UV) pytest tests/integration/local/ -x
40
+
41
+ # --- quality ---
42
+ lint: ## Lint with ruff
43
+ $(UV) ruff check .
44
+
45
+ format: ## Auto-format with ruff
46
+ $(UV) ruff format .
47
+
48
+ format-check: ## Check formatting without modifying files (CI gate)
49
+ $(UV) ruff format --check .
50
+
51
+ typecheck: ## Type-check with pyright and mypy
52
+ $(UV) pyright
53
+ $(UV) mypy $(PKG)
54
+
55
+ security: ## Security scan (bandit blocking; pip-audit advisory, mirrors CI)
56
+ $(UV) bandit -r src/
57
+ -$(UV) pip-audit
58
+
59
+ # --- OpenAPI spec ---
60
+ fetch-spec: ## Refresh the bundled OpenAPI spec from source (never hand-edit it)
61
+ curl -fsS $(SPEC_URL) -o $(SPEC_PATH)
62
+
63
+ audit-spec: ## Audit the bundled spec for MCP tool-generation issues
64
+ $(UV) python scripts/audit_openapi.py --filtered-defaults --instantiate-server
65
+
66
+ # --- docker (mirrors the CI container-tests job) ---
67
+ docker-build: ## Build the Docker image
68
+ docker build -t $(IMAGE) .
69
+
70
+ docker-test: docker-build ## Build the image and run the containerized server smoke test (needs ROOTLY_API_TOKEN)
71
+ docker run -d --name $(IMAGE) -p 8000:8000 -e ROOTLY_API_TOKEN="$(ROOTLY_API_TOKEN)" $(IMAGE)
72
+ timeout 30s bash -c 'until curl -fsS http://localhost:8000/health || curl -fsS http://localhost:8000/; do sleep 2; done'
73
+ MCP_SERVER_URL=http://localhost:8000 $(UV) pytest tests/integration/remote/test_essential.py -v --timeout=60; \
74
+ status=$$?; docker stop $(IMAGE) && docker rm $(IMAGE); exit $$status
75
+
76
+ # --- aggregates ---
77
+ check: lint format-check typecheck test-unit ## Fast pre-push gate (mirrors CI quality + unit tests)
78
+
79
+ ci: lint format-check typecheck security test-unit audit-spec ## Everything CI enforces (excl. docker/remote)
80
+
81
+ # --- misc ---
82
+ hooks: ## Install the git pre-commit hook
83
+ ./scripts/setup-hooks.sh
84
+
85
+ clean: ## Remove build and test artifacts
86
+ rm -rf dist build .pytest_cache .mypy_cache .ruff_cache coverage.xml htmlcov
87
+ find . -type d -name __pycache__ -prune -exec rm -rf {} +