Skip to content

Commit 0bd5fb6

Browse files
dcramerclaude
andcommitted
feat: integrate Seer AI analysis into issue details
Enhanced get_issue_details to include Seer AI analysis when available, providing users with both raw issue data and AI-powered insights in a single tool call. Changes: - Add Seer analysis context to issue details output - Update tool descriptions to clarify use cases - Add formatSeerContext utility for clean analysis display - Include tests for Seer integration - Fix markdown formatting in documentation - Export autofixStateFixture for testing Fixes #360, #361 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 3d35862 commit 0bd5fb6

File tree

8 files changed

+171
-41
lines changed

8 files changed

+171
-41
lines changed

docs/architecture.mdc

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ packages/
2929
The core MCP implementation and npm-publishable package.
3030

3131
**Structure:**
32+
3233
```
3334
src/
3435
├── api-client/ # Sentry API client
@@ -43,14 +44,15 @@ src/
4344
```
4445

4546
**Key responsibilities:**
47+
4648
- Implements MCP protocol using the official SDK
4749
- Provides tools for Sentry operations (issues, projects, etc.)
4850
- Handles authentication and API communication
4951
- Formats responses for LLM consumption
5052

5153
### packages/mcp-cloudflare
5254

53-
A separate web chat application that uses the MCP server.
55+
A separate web chat application that uses the MCP server.
5456

5557
**Note**: This is NOT part of the MCP server itself - it's a demonstration of how to build a chat interface that consumes MCP.
5658

@@ -61,6 +63,7 @@ See [Cloudflare Web App Documentation](./cloudflare/overview.md) for details.
6163
Evaluation tests that verify real Sentry operations.
6264

6365
**Uses:**
66+
6467
- Vercel AI SDK for LLM integration
6568
- Real Sentry API calls with mocked responses
6669
- Factuality scoring for output validation
@@ -70,6 +73,7 @@ Evaluation tests that verify real Sentry operations.
7073
Centralized mock data and MSW handlers.
7174

7275
**Provides:**
76+
7377
- Fixture data for all Sentry entities
7478
- MSW request handlers
7579
- Shared test utilities
@@ -79,6 +83,7 @@ Centralized mock data and MSW handlers.
7983
Interactive CLI for testing the MCP server with an AI agent.
8084

