news 2026/10/8 6:08:17

DeepSeek操作MySQL数据库:用MCP实现数据库查询的完整配置指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepSeek操作MySQL数据库:用MCP实现数据库查询的完整配置指南

1. 为什么要在本地让 DeepSeek 直接查 MySQL

我最近在做一个库存管理的小工具,后台是 MySQL,前端还没写完,但运营同事已经天天在群里问“低于 300 件的商品还有哪些”“上个月哪个客户买了笔记本”。每次都要我手动写 SQL 再截图发过去,效率低得离谱。后来我换了个思路:既然 DeepSeek 能理解自然语言,MySQL 又有标准协议,那能不能让模型自己把“人话”翻译成 SQL 并执行,我只看结果?

这就是 MCP(Model Context Protocol)要解决的问题。MCP 是一套开放协议,专门用来标准化 AI 模型和外部数据源、工具之间的交互方式。你可以把它理解成“AI 世界的 USB 接口”——模型不需要知道每个数据库的驱动怎么装、连接串怎么写,只要按 MCP 约定暴露工具,模型就能调用。DeepSeek 本身支持工具调用(Function Calling),配合 MCP 服务端,就能实现“自然语言进,查询结果出”。

这个方案适合谁?三类人最受益:一是本地开发时不想反复切终端写 SQL 的后端同学;二是需要快速做数据探查、又不想学 SQL 语法的产品/运营;三是想把数据库查询能力集成进自己 Agent 应用的开发者。整个链路跑通后,你问“11 月收入是多少”,DeepSeek 会自动调工具、查订单表、算总和,最后把数字告诉你。

需要提前说明的是,本文所有操作都在本地开发环境完成,数据库连接信息只存在你自己的机器上。MCP 服务端通过标准输入输出和客户端通信,不涉及任何外部网络转发,安全性可控。下面我从环境准备开始,一步步把这条链路搭起来。

2. TaoToken 前置准备:拿到 DeepSeek 的调用凭证

DeepSeek 官方 API 在高峰期偶尔会限流,而且如果你同时想对比 Claude、GPT 等模型做工具调用,一个个申请 Key 很麻烦。我实测下来,用 TaoToken 做统一接入层比较省事——它兼容 OpenAI 的接口格式,DeepSeek 系列模型可以直接调,Base URL 和 Key 一套搞定。

具体操作分三步。第一步,打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 注册账号,邮箱验证后进控制台。第二步,在控制台左侧找到“API Keys”,点“创建新密钥”,复制生成的 sk- 开头的字符串。这个 Key 只显示一次,建议先存到本地环境变量里,别直接写进代码提交到 Git。

第三步,确认你要用的模型 ID。DeepSeek 在 TaoToken 上的模型名通常是deepseek-chat(对话)和deepseek-reasoner(推理)。做数据库查询这种需要工具调用的场景,用deepseek-chat就够了,它对 Function Calling 的支持比较稳定。如果你后面想跑长期编码任务或 Agent 流程,可以了解下 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite),额度更划算。

配置环境变量时,Linux/macOS 用export,Windows 用set:

# Linux / macOS export TAOTOKEN_API_KEY="sk-你的密钥" export TAOTOKEN_BASE_URL="https://taotoken.net/api" # Windows PowerShell $env:TAOTOKEN_API_KEY="sk-你的密钥" $env:TAOTOKEN_BASE_URL="https://taotoken.net/api"

这里有个坑要注意:Base URL 末尾不要加/v1,TaoToken 的兼容层已经处理了路径映射,加了反而会 404。Key 的权限方面,建议在控制台里给这个 Key 只开“模型调用”权限,不要开“账户管理”,降低泄露风险。如果你还没拿到 Key,可以先到模型对话页面(https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite)手动试几条消息,确认账号能正常调用再继续。

3. 可复制的 MCP 服务端配置:三个工具 + 完整代码

MCP 服务端的核心是暴露工具给模型调用。我设计了三个工具:execute_mysql_query执行任意 SQL、list_tables列出所有表、get_table_schema查看表结构。为什么拆三个而不是只留一个执行 SQL 的?因为 DeepSeek 有幻觉,它可能先入为主认为商品表叫Product,实际你的表叫products,直接执行就报错。有了list_tables和get_table_schema,模型会先查表名和字段,再写 SQL,成功率大幅提升。

先装依赖:

pip install mcp mysql-connector-python openai

然后创建mysql_mcp_server.py。数据库配置我放在文件顶部,实际项目建议用环境变量:

