Post

AI Agent 专题 - 自建一个MCP服务

或许有一天,你也要搭建一个自己的MCP服务。

AI Agent 专题 - 自建一个MCP服务

Background

作为上一篇文章个人代理的延续,今天我们来build 一个自定义的MCP 服务。

为什么要自建?

当我有某个基础服务,需要给多个agent 提供能力时,或者有些服务是业务垂直的,仅仅在我的公司里有许多用处,我就需要一个MCP服务来统一管理这些能力。

一个MCP服务需要什么?

Must have:

  • 定义tools上下文的能力:能够定义符合Model Context Protocol规范的tools
  • 具备tools的执行能力:能够与tools集成
  • 会话状态管理的能力

Better to have:

  • 支持多种不同的连接方式,比如websocket, http, grpc等
  • 支持不同的认证方式,比如token, oauth等

MCP服务不需要什么?

MCP 服务是一个很简单的执行层,它并不需要任何llm的能力。

咸盐少许,我们开始

这个例子里,我们还是使用ADK来搭建我们都MCP 服务。

实现一个MCP 需要实现list tools 和call tools的方法

在adk里,就是通过这两个注解来告诉框架,调用哪个方法。

  • @app.list_tools()
  • @app.call_tool()

@app.list_tools()

list tools 能够允许你列出,你希望agent知道的tools。例子里我们用现成的tool,来自googl的tool库。

https://google.github.io/adk-docs/api-reference/python/google-adk.html#module-google.adk.tools

load_web_page tool:Fetches the content in the url and returns the text in it.

根据文档描述,load_web_page tool是以文字方式获取网页内容的一个功能。

1
2
3
4
5
6
7
8
9
10
11
adk_tool_to_expose = FunctionTool(load_web_page)

# Implement the MCP server's handler to list available tools
@app.list_tools()
async def list_mcp_tools() -> list[mcp_types.Tool]:
    """MCP handler to list tools this server exposes."""
    print("MCP Server: Received list_tools request.")
    # Convert the ADK tool's definition to the MCP Tool schema format
    mcp_tool_schema = adk_to_mcp_tool_type(adk_tool_to_expose)
    print(f"MCP Server: Advertising tool: {mcp_tool_schema.name}")
    return [mcp_tool_schema]

@app.call_tool()

这是执行的实现

1
2
3
4
5
6
# Implement the MCP server's handler to execute a tool call
@app.call_tool()
async def call_mcp_tool(
    name: str, arguments: dict
) -> list[mcp_types.Content]:
# ...

启动MCP 服务

MCP本质是个服务, ADK提供了多这个服务的种连接方式

  • sse
  • streamable_http
  • websocket.py 例子里我们还是使用sse 来创建连接。sse 需要实现的是Route("/sse", endpoint=handle_sse, methods=["GET"]),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Define handler functions
async def handle_sse(request):
    async with sse.connect_sse(
        request.scope, request.receive, request._send
    ) as streams:
        await app.run(
            streams[0], streams[1], app.create_initialization_options()
        )
    # Return empty response to avoid NoneType error
    return Response()

# Create an SSE transport at an endpoint
sse = mcp.server.sse.SseServerTransport("/messages/")

# Create Starlette routes for SSE and message handling
routes = [
    Route("/sse", endpoint=handle_sse, methods=["GET"]),
    Mount("/messages/", app=sse.handle_post_message),
]

if __name__ == "__main__":
    # Create and run Starlette app
    starlette_app = Starlette(routes=routes)
    uvicorn.run(starlette_app, host="127.0.0.1")

run python

1
python3 mcp_server/my_adk_mcp_server.py

Image

调试MCP服务

我们能通过postman调试mcp。只需要创建新请求的时候选择mcp

Image

请求我们的mcp 服务之后,就能拉到所有的tools。点击tool就能执行tool。

Image

Image

结果是糟糕的,页面元素之复杂,导致返回的文字基本不可读。但是流程是通顺的。接下来的事情就是不停的优化这个tool的执行效果。

在agent里使用&调试

稍加修改我们在集成一个现成的MCP服务的程序,我们就能智能的使用这个tool了。

1
2
3
4
5
6
7
8
9
10
public static BaseAgent initAgent() {
    return LlmAgent.builder()
        .name(NAME)
        .model("gemini-2.0-flash")
        .description("Agent to get page content.")
        .instruction(
            "Use the 'load_web_page' tool to fetch content from a URL provided by the user.")
        .tools(integrateJiraMCP())
        .build();
}

这次我们用adk web 来进行调试,adk web会把所有的event记录清晰,有助于我们理解agent运行的机制。 java 启动adk-web 需要依赖sprint-boot,并且配置对应的agent 启动程序:

1
2
3
4
mvn exec:java \
    -Dexec.mainClass="com.google.adk.web.AdkWebServer" \
    -Dexec.args="--adk.agents.source-dir=src/main/java" \
    -Dexec.classpathScope="compile"

执行,进入调试页面 ,输入prompt:

help me to get the web https://www.jakobhe.com/posts/after-reading-breath/

Image

从左边的event栏,你很容易就能看到调用方法的情况。

一些想法

我们常常使用的是所谓的通用大模型,它适合用于处理一些通用和共识的问题,比如mysql,java这类技术问题,全世界的java 都有一样的knowledge base。

但是当我们要在垂直行业里,使用通用大模型时,企业就显得捉襟见肘了。

MCP恰恰就是提供这类垂直行业的执行能力的服务。比如绝大部分的软件从业人员,都有一套比较规范的流程,先从jira开始,到产品,到开发,到测试。

但是在餐饮行业,这个流程很可能是一个完完全全不一样的流程。 假设是:竞品调研,内部讨论,产品设计,开发,测试,发布。

恰好某餐饮公司,开发了一个竞品调研系统,那么竞品调研就可以是一个tools深度的集成在许多agent里,比如menu R&D流程的agent里,市场策略定制的agent里,等等。

总结一下子

今天我们一起做了:

  • 实现了一个基本的MCP服务
  • 利用postman调试MCP服务
  • 集成MCP服务到agent里
  • 利用adk web调试agent
  • 从evnet来理解agent的运行机制

references

This post is licensed under CC BY 4.0 by the author.