8185
**Key features:**
86+
8287
- Vercel AI SDK integration with Anthropic
8388
- Interactive and single-prompt modes
8489
- OAuth authentication for remote servers
@@ -107,12 +112,14 @@ server.setRequestHandler(ListToolsRequestSchema, () => ({
107112
The MCP server supports multiple transport mechanisms:
108113

109114
**Stdio Transport** (Primary):
115+
110116
- Direct process communication
111117
- Used by IDEs (Cursor, VS Code) and local tools
112118
- Configured via command-line args
113119
- This is the standard MCP transport
114120

115121
**HTTP/SSE Transport** (For web apps):
122+
116123
- Allows web applications to connect to MCP
117124
- Used by the example Cloudflare chat app
118125
- Not part of core MCP spec
@@ -168,6 +175,7 @@ Each tool follows a consistent structure:
168175
- Evaluation tests
169176

170177
**Tool Count Constraints:**
178+
171179
- AI agents have a 45 tool limit (Cursor, etc.)
172180
- Sentry MCP must stay under 25 tools (target: ~20)
173181
- Consolidate functionality where possible
@@ -183,6 +191,7 @@ Two-tier error system:
183191
### 7. Build System
184192

185193
Turbo for monorepo orchestration:
194+
186195
- Dependency-aware builds
187196
- Parallel task execution
188197
- Shared TypeScript configs
@@ -207,20 +216,26 @@ Turbo for monorepo orchestration:
207216
## MCP Concept Mappings
208217

209218
### Tools
219+
210220
Execute actions and retrieve data:
221+
211222
- `find_issues` - Search for issues
212223
- `get_project_details` - Fetch project info
213224
- `create_issue_comment` - Add comments
214225
- `search_docs` - Search Sentry documentation
215226
- `get_doc` - Fetch full documentation pages
216227

217228
### Prompts
229+
218230
Multi-step workflows:
231+
219232
- `find_errors_in_file` - Analyze file errors
220233
- `fix_issue_with_seer` - AI-suggested fixes
221234

222235
### Resources
236+
223237
External documentation and data:
238+
224239
- Platform docs (React, Python, etc.)
225240
- API references
226241
- Configuration examples

docs/cloudflare/prompts-integration.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ Users can type `/prompts` in the chat to see all available MCP prompts:
138138
```
139139

140140
This displays a formatted list with:
141+
141142
- Prompt names and descriptions
142143
- Required and optional parameters
143144
- Parameter types and descriptions
@@ -197,4 +198,4 @@ The AI agent is automatically aware of available prompts through its enhanced sy
197198
- Zod schemas are converted to simple JSON schemas for client consumption
198199
- Graceful fallback to stream data if metadata endpoint fails
199200
- Loading and error states provide better user experience
200-
- The implementation is designed to be easily removable once AI SDK supports prompts natively
201+
- The implementation is designed to be easily removable once AI SDK supports prompts natively

packages/mcp-server-mocks/src/index.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ export const restHandlers = buildHandlers([
722722
path: "/api/0/organizations/sentry-mcp-evals/issues/6507376926/",
723723
fetch: () => HttpResponse.json(issueFixture2),
724724
},
725+
725726
{
726727
method: "get",
727728
path: "/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-41/events/7ca573c0f4814912aaa9bdc77d1a7d51/",
@@ -754,6 +755,7 @@ export const restHandlers = buildHandlers([
754755
path: "/api/0/organizations/sentry-mcp-evals/issues/6507376926/events/latest/",
755756
fetch: () => HttpResponse.json(eventsFixture),
756757
},
758+
757759
{
758760
method: "get",
759761
path: "/api/0/organizations/sentry-mcp-evals/releases/",
@@ -769,36 +771,22 @@ export const restHandlers = buildHandlers([
769771
path: "/api/0/organizations/sentry-mcp-evals/tags/",
770772
fetch: () => HttpResponse.json(tagsFixture),
771773
},
772-
{
773-
method: "get",
774-
path: "/api/0/organizations/sentry-mcp-evals/issues/6507376925/autofix/",
775-
fetch: () => HttpResponse.json(autofixStateFixture),
776-
},
777774
{
778775
method: "get",
779776
path: "/api/0/organizations/sentry-mcp-evals/issues/PEATED-A8/autofix/",
780777
fetch: () => HttpResponse.json(autofixStateFixture),
781778
},
782779
{
783780
method: "post",
784-
path: "/api/0/organizations/sentry-mcp-evals/issues/6507376925/autofix/",
781+
path: "/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-42/autofix/",
785782
fetch: () => HttpResponse.json({ run_id: 123 }),
786783
},
787784
{
788785
method: "post",
789786
path: "/api/0/organizations/sentry-mcp-evals/issues/PEATED-A8/autofix/",
790787
fetch: () => HttpResponse.json({ run_id: 123 }),
791788
},
792-
{
793-
method: "get",
794-
path: "/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-41/autofix/",
795-
fetch: () => HttpResponse.json({ autofix: null }),
796-
},
797-
{
798-
method: "post",
799-
path: "/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-41/autofix/",
800-
fetch: () => HttpResponse.json({ run_id: 12 }),
801-
},
789+
802790
{
803791
method: "get",
804792
path: "/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-45/autofix/",
@@ -1203,3 +1191,6 @@ export const mswServer = setupServer(
12031191
...searchHandlers,
12041192
...docsHandlers,
12051193
);
1194+
1195+
// Export fixtures for use in tests
1196+
export { autofixStateFixture };

packages/mcp-server/src/internal/formatting.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* and contextual information with consistent formatting patterns.
77
*/
88
import type { z } from "zod";
9-
import type { Event, Issue } from "../api-client/types";
9+
import type { Event, Issue, AutofixRunState } from "../api-client/types";
1010
import type {
1111
ErrorEntrySchema,
1212
ErrorEventSchema,
@@ -17,6 +17,11 @@ import type {
1717
ThreadsEntrySchema,
1818
SentryApiService,
1919
} from "../api-client";
20+
import {
21+
getOutputForAutofixStep,
22+
getStatusDisplayName,
23+
isTerminalStatus,
24+
} from "../tools/utils/seer-utils";
2025

2126
// Language detection mappings
2227
const LANGUAGE_EXTENSIONS: Record<string, string> = {
@@ -604,6 +609,63 @@ function formatContexts(contexts: z.infer<typeof EventSchema>["contexts"]) {
604609
.join("\n\n")}\n\n`;
605610
}
606611

612+
/**
613+
* Formats Seer AI analysis context for inclusion in issue details.
614+
* Provides a minimal summary showing just the key solution when available.
615+
*
616+
* @param autofixState - The autofix state containing Seer analysis data
617+
* @returns Formatted markdown string with Seer context, or empty string if no analysis exists
618+
*/
619+
function formatSeerContext(autofixState: AutofixRunState): string {
620+
if (!autofixState.autofix) {
621+
return "";
622+
}
623+
624+
const { autofix } = autofixState;
625+
const parts: string[] = [];
626+
627+
parts.push("## Seer AI Analysis");
628+
parts.push("");
629+
630+
// For completed analyses, show just the key solution
631+
if (isTerminalStatus(autofix.status) && autofix.steps.length > 0) {
632+
const completedSteps = autofix.steps.filter(
633+
(step) => step.status === "COMPLETED",
634+
);
635+
636+
// Find the solution step and show its description directly
637+
const solutionStep = completedSteps.find(
638+
(step) => step.type === "solution",
639+
);
640+
641+
if (solutionStep) {
642+
// For solution steps, use the description directly
643+
const solutionDescription = solutionStep.description;
644+
if (
645+
solutionDescription &&
646+
typeof solutionDescription === "string" &&
647+
solutionDescription.trim()
648+
) {
649+
parts.push(solutionDescription.trim());
650+
} else {
651+
// Fallback to extracting from output if no description
652+
const solutionOutput = getOutputForAutofixStep(solutionStep);
653+
const lines = solutionOutput.split("\n");
654+
const firstParagraph = lines.find(
655+
(line) =>
656+
line.trim().length > 50 &&
657+
!line.startsWith("#") &&
658+
!line.startsWith("*"),
659+
);
660+
if (firstParagraph) {
661+
parts.push(firstParagraph.trim());
662+
}
663+
}
664+
}
665+
}
666+
return `${parts.join("\n")}\n\n`;
667+
}
668+
607669
/**
608670
* Formats a Sentry issue with its latest event into comprehensive markdown output.
609671
* Includes issue metadata, event details, and usage instructions.
@@ -616,11 +678,13 @@ export function formatIssueOutput({
616678
issue,
617679
event,
618680
apiService,
681+
autofixState,
619682
}: {
620683
organizationSlug: string;
621684
issue: Issue;
622685
event: Event;
623686
apiService: SentryApiService;
687+
autofixState?: AutofixRunState;
624688
}) {
625689
let output = `# Issue ${issue.shortId} in **${organizationSlug}**\n\n`;
626690
output += `**Description**: ${issue.title}\n`;
@@ -644,6 +708,12 @@ export function formatIssueOutput({
644708
}
645709
output += "\n";
646710
output += formatEventOutput(event);
711+
712+
// Add Seer context if available
713+
if (autofixState) {
714+
output += formatSeerContext(autofixState);
715+
}
716+
647717
output += "# Using this information\n\n";
648718
output += `- You can reference the IssueID in commit messages (e.g. \`Fixes ${issue.shortId}\`) to automatically close the issue when the commit is merged.\n`;
649719
output +=

packages/mcp-server/src/tools/analyze-issue-with-seer.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ import {
2323
export default defineTool({
2424
name: "analyze_issue_with_seer",
2525
description: [
26-
"**ALWAYS use this tool when a user asks how to fix a Sentry issue.** Seer AI analyzes production errors to identify root causes and provide specific code fixes.",
26+
"Use Seer AI to analyze production errors and get detailed root cause analysis with specific code fixes.",
2727
"",
28-
"Use this tool IMMEDIATELY when:",
29-
'- User asks "how do I fix this error?" or "what\'s causing this issue?"',
30-
"- User shares a Sentry issue URL and wants help resolving it",
31-
"- User needs to understand why an error is happening in production",
32-
"- User wants specific code changes to fix their issue",
33-
"- User asks about the root cause of any Sentry error",
28+
"Use this tool when you need:",
29+
"- Detailed AI-powered root cause analysis",
30+
"- Specific code fixes and implementation guidance",
31+
"- Step-by-step troubleshooting for complex issues",
32+
"- Understanding why an error is happening in production",
3433
"",
3534
"What this tool provides:",
3635
"- Root cause analysis with code-level explanations",
@@ -44,12 +43,6 @@ export default defineTool({
4443
"3. Returns complete fix recommendations",
4544
"",
4645
"<examples>",
47-
'### User: "How do I fix ISSUE-123?"',
48-
"",
49-
"```",
50-
"analyze_issue_with_seer(organizationSlug='my-organization', issueId='ISSUE-123')",
51-
"```",
52-
"",
5346
'### User: "What\'s causing this error? https://my-org.sentry.io/issues/PROJECT-1Z43"',
5447
"",
5548
"```",
@@ -64,7 +57,7 @@ export default defineTool({
6457
"</examples>",
6558
"",
6659
"<hints>",
67-
"- ALWAYS prefer this over get_issue_details when users want fixes, not just error details",
60+
"- Use this tool when you need deeper analysis beyond basic issue details",
6861
"- If the user provides an issueUrl, extract it and use that parameter alone",
6962
"- The analysis includes actual code snippets and fixes, not just error descriptions",
7063
"- Results are cached - subsequent calls return instantly",

packages/mcp-server/src/tools/get-issue-details.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { describe, it, expect } from "vitest";
2+
import { http, HttpResponse } from "msw";
3+
import { mswServer, autofixStateFixture } from "@sentry/mcp-server-mocks";
24
import getIssueDetails from "./get-issue-details.js";
35

46
describe("get_issue_details", () => {
@@ -263,4 +265,33 @@ describe("get_issue_details", () => {
263265
"Invalid regionUrl provided: https. Must be a valid URL.",
264266
);
265267
});
268+
269+
it("includes Seer analysis when available", async () => {
270+
// Add ADDITIONAL endpoint binding for autofix state using mswServer.use()
271+
// The default fixtures will handle the regular issue and events endpoints
272+
mswServer.use(
273+
http.get(
274+
"https://sentry.io/api/0/organizations/sentry-mcp-evals/issues/CLOUDFLARE-MCP-41/autofix/",
275+
() => HttpResponse.json(autofixStateFixture),
276+
),
277+
);
278+
279+
const result = await getIssueDetails.handler(
280+
{
281+
organizationSlug: "sentry-mcp-evals",
282+
issueId: "CLOUDFLARE-MCP-41",
283+
eventId: undefined,
284+
issueUrl: undefined,
285+
regionUrl: undefined,
286+
},
287+
{
288+
accessToken: "access-token",
289+
userId: "1",
290+
organizationSlug: null,
291+
},
292+
);
293+
294+
expect(result).toContain("## Seer AI Analysis");
295+
expect(result).toContain("Consolidate bottle and price data fetching");
296+
});
266297
});

0 commit comments

Comments
 (0)