# How to use MCP for monitoring and alerting

- Tool: MCP
- Difficulty: Advanced
- Time required: 30-40 min
- Compatibility: MCP TypeScript SDK v1.x, Sentry API, Datadog API, Node.js 18+
- Last updated: March 2026

## TL;DR

Connect Sentry and Datadog to AI assistants via MCP servers for intelligent incident response. The AI queries error trends, fetches stack traces, checks infrastructure metrics, and suggests fixes — all through natural language. Build custom MCP tools that wrap monitoring APIs so the AI can triage alerts, identify root causes, and help resolve incidents faster than manual dashboard navigation.

## AI-Powered Incident Response with MCP Monitoring Tools

When an alert fires at 2am, the last thing you want is to manually dig through dashboards and log files. MCP monitoring tools let AI assistants do the initial triage: query Sentry for error details, check Datadog for related metrics, read the relevant source code, and suggest a fix. This tutorial builds MCP tools that wrap Sentry and Datadog APIs, giving your AI assistant the same observability data your on-call engineers use.

## Before you start

- A Sentry account with API authentication token
- A Datadog account with API and application keys (optional)
- Node.js 18+ and npm installed
- Claude Desktop or Cursor with MCP support

## Step-by-step guide

### 1. Build Sentry MCP tools for error investigation

Create MCP tools that query the Sentry API for recent issues, error details, and stack traces. The Sentry API provides endpoints for listing project issues, getting event details, and fetching stack traces. Wrap these as MCP tools so the AI can investigate errors by project, time range, or error type.

```
// src/sentry-tools.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const SENTRY_TOKEN = process.env.SENTRY_AUTH_TOKEN!;
const SENTRY_ORG = process.env.SENTRY_ORG!;

async function sentryApi(path: string) {
  const res = await fetch(`https://sentry.io/api/0${path}`, {
    headers: { Authorization: `Bearer ${SENTRY_TOKEN}` },
  });
  return res.json();
}

export function registerSentryTools(server: McpServer) {
  server.tool("get_recent_errors", "Get recent error issues from Sentry", {
    project: z.string().describe("Sentry project slug"),
    hours: z.number().default(24).describe("Look back period in hours"),
    limit: z.number().default(10),
  }, async ({ project, hours, limit }) => {
    const since = new Date(Date.now() - hours * 3600000).toISOString();
    const issues = await sentryApi(
      `/projects/${SENTRY_ORG}/${project}/issues/?query=is:unresolved&sort=freq&limit=${limit}&start=${since}`
    );
    const summary = issues.map((i: any) => ({
      id: i.id, title: i.title, count: i.count, level: i.level,
      firstSeen: i.firstSeen, lastSeen: i.lastSeen, culprit: i.culprit,
    }));
    return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
  });

  server.tool("get_error_details", "Get full details and stack trace for a Sentry issue", {
    issueId: z.string().describe("Sentry issue ID"),
  }, async ({ issueId }) => {
    const events = await sentryApi(`/issues/${issueId}/events/latest/`);
    const trace = events.entries?.find((e: any) => e.type === "exception");
    return { content: [{ type: "text", text: JSON.stringify({
      message: events.message,
      tags: events.tags,
      stackTrace: trace?.data?.values?.map((v: any) => ({
        type: v.type, value: v.value,
        frames: v.stacktrace?.frames?.slice(-5).map((f: any) => ({
          filename: f.filename, function: f.function, lineNo: f.lineNo, context: f.context,
        })),
      })),
    }, null, 2) }] };
  });
}
```

**Expected result:** MCP tools that query Sentry for recent errors and detailed stack traces.

### 2. Add Datadog MCP tools for metrics and infrastructure monitoring

Build MCP tools that query Datadog for metrics, active alerts, and host information. The Datadog API provides time-series metrics, alert status, and infrastructure data. These tools help the AI correlate errors with infrastructure issues — like a Sentry spike matching a CPU spike on Datadog.

```
// src/datadog-tools.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

const DD_API_KEY = process.env.DD_API_KEY!;
const DD_APP_KEY = process.env.DD_APP_KEY!;

async function datadogApi(path: string, params?: Record<string, string>) {
  const url = new URL(`https://api.datadoghq.com/api/v1${path}`);
  if (params) Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
  const res = await fetch(url, {
    headers: { "DD-API-KEY": DD_API_KEY, "DD-APPLICATION-KEY": DD_APP_KEY },
  });
  return res.json();
}

