📌 新手提示:本文结尾提供了一键部署脚本(Windows / macOS / Linux 通用),不想手动逐条敲命令的同学,可以直接拉到文末下载运行,脚本会自动检测网络环境并选择最快的下载源。

引言

如果你用过 Claude Code,一定体验过它在你的项目里读代码、改文件、运行命令的丝滑感。但如果我问你:Claude Code 能不能查你公司内部的 MySQL 数据库?能不能调你团队内部的工单 API?能不能读你私有知识库里的文档?

答案是:能,只要你写一个 MCP Server。

MCP(Model Context Protocol,模型上下文协议) 是 Anthropic 于 2024 年底发布的开源标准,专门用来解决一个问题:AI 助手如何安全、标准化地接入外部数据源和工具。你可以把它理解成 AI 世界的"USB-C 接口"——不管后端是什么(数据库、API、文件系统、第三方服务),只要实现 MCP 协议,AI 就能即插即用。

MCP 协议架构示意图

上图展示了 MCP 的核心架构:Host(宿主进程,比如 Claude Code)通过 Client 与 Server 建立一对一的有状态连接,Server 则暴露 Resources(资源)、Tools(工具)、Prompts(提示词) 三种能力。

本教程会带你从零开始,用 Python 写一个真正能用的 MCP Server——先让它暴露一个简单的计算工具,再接上一个 SQLite 数据库和内部 API 调用,最后部署到云 Agent 沙箱里,让 Claude Code 在生产环境中安全地访问你的私有数据。

读完本文,你将掌握:

  • MCP 协议的核心概念:Host、Client、Server 三角色各干什么,为什么这样设计
  • 用 Python SDK 手写 MCP Server:从 15 行代码的玩具到能查数据库、调 API 的真实工具
  • 接入 Claude Code:配置 .mcp.json,让 AI 在你的项目里直接调用你的 Server
  • 部署到生产环境:用云 Agent 沙箱实现容器隔离、出站白名单、自动休眠

一、什么是 MCP——给 AI 装一个"万能接口"

1.1 先理解一个痛点

在没有 MCP 之前,如果你想让 AI 助手访问你的私有数据,你只有几条路:

  • 把数据贴进聊天框(贴得下吗?贴得完吗?每次都要贴吗?)
  • 写一个自定义插件(不同 AI 工具格式不同,写完 Claude Code 的还得写 ChatGPT 的,写完 ChatGPT 的还得写 Cursor 的)
  • 自己搭一个 API 网关(认证、鉴权、限流、格式转换……折腾一圈,最后发现每个 AI 工具的接口都不一样)

MCP 就是来解决这个碎片化问题的。 它定义了一套统一的协议,任何 AI 应用(称为 Host)只要支持 MCP,就能通过同一个接口接入任何实现了 MCP 的数据源或工具(称为 Server)。

1.2 一句话讲清楚 MCP 是什么

MCP = 连接 AI 应用与外部系统的开源标准协议。

类比:就像 USB-C 让同一根线能连手机、显示器、硬盘、键盘一样,MCP 让同一个接口能连数据库、API、文件系统、第三方服务。

官方列举了几个典型场景:

场景说明
个人 AI 助手AI 访问你的 Google Calendar、Notion,帮你安排日程、整理笔记
设计稿转代码Claude Code 拿 Figma 设计稿,直接生成整站 Web App
企业数据分析聊天框里用自然语言问"上季度华南区销售额 Top 10 是谁",AI 自动查数据库返回结果
3D 建模AI 在 Blender 里创建 3D 设计,再直接送 3D 打印

1.3 谁在支持 MCP

目前已有 Claude、ChatGPT、VS Code、Cursor、MCPJam 等主流 AI 工具和平台宣布支持 MCP。这意味着你写一个 MCP Server,可以在多个 AI 应用里复用——真正的"一次编写,到处运行"。

二、MCP 协议架构:三个角色一台戏

MCP 协议底层基于 JSON-RPC(一种用 JSON 格式进行远程过程调用的协议,可以理解为"用 JSON 格式发请求、收结果"),是一个有状态的会话协议。

整个架构由三个角色组成:

2.1 Host(宿主进程)

Host 是"大管家"角色,负责:

  • 创建并管理多个 Client 实例
  • 控制每个 Client 的连接权限和生命周期
  • 强制执行安全策略(比如用户确认后才能访问敏感数据)
  • 协调 AI 模型(LLM)与各个 Server 之间的交互

在 Claude Code 里,Claude Code 本身就是一个 Host。 当你输入"帮我查一下数据库里昨天的订单"时,Claude Code(Host)会判断应该调用哪个 MCP Server 的哪个工具,然后把结果拿回来继续推理。

2.2 Client(客户端)

Client 由 Host 创建,与一个 Server 维持 1 对 1 的隔离连接。它的职责是:

  • 建立有状态会话(session)
  • 与 Server 协商能力(capability exchange)——“你能做什么?你有什么工具?”
  • 双向路由协议消息
  • 维护 Server 之间的安全边界

简单理解:Client 就是 Host 和 Server 之间的"专属电话线"。Host 可以同时打多个电话(连接多个 Server),但每个电话只连一个 Server。

2.3 Server(服务器)

Server 是真正干活的人,通过 MCP 定义的三种 Primitives(原语,即基本能力单元) 暴露功能:

Primitive作用示例
Resources(资源)暴露只读数据,类似文件路径db://schema(数据库表结构)、docs://readme(文档内容)
Tools(工具)暴露可执行操作,AI 可以调用并获取结果sql_query(sql)(执行 SQL)、create_ticket(title)(创建工单)
Prompts(提示词)暴露预定义的提示词模板,帮助 AI 更好地使用你的工具"分析这张表的最佳实践"提示词

Server 还有一个特殊能力:反向请求 Sampling。意思是 Server 可以反过来请求 Host 的 AI 模型帮它生成内容——比如 Server 在处理一个复杂查询时,可以让 AI 先生成一段 SQL,再执行。

2.4 设计原则

MCP 官方明确了四条设计原则:

  1. Server 应该极其容易构建——这是 MCP 最核心的理念。后面你会看到,15 行 Python 代码就能写完一个 Server。
  2. Host 负责复杂的编排——把难的事交给平台,简单的事留给开发者。
  3. Server 专注特定、明确定义的能力——一个 Server 只做一件事,做好。
  4. 简单至上——能用简单方式解决的问题,绝不搞复杂。

