rootly-mcp-server 2.2.17__tar.gz → 2.2.19__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.2.17 → rootly_mcp_server-2.2.19}/CHANGELOG.md +34 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/PKG-INFO +7 -3
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/README.md +6 -2
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/pyproject.toml +1 -1
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/server_defaults.py +2 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/incidents.py +102 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_server.py +13 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_server_defaults_module.py +2 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_tools.py +65 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/uv.lock +1 -1
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.dockerignore +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.gitattributes +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/dependabot.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/openapi-audit-remote-baseline.json +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/workflows/ci.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/workflows/dependency-review.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/workflows/openapi-audit.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/workflows/pypi-release.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.gitignore +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.semaphore/deploy-staging.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.semaphore/deploy.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.semaphore/semaphore.yml +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.semaphore/update-task-definition.sh +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/CONTRIBUTING.md +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/Dockerfile +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/LICENSE +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/examples/skills/README.md +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/gemini-extension.json +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/rootly-mcp-server-demo.gif +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/rootly_openapi.json +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/scripts/audit_openapi.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/scripts/setup-hooks.sh +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/server.json +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/__init__.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/__main__.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/client.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/code_mode.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/data/__init__.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/exceptions.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/legacy_server.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/mcp_error.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/monitoring.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/och_client.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/pagination.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/payload_stripping.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/security.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/server.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/smart_utils.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/spec_transform.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/__init__.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/alerts.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/oncall.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/resources.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/transport.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/utils.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/validators.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/README.md +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/conftest.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/integration/local/test_basic.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/integration/local/test_smart_tools.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/integration/remote/test_essential.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/test_client.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_alert_stripping.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_authentication.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_code_mode_module.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_exceptions.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_http_headers.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_legacy_server_module.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_main_transport.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_mcp_error_module.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_och_client.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_oncall_handoff.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_oncall_metrics.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_oncall_new_tools.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_oncall_severity_normalization.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_payload_stripping_module.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_security.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_smart_utils.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_transport_module.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_utils.py +0 -0
- {rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_validators.py +0 -0
|
@@ -5,6 +5,40 @@ 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.2.19] - Released 2026-04-17
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
- **Scoped Incident Creation Tool**: Added a custom `createIncident` tool so agents can create incidents directly from MCP without exposing the full raw `/incidents` OpenAPI surface
|
|
13
|
+
|
|
14
|
+
### Documentation
|
|
15
|
+
|
|
16
|
+
- **Custom Tool List Updated**: Added `createIncident` to the README custom tool section with its scoped workflow-oriented behavior
|
|
17
|
+
|
|
18
|
+
## [2.2.18] - Released 2026-04-15
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
- **Workflow Task Tools**: Added complete workflow task management tools to enable creation, listing, retrieval, and updating of workflow actions/tasks
|
|
23
|
+
- **Enhanced Workflow Functionality**: Users can now build complete functional workflows instead of just workflow shells
|
|
24
|
+
|
|
25
|
+
### New Tools
|
|
26
|
+
|
|
27
|
+
- `createWorkflowTask` - Create new workflow actions (POST `/v1/workflows/{workflow_id}/workflow_tasks`)
|
|
28
|
+
- `listWorkflowTasks` - List all actions in a workflow (GET `/v1/workflows/{workflow_id}/workflow_tasks`)
|
|
29
|
+
- `getWorkflowTask` - Retrieve specific workflow action details (GET `/v1/workflow_tasks/{id}`)
|
|
30
|
+
- `updateWorkflowTask` - Modify existing workflow actions (PUT `/v1/workflow_tasks/{id}`)
|
|
31
|
+
|
|
32
|
+
### Documentation
|
|
33
|
+
|
|
34
|
+
- **Tool Count Updated**: Increased from 105 to 109 tools reflecting new workflow task capabilities
|
|
35
|
+
- **Tool List Updated**: Added workflow task tools to OpenAPI-generated tools section
|
|
36
|
+
- **Badge Cleanup**: Removed broken Cursor install badge
|
|
37
|
+
|
|
38
|
+
### Security
|
|
39
|
+
|
|
40
|
+
- **Delete Operations**: `deleteWorkflowTask` remains intentionally excluded following security policy for destructive operations
|
|
41
|
+
|
|
8
42
|
## [2.2.17] - Released 2026-04-14
|
|
9
43
|
|
|
10
44
|
### Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rootly-mcp-server
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.19
|
|
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
|
|
@@ -46,7 +46,6 @@ Description-Content-Type: text/markdown
|
|
|
46
46
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
47
47
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
48
48
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
49
|
-
[](https://cursor.com/install-mcp?name=rootly&config=eyJ1cmwiOiJodHRwczovL21jcC5yb290bHkuY29tL21jcCIsImhlYWRlcnMiOnsiQXV0aG9yaXphdGlvbiI6IkJlYXJlciA8WU9VUl9ST09UTFlfQVBJX1RPS0VOPiJ9fQo=)
|
|
50
49
|
|
|
51
50
|
An MCP server for the [Rootly API](https://docs.rootly.com/api-reference/overview) for Cursor, Windsurf, Claude, and other MCP clients.
|
|
52
51
|
|
|
@@ -409,13 +408,14 @@ docker run -p 8000:8000 \
|
|
|
409
408
|
|
|
410
409
|
## Supported Tools
|
|
411
410
|
|
|
412
|
-
The default server configuration exposes **
|
|
411
|
+
The default server configuration exposes **110 tools**.
|
|
413
412
|
|
|
414
413
|
### Custom Agentic Tools
|
|
415
414
|
|
|
416
415
|
- `check_oncall_health_risk`
|
|
417
416
|
- `check_responder_availability`
|
|
418
417
|
- `collect_incidents`
|
|
418
|
+
- `createIncident` - create a new incident with a scoped set of fields for agent workflows
|
|
419
419
|
- `create_override_recommendation`
|
|
420
420
|
- `find_related_incidents`
|
|
421
421
|
- `getIncident` - retrieve a single incident for direct verification, including PIR-related fields
|
|
@@ -457,6 +457,7 @@ createService
|
|
|
457
457
|
createSeverity
|
|
458
458
|
createTeam
|
|
459
459
|
createWorkflow
|
|
460
|
+
createWorkflowTask
|
|
460
461
|
deleteEscalationLevel
|
|
461
462
|
deleteEscalationPath
|
|
462
463
|
deleteEscalationPolicy
|
|
@@ -482,6 +483,7 @@ getSeverity
|
|
|
482
483
|
getTeam
|
|
483
484
|
getUser
|
|
484
485
|
getWorkflow
|
|
486
|
+
getWorkflowTask
|
|
485
487
|
listAlerts
|
|
486
488
|
listEnvironments
|
|
487
489
|
listEscalationLevels
|
|
@@ -506,6 +508,7 @@ listShifts
|
|
|
506
508
|
listTeams
|
|
507
509
|
listUsers
|
|
508
510
|
listWorkflows
|
|
511
|
+
listWorkflowTasks
|
|
509
512
|
updateAlert
|
|
510
513
|
updateEnvironment
|
|
511
514
|
updateEscalationLevel
|
|
@@ -524,6 +527,7 @@ updateSeverity
|
|
|
524
527
|
updateTeam
|
|
525
528
|
updateUser
|
|
526
529
|
updateWorkflow
|
|
530
|
+
updateWorkflowTask
|
|
527
531
|
```
|
|
528
532
|
|
|
529
533
|
Delete operations are intentionally scoped to screenshot coverage paths:
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
5
5
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
6
6
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
7
|
-
[](https://cursor.com/install-mcp?name=rootly&config=eyJ1cmwiOiJodHRwczovL21jcC5yb290bHkuY29tL21jcCIsImhlYWRlcnMiOnsiQXV0aG9yaXphdGlvbiI6IkJlYXJlciA8WU9VUl9ST09UTFlfQVBJX1RPS0VOPiJ9fQo=)
|
|
8
7
|
|
|
9
8
|
An MCP server for the [Rootly API](https://docs.rootly.com/api-reference/overview) for Cursor, Windsurf, Claude, and other MCP clients.
|
|
10
9
|
|
|
@@ -367,13 +366,14 @@ docker run -p 8000:8000 \
|
|
|
367
366
|
|
|
368
367
|
## Supported Tools
|
|
369
368
|
|
|
370
|
-
The default server configuration exposes **
|
|
369
|
+
The default server configuration exposes **110 tools**.
|
|
371
370
|
|
|
372
371
|
### Custom Agentic Tools
|
|
373
372
|
|
|
374
373
|
- `check_oncall_health_risk`
|
|
375
374
|
- `check_responder_availability`
|
|
376
375
|
- `collect_incidents`
|
|
376
|
+
- `createIncident` - create a new incident with a scoped set of fields for agent workflows
|
|
377
377
|
- `create_override_recommendation`
|
|
378
378
|
- `find_related_incidents`
|
|
379
379
|
- `getIncident` - retrieve a single incident for direct verification, including PIR-related fields
|
|
@@ -415,6 +415,7 @@ createService
|
|
|
415
415
|
createSeverity
|
|
416
416
|
createTeam
|
|
417
417
|
createWorkflow
|
|
418
|
+
createWorkflowTask
|
|
418
419
|
deleteEscalationLevel
|
|
419
420
|
deleteEscalationPath
|
|
420
421
|
deleteEscalationPolicy
|
|
@@ -440,6 +441,7 @@ getSeverity
|
|
|
440
441
|
getTeam
|
|
441
442
|
getUser
|
|
442
443
|
getWorkflow
|
|
444
|
+
getWorkflowTask
|
|
443
445
|
listAlerts
|
|
444
446
|
listEnvironments
|
|
445
447
|
listEscalationLevels
|
|
@@ -464,6 +466,7 @@ listShifts
|
|
|
464
466
|
listTeams
|
|
465
467
|
listUsers
|
|
466
468
|
listWorkflows
|
|
469
|
+
listWorkflowTasks
|
|
467
470
|
updateAlert
|
|
468
471
|
updateEnvironment
|
|
469
472
|
updateEscalationLevel
|
|
@@ -482,6 +485,7 @@ updateSeverity
|
|
|
482
485
|
updateTeam
|
|
483
486
|
updateUser
|
|
484
487
|
updateWorkflow
|
|
488
|
+
updateWorkflowTask
|
|
485
489
|
```
|
|
486
490
|
|
|
487
491
|
Delete operations are intentionally scoped to screenshot coverage paths:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "rootly-mcp-server"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.19"
|
|
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"
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/incidents.py
RENAMED
|
@@ -29,6 +29,14 @@ def _split_csv_values(value: str) -> list[str]:
|
|
|
29
29
|
return [part.strip() for part in value.split(",") if part.strip()]
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
def _normalize_optional_text(value: str | None) -> str | None:
|
|
33
|
+
"""Normalize optional text inputs by trimming whitespace and empty values."""
|
|
34
|
+
if value is None:
|
|
35
|
+
return None
|
|
36
|
+
normalized = value.strip()
|
|
37
|
+
return normalized or None
|
|
38
|
+
|
|
39
|
+
|
|
32
40
|
def _extract_incident_severity(severity_value: Any) -> str | None:
|
|
33
41
|
"""Normalize severity values from Rootly API responses into a compact string."""
|
|
34
42
|
if severity_value is None:
|
|
@@ -641,6 +649,100 @@ def register_incident_tools(
|
|
|
641
649
|
),
|
|
642
650
|
)
|
|
643
651
|
|
|
652
|
+
@mcp.tool(name="createIncident")
|
|
653
|
+
async def create_incident(
|
|
654
|
+
title: Annotated[
|
|
655
|
+
str | None,
|
|
656
|
+
Field(description="Incident title. If omitted, Rootly may autogenerate one."),
|
|
657
|
+
] = None,
|
|
658
|
+
summary: Annotated[
|
|
659
|
+
str | None,
|
|
660
|
+
Field(description="Incident summary or short description."),
|
|
661
|
+
] = None,
|
|
662
|
+
severity_id: Annotated[
|
|
663
|
+
str | None,
|
|
664
|
+
Field(description="Optional severity ID to attach to the incident."),
|
|
665
|
+
] = None,
|
|
666
|
+
service_ids: Annotated[
|
|
667
|
+
str | None,
|
|
668
|
+
Field(description="Comma-separated service IDs to attach to the incident."),
|
|
669
|
+
] = None,
|
|
670
|
+
team_ids: Annotated[
|
|
671
|
+
str | None,
|
|
672
|
+
Field(description="Comma-separated team IDs to attach to the incident."),
|
|
673
|
+
] = None,
|
|
674
|
+
environment_ids: Annotated[
|
|
675
|
+
str | None,
|
|
676
|
+
Field(description="Comma-separated environment IDs to attach to the incident."),
|
|
677
|
+
] = None,
|
|
678
|
+
incident_type_ids: Annotated[
|
|
679
|
+
str | None,
|
|
680
|
+
Field(description="Comma-separated incident type IDs to attach to the incident."),
|
|
681
|
+
] = None,
|
|
682
|
+
) -> JsonDict:
|
|
683
|
+
"""Create an incident with a scoped set of fields for agent-driven workflows."""
|
|
684
|
+
normalized_title = _normalize_optional_text(title)
|
|
685
|
+
normalized_summary = _normalize_optional_text(summary)
|
|
686
|
+
|
|
687
|
+
if normalized_title is None and normalized_summary is None:
|
|
688
|
+
return cast(
|
|
689
|
+
JsonDict,
|
|
690
|
+
mcp_error.tool_error(
|
|
691
|
+
"Must provide at least one of title or summary",
|
|
692
|
+
"validation_error",
|
|
693
|
+
),
|
|
694
|
+
)
|
|
695
|
+
|
|
696
|
+
attributes: dict[str, Any] = {}
|
|
697
|
+
|
|
698
|
+
if normalized_title is not None:
|
|
699
|
+
attributes["title"] = normalized_title
|
|
700
|
+
if normalized_summary is not None:
|
|
701
|
+
attributes["summary"] = normalized_summary
|
|
702
|
+
|
|
703
|
+
normalized_severity_id = _normalize_optional_text(severity_id)
|
|
704
|
+
if normalized_severity_id is not None:
|
|
705
|
+
attributes["severity_id"] = normalized_severity_id
|
|
706
|
+
|
|
707
|
+
csv_attribute_map = (
|
|
708
|
+
("service_ids", service_ids),
|
|
709
|
+
("group_ids", team_ids),
|
|
710
|
+
("environment_ids", environment_ids),
|
|
711
|
+
("incident_type_ids", incident_type_ids),
|
|
712
|
+
)
|
|
713
|
+
for attribute_name, raw_value in csv_attribute_map:
|
|
714
|
+
if raw_value is None:
|
|
715
|
+
continue
|
|
716
|
+
values = _split_csv_values(raw_value)
|
|
717
|
+
if values:
|
|
718
|
+
attributes[attribute_name] = values
|
|
719
|
+
|
|
720
|
+
payload = {
|
|
721
|
+
"data": {
|
|
722
|
+
"type": "incidents",
|
|
723
|
+
"attributes": attributes,
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
try:
|
|
728
|
+
response = await make_authenticated_request("POST", "/v1/incidents", json=payload)
|
|
729
|
+
response.raise_for_status()
|
|
730
|
+
|
|
731
|
+
response_data = response.json()
|
|
732
|
+
if isinstance(response_data.get("data"), dict):
|
|
733
|
+
stripped = strip_heavy_nested_data({"data": [response_data["data"]]})
|
|
734
|
+
response_data["data"] = stripped["data"][0]
|
|
735
|
+
return cast(JsonDict, response_data)
|
|
736
|
+
except Exception as e:
|
|
737
|
+
error_type, error_message = mcp_error.categorize_error(e)
|
|
738
|
+
return cast(
|
|
739
|
+
JsonDict,
|
|
740
|
+
mcp_error.tool_error(
|
|
741
|
+
f"Failed to create incident: {error_message}",
|
|
742
|
+
error_type,
|
|
743
|
+
),
|
|
744
|
+
)
|
|
745
|
+
|
|
644
746
|
@mcp.tool(name="updateIncident")
|
|
645
747
|
async def update_incident(
|
|
646
748
|
incident_id: Annotated[str, Field(description="Incident ID to update")],
|
|
@@ -215,6 +215,19 @@ class TestBundledIncidentFormFieldSelectionTools:
|
|
|
215
215
|
|
|
216
216
|
assert "deleteIncidentFormFieldSelection" not in tool_names
|
|
217
217
|
|
|
218
|
+
async def test_workflow_task_tools_are_available_without_delete(self, mock_environment_token):
|
|
219
|
+
server = create_rootly_mcp_server(hosted=False)
|
|
220
|
+
|
|
221
|
+
tools = await server.list_tools()
|
|
222
|
+
tool_names = {tool.name for tool in tools}
|
|
223
|
+
|
|
224
|
+
assert "createWorkflowTask" in tool_names
|
|
225
|
+
assert "listWorkflowTasks" in tool_names
|
|
226
|
+
assert "getWorkflowTask" in tool_names
|
|
227
|
+
assert "updateWorkflowTask" in tool_names
|
|
228
|
+
|
|
229
|
+
assert "deleteWorkflowTask" not in tool_names
|
|
230
|
+
|
|
218
231
|
|
|
219
232
|
@pytest.mark.unit
|
|
220
233
|
class TestAuthenticatedHTTPXClient:
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_server_defaults_module.py
RENAMED
|
@@ -11,6 +11,8 @@ class TestServerDefaultsModule:
|
|
|
11
11
|
assert "/incidents/{incident_id}/alerts" in DEFAULT_ALLOWED_PATHS
|
|
12
12
|
assert "/incidents/{incident_id}/form_field_selections" in DEFAULT_ALLOWED_PATHS
|
|
13
13
|
assert "/incident_form_field_selections/{id}" in DEFAULT_ALLOWED_PATHS
|
|
14
|
+
assert "/workflows/{workflow_id}/workflow_tasks" in DEFAULT_ALLOWED_PATHS
|
|
15
|
+
assert "/workflow_tasks/{id}" in DEFAULT_ALLOWED_PATHS
|
|
14
16
|
assert "/shifts" in DEFAULT_ALLOWED_PATHS
|
|
15
17
|
assert "/on_call_roles" in DEFAULT_ALLOWED_PATHS
|
|
16
18
|
|
|
@@ -143,9 +143,74 @@ class TestScopedIncidentUpdateTool:
|
|
|
143
143
|
async def test_update_incident_tool_is_registered_with_customer_facing_name(self):
|
|
144
144
|
tools, _ = self._register_tools()
|
|
145
145
|
|
|
146
|
+
assert "createIncident" in tools
|
|
146
147
|
assert "updateIncident" in tools
|
|
147
148
|
assert "getIncident" in tools
|
|
148
149
|
|
|
150
|
+
@pytest.mark.asyncio
|
|
151
|
+
async def test_create_incident_sends_only_allowed_fields(self):
|
|
152
|
+
tools, request = self._register_tools()
|
|
153
|
+
response = Mock()
|
|
154
|
+
response.raise_for_status.return_value = None
|
|
155
|
+
response.json.return_value = {
|
|
156
|
+
"data": {
|
|
157
|
+
"id": "inc-123",
|
|
158
|
+
"type": "incidents",
|
|
159
|
+
"attributes": {
|
|
160
|
+
"title": "Database latency spike",
|
|
161
|
+
"summary": "Primary API requests timing out",
|
|
162
|
+
"severity_id": "sev-1",
|
|
163
|
+
"service_ids": ["svc-1", "svc-2"],
|
|
164
|
+
"group_ids": ["team-1", "team-2"],
|
|
165
|
+
"environment_ids": ["env-1"],
|
|
166
|
+
"incident_type_ids": ["type-1"],
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
request.return_value = response
|
|
171
|
+
|
|
172
|
+
result = await tools["createIncident"](
|
|
173
|
+
title=" Database latency spike ",
|
|
174
|
+
summary=" Primary API requests timing out ",
|
|
175
|
+
severity_id=" sev-1 ",
|
|
176
|
+
service_ids="svc-1, svc-2",
|
|
177
|
+
team_ids="team-1, team-2",
|
|
178
|
+
environment_ids="env-1",
|
|
179
|
+
incident_type_ids="type-1",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
request.assert_awaited_once_with(
|
|
183
|
+
"POST",
|
|
184
|
+
"/v1/incidents",
|
|
185
|
+
json={
|
|
186
|
+
"data": {
|
|
187
|
+
"type": "incidents",
|
|
188
|
+
"attributes": {
|
|
189
|
+
"title": "Database latency spike",
|
|
190
|
+
"summary": "Primary API requests timing out",
|
|
191
|
+
"severity_id": "sev-1",
|
|
192
|
+
"service_ids": ["svc-1", "svc-2"],
|
|
193
|
+
"group_ids": ["team-1", "team-2"],
|
|
194
|
+
"environment_ids": ["env-1"],
|
|
195
|
+
"incident_type_ids": ["type-1"],
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
)
|
|
200
|
+
assert result["data"]["id"] == "inc-123"
|
|
201
|
+
assert result["data"]["attributes"]["title"] == "Database latency spike"
|
|
202
|
+
|
|
203
|
+
@pytest.mark.asyncio
|
|
204
|
+
async def test_create_incident_requires_title_or_summary(self):
|
|
205
|
+
tools, request = self._register_tools()
|
|
206
|
+
|
|
207
|
+
result = await tools["createIncident"](title=" ", summary=None)
|
|
208
|
+
|
|
209
|
+
request.assert_not_called()
|
|
210
|
+
assert result["error"] is True
|
|
211
|
+
assert result["error_type"] == "validation_error"
|
|
212
|
+
assert "Must provide at least one of title or summary" in result["message"]
|
|
213
|
+
|
|
149
214
|
@pytest.mark.asyncio
|
|
150
215
|
async def test_get_incident_fetches_single_incident(self):
|
|
151
216
|
tools, request = self._register_tools()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/openapi-audit-remote-baseline.json
RENAMED
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/.github/workflows/dependency-review.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/data/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/legacy_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/payload_stripping.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/spec_transform.py
RENAMED
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/src/rootly_mcp_server/tools/resources.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/integration/local/test_smart_tools.py
RENAMED
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/integration/remote/test_essential.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_legacy_server_module.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rootly_mcp_server-2.2.17 → rootly_mcp_server-2.2.19}/tests/unit/test_payload_stripping_module.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|