1. 为什么要在本地给 AI 模型接一个 SQL Server 的 MCP你可能遇到过这种场景数据库里有一张用户表、一张订单表想让 AI 帮你查「上周注册且下过单的用户有哪些」结果它只能凭你贴过去的表结构瞎猜字段名写出来的 SQL 跑一次报一次错。问题不在于模型不够聪明而在于它根本「看不见」你的库。MCPModel Context Protocol就是来解决这件事的。它是一套让 AI 客户端Cursor、Claude Desktop、Cherry Studio 等通过标准协议调用外部工具的规范。你写一个 MCP Server把「查 SQL Server」封装成一个 tool模型就能在对话里自己决定什么时候调用、传什么参数然后把真实查询结果拿回来继续推理。这篇要交付的是一个能直接跑的 FastMCP 服务端骨架覆盖 stdio 和 SSE 两种 IO 方式配合 uv 管理依赖目标是两天内从零到「AI 能实时查你的 SQL Server」。适合有 Python 基础、手上有 SQL Server 实例、想让本地 AI 编码助手接上业务库的开发者。核心检索词就三个FastMCP 怎么写、SQL Server 怎么连、两种 IO 怎么切。我试过用旧的mcp.server.Server写法装饰器和生命周期管理都比较绕换成FastMCP之后一个mcp.tool()就是一个工具代码量直接砍半。下面按「环境 → 骨架 → 配置 → 验证 → 排障」的顺序走。2. 前置准备uv 环境与 FastMCP 依赖清单2.1 用 uv 初始化项目uv 是目前 Python 依赖管理里启动最快的一个装完基本不用管虚拟环境。Windows PowerShell 下执行powershell -ExecutionPolicy ByPass -c irm https://astral.sh/uv/install.ps1 | iex装完确认版本然后建项目目录uv --version mkdir SqlserverMCP cd SqlserverMCP uv init . -p 3.13.5uv init会生成pyproject.toml和.python-version。这里有个坑我踩过如果你先用 PyCharm 之类的 IDE 打开了目录IDE 会自动创建一个.venv然后uv add时就会报error: failed to remove directory .venv: 拒绝访问。 (os error 5) error: Project virtual environment directory .venv cannot be used because it is not a compatible environment解决办法很简单关掉 IDE手动删掉.venv目录再重新uv add。uv 会自己重建一个干净的虚拟环境。2.2 依赖清单pyproject.toml里关键的就两块运行时依赖和构建配置。SQL Server 走 ODBC所以pyodbc必装MCP 用官方 SDK 的 FastMCP 入口。[project] name sqlserver-fastmcp version 1.0.0 description SQL Server FastMCP Server requires-python 3.10 dependencies [ mcp[cli]1.2.0, pyodbc5.0.0, ] [build-system] requires [hatchling] build-backend hatchling.build [tool.hatch.build.targets.wheel] packages [sqlserver_mcp]装依赖uv add mcp[cli] pyodbcmcp[cli]会带上mcp命令行工具后面调试用得上。pyodbc是连接 SQL Server 的驱动封装注意它依赖系统里已安装的 ODBC DriverWindows 上一般装的是ODBC Driver 17 for SQL Server或 18装完可以在「ODBC 数据源管理器」里确认。注意pyodbc是编译型包如果 uv 拉不到预编译 wheel会尝试本地编译需要 Visual C Build Tools。Windows 上通常能直接拿到 wheel遇到编译报错再补装 Build Tools。3. 可复制的 FastMCP 服务端骨架3.1 目录结构SqlserverMCP/ ├── pyproject.toml ├── sqlserver_mcp/ │ ├── __init__.py │ └── server.py └── .env3.2 核心 server.py下面这份代码把「连接配置」「查询工具」「两种 IO 启动」都放进去了可以直接复制改连接串。import os import logging import argparse import pyodbc from mcp.server.fastmcp import FastMCP logging.basicConfig(levellogging.INFO) logger logging.getLogger(sqlserver-mcp) mcp FastMCP(sqlserver-mcp) DB_CONFIG { server: os.getenv(DB_SERVER, localhost), database: os.getenv(DB_DATABASE, master), username: os.getenv(DB_USERNAME, sa), password: os.getenv(DB_PASSWORD, ), driver: os.getenv(DB_DRIVER, ODBC Driver 17 for SQL Server), } def get_connection(): conn_str ( fDRIVER{{{DB_CONFIG[driver]}}}; fSERVER{DB_CONFIG[server]}; fDATABASE{DB_CONFIG[database]}; fUID{DB_CONFIG[username]}; fPWD{DB_CONFIG[password]}; TrustServerCertificateyes; ) return pyodbc.connect(conn_str, timeout10) mcp.tool() def list_tables() - str: 列出当前数据库中的所有用户表 with get_connection() as conn: cursor conn.cursor() cursor.execute( SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPEBASE TABLE ORDER BY TABLE_NAME ) rows cursor.fetchall() return \n.join(f{r[0]}.{r[1]} for r in rows) or 无表 mcp.tool() def describe_table(table_name: str) - str: 查看指定表的字段结构table_name 支持 schema.table 或纯表名 if . in table_name: schema, name table_name.split(., 1) else: schema, name dbo, table_name with get_connection() as conn: cursor conn.cursor() cursor.execute( SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA? AND TABLE_NAME? ORDER BY ORDINAL_POSITION, schema, name, ) rows cursor.fetchall() if not rows: return f未找到表 {schema}.{name} return \n.join(f{c[0]} {c[1]} nullable{c[2]} for c in rows) mcp.tool() def run_query(sql: str, max_rows: int 100) - str: 执行只读 SELECT 查询返回前 max_rows 行结果 stripped sql.strip().lower() if not stripped.startswith(select): return 仅允许 SELECT 查询 with get_connection() as conn: cursor conn.cursor() cursor.execute(sql) cols [d[0] for d in cursor.description] rows cursor.fetchmany(max_rows) lines [ | .join(cols)] lines [ | .join(str(v) for v in row) for row in rows] return \n.join(lines) def parse_arguments(): parser argparse.ArgumentParser() parser.add_argument(--transport, defaultstdio, choices[stdio, sse, streamable-http]) parser.add_argument(--host, default127.0.0.1) parser.add_argument(--port, typeint, default3001) parser.add_argument(--log-level, defaultINFO) return parser.parse_args() def main(): args parse_arguments() logging.getLogger().setLevel(getattr(logging, args.log_level)) try: if args.transport stdio: logger.info(启动 stdio 模式) mcp.run() elif args.transport sse: logger.info(f启动 SSE 模式监听 {args.host}:{args.port}) mcp.run(transportsse, hostargs.host, portargs.port) else: logger.info(f启动 {args.transport} 模式监听 {args.host}:{args.port}) mcp.run(transportargs.transport, hostargs.host, portargs.port) except KeyboardInterrupt: logger.info(服务器已停止) if __name__ __main__: main()几个设计点说明一下。run_query里做了个SELECT前缀校验防止模型手滑生成DROPfetchmany(max_rows)限制返回行数避免一次拉几十万行把上下文撑爆TrustServerCertificateyes是本地自签证书场景下省事的做法生产环境建议换成正规证书。3.3 两种 IO 方式的差异维度stdioSSE通信方式标准输入输出HTTP 长连接启动命令uv run sqlserver-mcp.pypython sqlserver-mcp.py --transport sse客户端配置command argsurl调试便利度需借助 Inspector直接看服务端日志适用场景本地单机、Cursor/Claude Desktop远程共享、多客户端stdio 是「客户端拉起进程、通过管道对话」SSE 是「服务端常驻、客户端连 URL」。前者简单但不好观察后者适合调试和多人共用。4. 客户端配置Cursor 与 Claude 的 mcp.json4.1 stdio 配置Cursor 里随便建个文件夹打开创建.cursor/mcp.json内容{ mcpServers: { sqlserver-mcp-uv: { command: uv, type: stdio, isActive: true, description: sql server mcp 调用, args: [ --directory, C:\\Users\\Administrator\\PycharmProjects\\SqlserverMCP, run, sqlserver-mcp.py ], env: { DB_SERVER: localhost, DB_DATABASE: YourDB, DB_USERNAME: sa, DB_PASSWORD: your_password, DB_DRIVER: ODBC Driver 17 for SQL Server } } } }Claude Desktop 的配置在设置里格式和上面基本一致把这段贴进claude_desktop_config.json的mcpServers即可。Claude 的界面看不到工具列表但编码能力确实强配置对了就能用。4.2 SSE 配置先启动服务端python .\sqlserver-mcp.py --transport sse --port 3001看到启动 SSE 模式监听 127.0.0.1:3001就说明起来了。客户端配置改成 URL 形式{ mcpServers: { sqlserver-sse: { type: sse, url: http://localhost:3001/sse } } }这里有个高频错误URL 一定要带/sse后缀。只写http://localhost:3001会返回 404加上/sse才是 200 OK。如果客户端支持自定义 header可以再加一层鉴权{ sqlserver-sse: { type: sse, url: http://localhost:3001/sse, headers: { Content-Type: application/json, Authorization: Bearer your_token } } }注意Cursor 对 SSE 的支持在不同版本里表现不一致如果连不上先用 Cherry Studio 或 MCP Inspector 验证服务端本身没问题再回头调 Cursor 配置。5. 验证请求从 Inspector 到真实查询5.1 用 MCP Inspector 做协议级验证官方 Inspector 是最直接的调试工具不用装到项目里npx modelcontextprotocol/inspector python sqlserver-mcp.py它会起一个本地 Web 界面左边列出list_tables、describe_table、run_query三个工具点进去填参数就能调用。这一步能确认「服务端逻辑没问题」把协议层和客户端层的问题分开。5.2 在 Cursor 里跑真实查询配置生效后在 Cursor 对话里直接说「帮我查一下数据库里有哪些表」。模型会自己调用list_tables拿到结果后再决定下一步。接着问「用户表里最近注册的 10 个用户」它会先describe_table看字段再拼run_query。实测下来Cursor 的 MCP 调用比 Cherry Studio 主动得多。Cherry 经常需要你明确说「用 MCP 查」Cursor 基本能自己判断该不该调工具。如果模型没找到表多半是DB_DATABASE配错了库或者describe_table的 schema 默认值不对——代码里默认走dbo非 dbo 的表要显式传schema.table。5.3 一个进阶玩法如果你把存储过程、视图的定义也拉到一个本地文件夹再写个工具让模型搜索这些脚本它就能「先读代码理解业务逻辑再自动推断该查哪张表、怎么关联」。我试过让它分析一段存储过程后自动写出关联查询不需要你告诉它表名它会从脚本里的JOIN和WHERE反推。这个能力对复杂业务库特别有用。6. 本篇常见错误排查6.1 uv add 报「拒绝访问」error: failed to remove directory .venv: 拒绝访问。 (os error 5)原因IDE 占用了.venv目录。关掉 IDE删掉.venv重新uv add。6.2 pyodbc 报「Data source name not found」pyodbc.Error: (IM002, [IM002] [Microsoft][ODBC Driver Manager] Data source name not found)原因DB_DRIVER写的驱动名系统里没装。去「ODBC 数据源管理器 → 驱动程序」看实际名字常见的是ODBC Driver 17 for SQL Server或ODBC Driver 18 for SQL Server注意大小写和空格。6.3 SSE 连接返回 404原因URL 少了/sse。改成http://localhost:3001/sse。6.4 登录失败「Login failed for user sa」原因SQL Server 默认可能只开了 Windows 认证。需要在 SSMS 里把服务器属性改成「SQL Server 和 Windows 身份验证模式」并确认sa账号已启用、密码正确。另外 SQL Server 配置管理器里 TCP/IP 协议要启用端口默认 1433。6.5 模型不主动调用 MCP原因客户端差异。Cursor 判断力强Cherry Studio 偏保守。可以在提示词里明确「请使用 MCP 工具查询数据库」或者换客户端。另外确认mcp.json里isActive是true配置改完要重启客户端。6.6 stdio 模式下看不到日志原因stdio 把标准输出当协议通道了print会污染协议。所有日志走logging到 stderr或者干脆切 SSE 模式调试日志直接打在终端上。7. 把 MCP 接进你的日常编码流骨架跑通之后真正提升效率的是把它接进你每天用的工具链。如果你主要用 Cursor 写代码stdio 模式最省事配置一次就不用管如果团队里多人要共用同一个数据库查询入口SSE 模式更合适服务端跑在一台机器上大家连 URL 就行。想让模型能力更稳可以在 TaoToken 的模型对话里先验证提示词和工具调用逻辑确认模型能正确理解list_tables、describe_table、run_query的语义再落到 Cursor 里跑真实库。长期做编码和 Agent 的话Coding Plan 那条线更适合持续迭代把 MCP 工具和你的项目上下文绑在一起。接入文档里有完整的客户端配置示例和鉴权说明API Keys 页面可以拿到调用凭证。配置过程中如果卡在某个报错优先用 MCP Inspector 把服务端单独验一遍能省掉大量「到底是服务端还是客户端」的排查时间。
企业数字化 ERP 产品动态
相关推荐
minimaxH3可控运镜引擎:三维重建的高质量多视角数据生成方案 1. 这不是“又一个AI视频工具”,而是三维内容生产链的底层逻辑切换你有没有试过,用手机绕着一个咖啡杯拍360度视频,结果导出后发现——画面抖、光线跳、角度歪,根本没法喂给任何三维重建模型?我去年帮三个工业设计团队… · 2026/9/25 16:25:40
四个AI开源项目实战盘点:本地大模型、Agent框架、编程助手与嵌入式AI 1. 四个AI开源项目的整体盘点思路1.1 为什么挑这四个方向AI开源项目这两年属于井喷状态,GitHub上每天都有新仓库冒出来,但真正能落地、能跑通、能解决实际问题的其实不多。我平时有定期翻Trending和Awesome系列的习惯,踩过不少坑,… · 2026/9/25 16:25:40
Atlas 300V 24G加速卡部署YOLO完整实战指南 做了这么多年推理部署,说真的,最近被问得最多的一个词就是 Atlas,十个里有八个都是同一个问题:“atlas 300v 24g 是运算加速卡吗”,然后紧接着第二句就是“atlas部署yolo怎么搞”。这两个问题其实是同一件事的两面&… · 2026/9/25 16:25:34
ChatGPT failed to start报错 文章目录前言一、移动到C盘二、编辑环境变量1.下载文件总结前言
8月27日windows打开gpt后报错: ChatGPT failed to start. Unable to locate the Codex CLI binary. Set CODEX_CLI_PATH or ensure the Electron resources include bin/codex.
一、移动到C盘
第一… · 2026/9/25 16:24:57
Ghidra MCP 7.0.0 工具整合迁移指南:272→251工具的破坏性变更全解析 Ghidra MCP 7.0.0 工具整合迁移指南:272→251工具的破坏性变更全解析 【免费下载链接】ghidra-mcp Ghidra MCP Server — 200 MCP tools for AI-powered reverse engineering. GUI plugin headless server, lazy tool loading, convention enforcement, batch oper… · 2026/9/25 16:24:27
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37