import mysql.connector from mysql.connector import Error from mcp.server.fastmcp import FastMCP DB_CONFIG = { "host": "127.0.0.1", "port": 3306, "user": "dev_user", "password": "your_password", "database": "shop_db", } mcp = FastMCP("mysql-query-server") @mcp.tool() def execute_mysql_query(sql_query: str, max_rows: int = 100) -> str: """执行给定的 SQL 查询语句并返回结果或错误信息。 Args: sql_query: 由 LLM 生成的 SQL 查询语句。 max_rows: SELECT 查询返回的最大行数,防止结果过大。 """ connection = None cursor = None try: connection = mysql.connector.connect(**DB_CONFIG) if connection.is_connected(): cursor = connection.cursor(dictionary=True) cursor.execute(sql_query) if cursor.description: results = cursor.fetchmany(max_rows) column_names = [i[0] for i in cursor.description] if not results: return "查询成功执行,但没有返回任何结果。" output = "查询结果:\n" output += ", ".join(column_names) + "\n" output += "-" * len(", ".join(column_names)) + "\n" for row in results: row_values = [ str(row[col]) if row[col] is not None else "NULL" for col in column_names ] output += ", ".join(row_values) + "\n" if cursor.fetchone() is not None: output += f"\n注意:结果超过 {max_rows} 行,已截断。" return output.strip() else: affected_rows = cursor.rowcount connection.commit() return f"操作成功执行。影响的行数: {affected_rows}" except Error as e: if connection and connection.is_connected(): try: connection.rollback() except Error as rb_err: return f"回滚事务时出错: {rb_err}" return f"数据库错误: {e}" except Exception as ex: return f"执行查询时发生未知错误: {ex}" finally: if cursor: cursor.close() if connection and connection.is_connected(): connection.close() @mcp.tool() def list_tables() -> str: """获取当前数据库中所有表的列表。""" return execute_mysql_query(sql_query="SHOW TABLES;") @mcp.tool() def get_table_schema(table_name: str) -> str: """获取指定数据表的结构(列信息)。 Args: table_name: 需要查询结构的数据表名称。 """ if not table_name or not table_name.isidentifier(): return f"错误:无效的表名 '{table_name}'。" sql = f"DESCRIBE `{table_name}`;" return execute_mysql_query(sql_query=sql) if __name__ == "__main__": mcp.run()

这段代码里max_rows默认 100,防止模型查全表把上下文撑爆。dictionary=True让结果以字典返回,格式化时更直观。非 SELECT 语句会 commit,SELECT 不会。错误信息直接返回给模型,模型看到“表不存在”会自己调list_tables重试。

接下来是 MCP 客户端的配置。如果你用 Claude Code 或 Cline,它们有标准的 MCP 配置文件。以 Cline 为例,在cline_mcp_settings.json里加:

{ "mcpServers": { "mysql-query": { "command": "python", "args": ["/absolute/path/to/mysql_mcp_server.py"], "env": { "TAOTOKEN_API_KEY": "sk-你的密钥", "TAOTOKEN_BASE_URL": "https://taotoken.net/api" } } } }

如果你用 Codex,配置写在~/.codex/auth.json和config.toml里,三件套缺一不可:Base URL 填https://taotoken.net/api,Key 填你的 sk- 字符串,Model ID 填deepseek-chat。Cline 的 MCP 配置里如果同时要调模型和 MCP 服务,记得把模型凭证也放进env,否则客户端启动时会报local proxy failed。

4. 验证请求:从提问到返回结果的完整链路

配置写完后,先单独测 MCP 服务端能不能跑。在终端执行:

python mysql_mcp_server.py

如果没报错,说明服务端在等待 stdio 输入。更直观的验证是写一个最小客户端,直接调 DeepSeek 并处理工具调用。创建test_client.py:

import asyncio import json from openai import OpenAI client = OpenAI( api_key="sk-你的密钥", base_url="https://taotoken.net/api", ) TOOLS = [ { "type": "function", "function": { "name": "list_tables", "description": "获取当前数据库中所有表的列表", "parameters": {"type": "object", "properties": {}}, }, }, { "type": "function", "function": { "name": "get_table_schema", "description": "获取指定数据表的结构", "parameters": { "type": "object", "properties": { "table_name": {"type": "string", "description": "表名"} }, "required": ["table_name"], }, }, }, { "type": "function", "function": { "name": "execute_mysql_query", "description": "执行 SQL 查询并返回结果", "parameters": { "type": "object", "properties": { "sql_query": {"type": "string", "description": "SQL 语句"} }, "required": ["sql_query"], }, }, }, ] async def chat(prompt): messages = [{"role": "user", "content": prompt}] response = client.chat.completions.create( model="deepseek-chat", messages=messages, tools=TOOLS, tool_choice="auto", ) msg = response.choices[0].message if msg.tool_calls: for tc in msg.tool_calls: print(f"模型请求调用: {tc.function.name}") print(f"参数: {tc.function.arguments}") else: print(f"直接回复: {msg.content}") asyncio.run(chat("数据库里有哪些表?"))

