基于MCP协议与FastAPI构建AI可调用的图书管理API实战
1. 项目概述一个基于MCP协议的图书管理API最近在探索AI开发工具链的集成特别是Model Context Protocol这个新兴标准。简单来说MCP就像是一个“翻译官”它能让不同的AI助手比如Cursor、Claude Desktop里的助手安全、标准地调用你本地的工具和数据而无需你把敏感信息上传到云端。我决定动手实践一下用Python和FastAPI构建一个名为booksapi-mcp的服务它既是一个标准的RESTful API也是一个功能完整的MCP服务器专门用于管理一个简单的图书数据库。这个项目的核心价值在于“一体两面”你既可以通过传统的HTTP请求来操作图书数据也可以直接在VSCode或Cursor的AI聊天窗口里用自然语言告诉AI“帮我把《深入理解计算机系统》这本书加进去”AI就会通过MCP协议调用我写的这个服务来完成操作。对于日常需要频繁操作数据库的开发者来说这能极大提升效率把重复的CRUD操作交给AI自己则专注于更复杂的逻辑。无论你是想学习MCP协议的具体实现还是希望为自己的本地工具增加AI能力这个项目都能提供一个清晰、可运行的参考。2. 技术栈选型与项目架构解析2.1 为什么选择FastAPI MariaDB MCP的组合在技术选型上我主要考虑了易用性、性能和学习曲线。FastAPI是现代Python Web框架的佼佼者它基于Pydantic的类型提示提供了自动的请求验证和生成OpenAPI文档的能力这对于需要暴露清晰接口的API服务来说至关重要。它的异步特性也能很好地处理MCP服务器可能面临的并发请求。数据库方面我选择了MariaDB。它完全兼容MySQL协议性能稳定社区活跃并且对于这种小型的个人项目在本地部署非常方便。相比SQLiteMariaDB更贴近生产环境能练习到连接池、事务等更实际的操作相比MongoDB等NoSQL关系型数据库的结构对于图书标题、作者、ISBN、状态这类结构化数据的管理更为直观和严谨。最核心的MCPModel Context Protocol部分我使用了官方推荐的mcpPython SDK。这个SDK抽象了协议底层的细节让我们可以专注于实现工具Tools和资源Resources的逻辑。选择Python来实现MCP服务器是因为其生态丰富FastAPI社区成熟能快速搭建出原型并且官方SDK对Python的支持非常友好。2.2 项目目录结构与职责划分一个清晰的项目结构是后续开发和维护的基石。booksapi-mcp的目录结构虽然不复杂但每一部分都职责明确booksapi-mcp/ ├── src/ # 核心源代码目录 │ ├── __init__.py │ ├── api.py # FastAPI应用 MCP服务器主入口 │ ├── database.py # 数据库连接与引擎配置 │ ├── models.py # Pydantic数据模型请求/响应和SQLAlchemy ORM模型 │ ├── crud.py # 数据库增删改查操作的核心函数 │ └── mcp_tools.py # MCP工具Tools的具体实现 ├── requests/ # 用于测试API的HTTP请求文件REST Client格式 │ ├── POST.http │ ├── GET.http │ ├── PUT.http │ └── DELETE.http ├── db.py # 数据库初始化脚本建表、插入种子数据 ├── pyproject.toml # 项目依赖声明和配置使用uv ├── .env.example # 环境变量示例文件 └── README.md # 项目说明文档这种结构的关键在于分离关注点。api.py只负责路由和HTTP/MCP的协议适配crud.py纯粹处理数据库交互逻辑mcp_tools.py则封装了供AI调用的函数。当需要修改数据库查询逻辑时你只需要改动crud.py而不会影响到API的路由定义或MCP的工具暴露方式。注意在实际开发中我强烈建议将数据库密码等敏感信息从代码中完全剥离。这就是为什么使用.env文件并通过python-dotenv加载。务必确保.env文件被添加到.gitignore中避免将密钥意外提交到公开仓库。3. 环境准备与依赖安装实战3.1 前置条件检查与工具安装开始之前请确保你的系统已经准备好。你需要一个稳定的Python环境推荐3.9及以上版本以及Git用于克隆代码。我个人的开发环境是VSCode因为它对Python、MCP以及REST Client测试的支持都非常好。接下来的依赖管理我放弃了传统的pipvenv组合转而使用uv。这是一个用Rust写的极速Python包安装器和解析器由Astral团队也是Ruff和uvicorn的开发者打造。它的速度比pip快10-100倍并且集成了虚拟环境管理一个工具搞定所有事。首先安装uv。如果你的系统没有pipx一个用于安装Python命令行工具的工具可以先安装它# 在Windows上 py -m pip install pipx pipx ensurepath # 在Linux/macOS上 python3 -m pip install pipx pipx ensurepath然后通过pipx安装uvpipx install uv安装完成后你可以用uv --version来验证。使用uv后你会发现创建虚拟环境和安装依赖变得异常迅速。3.2 项目克隆与依赖同步现在将项目代码克隆到本地git clone https://github.com/SepulvedaRafael/booksapi-mcp.git cd booksapi-mcp进入项目根目录后使用uv来创建虚拟环境并安装所有依赖# 创建虚拟环境默认在.venv目录 uv venv # 激活虚拟环境 # Windows: .venv\Scripts\activate # Linux/macOS: source .venv/bin/activate # 安装项目依赖uv会根据pyproject.toml文件处理 uv pip install -r pyproject.toml # 或者直接使用sync命令它会同时处理依赖和可能的项目自身安装 uv syncuv sync命令非常强大它不仅会安装pyproject.toml中[project]部分声明的依赖还会以“可编辑模式”安装当前项目本身如果你在pyproject.toml中配置了[project]的name和version这对于开发中的项目非常方便。让我们看一眼pyproject.toml的关键部分了解我们都装了些什么[project] name booksapi-mcp version 0.1.0 dependencies [ fastapi0.104.0, uvicorn[standard]0.24.0, sqlalchemy2.0.0, pymysql1.1.0, # MariaDB/MySQL驱动 pydantic2.0.0, pydantic-settings2.0.0, # 用于管理.env配置 mcp1.0.0, # MCP官方Python SDK python-dotenv1.0.0, ]这里有几个关键包fastapi和uvicorn构成我们的Web服务器sqlalchemy搭配pymysql作为ORM和数据库驱动pydantic负责数据验证mcp是核心协议库python-dotenv用于加载环境变量。4. 数据库配置与初始化详解4.1 MariaDB安装与连接配置这个项目使用MariaDB作为数据存储。如果你还没有安装MariaDB可以去其官网下载安装包或者使用包管理器安装。在Ubuntu上可以运行sudo apt install mariadb-server mariadb-client。安装后记得启动服务并运行安全初始化脚本sudo mysql_secure_installation。项目通过环境变量来管理数据库连接配置这是12-Factor应用倡导的最佳实践能方便地在不同环境开发、测试、生产间切换。在项目根目录下你需要复制.env.example文件并重命名为.env然后填入你自己的数据库信息# .env 文件内容示例 DB_USERroot DB_PASSWORDyour_secure_password_here # 务必使用强密码不要用‘password_db’ DB_HOSTlocalhost DB_PORT3306 DB_NAMEbooksapi这里有一个我踩过的坑变量名命名的一致性。在Python代码中我们使用settings.DB_USER来读取所以在.env文件里变量名必须与Pydantic Settings模型中的字段名匹配。我最初在.env里用了USER_DB结果代码死活连不上数据库调试了半天才发现是变量名对不上。因此我统一采用了DB_作为前缀的命名方式。4.2 数据库初始化脚本解析配置好环境变量后就可以运行db.py脚本来初始化数据库了。这个脚本做了几件关键事情# db.py 核心逻辑摘要 import os from sqlalchemy import create_engine, text from dotenv import load_dotenv load_dotenv() # 加载.env文件中的变量 # 1. 构建数据库连接URL DATABASE_URL fmysqlpymysql://{os.getenv(DB_USER)}:{os.getenv(DB_PASSWORD)}{os.getenv(DB_HOST)}:{os.getenv(DB_PORT)}/ # 2. 创建引擎暂时连接到无数据库的实例 engine create_engine(DATABASE_URL) # 3. 创建数据库如果不存在 with engine.connect() as conn: conn.execute(text(fCREATE DATABASE IF NOT EXISTS {os.getenv(DB_NAME)})) conn.commit() # 4. 重新构建连接到具体数据库的URL和引擎 DATABASE_URL_WITH_DB f{DATABASE_URL}{os.getenv(DB_NAME)} engine_with_db create_engine(DATABASE_URL_WITH_DB) # 5. 创建数据表使用SQLAlchemy的元数据 from src.models import Base Base.metadata.create_all(bindengine_with_db) # 6. 可选的插入一些初始数据种子数据 # ...这个脚本的设计考虑到了容错性。CREATE DATABASE IF NOT EXISTS确保不会因为数据库已存在而报错。Base.metadata.create_all()会根据你在src/models.py中定义的SQLAlchemy模型自动生成建表语句这比手写SQL更安全也更容易维护。重要提示在生产环境中绝对不要使用具有CREATE DATABASE权限的账号如root作为应用运行时的连接账号。正确的做法是先用高权限账号创建好数据库和专用用户然后在应用的.env文件中使用一个只有特定数据库SELECT、INSERT、UPDATE、DELETE权限的专用账号。这能有效遵循最小权限原则减少安全风险。5. 核心数据模型与CRUD逻辑实现5.1 使用SQLAlchemy和Pydantic定义数据层在src/models.py中我定义了两个核心模型一个是SQLAlchemy的Base派生类负责与数据库表映射另一个是Pydantic的BaseModel派生类负责API请求和响应的数据验证与序列化。from sqlalchemy import Column, Integer, String, Text from sqlalchemy.orm import DeclarativeBase from pydantic import BaseModel, Field # SQLAlchemy ORM 模型对应数据库表 class Base(DeclarativeBase): pass class BookDB(Base): __tablename__ books id Column(Integer, primary_keyTrue, indexTrue) title Column(String(200), nullableFalse) author Column(String(100), nullableFalse) isbn Column(String(13), uniqueTrue, indexTrue) # ISBN通常13位 description Column(Text, nullableTrue) status Column(String(20), defaultavailable) # 例如available, borrowed # Pydantic 模型用于请求/响应 class BookCreate(BaseModel): title: str Field(..., min_length1, max_length200) author: str Field(..., min_length1, max_length100) isbn: str Field(..., patternr^\d{13}$) # 使用正则确保13位数字 description: str | None Field(None, max_length1000) status: str Field(available, patternr^(available|borrowed|reserved)$) class BookResponse(BookCreate): id: int class Config: from_attributes True # 允许从ORM对象转换这里有几个设计要点字段约束在数据库模型BookDB中我设置了nullableFalse来保证数据完整性在Pydantic模型BookCreate中我使用了Field来添加更丰富的验证逻辑如长度限制、正则匹配确保ISBN格式正确、枚举值验证status字段。这实现了双重验证既在API入口处拦截非法数据也在数据库层守住最后一道防线。模型分离BookCreate用于创建图书接收请求BookResponse用于返回图书数据包含由数据库生成的id。这种分离是良好的实践避免将内部ID等字段暴露在创建请求中。from_attributes配置这是Pydantic V2的特性允许我们直接使用BookResponse.model_validate(book_db_instance)将SQLAlchemy对象快速、安全地转换为响应模型无需手动提取每个字段。5.2 封装健壮的CRUD操作在src/crud.py中我封装了所有的数据库交互函数。使用独立的CRUD层而不是把SQLAlchemy查询直接写在路由函数里使得代码更清晰、更易于测试和复用。from sqlalchemy.orm import Session from sqlalchemy import select from . import models, schemas def create_book(db: Session, book: schemas.BookCreate): # 1. 将Pydantic模型转换为字典 book_data book.model_dump() # 2. 创建ORM实例 db_book models.BookDB(**book_data) # 3. 添加到会话并提交 db.add(db_book) db.commit() db.refresh(db_book) # 获取数据库生成的新id等数据 return db_book def get_book(db: Session, book_id: int): # 使用select()新语法更符合Python风格 stmt select(models.BookDB).where(models.BookDB.id book_id) result db.execute(stmt) return result.scalar_one_or_none() # 返回一个对象或None def get_books(db: Session, skip: int 0, limit: int 100): stmt select(models.BookDB).offset(skip).limit(limit) result db.execute(stmt) return result.scalars().all() # 返回对象列表 def update_book(db: Session, book_id: int, book_update: schemas.BookCreate): # 1. 先查询出要更新的对象 db_book get_book(db, book_id) if db_book is None: return None # 2. 遍历更新字段 update_data book_update.model_dump(exclude_unsetTrue) # 只包含用户提供的字段 for field, value in update_data.items(): setattr(db_book, field, value) # 3. 提交更改 db.commit() db.refresh(db_book) return db_book def delete_book(db: Session, book_id: int): db_book get_book(db, book_id) if db_book is None: return None db.delete(db_book) db.commit() return db_book实操心得会话管理注意每个函数都接收一个db: Session参数。这个会话应该由上层如FastAPI的依赖项创建和管理并在请求结束后关闭。这确保了数据库连接的正确释放避免了连接泄漏。refresh的重要性在create_book和update_book中提交后调用db.refresh(db_book)是必要的。这会从数据库中重新加载该对象的所有属性确保你返回的数据比如自动递增的ID、数据库设置的默认值是最新的。部分更新技巧在update_book中我使用了model_dump(exclude_unsetTrue)。这意味着如果用户只想更新title字段那么在请求体中只提供{title: 新书名}即可其他字段不会被意外覆盖为None或默认值。这是实现PATCH语义部分更新的常用方法。6. FastAPI应用与MCP服务器融合开发6.1 构建双模式应用入口项目的核心在src/api.py。这个文件巧妙地创建了一个既能通过HTTP访问又能通过stdio标准输入输出作为MCP服务器运行的应用。from contextlib import asynccontextmanager from fastapi import FastAPI, Depends, HTTPException from sqlalchemy.orm import Session import mcp.server as mcp import mcp.server.stdio from . import crud, models, schemas from .database import SessionLocal, engine # 1. 创建MCP服务器实例 mcp_server mcp.Server(booksapi-mcp) # 2. 定义MCP工具具体实现在mcp_tools.py中导入 from .mcp_tools import register_tools register_tools(mcp_server) # 3. 生命周期管理启动时创建表关闭时清理 asynccontextmanager async def lifespan(app: FastAPI): # 启动时可确保表存在生产环境通常用迁移工具 models.Base.metadata.create_all(bindengine) yield # 关闭时可以在这里关闭连接池等资源 pass # 4. 创建FastAPI应用并注入MCP服务器的lifespan app FastAPI(lifespanlifespan) # 5. 数据库会话依赖项 def get_db(): db SessionLocal() try: yield db finally: db.close() # 6. 标准的FastAPI路由 app.post(/books/, response_modelschemas.BookResponse) def create_book_endpoint(book: schemas.BookCreate, db: Session Depends(get_db)): return crud.create_book(dbdb, bookbook) app.get(/books/{book_id}, response_modelschemas.BookResponse) def read_book(book_id: int, db: Session Depends(get_db)): db_book crud.get_book(db, book_idbook_id) if db_book is None: raise HTTPException(status_code404, detailBook not found) return db_book # ... 其他GET /books, PUT, DELETE路由 # 7. 应用主入口判断运行模式 if __name__ __main__: import sys # 如果以uv run api.py启动通常是MCP模式stdio # 我们可以通过判断是否有特定参数或环境变量来区分这里简单判断是否直接运行 # 更健壮的做法是使用asyncio.run()来启动MCP服务器 try: # 尝试以MCP服务器模式运行通过stdio通信 mcp.server.stdio.run(mcp_server) except (EOFError, KeyboardInterrupt): # 处理MCP服务器正常退出 pass except Exception as e: # 如果MCP模式失败则降级为普通的FastAPI开发服务器 import uvicorn uvicorn.run(app, host0.0.0.0, port8000)这个设计非常巧妙。当你想通过HTTP测试API时可以直接用uvicorn src.api:app --reload运行。当你想作为MCP服务器连接AI工具时则通过uv run api.py启动这时程序会进入mcp.server.stdio.run(mcp_server)等待来自标准输入stdin的MCP协议消息。6.2 实现MCP工具ToolsMCP的核心概念之一是“工具”Tools。你可以把工具理解为一个个函数AI助手可以调用这些函数来执行具体操作。在src/mcp_tools.py中我注册了与CRUD对应的五个工具。import mcp.server as mcp from mcp.types import Tool from . import crud, schemas from .database import SessionLocal def register_tools(server: mcp.Server): 向MCP服务器注册所有可用的工具 server.list_tools() async def handle_list_tools(): # 返回工具列表AI助手会据此知道它能调用什么 return [ Tool( namecreate_book, descriptionAdd a new book to the library database., inputSchema{ type: object, properties: { title: {type: string, description: The title of the book}, author: {type: string, description: The author of the book}, isbn: {type: string, description: 13-digit ISBN number}, description: {type: string, description: Optional description}, status: {type: string, enum: [available, borrowed, reserved], description: Current status of the book}, }, required: [title, author, isbn] } ), # ... 类似地定义 get_books, get_book_by_id, update_book, delete_book 工具 ] server.call_tool() async def handle_call_tool(name: str, arguments: dict): # 根据工具名称分发处理 db SessionLocal() try: if name create_book: # 1. 验证参数是否符合Pydantic模型 book_data schemas.BookCreate(**arguments) # 2. 调用CRUD函数 new_book crud.create_book(db, book_data) # 3. 返回结构化的结果给AI return [{ type: text, text: fBook created successfully! ID: {new_book.id}, Title: {new_book.title} }] elif name get_books: books crud.get_books(db) if not books: return [{type: text, text: No books found in the library.}] # 将图书列表格式化为易读的文本 books_list \n.join([f- {b.id}: {b.title} by {b.author} ({b.status}) for b in books]) return [{type: text, text: fFound {len(books)} books:\n{books_list}}] # ... 处理其他工具 except Exception as e: # 捕获异常并返回友好错误信息 return [{type: text, text: fError: {str(e)}}] finally: db.close()关键点解析工具定义Tool对象中的inputSchema至关重要。它使用JSON Schema格式精确描述了AI调用此工具时需要提供的参数类型、是否必需等。这相当于给AI提供了一份严格的“函数签名”能极大提高调用的准确性。参数验证在handle_call_tool中我直接将传入的arguments字典解包给schemas.BookCreate(**arguments)。这利用了Pydantic强大的验证能力如果用户通过AI提供的参数格式错误比如ISBN不是13位数字Pydantic会抛出清晰的验证错误我们可以捕获并返回给AI。会话管理每个工具调用都创建了一个新的数据库会话SessionLocal()并在finally块中确保关闭。这是必要的因为MCP服务器是长生命周期的不能在整个应用生命周期共享一个会话。响应格式MCP工具返回一个包含TextContent对象的列表。AI助手会接收并解析这个文本内容展示给用户。返回清晰、结构化的文本如列表形式能帮助AI更好地理解和总结结果。7. 双通道测试与验证流程7.1 通过HTTP REST API测试这是验证后端逻辑是否正确的最直接方式。在项目requests/目录下我准备了四个.http文件对应增删改查操作。你需要先启动FastAPI开发服务器# 确保在项目根目录且虚拟环境已激活 cd src uvicorn api:app --reload看到Uvicorn running on http://127.0.0.1:8000的输出后就可以用VSCode的REST Client扩展或类似的工具如Thunder Client来测试了。以POST.http为例### 创建一本新书 POST http://localhost:8000/books/ Content-Type: application/json { title: The Pragmatic Programmer, author: David Thomas, Andrew Hunt, isbn: 9780135957059, description: Your journey to mastery., status: available }点击“Send Request”你应该会收到一个201 Created的响应并包含刚刚创建的图书信息含ID。用同样的方法测试GET查询、PUT更新、DELETE删除接口。这种测试方式能快速定位是API路由问题、参数验证问题还是数据库操作问题。7.2 配置并连接MCP服务器到AI助手这是项目的精髓所在——让AI能直接操作你的数据库。这里以VSCode Cursor或已安装GitHub Copilot Chat的VSCode为例。启动MCP服务器首先确保你的MCP服务器脚本能独立运行。在终端中进入src目录并运行uv run api.py如果脚本正常启动它会进入等待状态不会输出Web服务器那样的地址因为它现在是通过标准输入输出stdio进行通信。在编辑器中添加MCP服务器在VSCode/Cursor中按下CtrlShiftP(Windows/Linux) 或CmdShiftP(Mac) 打开命令面板。输入MCP: Add New Server并选择。选择Command (stdio)类型。在“Command”输入框中你需要填写启动命令。关键点来了这里不能直接填uv run api.py因为编辑器需要知道完整路径。你应该填写uv的绝对路径或确保它在系统PATH中并将--directory参数指向你的src目录。 例如如果你的项目在D:\projects\booksapi-mcp那么命令应该是uv --directory D:\projects\booksapi-mcp\src run api.py注意Windows路径使用反斜杠但在JSON配置中可能需要转义或使用正斜杠给服务器起个名字比如my-book-library。选择配置范围Workspace或Global。Workspace配置只对当前项目有效更推荐。验证连接配置完成后编辑器通常会尝试启动服务器。你可以打开输出面板CtrlShiftU在输出下拉菜单中选择你刚配置的MCP服务器名称如MCP: my-book-library。如果看到服务器启动日志且没有报错说明连接成功。更直接的验证是打开Copilot Chat点击输入框上方或侧边的工具按钮通常是一个齿轮或两个交叉的工具图标在弹出的工具列表中你应该能看到my-book-library以及其下的五个工具create_book,get_books等被勾选或可用。7.3 通过自然语言与AI交互连接成功后你就可以在Chat界面中像和人对话一样让AI帮你管理图书了。确保Chat的“Agent”模式已开启并且选择了你的MCP服务器。你可以尝试输入“查看一下我的图书馆里有哪些书。”“添加一本新书书名是《流畅的Python》作者是Luciano RamalhoISBN是9781492056355。”“我想借阅ID为3的那本书请将其状态更新为‘borrowed’。”AI会理解你的意图调用对应的MCP工具并在执行前向你请求确认这是MCP的安全设计防止AI自动执行危险操作。确认后AI会执行工具并返回操作结果。踩坑实录我第一次配置时工具列表始终出不来。排查后发现是两个问题第一uv命令的路径或--directory参数不正确导致服务器启动失败。第二我的工具处理函数handle_call_tool里没有正确处理异常当数据库连接失败时函数静默崩溃没有向MCP协议返回任何响应导致AI端认为工具调用超时或无响应。后来我在函数内部加了详细的try...except日志才定位到是数据库连接字符串的问题。所以MCP服务器的错误处理必须非常健壮任何未捕获的异常都可能导致整个工具调用链对AI不可见。8. 常见问题排查与性能优化建议8.1 连接与配置问题排查表问题现象可能原因排查步骤与解决方案运行db.py时报数据库连接错误1..env文件不存在或路径不对。2. 环境变量名与代码中读取的不一致。3. MariaDB服务未启动。4. 用户名/密码错误。1. 确认在项目根目录运行且存在.env文件。2. 检查.env文件中的变量名是否为DB_USER,DB_PASSWORD等并与database.py中的Settings模型字段匹配。3. 运行sudo systemctl status mariadb(Linux) 或查看服务管理器(Windows)确认服务状态。4. 尝试用mysql -u root -p命令行直接连接验证。运行uvicorn api:app --reload时报模块导入错误1. 未在src目录下运行。2. 虚拟环境未激活或依赖未安装。3. Python路径问题。1. 确保在src的上一级目录即项目根目录运行此命令或使用uvicorn src.api:app --reload。2. 确认终端提示符前有(.venv)并运行uv sync重装依赖。3. 尝试在VSCode中设置正确的Python解释器选择.venv下的python。MCP服务器在编辑器中配置后工具列表不显示1. MCP服务器命令配置错误未能成功启动。2. 编辑器扩展如Copilot Chat未正确加载MCP配置。3. 服务器启动后立即崩溃。1. 打开输出面板(CtrlShiftU)选择对应的MCP服务器输出查看启动日志和错误信息。2. 重启VSCode/Cursor。3. 检查api.py中MCP服务器的lifespan或工具注册代码是否有语法错误导致启动失败。可以尝试在终端直接运行uv run api.py看是否有报错。AI可以调用工具但总是返回“Error”或操作失败1. 数据库操作逻辑错误如唯一约束冲突。2. Pydantic验证失败。3. MCP工具函数内部异常未妥善处理。1. 查看MCP服务器的输出日志通常会有详细的Python错误堆栈信息。2. 检查AI提供的参数是否完整且符合inputSchema要求如ISBN必须是13位数字。3. 在mcp_tools.py的handle_call_tool函数中增加更详细的日志打印定位具体出错行。8.2 安全与性能优化进阶建议当这个原型项目跑通后如果你打算用于更严肃的场景或学习更深度的知识可以考虑以下优化方向数据库连接池目前每个工具调用都创建新连接。对于高频调用应该使用SQLAlchemy的scoped_session或FastAPI的依赖项缓存机制配合连接池如asyncmy或aiomysql用于异步驱动可以大幅提升性能。异步化改造FastAPI和MCP都很好地支持异步。可以将CRUD函数和数据库操作改为异步使用async def和async版本的SQLAlchemy驱动如asyncpgfor PostgreSQL或aiomysql这能提高服务器的并发处理能力。增加认证与授权目前的API和MCP工具都是全开放的。在实际应用中你必须添加认证。对于HTTP API可以使用FastAPI的OAuth2PasswordBearer对于MCP服务器虽然协议本身支持传输层安全但工具级别的权限控制需要在你的handle_call_tool函数中实现例如检查调用上下文中的用户身份。结构化日志使用structlog或loguru库替代print语句输出结构化的JSON日志便于使用ELK或Loki等工具进行收集和查询这对调试分布式MCP应用尤其重要。容器化部署使用Docker将你的应用、数据库以及可能的其他服务如Redis缓存打包。这能保证环境一致性并简化部署流程。一个简单的Dockerfile和docker-compose.yml就能让整个项目一键启动。这个项目从零开始搭建了一个兼具传统API和现代AI代理能力的服务涵盖了从环境搭建、数据库设计、业务逻辑封装到协议集成的完整流程。最大的收获不仅仅是学会了MCP怎么用更是理解了如何将一个具体的业务能力图书管理封装成AI可理解和安全调用的工具。这种模式可以扩展到任何你想让AI辅助操作的本地系统或数据源上比如管理你的待办事项、查询服务器状态、生成数据分析报告等等。动手实现一遍你会对AI应用开发的未来形态有更具体的感知。