Artificial Intelligence 25 min read

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.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Unlocking AI Data Access: How Model Context Protocol (MCP) Bridges LLMs with External Services

MCP Introduction

MCP

(Model Context Protocol) is an open standard released by

Anthropic

that 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

GET

request) so that information can be loaded into the LLM’s context.

Provide functionality through

Tools

(similar to a

POST

request) 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

AWS

Knowledge Base Retrieval – uses

Bedrock Agent Runtime

to fetch information from an AWS knowledge base.

Brave

Search – leverages Brave’s search

API

for 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

Sentry

as a bug reporting platform. By combining

Sentry

with 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

Sentry MCP component diagram
Sentry MCP component diagram

Program Flow : The entry point

main

receives 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

ApkHistoryData

store issue details, session statistics, and APK history respectively.

Handler functions like

handle_sentry_issue

,

handle_session_stats

, and

handle_apk_history

fetch 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 mcp

4.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

main

function 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 server

The

serve

function 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

SentryIssueData

object.

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_stats

we can query crash‑rate data for specific versions; the generated HTML reports show session counts, crash rates, and percentile metrics.

Crash rate report
Crash rate report

Querying a specific bug ID via

handle_sentry_issue

returns 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.

Performance comparison
Performance comparison

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.

PythonMCPLow CodeSentryServerModel Context ProtocolAI integration
Sohu Tech Products
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.