运行后你会看到类似输出:

模型请求调用: list_tables 参数: {}

这说明 DeepSeek 正确识别了工具并生成了调用请求。接下来把工具执行结果回传,模型就能给出自然语言答案。完整链路是:用户提问 → DeepSeek 返回 tool_calls → 客户端执行 MCP 工具 → 结果作为 tool 角色消息回传 → DeepSeek 生成最终回复。如果模型连续调多个工具(比如先list_tables再get_table_schema再execute_mysql_query),客户端要用循环处理,直到模型不再返回 tool_calls。

实测一个多表查询场景:问“哪些客户购买了笔记本电脑,列出邮箱”。DeepSeek 会先调list_tables看到customers、orders、products,再调get_table_schema确认字段,最后写 JOIN 查询。整个过程不需要你手写一行 SQL。

5. 本篇常见错误排查:401、local proxy failed、reading choices

配置过程中最容易卡在几个报错上,我逐个说下排查思路。

401 Unauthorized:九成是 Key 的问题。先确认TAOTOKEN_API_KEY环境变量有没有生效,在 Python 里print(os.environ.get("TAOTOKEN_API_KEY"))看是不是 None。如果 Key 正确还报 401,检查 Base URL 是不是写成了https://taotoken.net/api/v1,多写的/v1会导致鉴权路径错位。另外 Key 如果被控制台禁用或额度耗尽也会 401,去 API Keys 页面(https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite)确认状态。

local proxy failed:这个报错通常出现在 Cline 或 Claude Code 启动 MCP 服务时。原因是客户端尝试用本地代理转发请求,但代理进程没起来或端口被占。排查方法:先确认mysql_mcp_server.py能独立运行不报错;再检查 MCP 配置里的command路径是不是绝对路径,相对路径在客户端工作目录下会找不到文件;最后看env里有没有把TAOTOKEN_BASE_URL传进去,缺了它客户端不知道往哪发请求。

Error reading choices / choices 字段为空:这个报错说明 API 返回体里没有choices数组,通常是模型名写错了。比如把deepseek-chat写成了deepseek,TaoToken 会返回错误结构。确认 Model ID 拼写,DeepSeek 系列在 TaoToken 上的标准名是deepseek-chat和deepseek-reasoner。如果用的是 Claude Code 做润色类任务,注意 Claude Code 的配置文件和 DeepSeek 不通用,需要单独在settings.json里指定 Anthropic 格式的 Base URL。

OAuth 相关报错:如果你在 Claude Code 里看到 OAuth token 失效,那是因为 Claude Code 默认走 Anthropic 官方鉴权。要切到 TaoToken,需要在 Claude Code 的配置文件里把ANTHROPIC_BASE_URL指向https://taotoken.net/api,同时把ANTHROPIC_API_KEY设成你的 sk- 密钥。ClaudeCodeAnthropic 的接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite)里有完整的 settings 片段,照着改就行。

工具调用死循环:模型反复调同一个工具不返回结果。原因是工具返回的错误信息不够明确,模型不知道下一步该干嘛。比如execute_mysql_query返回“数据库错误”但没说是表不存在还是语法错,模型就会重试。改进方法是把 MySQL 的原始错误信息完整返回,模型看到“Table 'shop_db.Product' doesn't exist”就会去调list_tables。

6. 把这条链路用起来:从查询到 Agent 的延伸

跑通基础查询后,你可以把 MCP 服务端挂到更复杂的 Agent 流程里。比如做一个“每日库存预警”脚本:定时用 DeepSeek 查低于阈值的商品,自动生成补货建议发到群里。这时候 MCP 服务端不用改,只需要在客户端侧加定时任务和消息推送。

如果你要长期跑编码类 Agent 任务,建议了解下 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite),它的额度模型更适合高频工具调用场景。模型对话页面(https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite)可以快速验证 DeepSeek 对复杂 SQL 的理解能力,接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite)里有 MCP 和各类客户端的完整配置示例。

最后提醒一个安全细节:MCP 服务端的数据库账号建议只给 SELECT 权限,除非你明确需要模型执行写操作。execute_mysql_query虽然能跑 INSERT/UPDATE,但生产环境最好在服务端加一层 SQL 白名单校验,只放行 SELECT 和 SHOW 类语句。本地开发图省事可以全开,上线前一定要收紧。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 6:06:19

Claude Code 完全使用指南:从入门到精通,把 settings 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 6:05:42

一份问卷,从“想问什么”开始变得清楚

晚上十点,研究生小林还盯着电脑屏幕。她想研究“大学生对线上学习平台的使用体验”,却迟迟没有开始。脑海里有很多想问的内容:使用频率、课程满意度、互动体验、学习效果、教师反馈……问题越想越多,问卷反而越没有形状。这正是许…

作者头像 李华