Skip to main content
Glama
Rootly-AI-Labs

Rootly MCP server

Official

listServices

Retrieve and filter service data from the Rootly MCP server. Use query parameters to sort, paginate, or search by specific criteria such as name, slug, or created date.

Instructions

List services

Query Parameters:

  • include: No description.

  • page_number: No description.

  • page_size: No description.

  • filter_search: No description.

  • filter_name: No description.

  • filter_slug: No description.

  • filter_backstage_id: No description.

  • filter_cortex_id: No description.

  • filter_opslevel_id: No description.

  • filter_external_id: No description.

  • filter_created_at_gt: No description.

  • filter_created_at_gte: No description.

  • filter_created_at_lt: No description.

  • filter_created_at_lte: No description.

  • sort: No description.

Responses:

  • 200 (Success): success

    • Content-Type: application/vnd.api+json

    • Example:

{
  "key": "value"
}

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filter_backstage_idNo
filter_cortex_idNo
filter_created_at_gtNo
filter_created_at_gteNo
filter_created_at_ltNo
filter_created_at_lteNo
filter_external_idNo
filter_nameNo
filter_opslevel_idNo
filter_searchNo
filter_slugNo
includeNo
page_numberNo
page_sizeNo
sortNo

Implementation Reference

  • DEFAULT_ALLOWED_PATHS includes '/services' enabling the OpenAPI path that generates the 'listServices' MCP tool.
    DEFAULT_ALLOWED_PATHS = [
        "/incidents/{incident_id}/alerts",
        "/alerts",
        "/alerts/{alert_id}",
        "/severities",
        "/severities/{severity_id}",
        "/teams",
        "/teams/{team_id}",
        "/services",
        "/services/{service_id}",
        "/functionalities",
        "/functionalities/{functionality_id}",
        # Incident types
        "/incident_types",
        "/incident_types/{incident_type_id}",
        # Action items (all, by id, by incident)
        "/incident_action_items",
        "/incident_action_items/{incident_action_item_id}",
        "/incidents/{incident_id}/action_items",
        # Workflows
        "/workflows",
        "/workflows/{workflow_id}",
        # Workflow runs
        "/workflow_runs",
        "/workflow_runs/{workflow_run_id}",
        # Environments
        "/environments",
        "/environments/{environment_id}",
        # Users
        "/users",
        "/users/{user_id}",
        "/users/me",
        # Status pages
        "/status_pages",
        "/status_pages/{status_page_id}",
        # On-call schedules and shifts
        "/schedules",
        "/schedules/{schedule_id}",
        "/schedules/{schedule_id}/shifts",
        "/shifts",
        "/schedule_rotations/{schedule_rotation_id}",
        "/schedule_rotations/{schedule_rotation_id}/schedule_rotation_users",
        "/schedule_rotations/{schedule_rotation_id}/schedule_rotation_active_days",
        # On-call overrides
        "/schedules/{schedule_id}/override_shifts",
        "/override_shifts/{override_shift_id}",
        # On-call shadows and roles
        "/schedules/{schedule_id}/on_call_shadows",
        "/on_call_shadows/{on_call_shadow_id}",
        "/on_call_roles",
        "/on_call_roles/{on_call_role_id}",
    ]
  • FastMCP.from_openapi registers all filtered OpenAPI operations as MCP tools, including 'listServices' from the GET /services operationId.
    # By default, all routes become tools which is what we want
    mcp = FastMCP.from_openapi(
        openapi_spec=filtered_spec,
        client=http_client.client,
        name=name,
        timeout=30.0,
        tags={"rootly", "incident-management"},
    )
  • AuthenticatedHTTPXClient proxies HTTP requests to Rootly API; used by generated tools like listServices to call GET /v1/services.
    class AuthenticatedHTTPXClient:
        """An HTTPX client wrapper that handles Rootly API authentication and parameter transformation."""
    
        def __init__(self, base_url: str = "https://api.rootly.com", hosted: bool = False, parameter_mapping: Optional[Dict[str, str]] = None):
            self._base_url = base_url
            self.hosted = hosted
            self._api_token = None
            self.parameter_mapping = parameter_mapping or {}
    
            if not self.hosted:
                self._api_token = self._get_api_token()
    
            # Create the HTTPX client  
            headers = {
                "Content-Type": "application/vnd.api+json", 
                "Accept": "application/vnd.api+json"
                # Let httpx handle Accept-Encoding automatically with all supported formats
            }
            if self._api_token:
                headers["Authorization"] = f"Bearer {self._api_token}"
    
            self.client = httpx.AsyncClient(
                base_url=base_url,
                headers=headers,
                timeout=30.0,
                follow_redirects=True,
                # Ensure proper handling of compressed responses
                limits=httpx.Limits(max_keepalive_connections=5, max_connections=10)
            )
    
        def _get_api_token(self) -> Optional[str]:
            """Get the API token from environment variables."""
            api_token = os.getenv("ROOTLY_API_TOKEN")
            if not api_token:
                logger.warning("ROOTLY_API_TOKEN environment variable is not set")
                return None
            return api_token
    
        def _transform_params(self, params: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
            """Transform sanitized parameter names back to original names."""
            if not params or not self.parameter_mapping:
                return params
    
            transformed = {}
            for key, value in params.items():
                # Use the original name if we have a mapping, otherwise keep the sanitized name
                original_key = self.parameter_mapping.get(key, key)
                transformed[original_key] = value
                if original_key != key:
                    logger.debug(f"Transformed parameter: '{key}' -> '{original_key}'")
            return transformed
    
        async def request(self, method: str, url: str, **kwargs):
            """Override request to transform parameters."""
            # Transform query parameters
            if 'params' in kwargs:
                kwargs['params'] = self._transform_params(kwargs['params'])
    
            # Call the underlying client's request method and let it handle everything
            return await self.client.request(method, url, **kwargs)
    
        async def get(self, url: str, **kwargs):
            """Proxy to request with GET method."""
            return await self.request('GET', url, **kwargs)
    
        async def post(self, url: str, **kwargs):
            """Proxy to request with POST method."""
            return await self.request('POST', url, **kwargs)
    
        async def put(self, url: str, **kwargs):
            """Proxy to request with PUT method."""
            return await self.request('PUT', url, **kwargs)
    
        async def patch(self, url: str, **kwargs):
            """Proxy to request with PATCH method."""
            return await self.request('PATCH', url, **kwargs)
    
        async def delete(self, url: str, **kwargs):
            """Proxy to request with DELETE method."""
            return await self.request('DELETE', url, **kwargs)
    
        async def __aenter__(self):
            return self
    
        async def __aexit__(self, exc_type, exc_val, exc_tb):
            pass
    
        def __getattr__(self, name):
            # Delegate all other attributes to the underlying client, except for request methods
            if name in ['request', 'get', 'post', 'put', 'patch', 'delete']:
                # Use our overridden methods instead
                return getattr(self, name)
            return getattr(self.client, name)
        
        @property 
        def base_url(self):
            return self._base_url
            
        @property
        def headers(self):
            return self.client.headers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Rootly-AI-Labs/Rootly-MCP-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server