说在前面

为什么会写这篇文章呢?
前几天因为有调试需求,需要本地启动一个mcp server,本以为会很简单,让大模型哐哐一顿写,我只需要执行脚本就可以了,结果硬生生花了3天,到处找资料,代码放到文章里帮助有缘人,希望可以节约你的时间。

官方资源

这里是官网,不需要翻墙。
官方也给了一个server的简单示例,但是这是stdio 形式的,不符合需求。

代码

from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette
from mcp.server.sse import SseServerTransport
from starlette.requests import Request
from starlette.routing import Mount, Route
from mcp.server import Server
import uvicorn

# Initialize FastMCP server for CSDN tools (SSE)
mcp = FastMCP("csdn")

@mcp.tool()
async def get_book_info(book_name: str) -> str:
    """获取图书信息(本地数据)

    参数:
        book_name: 图书名称(支持模糊搜索)
    """
    # 本地图书数据数组
    local_books = [
        {
            "title": "Python编程:从入门到实践",
            "authors": ["埃里克·马瑟斯"],
            "publisher": "人民邮电出版社",
            "publishedDate": "2016-07",
            "description": "本书是一本全面的Python编程入门教程,涵盖从基本语法到实际项目开发的内容。",
        },
        {
            "title": "深入理解计算机系统",
            "authors": ["Randal E. Bryant", "David R. O'Hallaron"],
            "publisher": "机械工业出版社",
            "publishedDate": "2016-07",
            "description": "本书从程序员的视角详细阐述计算机系统的本质概念,包括程序的机器级表示、程序执行、存储系统、编译系统等内容。",
        },
        {
            "title": "算法导论",
            "authors": [
                "Thomas H. Cormen",
                "Charles E. Leiserson",
                "Ronald L. Rivest",
                "Clifford Stein",
            ],
            "publisher": "机械工业出版社",
            "publishedDate": "2013-01",
            "description": "本书是算法领域的经典著作,全面介绍了算法的设计、分析和实现。",
        },
    ]

    # 搜索图书(支持模糊匹配)
    matching_books = [
        book for book in local_books if book_name.lower() in book["title"].lower()
    ]

    if not matching_books:
        return "未找到相关图书信息。"

    # 提取图书信息(取第一本匹配的图书)
    book = matching_books[0]
    return f"""
    书名: {book.get('title', '未知')}
    作者: {', '.join(book.get('authors', ['未知']))}
    出版社: {book.get('publisher', '未知')}
    出版日期: {book.get('publishedDate', '未知')}
    简介: {book.get('description', '无简介')}
    """

def create_starlette_app(mcp_server: Server, *, debug: bool = False) -> Starlette:
    """Create a Starlette application that can server the provied mcp server with SSE."""
    sse = SseServerTransport("/messages/")

    async def handle_sse(request: Request) -> None:
        async with sse.connect_sse(
            request.scope,
            request.receive,
            request._send,  # noqa: SLF001
        ) as (read_stream, write_stream):
            await mcp_server.run(
                read_stream,
                write_stream,
                mcp_server.create_initialization_options(),
            )

    return Starlette(
        debug=debug,
        routes=[
            Route("/sse", endpoint=handle_sse),
            Mount("/messages/", app=sse.handle_post_message),
        ],
    )

if __name__ == "__main__":
    mcp_server = mcp._mcp_server  

    import argparse

    parser = argparse.ArgumentParser(description="Run MCP SSE-based server")
    parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
    parser.add_argument("--port", type=int, default=8080, help="Port to listen on")
    args = parser.parse_args()

    starlette_app = create_starlette_app(mcp_server, debug=True)

    uvicorn.run(starlette_app, host=args.host, port=args.port)

启动 python xx.py

说在最后

我好像有点错怪mcp官网了,我以为他们只给了stdio的示例,然后也没有sse的文档,但是当我打开sdk中的具体文件时,我发现代码文件里给了使用示例。
在这里插入图片描述
很快我还会写一篇mcp-client的文章,有需要的可以关注一下。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