export function registerDatadogTools(server: McpServer) {
  server.tool("get_active_alerts", "Get currently active Datadog monitors/alerts", {
    tag: z.string().optional().describe("Filter by tag, e.g. service:api"),
  }, async ({ tag }) => {
    const monitors = await datadogApi("/monitor", {
      ...(tag ? { monitor_tags: tag } : {}),
    });
    const active = monitors
      .filter((m: any) => m.overall_state === "Alert" || m.overall_state === "Warn")
      .map((m: any) => ({ id: m.id, name: m.name, state: m.overall_state, message: m.message }));
    return { content: [{ type: "text", text: JSON.stringify(active, null, 2) }] };
  });

  server.tool("query_metrics", "Query Datadog metrics for a time range", {
    query: z.string().describe("Datadog metric query, e.g. avg:system.cpu.user{service:api}"),
    hours: z.number().default(1).describe("Look back period in hours"),
  }, async ({ query, hours }) => {
    const now = Math.floor(Date.now() / 1000);
    const from = now - hours * 3600;
    const result = await datadogApi("/query", {
      query, from: String(from), to: String(now),
    });
    const series = result.series?.map((s: any) => ({
      metric: s.metric, scope: s.scope,
      points: s.pointlist?.slice(-10).map((p: any) => ({
        time: new Date(p[0]).toISOString(), value: p[1]?.toFixed(2),
      })),
    }));
    return { content: [{ type: "text", text: JSON.stringify(series, null, 2) }] };
  });
}
```

**Expected result:** MCP tools that query Datadog for active alerts and time-series metrics.

### 3. Combine monitoring with code context for root cause analysis

The real power comes from combining monitoring data with code access. When the AI finds an error in Sentry, it can read the actual source file via a Filesystem MCP server, understand the code around the failing line, and suggest a fix. Configure all three servers (Sentry, Datadog, Filesystem) together for comprehensive incident investigation.

```
// Complete MCP config with all monitoring + code servers:
{
  "mcpServers": {
    "sentry": {
      "command": "node",
      "args": ["dist/monitoring-server.js"],
      "env": {
        "SENTRY_AUTH_TOKEN": "sntrys_...",
        "SENTRY_ORG": "your-org"
      }
    },
    "datadog": {
      "command": "node",
      "args": ["dist/datadog-server.js"],
      "env": {
        "DD_API_KEY": "your-dd-api-key",
        "DD_APP_KEY": "your-dd-app-key"
      }
    },
    "codebase": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/repo"]
    }
  }
}

// Example incident investigation prompt:
// "We got paged for high error rates. Check Sentry for recent errors in the
//  api-gateway project, look at the stack traces, read the relevant source
//  files, and check Datadog for any infrastructure anomalies. Give me a
//  root cause analysis and suggested fix."
```

**Expected result:** AI investigates incidents by querying errors, reading code, checking metrics, and suggesting fixes.

### 4. Build automated alert triage workflows

Create a tool that automates the initial triage of monitoring alerts. When called, it queries recent errors from Sentry, checks related metrics in Datadog, categorizes the severity, and returns a structured incident summary. This can be triggered by a webhook when an alert fires, providing instant AI triage before a human even looks at the alert.

```
server.tool(
  "triage_incident",
  "Automated incident triage: checks errors and metrics, returns severity assessment",
  {
    project: z.string().describe("Sentry project slug"),
    service: z.string().describe("Service tag for Datadog metrics"),
  },
  async ({ project, service }) => {
    // Fetch recent errors
    const issues = await sentryApi(
      `/projects/${SENTRY_ORG}/${project}/issues/?query=is:unresolved&sort=date&limit=5`
    );

    // Fetch active alerts
    const monitors = await datadogApi("/monitor", { monitor_tags: `service:${service}` });
    const activeAlerts = monitors.filter((m: any) =>
      m.overall_state === "Alert" || m.overall_state === "Warn"
    );

    // Assess severity
    const errorCount = issues.reduce((sum: number, i: any) => sum + i.count, 0);
    const severity = activeAlerts.length > 2 || errorCount > 100 ? "CRITICAL"
      : activeAlerts.length > 0 || errorCount > 10 ? "HIGH" : "LOW";

    const triage = {
      severity,
      timestamp: new Date().toISOString(),
      errorSummary: {
        totalErrors: errorCount,
        topIssues: issues.slice(0, 3).map((i: any) => ({ title: i.title, count: i.count })),
      },
      activeAlerts: activeAlerts.map((m: any) => ({ name: m.name, state: m.overall_state })),
      recommendation: severity === "CRITICAL"
        ? "Immediate investigation required. Multiple alerts active."
        : severity === "HIGH"
        ? "Investigate soon. Error rates elevated."
        : "Monitor. Low error rates, no active alerts.",
    };

    return { content: [{ type: "text", text: JSON.stringify(triage, null, 2) }] };
  }
);
```

**Expected result:** An automated triage tool that assesses incident severity from monitoring data.

## Complete code example

File: `src/monitoring-server.ts`

```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const SENTRY_TOKEN = process.env.SENTRY_AUTH_TOKEN!;
const SENTRY_ORG = process.env.SENTRY_ORG!;

