1pub mod get_issue_details;
2pub mod get_trace_details;
3pub mod search_issue_events;
4
5use crate::api_client::SentryApiClient;
6use get_issue_details::{GetIssueDetailsInput, execute as execute_get_issue_details};
7use get_trace_details::{GetTraceDetailsInput, execute as execute_get_trace_details};
8use rmcp::{
9 ErrorData as McpError,
10 ServerHandler,
11 handler::server::{router::tool::ToolRouter, wrapper::Parameters},
12 model::*,
13 tool_handler, tool_router,
14};
15use search_issue_events::{SearchIssueEventsInput, execute as execute_search_events};
16use std::sync::Arc;
17use tracing::info;
18
19#[derive(Clone)]
20pub struct SentryTools {
21 client: Arc<SentryApiClient>,
22 tool_router: ToolRouter<SentryTools>,
23}
24
25impl Default for SentryTools {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31#[tool_router]
32impl SentryTools {
33 pub fn new() -> Self {
34 Self {
35 client: Arc::new(SentryApiClient::new()),
36 tool_router: Self::tool_router(),
37 }
38 }
39 #[rmcp::tool(description = "Retrieve detailed information about a specific Sentry issue including metadata, tags, and optionally an event. Accepts either an issueUrl OR (organizationSlug + issueId).")]
40 async fn get_issue_details(
41 &self,
42 Parameters(input): Parameters<GetIssueDetailsInput>,
43 ) -> Result<CallToolResult, McpError> {
44 info!("get_issue_details: {:?}", input);
45 execute_get_issue_details(&*self.client, input).await
46 }
47 #[rmcp::tool(description = "Retrieve trace details including span tree and timing information. Useful for analyzing distributed system performance.")]
48 async fn get_trace_details(
49 &self,
50 Parameters(input): Parameters<GetTraceDetailsInput>,
51 ) -> Result<CallToolResult, McpError> {
52 info!("get_trace_details: {:?}", input);
53 execute_get_trace_details(&*self.client, input).await
54 }
55 #[rmcp::tool(description = "Search events for a specific issue using a query string. Returns matching events with their details.")]
56 async fn search_issue_events(
57 &self,
58 Parameters(input): Parameters<SearchIssueEventsInput>,
59 ) -> Result<CallToolResult, McpError> {
60 info!("search_issue_events: {:?}", input);
61 execute_search_events(&*self.client, input).await
62 }
63}
64
65#[tool_handler]
66impl ServerHandler for SentryTools {
67 fn get_info(&self) -> ServerInfo {
68 ServerInfo {
69 protocol_version: ProtocolVersion::V_2024_11_05,
70 capabilities: ServerCapabilities {
71 tools: Some(ToolsCapability {
72 list_changed: Some(true),
73 }),
74 ..Default::default()
75 },
76 server_info: Implementation {
77 name: "sentry-mcp".to_string(),
78 version: env!("CARGO_PKG_VERSION").to_string(),
79 title: None,
80 icons: None,
81 website_url: None,
82 },
83 ..Default::default()
84 }
85 }
86}