三、环境准备:搭好开发台

在开始写代码之前,先把开发环境搭好。本章每一步都提供国内和海外两条路径,确保你在任何网络环境下都能跑通。

3.1 前置要求

要求最低版本检查命令
Python3.10 及以上python3 --version
uv(推荐)或 pip最新版uv --versionpip --version

Python 是一门编程语言,本教程用它来写 MCP Server。uv 是一个超快的 Python 包管理工具(可以理解成"pip 的 Pro Max 版"),官方推荐用来管理 MCP 项目,但 pip 也完全能用。

3.2 安装 Python(如果还没有)

海外用户:直接去 python.org 下载安装。

国内用户:推荐使用华为云镜像(速度更快):

# macOS / Linux
# 海外用户直连 python.org,国内用户用华为云镜像
# 以下以 Ubuntu/Debian 为例,其他系统类似
sudo apt update && sudo apt install python3 python3-pip -y

如果系统没有 apt,也可以直接下载安装包:

3.3 安装 uv(推荐)

uv 是官方推荐的 MCP 项目管理工具,安装只需一条命令:

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows PowerShell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

如果上述命令因网络问题失败,可以用 pip 替代:pip install uv。国内用户可加清华镜像:pip install uv -i https://pypi.tuna.tsinghua.edu.cn/simple

3.4 创建项目目录

mkdir mcp-server-demo && cd mcp-server-demo

如果是用 uv 管理项目,初始化一个项目:

uv init

3.5 安装 MCP Python SDK

# 推荐方式(uv,带 mcp CLI 工具)
uv add "mcp[cli]"

# 或 pip 方式(国内用户加清华镜像加速)
pip install "mcp[cli]" -i https://pypi.tuna.tsinghua.edu.cn/simple

说明:[cli] 是 SDK 的可选扩展,安装后你会获得 mcp devmcp runmcp install 等命令行工具——这些工具后面会频繁用到。不加 [cli] 只安装核心库,命令行工具不可用。