async function sentry(path: string) {
  const r = await fetch(`https://sentry.io/api/0${path}`, {
    headers: { Authorization: `Bearer ${SENTRY_TOKEN}` },
  });
  return r.json();
}

const server = new McpServer({ name: "monitoring", version: "1.0.0" });

server.tool("recent_errors", "Get recent unresolved errors from Sentry", {
  project: z.string(), hours: z.number().default(24), limit: z.number().default(10),
}, async ({ project, hours, limit }) => {
  const issues = await sentry(`/projects/${SENTRY_ORG}/${project}/issues/?query=is:unresolved&sort=freq&limit=${limit}`);
  const data = issues.map((i: any) => ({
    id: i.id, title: i.title, count: i.count, level: i.level, lastSeen: i.lastSeen,
  }));
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
});

server.tool("error_details", "Get stack trace for a Sentry issue", {
  issueId: z.string(),
}, async ({ issueId }) => {
  const event = await sentry(`/issues/${issueId}/events/latest/`);
  const exc = event.entries?.find((e: any) => e.type === "exception");
  const frames = exc?.data?.values?.[0]?.stacktrace?.frames?.slice(-5) || [];
  return { content: [{ type: "text", text: JSON.stringify({
    message: event.message,
    frames: frames.map((f: any) => ({ file: f.filename, fn: f.function, line: f.lineNo })),
  }, null, 2) }] };
});

server.tool("triage", "Assess incident severity", {
  project: z.string(),
}, async ({ project }) => {
  const issues = await sentry(`/projects/${SENTRY_ORG}/${project}/issues/?query=is:unresolved&sort=date&limit=10`);
  const total = issues.reduce((s: number, i: any) => s + (i.count || 0), 0);
  const severity = total > 100 ? "CRITICAL" : total > 10 ? "HIGH" : "LOW";
  return { content: [{ type: "text", text: JSON.stringify({
    severity, errorCount: total,
    topIssues: issues.slice(0, 3).map((i: any) => `${i.title} (${i.count}x)`),
  }, null, 2) }] };
});

async function main() {
  await server.connect(new StdioServerTransport());
  console.error("Monitoring MCP server running");
}
main().catch(e => { console.error(e); process.exit(1); });
```

## Common mistakes

- **Exposing monitoring API keys that have write access (resolve issues, silence alerts)** — undefined Fix: Create read-only API tokens for monitoring services. The AI should investigate, not modify alert states.
- **Returning entire stack traces with hundreds of frames, overwhelming the AI context** — undefined Fix: Limit stack trace output to the 5 most recent frames per exception. These contain the relevant application code.
- **Not including timestamps in monitoring data, making it hard for the AI to correlate events** — undefined Fix: Always include ISO timestamps in error and metric data so the AI can identify time-based patterns.

## Best practices

- Use read-only API tokens for all monitoring service integrations
- Limit stack traces to the 5 most recent frames to keep responses concise
- Include timestamps in all monitoring data for temporal correlation
- Combine error monitoring (Sentry) with infrastructure monitoring (Datadog) for full context
- Add a triage tool that automatically assesses incident severity
- Pair monitoring tools with Filesystem tools so the AI can read the actual failing code
- Log all monitoring API calls to stderr for debugging and audit trails

## Frequently asked questions

### Can the AI resolve Sentry issues or silence Datadog alerts?

Only if you give the API token write permissions. For safety, start with read-only tokens so the AI can investigate but not modify monitoring state.

### How do I handle rate limits from Sentry and Datadog APIs?

Add rate limiting to your MCP tools (see the rate limiting tutorial). Sentry allows 100 requests/minute, Datadog allows 300/minute for metrics queries.

### Can this work with PagerDuty or OpsGenie?

Yes. Build custom MCP tools that wrap the PagerDuty or OpsGenie REST API. The pattern is the same — query incidents, get details, and return structured data.

### Can RapidDev set up monitoring MCP integrations?

Yes. RapidDev builds turnkey monitoring MCP setups that combine Sentry, Datadog, PagerDuty, and code access for AI-powered incident response.

### How do I trigger AI triage automatically when an alert fires?

Use a webhook from your monitoring service to trigger a script that connects to the MCP server and calls the triage tool. The script can post the triage results to Slack or PagerDuty.

---

Source: https://www.rapidevelopers.com/mcp-tutorial/how-to-use-mcp-for-monitoring-and-alerts
© RapidDev — https://www.rapidevelopers.com/mcp-tutorial/how-to-use-mcp-for-monitoring-and-alerts
