TellWorldAI 世界档案
问档案English

首页›实践›实践

实践

第一个 MCP 服务器:从零跑通

用官方 SDK 写第一个 MCP 服务器:先装环境,写一个带加法工具和问候资源的计算器,再用 MCP Inspector 测试它。

这篇适合谁、读完能做到什么

如果你已经在用大模型,想让它调用自己写的工具、读取自己控制的数据,这篇适合你。读完你能搭好 MCP 的开发环境,写出一个带加法工具和问候资源的计算器服务器,用 MCP Inspector 测试它,并且知道搭建时哪些地方容易卡住。[1]

MCP 是什么

MCP(Model Context Protocol,模型上下文协议)是一个开放协议,规范应用如何向大模型提供上下文。可以把它理解成 AI 应用的 USB-C 接口:有了统一的接口,AI 模型就能接到不同的数据源和工具上。[1]

一个 MCP 服务器通常包含四类内容:服务器配置(端口、认证等设置)、资源(提供给大模型的数据和上下文)、工具(模型可以调用的功能)和提示词(用来生成或组织文本的模板)。[1] 服务器上的工具和资源可以被任何客户端使用,不论客户端有没有接大模型。[1]

这一点和普通的函数调用不同。工具和资源放在服务器上以后,换一个客户端就能复用,不必把同样的代码再写一遍。下面的练习就是按这个思路,先做一个最小的服务器,再让客户端去调用它。[1]

准备

  • 开发环境:C#、Java、Python、TypeScript 或 Rust 任选一种。
  • 编辑器:Visual Studio、Visual Studio Code、IntelliJ、Eclipse、PyCharm 或其他现代编辑器都可以。
  • 包管理器:NuGet、Maven/Gradle、pip、npm/yarn 或 Cargo,按你选的语言来。
  • API 密钥:只有宿主应用要调用 AI 服务时才需要。[1]

这篇的练习是一个计算器服务器,分五步完成:创建项目、添加依赖、创建项目文件、编写服务器代码、测试。下面先用 TypeScript 和 Python 各走一遍,Java、Rust 和 .NET 放在后面。[1]

第一步:用 TypeScript 建项目

新建一个目录,初始化 npm 项目:[1]

# Create project directory and initialize npm project
mkdir calculator-server
cd calculator-server
npm init -y

安装 MCP SDK 和用于校验参数的 Zod:[1]

# If not already installed, install TypeScript globally
npm install typescript -g

# Install the MCP SDK and Zod for schema validation
npm install @modelcontextprotocol/sdk zod
npm install -D @types/node typescript

示例的 package.json 里,build 脚本调用 tsc,start 脚本先编译再运行 ./build/index.js;依赖版本是 @modelcontextprotocol/sdk 的 ^1.16.0 和 zod 的 ^3.25.76。tsconfig.json 把编译输出目录 outDir 设为 ./build,源码目录 rootDir 设为 ./src,strict 开启,target 是 ES2022,module 和 moduleResolution 都是 Node16。[1]

这两个文件的作用不同:package.json 管依赖和脚本,tsconfig.json 管编译。编译规则写错,常见的表现是 build 目录里没有文件,或者运行时找不到入口,所以建好项目后先确认这两个文件的内容和示例一致。[1]

服务器代码的开头是导入 SDK 的类,然后创建服务器对象:[1]

import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
 
// Create an MCP server
const server = new McpServer({
  name: "Calculator MCP Server",
  version: "1.0.0"
});

McpServer 构造时传入的 name 和 version 就是服务器对外显示的名字和版本号。StdioServerTransport 是把服务器接到标准输入输出上的传输层,最后一行 server.connect(transport) 才真正让服务器开始接收消息。[1]

接着添加一个 add 工具和一个 greeting 资源。工具接收两个数字 a 和 b;资源通过 greeting://{name} 访问,参数是 name,返回一句问候语。[1]

server.tool(
  "add",
  { a: z.number(), b: z.number() },
  async ({ a, b }) => ({
    content: [{ type: "text", text: String(a + b) }]
  })
);

server.resource(
  "greeting",
  new ResourceTemplate("greeting://{name}", { list: undefined }),
  async (uri, { name }) => ({
    contents: [{
      uri: uri.href,
      text: `Hello, ${name}!`
    }]
  })
);

读这段代码可以看到,server.tool 的三个参数分别是工具名 add、输入参数的定义(a 和 b 都是数字,用 z.number() 声明)以及处理函数。处理函数返回的内容是一个数组,里面的元素带有 type: "text",也就是纯文本结果。资源的返回值则是 uri 和 text 两个字段:uri 用来标识这条资源,text 是实际内容。[1]

这种写法的好处是,参数类型写在工具定义里,调用方能据此知道该传什么。如果调用方传来的参数类型不对,SDK 会依据这份定义去检查。[1]

第二步:用 Python 写同样的服务器

Python 版本更短。先建虚拟环境,再安装 mcp[cli]。下面命令的第二行是 Windows 上激活虚拟环境的写法:[1]

# Create a virtual env and install dependencies
python -m venv venv
venv\Scripts\activate
pip install "mcp[cli]"