关于版本:当前 Python SDK 主分支是 v2(2026 年 7 月重大重构,支持最新 MCP 规范),pip install mcp 默认安装的就是 v2.x。如果你之前用过 v1,注意 v1 和 v2 的 API 有变化,迁移指南见官方文档(海外:https://py.sdk.modelcontextprotocol.io/migration/,国内可用 ghfast.top 镜像访问 GitHub 仓库)。

四、15 行代码写一个 MCP Server

现在进入正题。下面是 MCP 官方文档里的入门示例——一个完整的、能跑的 MCP Server:

# server.py
from mcp.server import MCPServer

# 创建一个 MCP Server 实例,名字叫 "Demo"
mcp = MCPServer("Demo")


@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"

是的,就这么多。15 行代码,包含两个功能。

4.1 逐行解释

第 1 行 from mcp.server import MCPServer 从 MCP 的 Python SDK 里导入 MCPServer 类。这个类就是 MCP Server 的"骨架"。

第 4 行 mcp = MCPServer("Demo") 创建一个 MCP Server 实例,名字叫 "Demo"。这个名字会在 MCP Inspector 和 Claude Code 里显示,方便你识别。

第 6-8 行 @mcp.tool() 装饰器 这是关键。@mcp.tool() 是一个装饰器(Decorator,Python 的一种语法,可以理解为"给函数贴标签")。贴上 @mcp.tool() 标签后,这个函数就变成了一个 MCP Tool(工具)——AI 可以调用它,传入参数,拿到返回值。

第 7 行 def add(a: int, b: int) -> int: 一个普通的 Python 函数,接收两个整数参数 ab,返回它们的和。重点:你不需要手写 JSON Schema,不需要手写请求解析,不需要手写协议处理。 a: int, b: int 这两个类型注解(Type Annotation,告诉 Python 参数是什么类型)会被 SDK 自动转为 JSON Schema,AI 就能"看懂"这个工具需要什么参数。

第 11-12 行 @mcp.resource("greeting://{name}") 这是另一种 MCP 能力:Resource(资源)。与 Tool 不同,Resource 是只读的,类似一个文件路径。"greeting://{name}" 定义了一个 URI 模板,{name} 是占位符——访问 greeting://Alice 会返回 "Hello, Alice!"

4.2 为什么这个设计好

对比一下没有 MCP SDK 时你需要写什么:

  • 手写 JSON-RPC 协议解析(几十行)
  • 手写 JSON Schema 定义(每个参数的 type、description、required 都要手写)
  • 手写请求路由(哪个方法对应哪个函数)
  • 手写错误处理
  • 手写 transport 层(stdio / HTTP / SSE)

而现在,两个类型注解函数 + 一个 docstring = 一个完整的 MCP Server。你只需要关注业务逻辑,其余全部由 SDK 处理。

五、用 MCP Inspector 测试你的 Server

写完代码后,不要急着接入 Claude Code——先用 MCP 官方提供的 MCP Inspector(检查器)测试。Inspector 是一个图形化的 MCP 调试工具,让你在浏览器里直接测试 Server 的每个工具和资源。

5.1 启动 Inspector

server.py 所在目录执行:

uv run mcp dev server.py

如果你用的是 pip 而不是 uv,可以这样:mcp dev server.py(前提是 pip 安装时带了 [cli] 扩展)。

命令执行后,终端会输出类似这样的信息:

MCP Inspector is running on http://localhost:5173

5.2 在浏览器里测试

打开浏览器访问 http://localhost:5173,你会看到一个类似 Postman 的调试界面:

  1. 左侧面板列出了你的 Server 暴露的所有 Tools 和 Resources
  2. 点击 add,在输入框里填入 a=1, b=2,点击"Call Tool"
  3. 右侧面板会显示返回结果:{"result": 3}
  4. 再试试 greeting Resource,输入 name=Alice,返回 "Hello, Alice!"

如果一切正常,恭喜你——你的第一个 MCP Server 已经跑通了!

5.3 常见启动失败排查

问题原因解决
command not found: uvuv 未安装或不在 PATH 中重新安装 uv(见第 3.3 节),或关闭终端重开
command not found: mcp未安装 [cli] 扩展重新执行 pip install "mcp[cli]"
ModuleNotFoundError: No module named 'mcp'未安装 MCP SDK执行 uv add "mcp[cli]"pip install "mcp[cli]"
Python version not supportedPython 版本低于 3.10升级 Python 到 3.10 或以上
端口 5173 被占用其他程序占用了 Inspector 端口关闭占用端口的程序,或 MCP 会自动尝试其他端口

六、接入 Claude Code:让 AI 真正调用你的工具

MCP Inspector 测试通过后,下一步就是把 Server 接入 Claude Code。这里需要做一些配置。

6.1 Claude Code 的 MCP 配置文件

Claude Code 通过一个 JSON 配置文件来管理 MCP Server。配置文件的位置有两种:

  • 项目级配置(推荐):在项目根目录创建 .mcp.json,只对当前项目生效
  • 用户级配置~/.claude/mcp.json(Linux/macOS)或 %USERPROFILE%\.claude\mcp.json(Windows),对所有项目生效

用项目级配置,在 mcp-server-demo 目录下创建 .mcp.json

{
  "mcpServers": {
    "demo": {
      "command": "uv",
      "args": ["run", "mcp", "run", "server.py", "--transport", "stdio"]
    }
  }
}

解释:command 是启动 Server 的命令,args 是命令参数。这里用的是 stdio transport(标准输入输出传输),Server 通过标准输入输出与 Claude Code 通信——这是本地开发最常用的方式。--transport stdio 告诉 MCP 用标准输入输出方式通信(而不是 HTTP 网络通信)。

如果你用的是 pip 而不是 uv,配置改成:

{
  "mcpServers": {
    "demo": {
      "command": "python3",
      "args": ["-m", "mcp", "run", "server.py", "--transport", "stdio"]
    }
  }
}

6.2 启动 Claude Code 并测试

在项目目录下启动 Claude Code:

claude

进入会话后,输入:

请帮我用 add 工具计算 123 + 456

如果一切正常,Claude Code 会调用你刚才写的 add 工具,返回 579。你还可以试试:

请用 greeting 资源问候一下 Alice

Claude Code 会调用 greeting Resource,返回 "Hello, Alice!"

到这里,你已经完成了"从零写一个 MCP Server 并接入 Claude Code"的全流程。工具虽然简单,但整个链路已经打通——接下来我们把能力升级到真实场景。

6.3 关于 Claude Code 的 API 访问

要让 Claude Code 跑起来,你需要一个能调用 Claude 模型的 API Key。官方 API 需要海外信用卡,且对非支持地区用户有封号风险。国内用户推荐使用 云间 APIhttps://cloudzone-api.cyou/)——一个稳定的 AI API 中转服务,原生支持 Anthropic 兼容接口,一键配置:

export ANTHROPIC_API_KEY="你的云间API-Key"
export ANTHROPIC_BASE_URL="https://cloudzone-api.cyou/v1"

云间 API 的 CC MAX 分组提供 Claude Opus / Sonnet / Haiku 全系列,折扣低至官方 0.5x,21 个模型可选,香港节点直连延迟极低,特别适合国内开发者日常使用。

七、实战:写一个能查数据库的 MCP Server

现在来真的。我们要写一个 MCP Server,包含两个真实功能:

  1. SQL 查询工具:让 Claude Code 能查本地的 SQLite 数据库
  2. 内部 API 调用工具:让 Claude Code 能调你公司内部的 HTTP API

7.1 准备测试数据

先创建一个简单的 SQLite 数据库作为示例:

# init_db.py
import sqlite3

conn = sqlite3.connect("company.db")
cursor = conn.cursor()

# 创建员工表
cursor.execute("""
CREATE TABLE IF NOT EXISTS employees (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    department TEXT NOT NULL,
    salary INTEGER NOT NULL
)
""")

# 插入几条测试数据
employees = [
    (1, "张三", "技术部", 25000),
    (2, "李四", "市场部", 18000),
    (3, "王五", "技术部", 30000),
    (4, "赵六", "人事部", 15000),
    (5, "钱七", "市场部", 22000),
]
cursor.executemany("INSERT OR REPLACE INTO employees VALUES (?, ?, ?, ?)", employees)
conn.commit()
conn.close()

print("数据库初始化完成:company.db")

运行:

python3 init_db.py

7.2 完整的 MCP Server 代码

# mcp_company_server.py
import sqlite3
import httpx
from mcp.server import MCPServer

mcp = MCPServer("Company Data Server")


# ========== Tool 1: SQL 查询工具 ==========
@mcp.tool()
def sql_query(sql: str) -> str:
    """Execute a SQL query on the company SQLite database.
    Use this to query employee information, department stats, etc.
    Only SELECT queries are allowed for safety.
    """
    # 安全检查:只允许 SELECT 语句
    sql_stripped = sql.strip().upper()
    if not sql_stripped.startswith("SELECT"):
        return "Error: Only SELECT queries are allowed for safety."

    try:
        conn = sqlite3.connect("company.db")
        conn.row_factory = sqlite3.Row  # 让结果可以用列名访问
        cursor = conn.cursor()
        cursor.execute(sql)
        rows = cursor.fetchall()
        conn.close()

        if not rows:
            return "Query returned no results."

        # 格式化为易读的文本
        columns = [desc[0] for desc in cursor.description]
        result_lines = [" | ".join(columns)]
        result_lines.append("-" * len(result_lines[0]))
        for row in rows:
            result_lines.append(" | ".join(str(row[col]) for col in columns))

        return "\n".join(result_lines)
    except Exception as e:
        return f"Query error: {str(e)}"


# ========== Tool 2: 内部 API 调用工具 ==========
@mcp.tool()
async def call_internal_api(
    endpoint: str,
    method: str = "GET",
    body: str = "",
) -> str:
    """Call an internal company API endpoint.
    endpoint: API path, e.g. '/api/v1/orders/today'
    method: HTTP method, 'GET' or 'POST'
    body: JSON body for POST requests
    """
    BASE_URL = "https://api.internal-company.com"

    async with httpx.AsyncClient(timeout=10.0) as client:
        try:
            if method.upper() == "GET":
                response = await client.get(f"{BASE_URL}{endpoint}")
            elif method.upper() == "POST":
                response = await client.post(
                    f"{BASE_URL}{endpoint}",
                    content=body,
                    headers={"Content-Type": "application/json"},
                )
            else:
                return f"Error: Unsupported method '{method}'. Use GET or POST."

            return f"Status: {response.status_code}\n{response.text[:2000]}"
        except Exception as e:
            return f"API call failed: {str(e)}"


# ========== Resource: 数据库结构 ==========
@mcp.resource("db://schema")
def get_db_schema() -> str:
    """Return the database schema so AI can understand available tables."""
    conn = sqlite3.connect("company.db")
    cursor = conn.cursor()
    cursor.execute(
        "SELECT sql FROM sqlite_master WHERE type='table' AND name='employees'"
    )
    row = cursor.fetchone()
    conn.close()

    if row:
        return f"Table: employees\n{row[0]}"
    return "No table found. Run init_db.py first."

7.3 代码解释

sql_query 工具

  • 接收一个 SQL 字符串参数
  • 安全检查:只允许 SELECT 语句,防止 AI 误删数据(DELETEDROP 等一律拒绝)
  • 使用 sqlite3.Row 让查询结果可以用列名访问,格式化输出为表格文本
  • 返回给 AI 的文本会直接显示在 Claude Code 的对话中

call_internal_api 工具

  • 接收三个参数:endpoint(API 路径)、method(GET/POST)、body(请求体)
  • 使用 httpx(一个支持异步的 HTTP 客户端库,比 requests 快)发送请求
  • 注意这里是 async def——因为 HTTP 请求是 I/O 操作,用异步可以避免阻塞
  • 返回 HTTP 状态码和响应内容(最多 2000 字符,避免超长响应)

db://schema Resource

  • 只读资源,返回数据库表结构
  • 命名用 db:// 前缀,表示这是一个数据库相关的资源
  • AI 在查询数据之前,可以先读这个 Resource 了解表结构,然后构造正确的 SQL

7.4 安装依赖

# uv 方式
uv add httpx

# pip 方式(国内用户加清华镜像)
pip install httpx -i https://pypi.tuna.tsinghua.edu.cn/simple

7.5 测试

用 MCP Inspector 测试:

uv run mcp dev mcp_company_server.py

在 Inspector 里测试 sql_query 工具,输入:

SELECT * FROM employees WHERE department = '技术部'

应该返回:

id | name | department | salary
------------------------------
1  | 张三 | 技术部     | 25000
3  | 王五 | 技术部     | 30000

7.6 接入 Claude Code

更新 .mcp.json 配置:

{
  "mcpServers": {
    "company-data": {
      "command": "uv",
      "args": ["run", "mcp", "run", "mcp_company_server.py", "--transport", "stdio"]
    }
  }
}

重启 Claude Code,然后试试这些问题:

  • “技术部的平均薪资是多少?”
  • “查一下公司所有员工,按薪资从高到低排列”
  • “市场部有几个人?”

Claude Code 会自动调用你的 sql_query 工具,执行 SQL,然后把结果翻译成自然语言回答你。

这就是 MCP 的真正威力:AI 不需要知道数据库在哪、怎么连——它只需要知道"有一个工具叫 sql_query,可以执行 SQL 查询"。剩下的全部由你的 Server 处理。

八、部署到生产环境:CZ 云 Agent 沙箱

开发时用 mcp dev 和 stdio transport 很方便,但生产环境有几个问题要解决:

  1. Server 需要持续运行,不能依赖你的本地终端
  2. 安全隔离:Server 可能访问敏感数据,必须和你的本地环境隔离
  3. 网络访问控制:Server 只能访问白名单里的外部服务,不能随意出站
  4. 资源管控:CPU、内存、磁盘需要配额限制

这些问题可以通过 云 Agent 沙箱 来解决。云间 API 平台(https://cloudzone-api.cyou/)提供了一个"云 Agent"功能——一个一键启动的独立容器环境,内置 PicoClaw(轻量级 AI Agent 运行时),支持对话、工具调用与多步骤工作流,你只需要把 MCP Server 代码放进去,就能获得一个生产级的运行环境。

8.1 云 Agent 沙箱的核心能力

特性说明
独立容器每个 Agent 沙箱是独立的容器实例,数据完全隔离,他人无法访问你的工作区
出站白名单严格限制出站网络访问,只能连接你指定的外部服务,防止数据泄露
资源配额CPU、内存、磁盘有上限,防止异常消耗
闲置自动暂停一段时间不用后自动暂停,保留期内可恢复,到期自动清理
独立访问密码专属 WebUI 带独立密码保护
内置 PicoClaw支持对话、工具调用与多步骤工作流,无需额外配置

8.2 部署步骤

第一步:在云间 API 面板启动云 Agent

登录 https://cloudzone-api.cyou/,进入「云 Agent」页面,点击启动。约 1 分钟就绪,系统会分配一个专属 WebUI 地址和访问密码。

第二步:上传 MCP Server 代码

通过云 Agent 的 WebUI 或 SSH 终端,将 mcp_company_server.pyinit_db.py 上传到沙箱内。你也可以直接在沙箱终端里 git clone 你的代码仓库。

第三步:安装依赖

pip install "mcp[cli]" httpx -i https://pypi.tuna.tsinghua.edu.cn/simple
python3 init_db.py

第四步:以 Streamable HTTP 模式启动 Server

生产环境不用 stdio transport,改用 Streamable HTTP(一种基于 HTTP 长连接的传输方式,支持服务端主动推送数据):

mcp run mcp_company_server.py --transport streamable-http --port 8000

第五步:配置出站白名单

在云 Agent 面板的安全设置里,添加你需要访问的外部服务白名单(比如 api.internal-company.com),确保 Server 只能访问你指定的服务。

第六步:连接 Claude Code

在 Claude Code 的 .mcp.json 中改用 HTTP 连接:

{
  "mcpServers": {
    "company-data": {
      "url": "https://your-agent.cloudzone-api.cyou/mcp",
      "transport": "streamable-http"
    }
  }
}

注意:url 替换为云 Agent 分配给你的实际地址。transport 设为 streamable-http 表示通过 HTTP 协议通信。

8.3 生产环境 vs 开发环境对比

维度开发环境(stdio)生产环境(云 Agent + HTTP)
通信方式标准输入输出(本地进程通信)HTTP(网络通信)
启动方式Claude Code 自动启动子进程独立运行,持续监听端口
隔离性与本地环境共享文件系统独立容器,完全隔离
网络控制无限制出站白名单
可用性依赖本地终端7x24 持续运行
资源管理无限制CPU/内存/磁盘配额

九、常见问题

Q1:MCP 和 Function Calling 有什么区别?

Function Calling(函数调用)是单个 AI 模型层面的能力——模型在回复中告诉调用方"我想调用这个函数,参数是这些"。但 Function Calling 不定义传输协议、不定义生命周期管理、不定义安全模型。

MCP 是一套完整的协议栈,定义了从传输层(stdio/HTTP/SSE)到能力层(Tools/Resources/Prompts)再到安全层(Host 授权、沙箱隔离)的全部规范。Function Calling 更像是 MCP 内部的一个子机制。

Q2:我的 Server 能同时接 Claude Code 和 ChatGPT 吗?

能。MCP 是标准协议,只要 AI 应用支持 MCP Host 角色,就能接入你的 Server。目前 Claude Code、ChatGPT、Cursor、VS Code 等都已支持。

Q3:Server 需要处理并发请求吗?

取决于你的 transport 选择:

  • stdio:单进程通信,天然串行,不需要处理并发
  • Streamable HTTP / SSE:可能同时有多个 Client 连接,需要确保代码是线程安全的。mcp run 命令默认会处理基本并发,但如果你的工具代码里用了全局变量或共享状态,需要自己加锁

Q4:如何保护敏感数据(比如数据库密码)?

不要在代码里硬编码密码。 推荐使用环境变量:

import os

DB_PASSWORD = os.environ.get("DB_PASSWORD", "")
if not DB_PASSWORD:
    raise RuntimeError("DB_PASSWORD environment variable not set")

在 Claude Code 的 .mcp.json 配置中传入环境变量:

{
  "mcpServers": {
    "company-data": {
      "command": "uv",
      "args": ["run", "mcp", "run", "mcp_company_server.py", "--transport", "stdio"],
      "env": {
        "DB_PASSWORD": "your-secret-password"
      }
    }
  }
}

Q5:pip install mcp 超时怎么办?

国内用户使用清华镜像:

pip install "mcp[cli]" httpx -i https://pypi.tuna.tsinghua.edu.cn/simple

如果清华镜像也超时,可以换阿里云镜像:

pip install "mcp[cli]" httpx -i https://mirrors.aliyun.com/pypi/simple

Q6:uv run mcp dev server.py 报错找不到模块?

确认你在 server.py 所在目录执行命令。如果用的是 pip 安装的 mcp,用 mcp dev server.py 而不是 uv run mcp dev server.py

Q7:MCP 支持哪些编程语言?

官方 SDK 目前支持 Python 和 TypeScript/JavaScript。社区也有 Go、Rust、Java、Kotlin、C# 等语言的实现。本教程使用 Python 是因为它上手最快、门槛最低。

十、总结

到这里,你已经从零开始,完整走通了 MCP Server 的开发链路:

  1. 理解了 MCP 协议:Host-Client-Server 三元组架构,基于 JSON-RPC 的有状态会话协议
  2. 用 Python SDK 写了 Server:从 15 行的玩具到能查数据库、调 API 的真实工具
  3. 接入 Claude Code:配置 .mcp.json,让 AI 在你的项目里直接调用你的工具
  4. 部署到生产环境:云 Agent 沙箱提供容器隔离、出站白名单、自动休眠

MCP 的意义在于,它把"AI 接入企业私有数据"这件事从"需要一个团队做半年"变成了"一个开发者一个下午就能搞定"。你不需要理解复杂的协议细节,不需要自己写 JSON-RPC 解析器,不需要操心传输层——Python SDK 帮你做了所有脏活累活,你只需要写好业务逻辑。

当然,这一切的前提是有一个稳定、低价的 API 入口来驱动 Claude Code。如果你还在为官方 API 的高昂费用和封号风险头疼,不妨试试 云间 APIhttps://cloudzone-api.cyou/)——它提供 GPT 低至 0.05x、DeepSeek 特惠 0.3x、Claude 全系列 0.5x 起的折扣价格,覆盖 90+ 模型,香港核心节点国模延迟低至 30ms,原生支持 Anthropic 和 OpenAI 兼容接口,替换 base_url 即可接入。更有云 Agent 沙箱一键部署,让你的 MCP Server 在生产环境中安全、稳定地运行。

现在就动手吧。 打开终端,创建一个 Python 文件,敲下 @mcp.tool(),然后把你的第一个 MCP Server 接入 Claude Code。你会发现,AI 不再只是聊天工具——它变成了你数据和业务的真正入口。

一键部署脚本

如果你觉得手动配置太繁琐,我们准备了一键部署脚本。脚本会自动完成:检测网络环境 → 安装 Python 依赖 → 初始化示例数据库 → 启动 MCP Server,全程引导式交互,国内国外网络都能用。

下载

平台脚本文件
macOS / Linux / WSLsetup-mcp-demo.sh
Windowssetup-mcp-demo.ps1

不方便下载的同学,可以直接复制文末的完整源码,新建文本文档粘贴后改后缀为 .sh.ps1 运行。

使用说明

macOS / Linux / WSL:

chmod +x setup-mcp-demo.sh
./setup-mcp-demo.sh

Windows:

Windows 默认会阻止运行未签名的 PowerShell 脚本(这是 Windows 的安全策略,不是杀毒软件拦截)。在 PowerShell 中执行以下命令临时放行当前会话的执行策略,再运行脚本:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
.\setup-mcp-demo.ps1

🔒 关于"为什么要放行执行策略":Windows 出于安全考虑,默认禁止运行未经数字签名(我们没有购买代码签名证书)的 .ps1 脚本。-Scope Process 表示仅在当前 PowerShell 窗口生效,关闭窗口后自动恢复原策略,不会永久改变你系统的安全设置。如果你仍不放心,可以先把脚本完整源码复制给任意 AI(包括 Claude、ChatGPT 等),让它帮你判断脚本是否安全,再决定是否运行。这就是我们公开全部源码的原因。

脚本完整源码

macOS / Linux / WSL 版(setup-mcp-demo.sh)


#!/usr/bin/env bash
# ============================================================
#  MCP Server 开发实战 一键脚本(macOS / Linux / WSL)
#  公开源码,欢迎审查 —— 不放心可先复制给 AI 判断
#  默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
#  功能:检测网络 → 装 Python 依赖(uv) → 生成示例 server.py → 启动 MCP Inspector
# ============================================================

set -u

CLOUDZONE_URL="https://cloudzone-api.cyou"
CLOUDZONE_API_BASE="https://cloudzone-api.cyou/v1"

GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
info()  { echo -e "${GREEN}[INFO]${NC} $1"; }
warn()  { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
step()  { echo -e "${CYAN}[STEP]${NC} $1"; }
fail()  { error "$1"; error "脚本无法继续。请把以上报错复制给 AI 或贴到 issue 求助。"; exit 1; }

# ---------- 第 0 步:检测网络环境(国内 / 国外)----------
detect_network() {
  step "检测网络环境(国内 / 国外)..."
  if curl -fsI --max-time 6 "https://pypi.org" >/dev/null 2>&1; then
    info "可直连 pypi.org,判定为海外网络"
    echo "overseas"
  else
    warn "无法直连 pypi.org,判定为国内网络环境,将使用清华/阿里 PyPI 镜像"
    echo "domestic"
  fi
}

# ---------- 第 1 步:检查 Python ≥ 3.10 ----------
check_python() {
  step "检查 Python 环境(需 3.10+)..."
  if ! command -v python3 >/dev/null 2>&1; then
    warn "未检测到 python3。请先安装 Python 3.10+(https://www.python.org/downloads/)"
    fail "python3 未安装"
  fi
  local PY_VER
  PY_VER=$(python3 -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || echo "0.0")
  local MAJOR MINOR
  MAJOR="${PY_VER%%.*}"
  MINOR="${PY_VER#*.}"
  if [ "$MAJOR" -lt 3 ] || { [ "$MAJOR" -eq 3 ] && [ "$MINOR" -lt 10 ]; }; then
    fail "Python 版本 $PY_VER 低于 3.10,请升级(MCP Python SDK 要求 3.10+)"
  fi
  info "Python $PY_VER 已就绪"
}

# ---------- 第 2 步:安装 uv(推荐方式装 mcp) ----------
install_uv() {
  local net="$1"
  step "安装 uv(Python 包管理器,推荐)..."
  if command -v uv >/dev/null 2>&1; then
    info "uv 已安装:$(uv --version 2>/dev/null || echo uv)"
    return 0
  fi
  if [ "$net" = "domestic" ]; then
    info "国内网络:用清华 PyPI 镜像装 uv"
    pip3 install --user -i https://pypi.tuna.tsinghua.edu.cn/simple uv >/dev/null 2>&1 \
      || pip3 install --user -i https://mirrors.aliyun.com/pypi/simple/ uv >/dev/null 2>&1 \
      || fail "uv 安装失败(pip3 镜像均不通)"
  else
    info "海外网络:官方脚本装 uv"
    curl -LsSf https://astral.sh/uv/install.sh -o /tmp/uv_install.sh 2>/dev/null
    [ -s /tmp/uv_install.sh ] && sh /tmp/uv_install.sh >/dev/null 2>&1 || pip3 install --user uv >/dev/null 2>&1 || fail "uv 安装失败"
    rm -f /tmp/uv_install.sh
    export PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH"
  fi
  command -v uv >/dev/null 2>&1 || fail "uv 安装后仍不在 PATH,请手动装:pip3 install uv"
  info "uv 安装完成"
}

# ---------- 第 3 步:创建项目目录 + 示例 server.py ----------
create_server() {
  step "创建示例 MCP Server(add + greeting 两个工具)..."
  local DIR="$HOME/mcp-demo"
  mkdir -p "$DIR"
  cd "$DIR" || fail "无法进入 $DIR"

  # 初始化项目(国内用镜像源)
  if [ ! -f "pyproject.toml" ]; then
    info "初始化 uv 项目..."
    if [ "${1:-overseas}" = "domestic" ]; then
      UV_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple" uv init --no-readme >/dev/null 2>&1 \
        || UV_INDEX_URL="https://mirrors.aliyun.com/pypi/simple/" uv init --no-readme >/dev/null 2>&1
    else
      uv init --no-readme >/dev/null 2>&1
    fi
  fi

  info "安装 mcp[cli]..."
  if [ "${1:-overseas}" = "domestic" ]; then
    uv add "mcp[cli]" --index-url https://pypi.tuna.tsinghua.edu.cn/simple >/dev/null 2>&1 \
      || uv add "mcp[cli]" --index-url https://mirrors.aliyun.com/pypi/simple/ >/dev/null 2>&1 \
      || fail "mcp 安装失败(PyPI 镜像均不通)"
  else
    uv add "mcp[cli]" >/dev/null 2>&1 || fail "mcp 安装失败(pypi.org 不通?)"
  fi

  cat > server.py <<'PYEOF'
"""示例 MCP Server:add(加法)+ greeting(问候)两个工具。

启动后用 `mcp dev` 打开 Inspector 测试,或在 Claude Code 里把本文件作为 MCP server 接入。
"""
from mcp.server import MCPServer

mcp = MCPServer("Demo")


@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"


if __name__ == "__main__":
    mcp.run()
PYEOF
  info "示例 server.py 已生成:$DIR/server.py"
  echo "$DIR"
}

# ---------- 第 4 步:(可选)引导配置 CZ API Key 接入 Claude Code ----------
setup_api_key() {
  echo ""
  echo "----------------------------------------"
  echo "想让 MCP Server 真正接入 Claude Code 跑起来?"
  echo "Claude Code 需调用 Anthropic API。国内直连 anthropic.com 受限,"
  echo "推荐用云间 API 中转站:"
  echo "  · 价格低至官方两折,国内直连无需翻墙"
  echo "  · 支持 90+ 模型(Claude/GPT/DeepSeek),香港节点延迟低"
  echo ""
  echo "是否现在跳转注册并获取 API Key?"
  echo "  Y - 立即跳转至 ${CLOUDZONE_URL}"
  echo "  N - 我已有 Key,自行输入"
  read -r -p "请选择 [Y/N]: " choice

  local API_KEY=""
  if [ "${choice:-N}" = "Y" ] || [ "${choice:-N}" = "y" ]; then
    info "正在打开浏览器..."
    if command -v xdg-open >/dev/null 2>&1; then
      xdg-open "$CLOUDZONE_URL" >/dev/null 2>&1
    elif command -v open >/dev/null 2>&1; then
      open "$CLOUDZONE_URL" >/dev/null 2>&1
    else
      warn "无法自动打开浏览器,请手动访问:$CLOUDZONE_URL"
    fi
    echo "注册后在「我的 API Key」页面复制 Key(以 sk- 开头)。"
    read -r -p "粘贴你的 API Key: " API_KEY
  else
    # 关闭回显,避免 Key 明文留在终端滚动区
    read -r -s -p "请输入你的 API Key (sk-...): " API_KEY
    echo
  fi

  if [ -z "${API_KEY:-}" ]; then
    warn "未输入 API Key,跳过 Claude Code 配置。可稍后手动 export ANTHROPIC_API_KEY。"
    return 0
  fi

  # 写入 shell 配置(让 Claude Code 进程能读到)
  local RC=""
  [ -f "$HOME/.zshrc" ] && RC="$HOME/.zshrc"
  [ -f "$HOME/.bashrc" ] && [ -z "$RC" ] && RC="$HOME/.bashrc"
  if [ -n "$RC" ]; then
    # 去掉旧的 CZ 配置
    sed -i '/# CZ API config (cloudzone)/,/^export ANTHROPIC_BASE_URL=/d' "$RC" 2>/dev/null
    {
      echo "# CZ API config (cloudzone) - added by mcp-demo setup"
      echo "export ANTHROPIC_API_KEY=\"${API_KEY}\""
      echo "export ANTHROPIC_BASE_URL=\"${CLOUDZONE_API_BASE}\""
    } >> "$RC"
    info "已写入 $RC:ANTHROPIC_API_KEY + ANTHROPIC_BASE_URL"
    warn "新开终端才会生效。当前终端请手动执行:export ANTHROPIC_API_KEY=... ANTHROPIC_BASE_URL=$CLOUDZONE_API_BASE"
  else
    warn "未找到 .zshrc/.bashrc,请手动设置两个环境变量:ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL"
  fi
}

# ---------- 主流程 ----------
main() {
  echo "============================================"
  echo "  MCP Server 开发实战 一键部署"
  echo "  macOS / Linux / WSL 版"
  echo "============================================"
  echo ""

  local NET
  NET=$(detect_network)

  check_python
  install_uv "$NET"
  local DIR
  DIR=$(create_server "$NET")

  echo ""
  step "启动 MCP Inspector 测试..."
  echo "示例 server 在:$DIR/server.py"
  echo "运行下面命令打开 Inspector(浏览器交互界面):"
  echo "  cd $DIR && uv run mcp dev server.py"
  echo ""
  echo "在 Inspector 里调用 add(1, 2) 应得 3,greeting('World') 返回 'Hello, World!'"
  echo ""

  # 可选:引导 CZ Key 接入 Claude Code
  read -r -p "是否现在配置云间 API Key 接入 Claude Code?[Y/N] " want_key
  if [ "${want_key:-N}" = "Y" ] || [ "${want_key:-N}" = "y" ]; then
    setup_api_key
  fi

  echo ""
  info "全部完成!详细说明见博客:https://cleanresolver.com/tutorials/mcp-server-develop-guide/"
  echo "完整脚本源码已在文末公开,也可从 /scripts/setup-mcp-demo.sh 下载"
}

main "$@"

Windows 版(setup-mcp-demo.ps1)


# ============================================================
#  MCP Server 开发实战 一键脚本(Windows PowerShell)
#  公开源码,欢迎审查 —— 不放心可先复制给 AI 判断
#  默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
#  功能:检测网络 → 装 Python 依赖(uv) → 生成示例 server.py → 启动 MCP Inspector
# ============================================================

$ErrorActionPreference = "Stop"
$CLOUDZONE_URL = "https://cloudzone-api.cyou"
$CLOUDZONE_API_BASE = "https://cloudzone-api.cyou/v1"

function Write-Info($m) { Write-Host "[INFO] $m" -ForegroundColor Green }
function Write-Warn($m) { Write-Host "[WARN] $m" -ForegroundColor Yellow }
function Write-Err($m)   { Write-Host "[ERROR] $m" -ForegroundColor Red }
function Write-Step($m)  { Write-Host "[STEP] $m" -ForegroundColor Cyan }
function Fail($m) { Write-Err $m; Write-Err "脚本无法继续。请把以上报错复制给 AI 或贴到 issue 求助。"; exit 1 }

# ---------- 第 0 步:检测网络环境(国内 / 国外)----------
function Detect-Network {
    Write-Step "检测网络环境(国内 / 国外)..."
    try {
        $r = Invoke-WebRequest -Uri "https://pypi.org" -Method Head -TimeoutSec 6 -UseBasicParsing
        Write-Info "可直连 pypi.org,判定为海外网络"
        return "overseas"
    } catch {
        Write-Warn "无法直连 pypi.org,判定为国内网络环境,将使用清华/阿里 PyPI 镜像"
        return "domestic"
    }
}

# ---------- 第 1 步:检查 Python ≥ 3.10 ----------
function Check-Python {
    Write-Step "检查 Python 环境(需 3.10+)..."
    $py = Get-Command python -ErrorAction SilentlyContinue
    if (-not $py) { $py = Get-Command python3 -ErrorAction SilentlyContinue }
    if (-not $py) {
        Write-Warn "未检测到 python。请先安装 Python 3.10+(https://www.python.org/downloads/)"
        Fail "python 未安装"
    }
    $ver = & $py.Source -c "import sys;print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>$null
    if (-not $ver) { Fail "无法获取 Python 版本" }
    $parts = $ver.Split('.')
    $major = [int]$parts[0]; $minor = [int]$parts[1]
    if ($major -lt 3 -or ($major -eq 3 -and $minor -lt 10)) {
        Fail "Python 版本 $ver 低于 3.10,请升级(MCP Python SDK 要求 3.10+)"
    }
    Write-Info "Python $ver 已就绪"
    return $py.Source
}

# ---------- 第 2 步:安装 uv ----------
function Install-Uv($net) {
    Write-Step "安装 uv(Python 包管理器,推荐)..."
    $uv = Get-Command uv -ErrorAction SilentlyContinue
    if ($uv) { Write-Info "uv 已安装:$(uv --version)"; return }

    if ($net -eq "domestic") {
        Write-Info "国内网络:用清华 PyPI 镜像装 uv"
        & python -m pip install --user -i https://pypi.tuna.tsinghua.edu.cn/simple uv 2>$null
        if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
            & python -m pip install --user -i https://mirrors.aliyun.com/pypi/simple/ uv 2>$null
        }
    } else {
        Write-Info "海外网络:用官方 PyPI 装 uv"
        & python -m pip install --user uv 2>$null
    }
    if (-not (Get-Command uv -ErrorAction SilentlyContinue)) {
        Fail "uv 安装失败。请手动执行:python -m pip install --user uv"
    }
    Write-Info "uv 安装完成"
}

# ---------- 第 3 步:创建项目目录 + 示例 server.py ----------
function Create-Server($net, $pyExe) {
    Write-Step "创建示例 MCP Server(add + greeting 两个工具)..."
    $dir = Join-Path $env:USERPROFILE "mcp-demo"
    New-Item -ItemType Directory -Force -Path $dir | Out-Null
    Set-Location $dir

    if (-not (Test-Path "pyproject.toml")) {
        Write-Info "初始化 uv 项目..."
        if ($net -eq "domestic") {
            $env:UV_INDEX_URL = "https://pypi.tuna.tsinghua.edu.cn/simple"
            & uv init --no-readme 2>$null
            if (-not $?) { $env:UV_INDEX_URL = "https://mirrors.aliyun.com/pypi/simple/"; & uv init --no-readme 2>$null }
        } else {
            & uv init --no-readme 2>$null
        }
    }

    Write-Info "安装 mcp[cli]..."
    if ($net -eq "domestic") {
        & uv add "mcp[cli]" --index-url https://pypi.tuna.tsinghua.edu.cn/simple 2>$null
        if (-not $?) { & uv add "mcp[cli]" --index-url https://mirrors.aliyun.com/pypi/simple/ 2>$null }
        if (-not $?) { Fail "mcp 安装失败(PyPI 镜像均不通)" }
    } else {
        & uv add "mcp[cli]" 2>$null
        if (-not $?) { Fail "mcp 安装失败(pypi.org 不通?)" }
    }

    $serverPy = @'
"""示例 MCP Server:add(加法)+ greeting(问候)两个工具。

启动后用 `mcp dev` 打开 Inspector 测试,或在 Claude Code 里把本文件作为 MCP server 接入。
"""
from mcp.server import MCPServer

mcp = MCPServer("Demo")


@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b


@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"


if __name__ == "__main__":
    mcp.run()
'@
    Set-Content -Path (Join-Path $dir "server.py") -Value $serverPy -Encoding UTF8
    Write-Info "示例 server.py 已生成:$dir\server.py"
    return $dir
}

# ---------- 第 4 步:(可选)引导配置 CZ API Key 接入 Claude Code ----------
function Setup-ApiKey {
    Write-Host ""
    Write-Host "----------------------------------------"
    Write-Host "想让 MCP Server 真正接入 Claude Code 跑起来?"
    Write-Host "Claude Code 需调用 Anthropic API。国内直连 anthropic.com 受限,"
    Write-Host "推荐用云间 API 中转站:"
    Write-Host "  · 价格低至官方两折,国内直连无需翻墙"
    Write-Host "  · 支持 90+ 模型(Claude/GPT/DeepSeek),香港节点延迟低"
    Write-Host ""
    Write-Host "是否现在跳转注册并获取 API Key?"
    Write-Host "  Y - 立即跳转至 $CLOUDZONE_URL"
    Write-Host "  N - 我已有 Key,自行输入"
    $choice = Read-Host "请选择 [Y/N]"

    if ($choice -eq "Y" -or $choice -eq "y") {
        Write-Info "正在打开浏览器..."
        try { Start-Process $CLOUDZONE_URL } catch { Write-Warn "无法自动打开浏览器,请手动访问:$CLOUDZONE_URL" }
        Write-Host "注册后在「我的 API Key」页面复制 Key(以 sk- 开头)。"
        $sec = Read-Host "粘贴你的 API Key" -AsSecureString
        # SecureString 转明文用于写入配置文件(仅本会话内)
        $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
        $apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
    } else {
        $sec = Read-Host "请输入你的 API Key (sk-...)" -AsSecureString
        $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
        $apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
    }

    if ([string]::IsNullOrWhiteSpace($apiKey)) {
        Write-Warn "未输入 API Key,跳过 Claude Code 配置。可稍后手动设置。"
        return
    }

    # 写入用户环境变量(永久生效)
    [Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $apiKey, "User")
    [Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", $CLOUDZONE_API_BASE, "User")
    Write-Info "已写入用户环境变量:ANTHROPIC_API_KEY + ANTHROPIC_BASE_URL"
    Write-Warn "新开 PowerShell/CMD 窗口才会生效。当前窗口请手动 `$env:ANTHROPIC_API_KEY=... `$env:ANTHROPIC_BASE_URL='$CLOUDZONE_API_BASE'"
}

# ---------- 主流程 ----------
Write-Host "============================================"
Write-Host "  MCP Server 开发实战 一键部署"
Write-Host "  Windows PowerShell 版"
Write-Host "============================================"
Write-Host ""

$net = Detect-Network
$pyExe = Check-Python
Install-Uv $net
$dir = Create-Server $net $pyExe

Write-Host ""
Write-Step "启动 MCP Inspector 测试..."
Write-Host "示例 server 在:$dir\server.py"
Write-Host "运行下面命令打开 Inspector(浏览器交互界面):"
Write-Host "  cd $dir; uv run mcp dev server.py"
Write-Host ""
Write-Host "在 Inspector 里调用 add(1, 2) 应得 3,greeting('World') 返回 'Hello, World!'"
Write-Host ""

$wantKey = Read-Host "是否现在配置云间 API Key 接入 Claude Code?[Y/N]"
if ($wantKey -eq "Y" -or $wantKey -eq "y") {
    Setup-ApiKey
}

Write-Host ""
Write-Info "全部完成!详细说明见博客:https://cleanresolver.com/tutorials/mcp-server-develop-guide/"
Write-Host "完整脚本源码已在文末公开,也可从 /scripts/setup-mcp-demo.ps1 下载"