open-swe/agent/integrations/datadog_mcp.py

69 lines
2.2 KiB
Python
Raw Permalink Normal View History

"""Server-side Datadog tools backed by Datadog's hosted MCP server.
Credentials live in team settings (encrypted at rest) and are attached as
``DD_API_KEY`` / ``DD_APPLICATION_KEY`` headers to the MCP connection, which runs
in the LangGraph server process. The sandbox never holds Datadog credentials.
The default toolset is ``core`` (query-oriented: logs, metrics, traces,
dashboards, monitors, incidents, hosts, services, events). Override via
``DATADOG_MCP_TOOLSETS``.
"""
from __future__ import annotations
import logging
import os
from datetime import timedelta
from langchain_core.tools import BaseTool
from ..dashboard.team_credentials import DatadogCredentials, get_datadog_credentials
logger = logging.getLogger(__name__)
DEFAULT_DATADOG_TOOLSETS = "core"
_MCP_TIMEOUT_SECONDS = 30.0
def _toolsets() -> str:
return os.environ.get("DATADOG_MCP_TOOLSETS", DEFAULT_DATADOG_TOOLSETS).strip() or (
DEFAULT_DATADOG_TOOLSETS
)
async def _build_mcp_tools(creds: DatadogCredentials) -> list[BaseTool]:
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient(
{
"datadog": {
"transport": "streamable_http",
"url": creds.mcp_url(_toolsets()),
"headers": {
"DD_API_KEY": creds.api_key,
"DD_APPLICATION_KEY": creds.app_key,
},
"timeout": timedelta(seconds=_MCP_TIMEOUT_SECONDS),
}
}
)
return await client.get_tools()
async def load_datadog_tools() -> list[BaseTool]:
"""Return Datadog MCP tools when the team has connected Datadog, else ``[]``.
Failures (no credentials, unreachable MCP server) degrade to an empty list so
the agent still starts without Datadog tools.
"""
creds = await get_datadog_credentials()
if creds is None:
return []
try:
tools = await _build_mcp_tools(creds)
except Exception: # noqa: BLE001
logger.warning("Failed to load Datadog MCP tools", exc_info=True)
return []
logger.info("Loaded %d Datadog MCP tool(s) (toolsets=%s)", len(tools), _toolsets())
return tools