服务器文件里,用 FastMCP 创建一个名为 Demo 的服务器:[1]

# server.py
from mcp.server.fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("Demo")

这里的 FastMCP 是 Python SDK 里的服务器类,构造时传入的字符串 Demo 就是服务器的名字。后面的工具和资源都注册在这个 mcp 对象上。[1]

用 @mcp.tool() 装饰器把 add 函数注册为工具,用 @mcp.resource("greeting://{name}") 注册问候资源:[1]

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


# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"

Python 版没有单独的注册步骤,装饰器本身就完成了注册。add 函数的类型注解(参数是 int,返回 int)和函数上方的文档字符串(说明工具用途的那一行)共同构成工具的描述。资源 greeting://{name} 的参数 name 来自 URI 中花括号里的部分,函数返回一句问候语。[1]

编译和运行

两个版本做的事情相同:都注册了一个加法工具和一个问候资源。区别主要在工程流程上。TypeScript 版要先用 tsc 把源码编译到 build 目录,再运行编译后的 build/index.js;依赖由 npm 管理。Python 版不需要编译,依赖由 pip 安装,直接用 mcp 命令启动。[1]

TypeScript 版先执行 npm run build 编译。Python 版用 mcp run server.py 启动。如果想同时打开 Inspector,就改用 mcp dev server.py,它会自动启动 Inspector,并带上所需的代理会话令牌;用 mcp run 的话,要自己手动启动 Inspector,再配置连接。[1]

每次改完代码都应该重新编译(TypeScript)或重新启动(Python),再去测试,否则测到的可能还是旧版本。

用 MCP Inspector 测试

MCP Inspector 是一个可视化测试工具。它能发现服务器的工具、资源和提示词,让你用不同参数试调工具,还能查看服务器信息、模式(schema)和配置。[1][2] Inspector 的源码在 GitHub 上的 modelcontextprotocol/inspector 仓库。[2]

TypeScript 版用下面的命令启动 Inspector:[1]

npx @modelcontextprotocol/inspector node build/index.js

Inspector 本身只是测试工具,它帮你连接到服务器、列出工具和资源,并让你手动调用。它不会替代服务器的自动化测试,也不会替你检查业务逻辑。把 add 的两个参数换成不同的数字,看返回的结果是否符合预期,是最直接的第一轮检查。

Java、Rust 和 .NET 怎么起步

这一节只给出各语言的起步命令。Java 和 Rust 的服务器代码较长,按上面的顺序读完 TypeScript 或 Python 之后,再回头看对应的语言会更容易理解。

Java 示例用 Spring Boot 生成项目,依赖 Spring AI。计算器服务把加、减、乘、除、乘方、开平方、取余和绝对值等操作都写成带 @Tool 注解的方法。构建和运行的命令是:[1]

./mvnw clean install -DskipTests
java -jar target/calculator-server-0.0.1-SNAPSHOT.jar

需要注意,Java 示例里的 HTTP 部分用的是旧的 HTTP+SSE 传输方式,对应的 SDK 兼容 MCP 2025-11-25。如果要做新的远程服务器,应该使用 2026-07-28 版的 Streamable HTTP 传输。[1]

Rust 版先用 cargo add 添加依赖:[1]

cargo add rmcp --features server,transport-io
cargo add serde
cargo add tokio --features rt-multi-thread

然后用 cargo fmt 格式化代码,用 cargo run 运行。[1]

.NET 版先创建控制台项目:[1]

dotnet new console -n McpCalculatorServer
cd McpCalculatorServer

常见问题

下面几条是这一步最常遇到的问题。排查时的顺序通常是:先确认服务器进程真的在运行,再核对端口,最后看依赖和跨域设置。大部分问题都能按这个顺序定位。[1]

  • 连接被拒绝(connection refused):先确认服务器已经在运行,而且端口正确。[1]
  • CORS 报错:跨域请求需要配置合适的 CORS 响应头。[1]
  • 服务器起不来:检查端口是否冲突,依赖是否装全。[1]

如果你在本地同时跑了多个服务,端口冲突是最常见的原因。Python 版和 TypeScript 版用的依赖都要装在当前项目的环境里,换一个终端或者换一个虚拟环境,就可能找不到依赖。[1]

下一步

MCP 官方提供了多种语言的 SDK:C# SDK(与 Microsoft 合作维护)、Java SDK(与 Spring AI 合作维护)、TypeScript、Python、Kotlin、Swift(与 Loopwork AI 合作维护)和 Rust。[1] 这篇只到本地服务器和本地测试为止。接下来可以选你熟悉的语言,把一个真正有用的工具接进来,再用 Inspector 检查它的输入和输出。

本文改编自 Microsoft 开源课程《MCP for Beginners》第 3 课中关于第一个服务器的一节[1],原文以 MIT 许可证发布。

来源

  1. 1
    Getting Started with MCPMicrosoft mcp-for-beginners (MIT)
  2. 2
    MCP InspectorModel Context Protocol

引用本页: 第一个 MCP 服务器:从零跑通. TellWorld, https://www.tellworld.net/zh/practice/practice-mcp-first-server. 更新于 2026-11-14

相关动态