ARTICLE DETAIL

资讯详情

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

MCP协议实战:用VSCode Copilot直接查询MySQL数据库

MCP协议实战:用VSCode Copilot直接查询MySQL数据库 刚看到 Copilot 能直接连数据库查数据时我第一反应是这不就是把 SQL 从“AI 生成”变成“AI 执行”吗但实际跑通以后我才意识到这背后真正的意义是 MCP 这个协议把 AI 助手和外部工具之间的链路彻底打通了。VSCode 里的 Copilot 不再只是给你补代码、写 SQL 的“纸面参谋”而是能真正拿着工具去 MySQL 里查结构、跑 SELECT、把结果带回来继续跟你讨论。这篇文章就把这件事从头到尾捋一遍MCP 是什么、为什么需要它、怎么在 VSCode 里配置 MySQL 的 MCP Server、权限和安全怎么设、以及我踩过的几个坑。哪怕你之前完全没接触过 MCP按着步骤走也能让 Copilot 帮你直接查库。1. 核心思路MCP 解决了 AI 查库的哪一环问题1.1 没有 MCP 时AI 写 SQL 的“最后一公里”有多难受先回想一下以前的常规操作。你让 Copilot 帮忙写一条 SQL它写得挺像样但接下来你得自己把这段 SQL 复制到命令行、Navicat、DBeaver 或者 Sequel Ace 里执行看到结果后再把结果截图或报错贴回聊天窗口让它继续分析。一次两次还行真查一张关联了七八张表的报表时这种来回切换能把人搞疯。问题不在于 Copilot 写 SQL 的能力而在于它没有“执行 SQL”的通道。写出来但看不到结果它就只能在猜测中反复调整。你拿到真实数据以后还得手动喂回给它这个“最后一公里”效率损耗非常大。MCP 就是来补这一环的。它允许 Copilot 这类 AI 助手在对话过程中直接调用一个“MySQL 工具”把 SQL 发过去、在数据库上执行、把结果集拿回模型上下文里。AI 看到真实数据后再决定下一步是继续查、换统计口径还是改代码整个推理链条是连续的。1.2 MCP 到底是软件协议还是硬件协议有人会把 MCP 和“MCP 协议”这个概念搞混。MCP 全称 Model Context Protocol模型上下文协议是地地道道的软件协议、应用层协议跟硬件接口没有关系。你可以把它理解成 AI 世界的“USB-C 接口”。USB-C 统一了设备之间的插拔接口标准MCP 统一的是 AI 客户端和外部能力提供方之间的调用方式。一个支持 MCP 的客户端可以在同一个协议框架下连接数据库、文件系统、浏览器、代码仓库、各种第三方 API而不是每个工具都单独做一套私有对接。MCP 架构里通常有四个角色MCP Client实际调度 AI 的客户端比如 VSCode、Cursor、Windsurf 这类集成开发环境里的插件。MCP Server提供具体能力的一方比如 MySQL Server、文件 Server、Git Server。ToolMCP Server 暴露给 AI 的具体能力类似函数。比如 list_tables、execute_sql。Model你真正对话的大模型。模型本身不直接碰工具它通过 Client 去请求 Server 执行工具再把结果拿回来。这层关系想清楚以后配置 MCP 的逻辑就顺了。你要做的不是“教 Copilot 连数据库”而是“让 VSCode 在启动 Copilot 会话时拉起一个 MySQL MCP Server 进程”剩下的交给协议去沟通。1.3 为什么不直接用 IDE 自带的数据库面板VSCode 的数据库插件也很多能看表、能跑 SQL但那是给人用的交互界面。MCP 解决的是模型怎么“用”数据库两者定位完全不同。打个比方数据库面板是一台带方向盘和仪表盘的汽车人是驾驶员MCP Server 是给自动驾驶系统留的 API 接口AI 是驾驶员。自动驾驶系统不可能伸出一只手去转方向盘它需要的是线控接口。MCP 就是这层接口。当然两者完全可以共存。我自己的使用习惯是数据库面板留着做人工巡检和改数据MCP 通道留给 AI 做只读查询和分析。互不冲突职责分开。2. 动手前的准备环境清单与方案选型2.1 需要准备哪些软件环境按最小可运行原则下面这些不是每一项都必须但至少满足其中一条配置路径VSCode建议用最新稳定版。MCP 支持在较新的版本里已经集成到 Copilot Chat 工作流中老版本可能没有入口。GitHub Copilot 扩展能正常打开 Copilot Chat 即可。MCP 是作为 Chat 的工具能力暴露的不是普通代码补全能力。MySQL建议 8.0 以上。MCP Server 通过 TCP 连接 MySQL所以不管 MySQL 装在哪台机器只要目标端口能被访问就行。Docker Desktop如果采用容器版 MCP Server 的话需要不装 Docker 也可以用 Python 自建。Python 3.10 和 uv / pip走自建 MCP Server 时需要后面第 5 节会写。这些准备动作没有特别复杂的地方大多数人电脑上已经有 VSCode 和 MySQL缺的就是 Docker 或 Python 环境。2.2 Docker 镜像版与 Python 自建版怎么选我见过两种主流方案实现方式上手难度推荐场景主要风险Docker 镜像 mcp/mysql低拉镜像跑容器就行快速验证、不想维护代码容器访问宿主机 MySQL 时网络配置容易踩坑镜像版本迭代也会变参数Python 自建 MCP Server中等需要写一点代码想控制暴露哪些 SQL、做白名单校验、二次开发需要自己维护依赖和启停逻辑我的建议很直接第一次尝试用 Docker 版跑通了再按需换自建。原因很简单Docker 版把 MCP Server 和 MySQL 驱动的依赖都封装好了你只需要配置连接参数自建版则能让你看清 MCP Server 的每个工具长什么样方便加上“只允许 SELECT”之类的防线。如果你在产品环境用我更推荐自建。因为生产环境里你大概率需要限制 AI 能查的表、能返回的行数以及把密码放在独立配置环境变量里。这些在 Docker 一键跑通版里不一定能优雅地实现。3. 完整实战配置让 Copilot 直接帮我查库3.1 第一步给 MCP 准备一个只读账号我强烈建议不要用 root 账号接 MCP哪怕只是本地测试。MCP 的调用权限来自账号权限账号是只读的AI 再怎么折腾也写不了数据。在 MySQL 里执行CREATE USER mcp_readonly% IDENTIFIED BY YourStrongPassword; GRANT SELECT ON myapp.* TO mcp_readonly%; FLUSH PRIVILEGES;这里解释两个细节mcp_readonly%表示允许从任意主机登录。方便起见可以这么建但如果你只想让本机连可以缩到mcp_readonlylocalhost。不过 Docker 容器访问宿主机 MySQL 时来源 IP 往往不是 127.0.0.1反而可能因为权限范围不对被拒绝所以本地测试用%更省心。GRANT SELECT ON myapp.*只给了 myapp 库的读权限。想把权限收得更紧比如只允许查 orders 表可以写GRANT SELECT ON myapp.orders TO ...。建好账号后先手工验证一下mysql -h 127.0.0.1 -P 3306 -u mcp_readonly -p -e SELECT 1能正常返回 1 就说明账号没问题。如果这步失败后面 MCP 配置再对也白搭。3.2 第二步用 Docker 启动 MySQL MCP Server账号准备好后先把 MCP Server 手动跑起来看看。命令行里运行docker run --rm -i \ -e MYSQL_HOSThost.docker.internal \ -e MYSQL_PORT3306 \ -e MYSQL_USERmcp_readonly \ -e MYSQL_PASSWORDYourStrongPassword \ -e MYSQL_DBmyapp \ mcp/mysql这条命令的几个关键点--rm容器退出后自动删除。MCP Server 本来就是一次会话拉起一个进程用完即走。-i保持标准输入打开这是 stdio 模式下必需的。注意不要加-t因为这不是给你在终端里交互用的它是等 VSCode 通过标准输入输出发 JSON-RPC 消息。MYSQL_HOSThost.docker.internal在 Docker Desktop for Mac / Windows 上容器里访问宿主机的地址是 host.docker.internal不是 127.0.0.1。很多人在这一步卡住原因就是容器里的 127.0.0.1 指向容器自己不是宿主机。不需要-p 3306:3306。MCP Server 自己不监听端口它通过标准输入输出和客户端通信不要把它当成数据库代理端口来映射。命令行跑起来以后你会发现进程一直挂着、没有任何输出。这是正常的它正在等待输入。如果 MySQL 地址、账号密码有问题通常几秒后会在终端里看到报错信息。3.3 第三步在 VSCode 里配置 MCP Server接下来把 MCP Server 注册到项目里。VSCode 支持在项目根目录创建.mcp.json文件来声明 MCP 服务器这种方式便于团队共用配置。我通常会这样做{ servers: { mysql: { type: stdio, command: docker, args: [ run, --rm, -i, -e, MYSQL_HOSThost.docker.internal, -e, MYSQL_PORT3306, -e, MYSQL_USERmcp_readonly, -e, MYSQL_PASSWORDYourStrongPassword, -e, MYSQL_DBmyapp, mcp/mysql ], env: {} } } }写完以后保存文件VSCode 会提示你是否信任并允许 MCP 服务器运行。点击允许之后在 Copilot Chat 面板的 MCP 工具图标里应该能看到 mysql 这个服务器以及它暴露的工具。这里有一个容易忽略的点如果 VSCode 启动 MCP Server 时找不到 docker 命令常见原因是桌面版 Docker 的终端命令路径和 VSCode 进程环境不一致。解决办法是把 command 改成 docker 的绝对路径比如/usr/local/bin/docker或C:\Program Files\Docker\Docker\resources\bin\docker.exe。路径正确以后MCP Server 就不会一直显示 connecting 了。3.4 第四步让 Copilot 真正执行一次查询配置完成后打开 Copilot Chat把对话模式切到 Agent 模式然后直接发指令。我第一次验证时用的是这样一句使用 mysql 工具先列出 myapp 库里的全部表然后统计 orders 表最近 30 天的订单数量按天分组返回。Copilot 解析完这句话后会调用 MCP Server 的工具。常见 MySQL MCP Server 会暴露 list_tables、describe_table、execute_sql 这几个工具。它会先列表接着生成 SQL 并执行最后把查询结果整理成表格返回。一次典型对话在底层大概是这样的模型决定调用 list_tables拿到表名列表。模型决定调用 execute_sql传入SELECT order_date, COUNT(*) FROM orders WHERE order_date DATE_SUB(CURDATE(), INTERVAL 30 DAY) GROUP BY order_date ORDER BY order_date。MySQL MCP Server 执行这条查询把结果 JSON 化后返回给模型。模型基于结果再用中文总结给你。如果 MCP Server 正常整个过程会在聊天面板里看到“正在执行工具”类似的提示并且结果会直接出现在对话流中。这里最爽的一点是AI 看到真实结果后如果觉得数据有问题会直接调整 SQL 再查一次不需要你手动去数据库里跑。4. 数据库授权与安全比跑通更重要的三件事4.1 给 AI 的账号要最小权限别心软MCP 通道本质上是一个“AI 可控的数据库客户端”。AI 模型不是恶意的但它的判断受到提示词、上下文、甚至外部注入内容影响。如果你给它一个 root 或业务超管账号那它一旦在工具调用上出现偏差可能性就不再是“不会发生”而是“只是时间问题”。我的底线做法是只授权 SELECT。只授权业务所需的库不给整个实例。只授权视图或表不给跨库查询。定期轮换密码因为密码会以明文形式出现在 .mcp.json 或环境变量里。如果担心 AI 需要用 UPDATE 来标记已处理数据那就换一个思路给 AI 的账号仍然只读真正需要写数据的操作走人工或者单独审批接口。不要让 AI 的动态 SQL 直接面对写权限。4.2 对敏感字段做“脱敏视图”而不是直接把用户表暴露给 AI数据库里的数据结构往往是业务全量可能包含手机号、身份证、邮箱、地址等敏感信息。你让 AI 直接查 user 表它能接触到完整数据。这不一定是你想要的。比较好的做法是在 MySQL 里建一批查询视图比如v_order_summary、v_user_basic把 email 字段处理成LEFT(email, 3) || ***这种脱敏形式然后只把视图的 SELECT 权限授给 mcp_readonly。这样 AI 的查询范围实际上是“你已经整理好的安全视图”而不是整个裸表。在权限模型层面你可以把 MCP 通道理解成一个“面向 AI 的只读数据接口”接口背后是什么数据面由你自己定。裸表、脱敏视图、汇总表都可以关键是你有意识地去设计这层边界。4.3 限制查询行数、超时时间和工具白名单AI 一句“查全部订单”可能会让数据库执行一次全表扫描如果表很大线上数据库很容易被慢查询拖垮。应对方式是在 MCP Server 或 SQL 执行层做几道闸设置返回行数上限比如最多 200 行。设置单条 SQL 执行超时比如 10 秒。在工具层只允许 SELECT并对 UPDATE、DELETE、DROP、TRUNCATE 这些关键字做拦截。在 MySQL 侧设置max_execution_time让超过阈值的查询直接中止不给慢查询留机会。这四条里行数限制和时间限制是最实用的。AI 的动态 SQL 质量再怎么好也扛不住数据库里几千万行的真实数据量没有保护措施就是给自己埋雷。5. 没有 Docker 的时候用 Python 自建一个最小 MCP Server5.1 环境初始化如果你不想依赖 Docker或者想把工具行为控制得更细可以自己写一个非常小的 MCP Server。依赖只需要两个mcp 和 pymysql。我用 uv 来管理项目uv init mcp-mysql-local cd mcp-mysql-local uv add mcp[cli] pymysql如果你更习惯 pip也可以python -m venv .venv source .venv/bin/activate pip install mcp[cli] pymysql然后新建一个.env文件把连接信息放进去MYSQL_HOSThost.docker.internal MYSQL_PORT3306 MYSQL_USERmcp_readonly MYSQL_PASSWORDYourStrongPassword MYSQL_DBmyapp5.2 核心代码只读查询工具写一个server.py提供两个关键函数一个是 list_tools 返回工具定义一个是 call_tool 处理执行。我这里以 mcp Python SDK 当前主版本的写法为例接口细节会随版本变化核心逻辑不变。import os import re import pymysql from mcp.server import Server, stdio_server server Server(mysql-helper) def get_connection(): return pymysql.connect( hostos.getenv(MYSQL_HOST, 127.0.0.1), portint(os.getenv(MYSQL_PORT, 3306)), useros.getenv(MYSQL_USER, mcp_readonly), passwordos.getenv(MYSQL_PASSWORD, ), databaseos.getenv(MYSQL_DB, myapp), charsetutf8mb4, cursorclasspymysql.cursors.DictCursor, ) server.list_tools() async def list_tools(): return [ { name: execute_select, description: 在 MySQL 上执行只读 SELECT 查询返回最多 50 行结果, inputSchema: { type: object, properties: { sql: {type: string, description: SQL 查询语句} }, required: [sql], }, } ] server.call_tool() async def call_tool(name: str, arguments: dict): if name ! execute_select: return {error: funknown tool: {name}} sql arguments.get(sql, ) sql sql.strip() if not re.match(r^select\b, sql, re.I): return {error: 只允许 SELECT 查询} lower_sql sql.lower() for keyword in [update, delete, drop, truncate, insert, alter]: if keyword in lower_sql: return {error: f检测到不允许的关键字: {keyword}} conn get_connection() try: with conn.cursor() as cur: cur.execute(sql) rows cur.fetchmany(50) return {rows: rows, row_count: len(rows)} finally: conn.close() async def main(): async with stdio_server() as (read, write): await server.run(read, write) if __name__ __main__: import asyncio asyncio.run(main())这段代码做了几件事只暴露一个 execute_select 工具。正则拦截非 SELECT 语句。返回结果最多 50 行。每次查询后主动关闭连接避免连接堆积。如果你用的 MCP Python SDK 接口比较新装饰器或 stdio_server 的用法可能略有调整以官方示例为准。这个版本的逻辑是通用的。5.3 把自建服务注册到 VSCode自建服务的.mcp.json要比 Docker 版稍微复杂一点主要问题是 command 需要用绝对路径。uv 的绝对路径可以用which uv查项目目录也要写绝对路径{ servers: { mysql-local: { type: stdio, command: /home/you/.local/bin/uv, args: [ run, --directory, /home/you/code/mcp-mysql-local, python, server.py ], env: { MYSQL_HOST: host.docker.internal, MYSQL_PORT: 3306, MYSQL_USER: mcp_readonly, MYSQL_PASSWORD: YourStrongPassword, MYSQL_DB: myapp } } } }存盘后重启 VSCode 窗口或者刷新 MCP 面板让自建服务跑起来。效果和 Docker 版一样但你能在代码里更灵活地加白名单、脱敏和日志。6. 常见问题排查与避坑实录6.1 我实际遇到过的七个问题和处理办法现象最可能的原因我的排查手法Copilot 聊天里看不到 MCP 工具没有开启 Agent 模式或 MCP 配置格式不对检查聊天面板的模式切换确认 .mcp.json 里的 servers 结构无误MCP Server 一直显示 connectingcommand 找不到可执行文件把 command 改成 docker 或 uv 的绝对路径再看输出面板日志容器里连不上宿主机 MySQLhost.docker.internal 没生效或 MySQL 只监听 127.0.0.1确认宿主机 MySQL bind-address 是否允许外部访问Windows/Mac 用 host.docker.internalLinux 可尝试 --network host报错 caching_sha2_passwordPython 驱动和 MySQL 8 默认认证插件不完全兼容安装 cryptography 并启用 pymysql 的 sha256 密码支持不要在生产环境随便降级认证插件查询结果乱码连接字符集不是 utf8mb4在连接参数里指定 charsetutf8mb4同时确认表和库的字符集密码里有特殊字符导致解析失败JSON 未转义或命令行没有引号包裹.mcp.json 里用 JSON 字符串转义命令行 docker run 时用单引号包住密码返回结果太多导致模型读不懂MCP Server 没有限制行数在工具实现里 fetchmany(50) 或加 LIMIT防止长结果撑爆上下文这里最有迷惑性的是第一个问题。我遇到过不少朋友配置完 MCP Server重启了半天VSCode 里也能看到 MySQL 服务器在线但 Copilot 就是不调用工具。后来发现是对话框还停留在普通模式而不是 Agent 模式。Copilot 只有在 Agent 模式下才会主动分析和调度 MCP 工具普通问答模式基本不会去碰外部工具。6.2 快速自检五步法配置卡住时按这个顺序查比乱试快得多手工在终端里跑一遍 docker run 命令确认 MCP Server 能正常连接数据库。检查 .mcp.json 里 server 的 name 是否唯一env 里是否有缺失变量。看 VSCode 输出面板里 MCP 相关的日志确认进程有没有启动成功。在 Copilot Chat 里切换到 Agent 模式确认工具列表已经出现。先从最简单的“列出所有表”开始问不要一上来就搞十表关联查询。6.3 还有几个容易忽略的细节.mcp.json如果包含密码别直接提交到公开仓库。要么用 VSCode 的变量替换能力要么把文件加入.gitignore否则密码就是裸奔状态。自建 Python 服务时如果 VSCode 启动进程后没有任何日志试着先在工作区终端里手动跑一次uv run python server.py看看是不是依赖或导入就报错了。不要把 MCP Server 当成常驻服务来跑。它应该是“客户端启动时拉起、会话结束时退出”的一个进程。如果你硬要把它部署成远程服务那就得考虑鉴权和传输加密复杂度会高不少。跑通这套配置以后我现在的日常姿势是在 Copilot 对话里直接说“看下最近七天订单量和退款率”AI 帮我查完数据库、把结果整理成表格再基于真实数据继续分析代码问题。这体验确实比复制粘贴 SQL 高出一大截。但我也想说一句实在话MCP 不是银弹。它最大的价值是给 AI 一个合规、可控、可审计的工具接口真正决定数据安全边界的仍然是账号权限、查询白名单和数据脱敏这些基本功。你把这些基本功做扎实MCP 才会成为得力的助手而不是一个开着 root 权限给 AI 随便折腾的后门。如果你想试建议从一台本地开发库开始只读账号配好选一张小表让 Copilot 先跑一次最简单的 SELECT。跑通以后再逐步扩大范围。我现在就是这个节奏稳得很。
返回列表