Unlocking AI Data Access: How Model Context Protocol (MCP) Bridges LLMs with External Services
This article introduces the Model Context Protocol (MCP), explains its core advantages such as capability expansion, standardized interfaces, and low‑code integration, and demonstrates a practical Sentry‑MCP implementation with Python code, detailed functions, and visual results for AI‑driven data access.
MCP Introduction
MCP(Model Context Protocol) is an open standard released by
Anthropicthat defines a communication protocol between large language models (
LLM) and external data sources or tools.
Using MCP, developers can build servers that expose data and functionality to LLM applications. An MCP server can:
Expose data through
Resources(similar to a
GETrequest) so that information can be loaded into the LLM’s context.
Provide functionality through
Tools(similar to a
POSTrequest) to execute code or produce side effects.
Define interaction patterns via
Prompts, which act like a service list describing available operations and required parameters.
The main purpose of MCP is to solve the data‑island problem that limits AI models, allowing them to safely access and manipulate local and remote data, effectively giving AI applications a universal interface to “connect everything”.
MCP Core Advantages
Capability Expansion : Enables AI models to go beyond their training data by fetching real‑time external information.
Standardized Interface : Provides a unified API specification that simplifies service integration.
Security & Control : Explicit permission management and access control protect data safety.
Low‑Code Integration : Reduces the need for glue code, lowering development cost.
Real‑Time Data Access : Allows AI to make decisions and responses based on the latest data.
Example Services Implemented via MCP
AWSKnowledge Base Retrieval – uses
Bedrock Agent Runtimeto fetch information from an AWS knowledge base.
BraveSearch – leverages Brave’s search
APIfor web and local searches.
EverArt– AI image generation.
Everything– reference/test server containing prompts, resources, and tools.
Fetch– network content retrieval and conversion to improve LLM efficiency.
File System – secure file operations with configurable access control.
Git,
GitHub,
GitLab– repository management and file operations.
Google Drive– file access and search.
Google Maps– location services, routing, and place details.
Memory System – persistent knowledge‑graph based memory.
PostgreSQL– read‑only database access with schema checks.
Puppeteer– browser automation and web scraping.
Redis– interaction with Redis key‑value store.
Sentry– issue retrieval and analysis via
Sentry.io.
Sequential Thinking– dynamic and reflective problem solving through thought sequences.
Sentry MCP Practice – Overview
In our project we use
Sentryas a bug reporting platform. By combining
Sentrywith an MCP server, we can seamlessly feed bug data to AI for analysis, crash‑cause identification, and crash‑rate queries. The official demo program provides a reference implementation for extending Sentry tool functionality.
4.1 Background & Implemented Functions
We integrate Sentry with MCP to submit bug IDs or URLs, retrieve detailed issue information, and expose it to AI. Additionally, we import Sentry session statistics and APM data into the service, enabling the cursor to query comprehensive application metrics.
4.2 Sentry MCP Service Component Structure
Program Flow : The entry point
mainreceives Sentry and SNS authentication tokens, creates an MCP server via
serve, registers handlers, and runs the event loop.
Main Components
Data classes such as
SentryIssueData,
SentrySessionStatsData, and
ApkHistoryDatastore issue details, session statistics, and APK history respectively.
Handler functions like
handle_sentry_issue,
handle_session_stats, and
handle_apk_historyfetch data from external APIs and convert it into structured objects.
Server configuration registers prompts, tools, and the tool‑call dispatcher.
4.3 Implementation Details
4.3.1 Installing MCP
pip install mcp4.3.2 Server Entry Point
# server.py
def main(auth_token: str, sns_token: str = None):
async def _run():
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
server = await serve(auth_token, sns_token)
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="sentry",
server_version="0.4.1",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={},
),
),
)
asyncio.run(_run())
if __name__ == "__main__":
# Directly invoke main
main()The
mainfunction creates a stdio communication channel, initializes the MCP server, configures options, and starts the run loop.
4.3.3 Server Instance Creation
# server.py
async def serve(auth_token: str, sns_token: str = None) -> Server:
server = Server("sentry")
http_client = httpx.AsyncClient(base_url=SENTRY_API_BASE)
apk_http_client = httpx.AsyncClient(base_url=APK_API_BASE)
@server.list_prompts()
async def handle_list_prompts() -> list[types.Prompt]:
prompts = [
types.Prompt(
name="sentry-issue",
description="Get Sentry issue details by ID or URL",
arguments=[],
),
types.Prompt(
name="session-stats",
description="Fetch Sentry session statistics and crash rates",
arguments=[],
),
types.Prompt(
name="apk-history",
description="Retrieve APK detection history",
arguments=[],
),
]
return prompts
@server.get_prompt()
async def handle_get_prompt(name: str, arguments: dict[str, str] | None) -> types.GetPromptResult:
if name == "sentry-issue":
...
return issue_data.to_prompt_result()
elif name == "session-stats":
...
return stats_data.to_prompt_result()
elif name == "apk-history":
...
return history_data.to_prompt_result()
else:
raise ValueError(f"Unknown prompt: {name}")
@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
tools = [
types.Tool(name="get_sentry_issue"),
types.Tool(name="get_sentry_session_stats"),
types.Tool(name="get_apk_history"),
]
return tools
@server.call_tool()
async def handle_call_tool(name: str, arguments: dict | None) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
if name == "get_sentry_issue":
return issue_data.to_tool_result()
elif name == "get_sentry_session_stats":
return stats_data.to_tool_result()
elif name == "get_apk_history":
return history_data.to_tool_result()
else:
raise ValueError(f"Unknown tool: {name}")
return serverThe
servefunction registers prompts, tools, and their corresponding handlers, forming the core of the Sentry MCP service.
4.4 Three Query Functions
4.4.1 Sentry Issue Detail Retrieval
async def handle_sentry_issue(http_client: httpx.AsyncClient, auth_token: str, issue_id_or_url: str) -> SentryIssueData:
try:
# Extract issue ID
issue_id = extract_issue_id(issue_id_or_url)
# Fetch issue details
response = await http_client.get(
f"organizations/xxx/issues/{issue_id}/",
headers={"Authorization": f"Bearer {auth_token}"},
)
if response.status_code == 401:
raise McpError("Error: Unauthorized. Please check your MCP_SENTRY_AUTH_TOKEN token.")
response.raise_for_status()
issue_data = response.json()
# Fetch issue hashes
hashes_response = await http_client.get(
f"organizations/xxx/issues/{issue_id}/hashes/",
headers={"Authorization": f"Bearer {auth_token}"},
)
hashes_response.raise_for_status()
hashes = hashes_response.json()
if not hashes:
raise McpError("No Sentry events found for this issue")
latest_event = hashes[0]["latestEvent"]
stacktrace = create_stacktrace(latest_event)
return SentryIssueData(
title=issue_data["title"],
issue_id=issue_id,
status=issue_data["status"],
level=issue_data["level"],
first_seen=issue_data["firstSeen"],
last_seen=issue_data["lastSeen"],
count=issue_data["count"],
stacktrace=stacktrace,
)
except SentryError as e:
raise McpError(str(e))
except httpx.HTTPStatusError as e:
raise McpError(f"Error fetching Sentry issue: {str(e)}")
except Exception as e:
raise McpError(f"An error occurred: {str(e)}")The function extracts the issue ID, retrieves detailed information and stack traces, and returns a formatted
SentryIssueDataobject.
4.4.2 Sentry Session Statistics Retrieval
async def handle_session_stats(
http_client: httpx.AsyncClient,
auth_token: str,
organization: str,
field: list[str],
start: str = None,
end: str = None,
environment: list[str] = None,
stats_period: str = None,
project: list[int] = None,
per_page: int = None,
interval: str = None,
group_by: list[str] = None,
order_by: str = None,
include_totals: int = 1,
include_series: int = 1,
query: str = None,
) -> SentrySessionStatsData:
try:
params = {"field": field}
if start:
params["start"] = start
if end:
params["end"] = end
if environment:
params["environment"] = environment
if stats_period:
params["statsPeriod"] = stats_period
if project:
params["project"] = project
if per_page:
params["per_page"] = per_page
if interval:
params["interval"] = interval
if group_by:
params["groupBy"] = group_by
if order_by:
params["orderBy"] = order_by
if include_totals is not None:
params["includeTotals"] = include_totals
if include_series is not None:
params["includeSeries"] = include_series
if query:
params["query"] = query
response = await http_client.get(
f"organizations/{organization}/sessions/",
headers={"Authorization": f"Bearer {auth_token}"},
params=params,
)
if response.status_code == 401:
raise McpError("Error: Unauthorized. Please check your MCP_SENTRY_AUTH_TOKEN token.")
response.raise_for_status()
data = response.json()
stats_data = SentrySessionStatsData(
organization=organization,
start_time=data.get("start", ""),
end_time=data.get("end", ""),
intervals=data.get("intervals", []),
groups=data.get("groups", []),
query=data.get("query", ""),
)
report_file_path = generate_crash_rate_html_report(data=data, params=params)
stats_data.report_file_path = report_file_path
return stats_data
except httpx.HTTPStatusError as e:
raise McpError(f"Error fetching Sentry session statistics: {str(e)}")
except Exception as e:
raise McpError(f"An error occurred: {str(e)}")This function builds flexible query parameters, calls the Sentry sessions API, and returns structured statistics along with an HTML report.
4.4.3 APK History Retrieval
async def handle_apk_history(http_client: httpx.AsyncClient, sns_token: str) -> ApkHistoryData:
try:
response = await http_client.get(
"getHistory/0",
headers={"sns_token": sns_token},
)
if response.status_code == 401:
raise McpError("Error: Unauthorized. Please check your SNS token.")
response.raise_for_status()
data = response.json()
apkData = ApkHistoryData(
apk_list=data.get("data", {}).get("apkList", []),
total_count=data.get("data", {}).get("totalCount", 0),
)
report_file_path = generate_apk_history_html_report(data=apkData)
apkData.report_file_path = report_file_path
return apkData
except httpx.HTTPStatusError as e:
raise McpError(f"Error fetching APK history data: {str(e)}")
except Exception as e:
raise McpError(f"An error occurred: {str(e)}")The function obtains APK detection history from an internal APM interface, parses version, size, component breakdown, and outputs an HTML summary.
Effect Demonstration
Using
handle_session_statswe can query crash‑rate data for specific versions; the generated HTML reports show session counts, crash rates, and percentile metrics.
Querying a specific bug ID via
handle_sentry_issuereturns a detailed analysis, stack trace, and remediation suggestions.
Sentry问题分析报告
我已经查询到关于您提供的Sentry问题的详细信息。这是一个发生在flavorsOnline_arm64环境中的项目6的错误:
错误概览
错误类型:RemoteServiceException$CannotDeliverBroadcastException
错误描述:can't deliver broadcast
问题ID:644
状态:未解决
严重级别:致命(fatal)
首次出现:2024-10-03 04:36:33
最近出现:2025-03-21 10:44:02
事件计数:18次
堆栈跟踪
ZygoteInit.java:954 in main
RuntimeInit.java:559 in run
Method.java:None in invoke
ActivityThread.java:8395 in main
Looper.java:300 in loop
Looper.java:211 in loopOnce
Handler.java:106 in dispatchMessage
ActivityThread.java:2349 in handleMessage
None:0 in -$$Nest$mthrowRemoteServiceException
ActivityThread.java:2087 in throwRemoteServiceException
崩溃率分析
崩溃率:约0.0001 (0.01%)
无崩溃率:约0.9999 (99.99%)
总会话数:1,239,555
建议解决方案
防御性编程:在发送广播前检查接收器是否存在,使用try‑catch包装广播发送代码。Comparing performance data between two app versions (e.g., 6.6.0 vs. 6.5.0) yields HTML visualizations that illustrate metric trends and highlight regressions.
Conclusion
This article provides a concise overview of the Model Context Protocol (
MCP). MCP is an efficient, generic protocol that enables AI models to safely and efficiently access local data. Using a Sentry‑MCP integration as an example, we demonstrated how to implement a server that fetches Sentry issue details, session statistics, and APK history, and how AI assistants can leverage this data for intelligent crash analysis and performance monitoring.
We hope readers gain a solid understanding of MCP, learn how to connect local data sources to AI, and find the presented patterns useful for their own AI‑driven applications.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.