ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

FastMCP + MySQL实战:让Claude和Cursor直接查询数据库,TaoToken统一Key接入

FastMCP + MySQL实战:让Claude和Cursor直接查询数据库,TaoToken统一Key接入 1. 为什么不让 Claude 直接连 MySQLFastMCP 封装数据库的真实场景很多人第一次听到「让 Claude 查数据库」脑子里浮现的画面是Claude 里填个 MySQL 地址、账号、密码然后直接SELECT。我试过在本地这么干能跑通但只敢在自己电脑上玩。原因很简单——你把数据库的完整读写权限交给了一个会「自由发挥」的模型它今天心情好帮你查订单明天可能因为一句模糊指令生成DELETE FROM customer WHERE 11。所以真实可用的架构一定是分层的Claude / Cursor 作为 MCP Client通过 MCP 协议调用你写的 FastMCP ServerServer 再去连 MySQL。数据库账号密码只存在于 Server 的环境变量里AI 客户端永远看不到。这一层 FastMCP Server 既是「工具层」也是「安全层」和「业务封装层」。这篇文章要解决的核心检索词就是FastMCP MySQL 让 Claude 和 Cursor 直接查询数据库。适合谁看三类人一是想让 AI 助手查自己业务库的后端/全栈开发者二是正在搭 AI Agent、需要给模型接内部数据源的工程师三是用 Cursor 写代码、希望 AI 能顺手查一下测试库表结构的同学。整条链路长这样用户提问 ↓ Claude / CursorMCP Client ↓ MCP 协议 FastMCP Server你写的 Python 服务 ↓ Service 层业务逻辑 固定 SQL ↓ MySQL ↓ JSON 结果 ↓ LLM 整理成自然语言关键点在于AI 不写 SQL只传参数。你提前把「查客户」「查订单」「查库存」这些动作写成固定工具模型只负责决定调哪个工具、传什么参数。这样即使模型抽风最坏结果也只是查错一条数据而不是删库。另外还有一个容易被忽略的痛点Claude Desktop、Cursor、Cline 这些客户端各自要配一套 API Key 和 endpoint管理起来很碎。本文会把 MCP Server 本身跑在本地但把模型通道统一收到 TaoToken 上一个 Key 管所有客户端后面会给出具体配置。先把结论放这FastMCP 负责「让 AI 能安全地碰数据库」TaoToken 负责「让所有 AI 客户端共用一个通道」。两件事分开做互不干扰。2. TaoToken 前置准备统一 Key 与 MCP 环境搭建在写 MCP Server 之前先把两件前置事情做完一是拿到统一的模型通道 Key二是把 Python 侧的 FastMCP 环境装好。这两件事都不难但顺序别搞反否则后面调试时会分不清是 MCP 的问题还是 Key 的问题。2.1 为什么要把 endpoint 统一到 TaoTokenClaude Desktop 用 Anthropic 的通道Cursor 可能用另一家Cline 又是第三家。每个客户端一套 Key、一套计费、一套额度时间一长自己都记不清哪个 Key 快到期了。把 endpoint 统一改到 TaoToken 之后所有客户端共用同一个 Base URL 和同一个 Key换模型、看用量、控成本都在一个地方。TaoToken 的 API 地址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为 Base URL 用。官网入口是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册和看文档都从这里进。你需要提前准备好三样东西后面配置里会反复用到项目说明示例Base URL统一模型通道地址https://taotoken.net/apiAPI Key在控制台创建形如sk-...sk-xxxxxxxxModel ID具体模型标识按需选claude-sonnet-4-5等API Key 在控制台的 API Keys 页面创建地址是https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite。创建后只显示一次记得立刻复制存到密码管理器里。2.2 安装 FastMCP 与 MySQL 驱动Python 版本建议 3.10 以上FastMCP 对类型注解依赖比较重。建一个干净的虚拟环境别在系统 Python 里装python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install mcp[cli] pymysql python-dotenvmcp[cli]会带上 FastMCP 和调试用的命令行工具pymysql是纯 Python 的 MySQL 驱动装起来没有编译依赖比 mysqlclient 省心。python-dotenv用来读.env文件避免把数据库密码写死在代码里。装完验证一下python -c from mcp.server.fastmcp import FastMCP; print(FastMCP OK)能打印出FastMCP OK就说明环境没问题。如果报ModuleNotFoundError八成是虚拟环境没激活或者 pip 装到了别的 Python 上用which python和which pip确认一下路径一致。2.3 项目结构建议一开始就分好层别把所有代码堆在一个文件里。后面加订单、库存、财务模块时你会感谢自己mcp-mysql/ ├── server.py # MCP Server 入口 ├── database.py # 数据库连接管理 ├── config.py # 读环境变量 ├── tools/ │ └── customer.py # 暴露给 AI 的工具 ├── services/ │ └── customer_service.py # 业务逻辑 固定 SQL ├── .env # 敏感配置别提交 Git └── requirements.txt职责划分很清楚tools只做参数校验和调用转发services写真正的 SQLdatabase.py管连接。AI 看到的是tools里的函数签名看不到services里的 SQL这就是安全边界。3. 可复制配置FastMCP Server 连接 MySQL 的完整代码这一节是全文的核心所有代码都可以直接复制改改就用。我会按「配置 → 连接 → Service → Tool → 启动」的顺序给全每一步都说明为什么这么写。3.1 环境变量配置先建.env文件把数据库信息和模型通道 Key 都放进去# MySQL 配置 MYSQL_HOST127.0.0.1 MYSQL_PORT3306 MYSQL_USERdemo_reader MYSQL_PASSWORDyour_db_password MYSQL_DATABASEcrm MYSQL_CHARSETutf8mb4 # TaoToken 统一通道供 MCP Server 内部调用模型时使用 TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEYsk-xxxxxxxxxxxxxxxx TAOTOKEN_MODELclaude-sonnet-4-5注意数据库账号用只读账号demo_reader别用 root。这是第一道防线即使 MCP Server 被攻破也只能读不能写。config.py负责把这些变量读进来import os from dotenv import load_dotenv load_dotenv() class Config: MYSQL_HOST os.getenv(MYSQL_HOST, 127.0.0.1) MYSQL_PORT int(os.getenv(MYSQL_PORT, 3306)) MYSQL_USER os.getenv(MYSQL_USER) MYSQL_PASSWORD os.getenv(MYSQL_PASSWORD) MYSQL_DATABASE os.getenv(MYSQL_DATABASE) MYSQL_CHARSET os.getenv(MYSQL_CHARSET, utf8mb4) TAOTOKEN_BASE_URL os.getenv(TAOTOKEN_BASE_URL, https://taotoken.net/api) TAOTOKEN_API_KEY os.getenv(TAOTOKEN_API_KEY) TAOTOKEN_MODEL os.getenv(TAOTOKEN_MODEL, claude-sonnet-4-5) config Config()3.2 数据库连接管理database.py用一个简单的连接工厂配合上下文管理器保证连接释放import pymysql from contextlib import contextmanager from config import config contextmanager def get_connection(): conn pymysql.connect( hostconfig.MYSQL_HOST, portconfig.MYSQL_PORT, userconfig.MYSQL_USER, passwordconfig.MYSQL_PASSWORD, databaseconfig.MYSQL_DATABASE, charsetconfig.MYSQL_CHARSET, cursorclasspymysql.cursors.DictCursor, autocommitTrue, ) try: yield conn finally: conn.close()cursorclasspymysql.cursors.DictCursor是关键它让查询结果直接返回字典而不是元组。前面 excerpt 里提到过LLM 对 JSON 的理解远好于元组{id: 1001, name: 张三}比(1001, 张三)好处理得多。3.3 Service 层固定 SQLservices/customer_service.py里写死 SQL只接受参数不接受拼接from database import get_connection class CustomerService: def query_by_id(self, customer_id: int): sql SELECT id, name, phone, level, created_at FROM customer WHERE id %s with get_connection() as conn: with conn.cursor() as cursor: cursor.execute(sql, (customer_id,)) row cursor.fetchone() if not row: return {success: False, message: f客户 {customer_id} 不存在} return {success: True, data: row} def top_customers(self, days: int 30, limit: int 10): sql SELECT c.id, c.name, SUM(o.amount) AS total_amount FROM customer c JOIN orders o ON o.customer_id c.id WHERE o.created_at DATE_SUB(NOW(), INTERVAL %s DAY) GROUP BY c.id, c.name ORDER BY total_amount DESC LIMIT %s with get_connection() as conn: with conn.cursor() as cursor: cursor.execute(sql, (days, limit)) rows cursor.fetchall() return {success: True, data: rows}注意%s占位符是 pymysql 的参数化写法它会把参数安全转义杜绝 SQL 注入。永远不要用 f-string 拼 SQL这是底线。3.4 Tool 层暴露给 AI 的接口tools/customer.py里定义 AI 能看到的工具函数签名和 docstring 就是给模型看的「说明书」from mcp.server.fastmcp import FastMCP from services.customer_service import CustomerService service CustomerService() def register_customer_tools(app: FastMCP): app.tool() def query_customer(customer_id: int) - dict: 根据客户 ID 查询客户基本信息姓名、电话、等级。 Args: customer_id: 客户编号整数 try: return service.query_by_id(customer_id) except Exception as e: return {success: False, message: str(e)} app.tool() def top_customers(days: int 30, limit: int 10) - dict: 查询最近 N 天成交金额最高的前 M 位客户。 Args: days: 统计天数默认 30 limit: 返回条数默认 10 try: return service.top_customers(days, limit) except Exception as e: return {success: False, message: str(e)}docstring 一定要写清楚参数含义模型就是靠这个决定传什么值的。异常统一 catch 后返回{success: False, ...}别让异常直接抛出去否则客户端只会看到一个看不懂的堆栈。3.5 Server 入口server.py把所有工具注册进来并启动from mcp.server.fastmcp import FastMCP from tools.customer import register_customer_tools app FastMCP(crm-mysql-server) register_customer_tools(app) if __name__ __main__: app.run()app.run()默认走 stdio 传输这是 Claude Desktop 和 Cursor 最常用的方式。启动后进程会挂在标准输入输出上等客户端连接不会打印一堆日志这是正常的。3.6 客户端配置片段Claude Desktop 的配置文件在~/Library/Application Support/Claude/claude_desktop_config.jsonmacOS或%APPDATA%\Claude\claude_desktop_config.jsonWindows{ mcpServers: { crm-mysql: { command: /path/to/venv/bin/python, args: [/path/to/mcp-mysql/server.py], env: { MYSQL_HOST: 127.0.0.1, MYSQL_PORT: 3306, MYSQL_USER: demo_reader, MYSQL_PASSWORD: your_db_password, MYSQL_DATABASE: crm } } } }Cursor 的 MCP 配置在~/.cursor/mcp.json结构类似{ mcpServers: { crm-mysql: { command: /path/to/venv/bin/python, args: [/path/to/mcp-mysql/server.py] } } }command一定要写虚拟环境里 Python 的绝对路径别写python否则客户端可能用系统 Python 启动找不到你装的mcp包。4. 验证请求在 Claude 和 Cursor 里跑通一次真实查询配置写完不算完得真跑一次查询才算数。这一节给出完整的验证步骤和预期结果。4.1 先用 MCP Inspector 本地自测在接客户端之前先用官方调试工具确认 Server 本身没问题mcp dev server.py它会启动一个本地 Web 界面列出所有注册的工具。点开query_customer填customer_id10086点运行。如果返回{ success: true, data: { id: 10086, name: 张三, phone: 138****8888, level: VIP, created_at: 2025-03-12T10:20:00 } }说明 Server 到 MySQL 这条链路是通的。如果这里就报错先别急着配客户端把错误解决掉。4.2 在 Claude Desktop 中验证重启 Claude Desktop让它重新加载配置。在对话框右下角能看到一个工具图标点开应该能看到crm-mysql这个 Server 和它下面的两个工具。然后直接问帮我查一下 10086 号客户的信息Claude 会先弹出一个工具调用确认框显示它准备调用query_customer参数是{customer_id: 10086}。点允许它会执行并返回客户 10086 的姓名是张三会员等级为 VIP联系电话 138****8888。整个过程 Claude 没有写一行 SQL它只是决定「调哪个工具、传什么参数」。这就是分层设计的价值。4.3 在 Cursor 中验证Cursor 里按Cmd/Ctrl L打开 Chat切到 Agent 模式。同样问查一下最近 30 天成交额最高的 5 位客户Cursor 会调用top_customers参数{days: 30, limit: 5}返回一个列表。你可以让它把结果整理成表格它会直接输出 Markdown 表格。4.4 把模型通道切到 TaoToken上面两步验证的是 MCP 链路。如果你还想让 Cursor 或 Cline 这类客户端的模型请求也走统一通道就在客户端设置里改 Base URL。以 Cursor 为例在 Settings → Models 里把 OpenAI/Anthropic 的 Base URL 改成https://taotoken.net/apiAPI Key 填 TaoToken 控制台创建的那个Model 填claude-sonnet-4-5。Cline 的配置在扩展设置里同样是三件套配置项值Base URLhttps://taotoken.net/apiAPI Keysk-xxxxxxxxTaoToken 控制台创建Model IDclaude-sonnet-4-5改完之后MCP 工具调用走本地 FastMCP Server模型推理走 TaoToken两条链路互不影响。想验证模型通道是否生效可以在模型对话页面发一条测试消息地址是https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite。5. 本篇常见错误排查401、local proxy failed、reading choices 全解析配置 MCP 数据库这类项目报错基本集中在几个固定位置。这一节按真实报错信息对照排查遇到问题直接对号入座。5.1 401 Unauthorized现象客户端调用模型时报 401或者 MCP Server 内部调用 TaoToken 时报 401。原因API Key 错误、过期、或者带了多余空格。复制 Key 时经常把首尾空格一起复制进去。排查curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-xxxxxxxx \ -H Content-Type: application/json \ -d {model:claude-sonnet-4-5,messages:[{role:user,content:hi}]}如果这条命令返回 401说明 Key 本身有问题去控制台重新创建一个。如果返回正常说明 Key 没问题是客户端配置里写错了。注意Bearer和 Key 之间是一个空格别多别少。5.2 local proxy failed / connection refused现象Claude Desktop 启动后工具图标是灰的日志里出现local proxy failed或connection refused。原因MCP Server 进程没起来或者command路径写错。排查先在终端手动跑一遍/path/to/venv/bin/python /path/to/mcp-mysql/server.py如果报ModuleNotFoundError: No module named mcp说明这个 Python 不是装依赖的那个。用which python确认虚拟环境路径把配置里的command改成绝对路径。如果手动跑没报错但客户端还是连不上检查配置文件 JSON 格式是否合法多一个逗号都会导致整个配置加载失败。5.3 reading choices / undefined is not an object现象客户端报Cannot read properties of undefined (reading choices)。原因模型通道返回的结构和客户端预期的不一致。常见于 Base URL 写成了https://taotoken.net少了/api或者写成了带/v1的完整路径导致重复。排查Base URL 统一写https://taotoken.net/api不要自己加/v1客户端会自动补。用 curl 测一下curl https://taotoken.net/api/v1/models \ -H Authorization: Bearer sk-xxxxxxxx能返回模型列表就说明地址对了。5.4 OAuth / authentication_error现象Claude Code 或某些客户端报 OAuth 相关错误。原因客户端默认走 OAuth 流程但你用的是 API Key 模式。排查在客户端设置里明确选择「API Key」认证方式别选 OAuth。Claude Code 的话检查~/.claude/settings.json里的env段{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-xxxxxxxx } }5.5 工具调用返回空 / 模型说「我没有这个工具」现象模型回复「我无法访问数据库」或「没有可用工具」。原因MCP Server 没被客户端识别或者工具注册失败。排查用mcp dev server.py确认工具列表里有query_customer。如果 Inspector 里能看到但客户端看不到重启客户端。Claude Desktop 对配置变更不敏感必须完全退出再启动不是关窗口。5.6 数据库连接超时现象工具调用卡住很久然后返回(2003, Cant connect to MySQL server)。原因MySQL 没启动、端口不对、或者账号没有远程访问权限。排查mysql -h 127.0.0.1 -P 3306 -u demo_reader -p crm -e SELECT 1能连上说明数据库没问题问题在 MCP Server 的环境变量。检查.env里的MYSQL_HOST是不是写成了localhost某些系统下会走 socket 而不是 TCP统一用127.0.0.1。6. 长期编码与 Agent 场景把通道和工具都管起来MCP Server 跑通只是起点。真正长期用起来你会遇到两个管理问题一是模型通道的额度和成本要统一看二是 MCP 工具会越加越多得有地方管。模型通道这块把所有客户端的 Base URL 都指向https://taotoken.net/api之后用量和成本在控制台一处可见。如果你打算长期跑编码 Agent、让 Cursor 或 Claude Code 持续调用可以了解下 Coding Plan地址是https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite。它适合高频编码场景比按量付费更可控。MCP 工具这块建议按业务域拆文件。客户、订单、库存各一个tools/xxx.py各自对应一个services/xxx_service.py。server.py里统一注册from tools.customer import register_customer_tools from tools.order import register_order_tools from tools.inventory import register_inventory_tools app FastMCP(crm-mysql-server) register_customer_tools(app) register_order_tools(app) register_inventory_tools(app)工具多了之后docstring 的质量直接决定模型选工具的准确率。写清楚「什么时候用这个工具」比写清楚「这个工具做什么」更重要。比如top_customers的 docstring 里加一句「当用户问『成交额最高』『大客户』『Top N』时使用」模型命中率会明显提升。安全上还有几个长期要守的规矩数据库账号永远只读SQL 永远参数化工具永远只暴露固定业务动作不暴露execute_sql每次工具调用记一条日志包含时间、工具名、参数、结果状态。日志不用多复杂写到一个本地文件就够排查用了import logging logging.basicConfig( filenamemcp_audit.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s )在 Tool 里调用前后各记一条出问题时能快速定位是模型传错了参数还是数据库返回了异常。最后留一个实用技巧调试 MCP 工具时把mcp dev server.py一直开着改完代码它会自动重载比每次重启客户端快得多。等 Inspector 里验证通过了再去客户端点确认能省掉大量来回折腾的时间。
返回列表