rootly-mcp-server 2.0.15__py3-none-any.whl → 2.1.0__py3-none-any.whl
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/__init__.py +9 -5
- rootly_mcp_server/__main__.py +44 -29
- rootly_mcp_server/client.py +98 -44
- rootly_mcp_server/data/__init__.py +1 -1
- rootly_mcp_server/exceptions.py +148 -0
- rootly_mcp_server/monitoring.py +378 -0
- rootly_mcp_server/pagination.py +98 -0
- rootly_mcp_server/security.py +404 -0
- rootly_mcp_server/server.py +1002 -467
- rootly_mcp_server/smart_utils.py +294 -209
- rootly_mcp_server/utils.py +48 -33
- rootly_mcp_server/validators.py +147 -0
- {rootly_mcp_server-2.0.15.dist-info → rootly_mcp_server-2.1.0.dist-info}/METADATA +66 -13
- rootly_mcp_server-2.1.0.dist-info/RECORD +18 -0
- {rootly_mcp_server-2.0.15.dist-info → rootly_mcp_server-2.1.0.dist-info}/WHEEL +1 -1
- rootly_mcp_server-2.0.15.dist-info/RECORD +0 -13
- {rootly_mcp_server-2.0.15.dist-info → rootly_mcp_server-2.1.0.dist-info}/entry_points.txt +0 -0
- {rootly_mcp_server-2.0.15.dist-info → rootly_mcp_server-2.1.0.dist-info}/licenses/LICENSE +0 -0
rootly_mcp_server/utils.py
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Shared utilities for Rootly MCP Server.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import re
|
|
6
5
|
import logging
|
|
7
|
-
|
|
6
|
+
import re
|
|
7
|
+
from typing import Any
|
|
8
8
|
|
|
9
9
|
logger = logging.getLogger(__name__)
|
|
10
10
|
|
|
@@ -12,57 +12,57 @@ logger = logging.getLogger(__name__)
|
|
|
12
12
|
def sanitize_parameter_name(name: str) -> str:
|
|
13
13
|
"""
|
|
14
14
|
Sanitize parameter names to match MCP property key pattern ^[a-zA-Z0-9_.-]{1,64}$.
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
Args:
|
|
17
17
|
name: Original parameter name
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
Returns:
|
|
20
20
|
Sanitized parameter name
|
|
21
21
|
"""
|
|
22
22
|
# Replace square brackets with underscores: filter[kind] -> filter_kind
|
|
23
|
-
sanitized = re.sub(r
|
|
24
|
-
|
|
23
|
+
sanitized = re.sub(r"\[([^\]]+)\]", r"_\1", name)
|
|
24
|
+
|
|
25
25
|
# Replace any remaining invalid characters with underscores
|
|
26
|
-
sanitized = re.sub(r
|
|
27
|
-
|
|
26
|
+
sanitized = re.sub(r"[^a-zA-Z0-9_.-]", "_", sanitized)
|
|
27
|
+
|
|
28
28
|
# Remove multiple consecutive underscores
|
|
29
|
-
sanitized = re.sub(r
|
|
30
|
-
|
|
29
|
+
sanitized = re.sub(r"_{2,}", "_", sanitized)
|
|
30
|
+
|
|
31
31
|
# Remove leading/trailing underscores
|
|
32
|
-
sanitized = sanitized.strip(
|
|
33
|
-
|
|
32
|
+
sanitized = sanitized.strip("_")
|
|
33
|
+
|
|
34
34
|
# Ensure the name doesn't exceed 64 characters
|
|
35
35
|
if len(sanitized) > 64:
|
|
36
|
-
sanitized = sanitized[:64].rstrip(
|
|
37
|
-
|
|
36
|
+
sanitized = sanitized[:64].rstrip("_")
|
|
37
|
+
|
|
38
38
|
# Ensure the name is not empty and starts with a letter or underscore
|
|
39
39
|
if not sanitized or sanitized[0].isdigit():
|
|
40
40
|
sanitized = "param_" + sanitized if sanitized else "param"
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
return sanitized
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def sanitize_parameters_in_spec(spec:
|
|
45
|
+
def sanitize_parameters_in_spec(spec: dict[str, Any]) -> dict[str, str]:
|
|
46
46
|
"""
|
|
47
47
|
Sanitize all parameter names in an OpenAPI specification.
|
|
48
|
-
|
|
49
|
-
This function modifies the spec in-place and builds a mapping
|
|
48
|
+
|
|
49
|
+
This function modifies the spec in-place and builds a mapping
|
|
50
50
|
of sanitized names to original names.
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
Args:
|
|
53
53
|
spec: OpenAPI specification dictionary
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
Returns:
|
|
56
56
|
Dictionary mapping sanitized names to original names
|
|
57
57
|
"""
|
|
58
58
|
parameter_mapping = {}
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
# Sanitize parameters in paths
|
|
61
61
|
if "paths" in spec:
|
|
62
|
-
for
|
|
62
|
+
for _path, path_item in spec["paths"].items():
|
|
63
63
|
if not isinstance(path_item, dict):
|
|
64
64
|
continue
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
# Sanitize path-level parameters
|
|
67
67
|
if "parameters" in path_item:
|
|
68
68
|
for param in path_item["parameters"]:
|
|
@@ -70,36 +70,51 @@ def sanitize_parameters_in_spec(spec: Dict[str, Any]) -> Dict[str, str]:
|
|
|
70
70
|
original_name = param["name"]
|
|
71
71
|
sanitized_name = sanitize_parameter_name(original_name)
|
|
72
72
|
if sanitized_name != original_name:
|
|
73
|
-
logger.debug(
|
|
73
|
+
logger.debug(
|
|
74
|
+
f"Sanitized path-level parameter: '{original_name}' -> '{sanitized_name}'"
|
|
75
|
+
)
|
|
74
76
|
param["name"] = sanitized_name
|
|
75
77
|
parameter_mapping[sanitized_name] = original_name
|
|
76
|
-
|
|
78
|
+
|
|
77
79
|
# Sanitize operation-level parameters
|
|
78
80
|
for method, operation in path_item.items():
|
|
79
|
-
if method.lower() not in [
|
|
81
|
+
if method.lower() not in [
|
|
82
|
+
"get",
|
|
83
|
+
"post",
|
|
84
|
+
"put",
|
|
85
|
+
"delete",
|
|
86
|
+
"patch",
|
|
87
|
+
"options",
|
|
88
|
+
"head",
|
|
89
|
+
"trace",
|
|
90
|
+
]:
|
|
80
91
|
continue
|
|
81
92
|
if not isinstance(operation, dict):
|
|
82
93
|
continue
|
|
83
|
-
|
|
94
|
+
|
|
84
95
|
if "parameters" in operation:
|
|
85
96
|
for param in operation["parameters"]:
|
|
86
97
|
if "name" in param:
|
|
87
98
|
original_name = param["name"]
|
|
88
99
|
sanitized_name = sanitize_parameter_name(original_name)
|
|
89
100
|
if sanitized_name != original_name:
|
|
90
|
-
logger.debug(
|
|
101
|
+
logger.debug(
|
|
102
|
+
f"Sanitized operation parameter: '{original_name}' -> '{sanitized_name}'"
|
|
103
|
+
)
|
|
91
104
|
param["name"] = sanitized_name
|
|
92
105
|
parameter_mapping[sanitized_name] = original_name
|
|
93
|
-
|
|
106
|
+
|
|
94
107
|
# Sanitize parameters in components (OpenAPI 3.0)
|
|
95
108
|
if "components" in spec and "parameters" in spec["components"]:
|
|
96
|
-
for
|
|
109
|
+
for _param_name, param_def in spec["components"]["parameters"].items():
|
|
97
110
|
if isinstance(param_def, dict) and "name" in param_def:
|
|
98
111
|
original_name = param_def["name"]
|
|
99
112
|
sanitized_name = sanitize_parameter_name(original_name)
|
|
100
113
|
if sanitized_name != original_name:
|
|
101
|
-
logger.debug(
|
|
114
|
+
logger.debug(
|
|
115
|
+
f"Sanitized component parameter: '{original_name}' -> '{sanitized_name}'"
|
|
116
|
+
)
|
|
102
117
|
param_def["name"] = sanitized_name
|
|
103
118
|
parameter_mapping[sanitized_name] = original_name
|
|
104
|
-
|
|
105
|
-
return parameter_mapping
|
|
119
|
+
|
|
120
|
+
return parameter_mapping
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Input validation utilities for the Rootly MCP Server.
|
|
3
|
+
|
|
4
|
+
This module provides validation functions for API inputs, parameters,
|
|
5
|
+
and data structures.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from .exceptions import RootlyValidationError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def validate_positive_integer(value: int, field_name: str, min_value: int = 1) -> int:
|
|
14
|
+
"""
|
|
15
|
+
Validate that a value is a positive integer.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
value: The value to validate
|
|
19
|
+
field_name: Name of the field for error messages
|
|
20
|
+
min_value: Minimum allowed value
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
The validated value
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
RootlyValidationError: If validation fails
|
|
27
|
+
"""
|
|
28
|
+
if not isinstance(value, int):
|
|
29
|
+
raise RootlyValidationError(f"{field_name} must be an integer, got {type(value).__name__}")
|
|
30
|
+
|
|
31
|
+
if value < min_value:
|
|
32
|
+
raise RootlyValidationError(f"{field_name} must be >= {min_value}, got {value}")
|
|
33
|
+
|
|
34
|
+
return value
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def validate_string(
|
|
38
|
+
value: str,
|
|
39
|
+
field_name: str,
|
|
40
|
+
min_length: int = 0,
|
|
41
|
+
max_length: int | None = None,
|
|
42
|
+
pattern: str | None = None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""
|
|
45
|
+
Validate a string value.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
value: The string to validate
|
|
49
|
+
field_name: Name of the field for error messages
|
|
50
|
+
min_length: Minimum allowed length
|
|
51
|
+
max_length: Maximum allowed length
|
|
52
|
+
pattern: Optional regex pattern to match
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
The validated string
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
RootlyValidationError: If validation fails
|
|
59
|
+
"""
|
|
60
|
+
if not isinstance(value, str):
|
|
61
|
+
raise RootlyValidationError(f"{field_name} must be a string, got {type(value).__name__}")
|
|
62
|
+
|
|
63
|
+
if len(value) < min_length:
|
|
64
|
+
raise RootlyValidationError(f"{field_name} must be at least {min_length} characters")
|
|
65
|
+
|
|
66
|
+
if max_length and len(value) > max_length:
|
|
67
|
+
raise RootlyValidationError(f"{field_name} must be at most {max_length} characters")
|
|
68
|
+
|
|
69
|
+
if pattern:
|
|
70
|
+
import re
|
|
71
|
+
|
|
72
|
+
if not re.match(pattern, value):
|
|
73
|
+
raise RootlyValidationError(f"{field_name} does not match required pattern")
|
|
74
|
+
|
|
75
|
+
return value
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def validate_dict(value: dict, field_name: str, required_keys: list[str] | None = None) -> dict:
|
|
79
|
+
"""
|
|
80
|
+
Validate a dictionary value.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
value: The dict to validate
|
|
84
|
+
field_name: Name of the field for error messages
|
|
85
|
+
required_keys: Optional list of required keys
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
The validated dict
|
|
89
|
+
|
|
90
|
+
Raises:
|
|
91
|
+
RootlyValidationError: If validation fails
|
|
92
|
+
"""
|
|
93
|
+
if not isinstance(value, dict):
|
|
94
|
+
raise RootlyValidationError(f"{field_name} must be a dict, got {type(value).__name__}")
|
|
95
|
+
|
|
96
|
+
if required_keys:
|
|
97
|
+
missing_keys = set(required_keys) - set(value.keys())
|
|
98
|
+
if missing_keys:
|
|
99
|
+
raise RootlyValidationError(
|
|
100
|
+
f"{field_name} is missing required keys: {', '.join(missing_keys)}"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return value
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def validate_enum(value: Any, field_name: str, allowed_values: list[Any]) -> Any:
|
|
107
|
+
"""
|
|
108
|
+
Validate that a value is one of the allowed values.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
value: The value to validate
|
|
112
|
+
field_name: Name of the field for error messages
|
|
113
|
+
allowed_values: List of allowed values
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
The validated value
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
RootlyValidationError: If validation fails
|
|
120
|
+
"""
|
|
121
|
+
if value not in allowed_values:
|
|
122
|
+
raise RootlyValidationError(f"{field_name} must be one of {allowed_values}, got {value}")
|
|
123
|
+
|
|
124
|
+
return value
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def validate_page_params(page_size: int, page_number: int) -> tuple[int, int]:
|
|
128
|
+
"""
|
|
129
|
+
Validate pagination parameters.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
page_size: Number of items per page
|
|
133
|
+
page_number: Page number (0 for all, 1+ for specific page)
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Tuple of validated (page_size, page_number)
|
|
137
|
+
|
|
138
|
+
Raises:
|
|
139
|
+
RootlyValidationError: If validation fails
|
|
140
|
+
"""
|
|
141
|
+
page_size = validate_positive_integer(page_size, "page_size", min_value=1)
|
|
142
|
+
page_number = validate_positive_integer(page_number, "page_number", min_value=0)
|
|
143
|
+
|
|
144
|
+
if page_size > 100:
|
|
145
|
+
raise RootlyValidationError("page_size cannot exceed 100")
|
|
146
|
+
|
|
147
|
+
return page_size, page_number
|
|
@@ -1,19 +1,27 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rootly-mcp-server
|
|
3
|
-
Version: 2.0
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 2.1.0
|
|
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
|
|
7
7
|
Author-email: Rootly AI Labs <support@rootly.com>
|
|
8
8
|
License-Expression: Apache-2.0
|
|
9
9
|
License-File: LICENSE
|
|
10
|
-
Keywords: automation,incidents,llm,mcp,rootly
|
|
10
|
+
Keywords: ai-sre,automation,devops,incident-management,incidents,llm,mcp,on-call,rate-limiting,rootly,security,sre
|
|
11
11
|
Classifier: Development Status :: 5 - Production/Stable
|
|
12
12
|
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
13
16
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Security
|
|
15
21
|
Classifier: Topic :: Software Development :: Build Tools
|
|
16
|
-
|
|
22
|
+
Classifier: Topic :: System :: Monitoring
|
|
23
|
+
Classifier: Topic :: System :: Systems Administration
|
|
24
|
+
Requires-Python: >=3.10
|
|
17
25
|
Requires-Dist: brotli>=1.0.0
|
|
18
26
|
Requires-Dist: fastmcp>=2.9.0
|
|
19
27
|
Requires-Dist: httpx>=0.24.0
|
|
@@ -22,8 +30,11 @@ Requires-Dist: pydantic>=2.0.0
|
|
|
22
30
|
Requires-Dist: requests>=2.28.0
|
|
23
31
|
Requires-Dist: scikit-learn>=1.3.0
|
|
24
32
|
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: bandit>=1.7.0; extra == 'dev'
|
|
25
34
|
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
26
35
|
Requires-Dist: isort>=5.0.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: safety>=2.0.0; extra == 'dev'
|
|
27
38
|
Description-Content-Type: text/markdown
|
|
28
39
|
|
|
29
40
|
# Rootly MCP Server
|
|
@@ -31,12 +42,11 @@ Description-Content-Type: text/markdown
|
|
|
31
42
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
32
43
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
33
44
|
[](https://pypi.org/project/rootly-mcp-server/)
|
|
45
|
+
[](https://cursor.com/install-mcp?name=rootly&config=eyJjb21tYW5kIjoibnB4IC15IG1jcC1yZW1vdGUgaHR0cHM6Ly9tY3Aucm9vdGx5LmNvbS9zc2UgLS1oZWFkZXIgQXV0aG9yaXphdGlvbjoke1JPT1RMWV9BVVRIX0hFQURFUn0iLCJlbnYiOnsiUk9PVExZX0FVVEhfSEVBREVSIjoiQmVhcmVyIDxZT1VSX1JPT1RMWV9BUElfVE9LRU4%2BIn19)
|
|
34
46
|
|
|
35
47
|
An MCP server for the [Rootly API](https://docs.rootly.com/api-reference/overview) that integrates seamlessly with MCP-compatible editors like Cursor, Windsurf, and Claude. Resolve production incidents in under a minute without leaving your IDE.
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-

|
|
49
|
+

|
|
40
50
|
|
|
41
51
|
## Prerequisites
|
|
42
52
|
|
|
@@ -45,7 +55,17 @@ An MCP server for the [Rootly API](https://docs.rootly.com/api-reference/overvie
|
|
|
45
55
|
```bash
|
|
46
56
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
47
57
|
```
|
|
48
|
-
- [Rootly API token](https://docs.rootly.com/api-reference/overview#how-to-generate-an-api-key%3F)
|
|
58
|
+
- [Rootly API token](https://docs.rootly.com/api-reference/overview#how-to-generate-an-api-key%3F) with appropriate permissions (see below)
|
|
59
|
+
|
|
60
|
+
### API Token Permissions
|
|
61
|
+
|
|
62
|
+
The MCP server requires a Rootly API token. Choose the appropriate token type based on your needs:
|
|
63
|
+
|
|
64
|
+
- **Global API Key** (Recommended): Full access to all entities across your Rootly instance. Required for organization-wide visibility across teams, schedules, and incidents.
|
|
65
|
+
- **Team API Key**: Team Admin permissions with full read/edit access to entities owned by that team. Suitable for team-specific workflows.
|
|
66
|
+
- **Personal API Key**: Inherits the permissions of the user who created it. Works for individual use cases but may have limited visibility.
|
|
67
|
+
|
|
68
|
+
For full functionality of tools like `get_oncall_handoff_summary`, `get_oncall_shift_metrics`, and organization-wide incident search, a **Global API Key** is recommended.
|
|
49
69
|
|
|
50
70
|
## Installation
|
|
51
71
|
|
|
@@ -144,11 +164,38 @@ Alternatively, connect directly to our hosted MCP server:
|
|
|
144
164
|
- **Smart Pagination**: Defaults to 10 items per request for incident endpoints to prevent context window overflow
|
|
145
165
|
- **API Filtering**: Limits exposed API endpoints for security and performance
|
|
146
166
|
- **Intelligent Incident Analysis**: Smart tools that analyze historical incident data
|
|
147
|
-
- **`find_related_incidents`**: Uses TF-IDF similarity analysis to find historically similar incidents
|
|
167
|
+
- **`find_related_incidents`**: Uses TF-IDF similarity analysis to find historically similar incidents
|
|
148
168
|
- **`suggest_solutions`**: Mines past incident resolutions to recommend actionable solutions
|
|
149
169
|
- **MCP Resources**: Exposes incident and team data as structured resources for easy AI reference
|
|
150
170
|
- **Intelligent Pattern Recognition**: Automatically identifies services, error types, and resolution patterns
|
|
151
171
|
|
|
172
|
+
## Example Skills
|
|
173
|
+
|
|
174
|
+
Want to get started quickly? We provide pre-built Claude Code skills that showcase the full power of the Rootly MCP server:
|
|
175
|
+
|
|
176
|
+
### 🚨 [Rootly Incident Responder](examples/skills/rootly-incident-responder.md)
|
|
177
|
+
|
|
178
|
+
An AI-powered incident response specialist that:
|
|
179
|
+
- Analyzes production incidents with full context
|
|
180
|
+
- Finds similar historical incidents using ML-based similarity matching
|
|
181
|
+
- Suggests solutions based on past successful resolutions
|
|
182
|
+
- Coordinates with on-call teams across timezones
|
|
183
|
+
- Correlates incidents with recent code changes and deployments
|
|
184
|
+
- Creates action items and remediation plans
|
|
185
|
+
- Provides confidence scores and time estimates
|
|
186
|
+
|
|
187
|
+
**Quick Start:**
|
|
188
|
+
```bash
|
|
189
|
+
# Copy the skill to your project
|
|
190
|
+
mkdir -p .claude/skills
|
|
191
|
+
cp examples/skills/rootly-incident-responder.md .claude/skills/
|
|
192
|
+
|
|
193
|
+
# Then in Claude Code, invoke it:
|
|
194
|
+
# @rootly-incident-responder analyze incident #12345
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
This skill demonstrates a complete incident response workflow using Rootly's intelligent tools combined with GitHub integration for code correlation.
|
|
198
|
+
|
|
152
199
|
### Available Tools
|
|
153
200
|
|
|
154
201
|
**Alerts**
|
|
@@ -296,10 +343,6 @@ get_shift_incidents(
|
|
|
296
343
|
|
|
297
344
|
Returns: `incidents` list + `summary` (counts, avg resolution time, grouping)
|
|
298
345
|
|
|
299
|
-
## About Rootly AI Labs
|
|
300
|
-
|
|
301
|
-
This project was developed by [Rootly AI Labs](https://labs.rootly.ai/), where we're building the future of system reliability and operational excellence. As an open-source incubator, we share ideas, experiment, and rapidly prototype solutions that benefit the entire community.
|
|
302
|
-

|
|
303
346
|
|
|
304
347
|
## Developer Setup & Troubleshooting
|
|
305
348
|
|
|
@@ -348,3 +391,13 @@ The server should now be ready to use with your MCP-compatible editor.
|
|
|
348
391
|
|
|
349
392
|
**For developers:** Additional testing tools are available in the `tests/` directory.
|
|
350
393
|
|
|
394
|
+
## Play with it on Postman
|
|
395
|
+
[<img src="https://run.pstmn.io/button.svg" alt="Run In Postman" style="width: 128px; height: 32px;">](https://god.gw.postman.com/run-collection/45004446-1074ba3c-44fe-40e3-a932-af7c071b96eb?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D45004446-1074ba3c-44fe-40e3-a932-af7c071b96eb%26entityType%3Dcollection%26workspaceId%3D4bec6e3c-50a0-4746-85f1-00a703c32f24)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
## About Rootly AI Labs
|
|
399
|
+
|
|
400
|
+
This project was developed by [Rootly AI Labs](https://labs.rootly.ai/), where we're building the future of system reliability and operational excellence. As an open-source incubator, we share ideas, experiment, and rapidly prototype solutions that benefit the entire community.
|
|
401
|
+

|
|
402
|
+
|
|
403
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
rootly_mcp_server/__init__.py,sha256=LAXe2qmP6Yw5MMx-02NAIObwY6l4lKDf8SegYJ0jUhs,873
|
|
2
|
+
rootly_mcp_server/__main__.py,sha256=mt74vaOpfHnX5rTO0CFAeulatR_9K3NBNCaLAhBLxlc,6886
|
|
3
|
+
rootly_mcp_server/client.py,sha256=Qca2R9cgBxXcyobQj4RHl8gdxLB4Jphq0RIr61DAVKw,6542
|
|
4
|
+
rootly_mcp_server/exceptions.py,sha256=67J_wlfOICg87eUipbkARzn_6u_Io82L-5cVnk2UPr0,4504
|
|
5
|
+
rootly_mcp_server/monitoring.py,sha256=k1X7vK65FOTrCrOsLUXrFm6AJxKpXt_a0PzL6xdPuVU,11681
|
|
6
|
+
rootly_mcp_server/pagination.py,sha256=2hZSO4DLUEJZbdF8oDfIt2_7X_XGBG1jIxN8VGmeJBE,2420
|
|
7
|
+
rootly_mcp_server/security.py,sha256=YkMoVALZ3XaKnMu3yF5kVf3SW_jdKHllSMwVLk1OlX0,11556
|
|
8
|
+
rootly_mcp_server/server.py,sha256=tJLRJgurdFlq-7m7jCsRYCeD1LFUbLff0YQ7yUQJWVc,115527
|
|
9
|
+
rootly_mcp_server/smart_utils.py,sha256=c7S-8H151GfmDw6dZBDdLH_cCmR1qiXkKEYSKc0WwUY,23481
|
|
10
|
+
rootly_mcp_server/texttest.json,sha256=KV9m13kWugmW1VEpU80Irp50uCcLgJtV1YT-JzMogQg,154182
|
|
11
|
+
rootly_mcp_server/utils.py,sha256=TWG1MaaFKrU1phRhU6FgHuZAEv91JOe_1w0L2OrPJMY,4406
|
|
12
|
+
rootly_mcp_server/validators.py,sha256=z1Lvel2SpOFLo1cPdQGSrX2ySt6zqR42w0R6QV9c2Cc,4092
|
|
13
|
+
rootly_mcp_server/data/__init__.py,sha256=KdWD6hiRssHXt0Ywgj3wjNHY1sx-XSPEqVHqrTArf54,143
|
|
14
|
+
rootly_mcp_server-2.1.0.dist-info/METADATA,sha256=0fXm7kY3z3npobc9BeEm-P0R6Et3yRGAisb-Wcr40vM,13560
|
|
15
|
+
rootly_mcp_server-2.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
16
|
+
rootly_mcp_server-2.1.0.dist-info/entry_points.txt,sha256=NE33b8VgigVPGBkboyo6pvN1Vz35HZtLybxMO4Q03PI,70
|
|
17
|
+
rootly_mcp_server-2.1.0.dist-info/licenses/LICENSE,sha256=c9w9ZZGl14r54tsP40oaq5adTVX_HMNHozPIH2ymzmw,11341
|
|
18
|
+
rootly_mcp_server-2.1.0.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
rootly_mcp_server/__init__.py,sha256=rvIuqIyuzgC7b9qSnylrdDP2zPO-7Ou9AoblR6re1co,629
|
|
2
|
-
rootly_mcp_server/__main__.py,sha256=_F4p65_VjnN84RtmEdESVLLH0tO5tL9qBfb2Xdvbj2E,6480
|
|
3
|
-
rootly_mcp_server/client.py,sha256=uit-YijR7OAJtysBoclqnublEDVkFfcb29wSzhpBv44,4686
|
|
4
|
-
rootly_mcp_server/server.py,sha256=Qmsv-BKNhsEj8_7S1glBgLEN6OlSKqOvMRgJ40ZFeCg,98716
|
|
5
|
-
rootly_mcp_server/smart_utils.py,sha256=lvGN9ITyJjBkm7ejpYagd8VWodLKnC6FmwECfCOcGwM,22973
|
|
6
|
-
rootly_mcp_server/texttest.json,sha256=KV9m13kWugmW1VEpU80Irp50uCcLgJtV1YT-JzMogQg,154182
|
|
7
|
-
rootly_mcp_server/utils.py,sha256=NyxdcDiFGlV2a8eBO4lKgZg0D7Gxr6xUIB0YyJGgpPA,4165
|
|
8
|
-
rootly_mcp_server/data/__init__.py,sha256=fO8a0bQnRVEoRMHKvhFzj10bhoaw7VsI51czc2MsUm4,143
|
|
9
|
-
rootly_mcp_server-2.0.15.dist-info/METADATA,sha256=stGxakp4C-3jGIZG7pqAm3wim_UxAlrTikO--kApdiE,10552
|
|
10
|
-
rootly_mcp_server-2.0.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
-
rootly_mcp_server-2.0.15.dist-info/entry_points.txt,sha256=NE33b8VgigVPGBkboyo6pvN1Vz35HZtLybxMO4Q03PI,70
|
|
12
|
-
rootly_mcp_server-2.0.15.dist-info/licenses/LICENSE,sha256=c9w9ZZGl14r54tsP40oaq5adTVX_HMNHozPIH2ymzmw,11341
|
|
13
|
-
rootly_mcp_server-2.0.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|