模型上下文协议服务器

MCP是一个开源标准,用于连接AI应用程序与外部系统,提供工具、资源和提示模板,使AI能够访问关键信息并执行任务。适用于AI应用开发、数据集成和自动化工作流。

  • by drueber
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 drueber/mcp-workshop

使用说明

MCP黑客马拉松初学者

欢迎这个降价为你提供了一个关于 模型上下文协议(MCP) 以及一个可以作为黑客马拉松起点的最小TypeScript服务器。


什么是MCP?

MCP(模型上下文协议)是用于将AI应用程序连接到外部系统的开源标准。 使用MCP,像Claude或ChatGPT这样的AI应用程序可以连接到数据源(例如本地文件、数据库)、工具(例如搜索引擎、计算器)和工作流 (例如专门的提示)——使他们能够访问关键信息并执行任务。

将MCP想象成AI应用程序的USB-C端口。正如USB-C提供了一种标准化的方式 连接电子设备,MCP提供了一种将AI应用程序连接到外部系统的标准化方法。

基本上,它是一个你可以连接你的人工智能应用程序的服务器。有了这个服务器,你可以做人工智能无法访问的事情。

关键图元:

  • 工具:人工智能应用程序可以调用以执行操作的可执行函数(例如,文件操作、API调用、数据库查询)
  • 资源:为人工智能应用程序提供上下文信息的数据源(例如,文件内容、数据库记录、API响应)
  • 提示词:可重用的模板,有助于构建与语言模型的交互(例如,系统提示、少数镜头示例)

全部信息来自: https://modelcontextprotocol.io/docs/learn/architecture 你可以在那里阅读更多信息。


以下介绍指南摘自: https://github.com/microsoft/mcp-for-beginners/blob/main/03-GettingStarted/01-first-server/README.md

MCP入门

欢迎来到模型上下文协议(MCP)的第一步!无论您是MCP新手还是希望加深理解,本指南都将引导您完成基本的设置和开发过程。您将了解MCP如何实现AI模型和应用程序之间的无缝集成,并学习如何快速为构建和测试MCP驱动的解决方案做好环境准备。

太长,读不下去了如果你构建人工智能应用程序,你知道你可以向你的LLM(大型语言模型)添加工具和其他资源,使LLM更有知识。但是,如果将这些工具和资源放置在服务器上,则任何具有/不具有LLM的客户端都可以使用应用程序和服务器功能。

概述

本课程提供了有关设置MCP环境和构建第一个MCP应用程序的实用指导。您将学习如何设置必要的工具和框架,构建基本的MCP服务器,创建主机应用程序,以及测试您的实现。

模型上下文协议(MCP)是一种开放协议,它规范了应用程序如何向LLM提供上下文。将MCP想象成AI应用程序的USB-C端口——它提供了一种将AI模型连接到不同数据源和工具的标准化方法。

学习目标

本课结束时,您将能够:

  • 使用C#、Java、Python、TypeScript和Rust为MCP设置开发环境
  • 构建和部署具有自定义功能(资源、提示和工具)的基本MCP服务器
  • 创建连接到MCP服务器的主机应用程序
  • 测试和调试MCP实现

设置MCP环境

在开始使用MCP之前,准备好开发环境并了解基本工作流程非常重要。本节将指导您完成初始设置步骤,以确保顺利开始使用MCP。

先决条件

在深入MCP开发之前,请确保您已经:

  • 开发环境:适用于您选择的语言(C#、Java、Python、TypeScript或Rust)
  • IDE/编辑器:Visual Studio、Visual Studio Code、IntelliJ、Eclipse、PyCharm或任何现代代码编辑器
  • 包装经理:NuGet、Maven/Gradle、pip、npm/yarn或Cargo
  • API密钥:对于您计划在主机应用程序中使用的任何AI服务

基本MCP服务器结构

MCP服务器通常包括:

  • 服务器配置:设置端口、身份验证和其他设置
  • 资源:向法学硕士提供数据和背景
  • 工具:模型可以调用的功能
  • 提示词:用于生成或构建文本的模板

以下是TypeScript中的一个简化示例:

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: "Demo",
  version: "1.0.0"
});

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

// Add a dynamic greeting resource
server.resource(
  "file",
  // The 'list' parameter controls how the resource lists available files. Setting it to undefined disables listing for this resource.
  new ResourceTemplate("file://{path}", { list: undefined }),
  async (uri, { path }) => ({
    contents: [{
      uri: uri.href,
      text: `File, ${path}!`
    }]
  })
);

// Add a file resource that reads the file contents
server.resource(
  "file",
  new ResourceTemplate("file://{path}", { list: undefined }),
  async (uri, { path }) => {
    let text;
    try {
      text = await fs.readFile(path, "utf8");
    } catch (err) {
      text = `Error reading file: ${err.message}`;
    }
    return {
      contents: [{
        uri: uri.href,
        text
      }]
    };
  }
);

server.prompt(
  "review-code",
  { code: z.string() },
  ({ code }) => ({
    messages: [{
      role: "user",
      content: {
        type: "text",
        text: `Please review this code:\n\n${code}`
      }
    }]
  })
);

// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);

在前面的代码中,我们:

  • 从MCP TypeScript SDK导入必要的类。
  • 创建并配置新的MCP服务器实例。
  • 注册自定义工具(calculator)带有处理函数。
  • 启动服务器以监听传入的MCP请求。

测试和调试

在开始测试MCP服务器之前,了解调试的可用工具和最佳实践非常重要。有效的测试可确保您的服务器按预期运行,并帮助您快速识别和解决问题。以下部分概述了验证MCP实施的推荐方法。

MCP提供工具来帮助您测试和调试服务器:

  • 检查员工具,此图形界面允许您连接到服务器并测试您的工具、提示和资源。
  • 卷曲,您还可以使用curl等命令行工具或其他可以创建和运行HTTP命令的客户端连接到服务器。

使用MCP检查器

这 MCP检查员 是一个可视化测试工具,可帮助您:

  1. 发现服务器功能:自动检测可用资源、工具和提示
  2. 测试工具执行:尝试不同的参数并实时查看响应
  3. 查看服务器元数据:检查服务器信息、架构和配置
# ex TypeScript, installing and running MCP Inspector
npx @modelcontextprotocol/inspector node build/index.js

当您运行上述命令时,MCP检查器将在您的浏览器中启动一个本地web界面。您可以看到一个仪表板,显示您注册的MCP服务器、它们的可用工具、资源和提示。该界面允许您交互式测试工具执行、检查服务器元数据和查看实时响应,从而更容易验证和调试MCP服务器实现。

以下是它的屏幕截图:

常见设置问题和解决方案

问题 可能的解决方案
连接被拒绝 检查服务器是否正在运行以及端口是否正确
工具执行错误 检查参数验证和错误处理
身份验证失败 验证API密钥和权限
架构验证错误 确保参数与定义的架构匹配
服务器未启动 检查端口冲突或缺少依赖项
CORS错误 为跨源请求配置正确的CORS标头
身份验证问题 验证令牌有效性和权限

地方发展

对于本地开发和测试,您可以直接在您的计算机上运行MCP服务器:

  1. 启动服务器进程:运行MCP服务器应用程序
  2. 配置网络:确保服务器在预期端口上可访问
  3. 连接客户端:使用本地连接URL,如 http://localhost:3000
# Example: Running a TypeScript MCP server locally
npm run start
# Server running at http://localhost:3000

构建您的第一个MCP服务器

我们已经覆盖 核心概念 在上一课中,现在是时候将这些知识付诸实践了。

服务器能做什么

在我们开始编写代码之前,让我们提醒自己服务器可以做什么:

例如,MCP服务器可以:

  • 访问本地文件和数据库
  • 连接到远程API
  • 执行计算
  • 与其他工具和服务集成
  • 提供用于交互的用户界面

太好了,既然我们知道我们能为它做些什么,让我们开始编码。

练习:创建服务器

要创建服务器,您需要执行以下步骤:

  • 安装MCP SDK。
  • 创建一个项目并设置项目结构。
  • 编写服务器代码。
  • 测试服务器。

-1-创建项目

TypeScript

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

python

# Create project dir
mkdir calculator-server
cd calculator-server
# Open the folder in Visual Studio Code - Skip this if you are using a different IDE
code .

.NET

dotnet new console -n McpCalculatorServer
cd McpCalculatorServer

Java

对于Java,创建一个Spring Boot项目:

curl https://start.spring.io/starter.zip \
  -d dependencies=web \
  -d javaVersion=21 \
  -d type=maven-project \
  -d groupId=com.example \
  -d artifactId=calculator-server \
  -d name=McpServer \
  -d packageName=com.microsoft.mcp.sample.server \
  -o calculator-server.zip

解压缩zip文件:

unzip calculator-server.zip -d calculator-server
cd calculator-server
# optional remove the unused test
rm -rf src/test/java

将以下完整配置添加到您的 pom.xml文件 文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <!-- Spring Boot parent for dependency management -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.0</version>
        <relativePath />
    </parent>

    <!-- Project coordinates -->
    <groupId>com.example</groupId>
    <artifactId>calculator-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Calculator Server</name>
    <description>Basic calculator MCP service for beginners</description>

    <!-- Properties -->
    <properties>
        <java.version>21</java.version>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
    </properties>

    <!-- Spring AI BOM for version management -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0-SNAPSHOT</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- Dependencies -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
    </dependencies>

    <!-- Build configuration -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <release>21</release>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- Repositories for Spring AI snapshots -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>
</project>

锈

mkdir calculator-server
cd calculator-server
cargo init

-2-添加依赖关系

现在您已经创建了项目,接下来让我们添加依赖关系:

TypeScript

# 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

python

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

Java

cd calculator-server
./mvnw clean install -DskipTests

锈

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

-3-创建项目文件

TypeScript

打开 package.json 将文件中的内容替换为以下内容,以确保您可以构建和运行服务器:

{
  "name": "calculator-server",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "build": "tsc",
    "start": "npm run build && node ./build/index.js",
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "A simple calculator server using Model Context Protocol",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.16.0",
    "zod": "^3.25.76"
  },
  "devDependencies": {
    "@types/node": "^24.0.14",
    "typescript": "^5.8.3"
  }
}

创建一个 Tsconflict.儿子 内容如下:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

为源代码创建一个目录:

mkdir src
touch src/index.ts

python

创建文件 服务器.py

touch server.py

.NET

安装所需的NuGet包:

dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.Hosting

Java

对于Java Spring Boot项目,项目结构是自动创建的。

锈

对于Rust,a src/main.rs 默认情况下,运行时会创建文件 cargo init。打开文件并删除默认代码。

-4-创建服务器代码

TypeScript

创建文件 index.ts 并添加以下代码:

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"
});

现在你有一台服务器,但它做得不多,让我们来解决这个问题。

python

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

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

.NET

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
    // Configure all logs to go to stderr
    consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();
await builder.Build().RunAsync();

// add features

Java

对于Java,创建核心服务器组件。首先,修改主应用程序类:

src/main/java/com/microsoft.com/mcp/sample/server/McpServerApplication.java:

package com.microsoft.mcp.sample.server;

import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.microsoft.mcp.sample.server.service.CalculatorService;

@SpringBootApplication
public class McpServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(McpServerApplication.class, args);
    }
    
    @Bean
    public ToolCallbackProvider calculatorTools(CalculatorService calculator) {
        return MethodToolCallbackProvider.builder().toolObjects(calculator).build();
    }
}

创建计算器服务 src/main/java/com/microsoft.com/mcp/sample/server/service/CalculatorService.java:

package com.microsoft.mcp.sample.server.service;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;

/**
 * Service for basic calculator operations.
 * This service provides simple calculator functionality through MCP.
 */
@Service
public class CalculatorService {

    /**
     * Add two numbers
     * @param a The first number
     * @param b The second number
     * @return The sum of the two numbers
     */
    @Tool(description = "Add two numbers together")
    public String add(double a, double b) {
        double result = a + b;
        return formatResult(a, "+", b, result);
    }

    /**
     * Subtract one number from another
     * @param a The number to subtract from
     * @param b The number to subtract
     * @return The result of the subtraction
     */
    @Tool(description = "Subtract the second number from the first number")
    public String subtract(double a, double b) {
        double result = a - b;
        return formatResult(a, "-", b, result);
    }

    /**
     * Multiply two numbers
     * @param a The first number
     * @param b The second number
     * @return The product of the two numbers
     */
    @Tool(description = "Multiply two numbers together")
    public String multiply(double a, double b) {
        double result = a * b;
        return formatResult(a, "*", b, result);
    }

    /**
     * Divide one number by another
     * @param a The numerator
     * @param b The denominator
     * @return The result of the division
     */
    @Tool(description = "Divide the first number by the second number")
    public String divide(double a, double b) {
        if (b == 0) {
            return "Error: Cannot divide by zero";
        }
        double result = a / b;
        return formatResult(a, "/", b, result);
    }

    /**
     * Calculate the power of a number
     * @param base The base number
     * @param exponent The exponent
     * @return The result of raising the base to the exponent
     */
    @Tool(description = "Calculate the power of a number (base raised to an exponent)")
    public String power(double base, double exponent) {
        double result = Math.pow(base, exponent);
        return formatResult(base, "^", exponent, result);
    }

    /**
     * Calculate the square root of a number
     * @param number The number to find the square root of
     * @return The square root of the number
     */
    @Tool(description = "Calculate the square root of a number")
    public String squareRoot(double number) {
        if (number < 0) {
            return "Error: Cannot calculate square root of a negative number";
        }
        double result = Math.sqrt(number);
        return String.format("√%.2f = %.2f", number, result);
    }

    /**
     * Calculate the modulus (remainder) of division
     * @param a The dividend
     * @param b The divisor
     * @return The remainder of the division
     */
    @Tool(description = "Calculate the remainder when one number is divided by another")
    public String modulus(double a, double b) {
        if (b == 0) {
            return "Error: Cannot divide by zero";
        }
        double result = a % b;
        return formatResult(a, "%", b, result);
    }

    /**
     * Calculate the absolute value of a number
     * @param number The number to find the absolute value of
     * @return The absolute value of the number
     */
    @Tool(description = "Calculate the absolute value of a number")
    public String absolute(double number) {
        double result = Math.abs(number);
        return String.format("|%.2f| = %.2f", number, result);
    }

    /**
     * Get help about available calculator operations
     * @return Information about available operations
     */
    @Tool(description = "Get help about available calculator operations")
    public String help() {
        return "Basic Calculator MCP Service\n\n" +
               "Available operations:\n" +
               "1. add(a, b) - Adds two numbers\n" +
               "2. subtract(a, b) - Subtracts the second number from the first\n" +
               "3. multiply(a, b) - Multiplies two numbers\n" +
               "4. divide(a, b) - Divides the first number by the second\n" +
               "5. power(base, exponent) - Raises a number to a power\n" +
               "6. squareRoot(number) - Calculates the square root\n" + 
               "7. modulus(a, b) - Calculates the remainder of division\n" +
               "8. absolute(number) - Calculates the absolute value\n\n" +
               "Example usage: add(5, 3) will return 5 + 3 = 8";
    }

    /**
     * Format the result of a calculation
     */
    private String formatResult(double a, String operator, double b, double result) {
        return String.format("%.2f %s %.2f = %.2f", a, operator, b, result);
    }
}

生产就绪服务的可选组件:

创建启动配置 src/main/java/com/microsoft.com/mcp/sample/server/config/StartupConfig.java:

package com.microsoft.mcp.sample.server.config;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class StartupConfig {
    
    @Bean
    public CommandLineRunner startupInfo() {
        return args -> {
            System.out.println("\n" + "=".repeat(60));
            System.out.println("Calculator MCP Server is starting...");
            System.out.println("SSE endpoint: http://localhost:8080/sse");
            System.out.println("Health check: http://localhost:8080/actuator/health");
            System.out.println("=".repeat(60) + "\n");
        };
    }
}

创建健康控制器 src/main/java/com/microsoft.com/mcp/sample/server/controller/HealthController.java:

package com.microsoft.mcp.sample.server.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@RestController
public class HealthController {
    
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> healthCheck() {
        Map<String, Object> response = new HashMap<>();
        response.put("status", "UP");
        response.put("timestamp", LocalDateTime.now().toString());
        response.put("service", "Calculator MCP Server");
        return ResponseEntity.ok(response);
    }
}

创建异常处理程序 src/main/java/com/microsoft.com/mcp/sample/server/exception/GlobalExceptionHandler.java:

package com.microsoft.mcp.sample.server.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException ex) {
        ErrorResponse error = new ErrorResponse(
            "Invalid_Input", 
            "Invalid input parameter: " + ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

    public static class ErrorResponse {
        private String code;
        private String message;

        public ErrorResponse(String code, String message) {
            this.code = code;
            this.message = message;
        }

        // Getters
        public String getCode() { return code; }
        public String getMessage() { return message; }
    }
}

创建自定义横幅 src/main/resources/banner.txt:

_____      _            _       _             
 / ____|    | |          | |     | |            
| |     __ _| | ___ _   _| | __ _| |_ ___  _ __ 
| |    / _` | |/ __| | | | |/ _` | __/ _ \| '__|
| |___| (_| | | (__| |_| | | (_| | || (_) | |   
 \_____\__,_|_|\___|\__,_|_|\__,_|\__\___/|_|   
                                                
Calculator MCP Server v1.0
Spring Boot MCP Application

锈

将以下代码添加到 src/main.rs 文件。这将为您的MCP服务器导入必要的库和模块。

use rmcp::{
    handler::server::{router::tool::ToolRouter, tool::Parameters},
    model::{ServerCapabilities, ServerInfo},
    schemars, tool, tool_handler, tool_router,
    transport::stdio,
    ServerHandler, ServiceExt,
};
use std::error::Error;

计算器服务器将是一个简单的服务器,可以将两个数字加在一起。让我们创建一个结构来表示计算器请求。

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct CalculatorRequest {
    pub a: f64,
    pub b: f64,
}

接下来,创建一个结构体来表示计算器服务器。此结构体将保存用于注册工具的工具路由器。

#[derive(Debug, Clone)]
pub struct Calculator {
    tool_router: ToolRouter<Self>,
}

现在,我们可以实施 Calculator struct创建服务器的新实例,并实现服务器处理程序以提供服务器信息。

#[tool_router]
impl Calculator {
    pub fn new() -> Self {
        Self {
            tool_router: Self::tool_router(),
        }
    }
}

#[tool_handler]
impl ServerHandler for Calculator {
    fn get_info(&self) -> ServerInfo {
        ServerInfo {
            instructions: Some("A simple calculator tool".into()),
            capabilities: ServerCapabilities::builder().enable_tools().build(),
            ..Default::default()
        }
    }
}

最后,我们需要实现启动服务器的主要功能。此函数将创建 Calculator 构造并通过标准输入/输出提供它。

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let service = Calculator::new().serve(stdio()).await?;
    service.waiting().await?;
    Ok(())
}

服务器现在已设置为提供有关其自身的基本信息。接下来,我们将添加一个工具来执行添加。

-5-添加工具和资源

通过添加以下代码添加工具和资源:

TypeScript

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}!`
    }]
  })
);

您的工具需要参数 a 和 b 并运行一个函数,该函数在表单上产生响应:

{
  contents: [{
    type: "text", content: "some content"
  }]
}

您的资源是通过字符串“greeting”访问的,并接受一个参数 name 并对工具产生类似的响应:

{
  uri: "<href>",
  text: "a text"
}

python

# 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}!"

在前面的代码中,我们有:

  • 定义了一个工具 add 这需要参数 a 和 p,两个整数。
  • 创建了一个名为的资源 greeting 这需要参数 name.

.NET

将此添加到Program.cs文件中:

[McpServerToolType]
public static class CalculatorTool
{
    [McpServerTool, Description("Adds two numbers")]
    public static string Add(int a, int b) => $"Sum {a + b}";
}

Java

在上一步中已经创建了这些工具。

锈

在内部添加新工具 impl Calculator 块:

#[tool(description = "Adds a and b")]
async fn add(
    &self,
    Parameters(CalculatorRequest { a, b }): Parameters<CalculatorRequest>,
) -> String {
    (a + b).to_string()
}

-6-最终代码

让我们添加所需的最后一段代码,以便服务器可以启动:

TypeScript

// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);

以下是完整的代码:

// index.ts
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"
});

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

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

// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
server.connect(transport);

python

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

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


# 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}!"

# Main execution block - this is required to run the server
if __name__ == "__main__":
    mcp.run()

.NET

创建一个包含以下内容的Program.cs文件:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
    // Configure all logs to go to stderr
    consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();
await builder.Build().RunAsync();

[McpServerToolType]
public static class CalculatorTool
{
    [McpServerTool, Description("Adds two numbers")]
    public static string Add(int a, int b) => $"Sum {a + b}";
}

Java

完整的主应用程序类应该如下所示:

// McpServerApplication.java
package com.microsoft.mcp.sample.server;

import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.microsoft.mcp.sample.server.service.CalculatorService;

@SpringBootApplication
public class McpServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(McpServerApplication.class, args);
    }
    
    @Bean
    public ToolCallbackProvider calculatorTools(CalculatorService calculator) {
        return MethodToolCallbackProvider.builder().toolObjects(calculator).build();
    }
}

锈

Rust服务器的最终代码应该如下:

use rmcp::{
    ServerHandler, ServiceExt,
    handler::server::{router::tool::ToolRouter, tool::Parameters},
    model::{ServerCapabilities, ServerInfo},
    schemars, tool, tool_handler, tool_router,
    transport::stdio,
};
use std::error::Error;

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
pub struct CalculatorRequest {
    pub a: f64,
    pub b: f64,
}

#[derive(Debug, Clone)]
pub struct Calculator {
    tool_router: ToolRouter<Self>,
}

#[tool_router]
impl Calculator {
    pub fn new() -> Self {
        Self {
            tool_router: Self::tool_router(),
        }
    }
    
    #[tool(description = "Adds a and b")]
    async fn add(
        &self,
        Parameters(CalculatorRequest { a, b }): Parameters<CalculatorRequest>,
    ) -> String {
        (a + b).to_string()
    }
}

#[tool_handler]
impl ServerHandler for Calculator {
    fn get_info(&self) -> ServerInfo {
        ServerInfo {
            instructions: Some("A simple calculator tool".into()),
            capabilities: ServerCapabilities::builder().enable_tools().build(),
            ..Default::default()
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let service = Calculator::new().serve(stdio()).await?;
    service.waiting().await?;
    Ok(())
}

-7-测试服务器

使用以下命令启动服务器:

TypeScript

npm run build

python

mcp run server.py

要使用MCP检查器,请使用 mcp dev server.py 其自动启动检查器并提供所需的代理会话令牌。如果使用 mcp run server.py,您需要手动启动检查器并配置连接。

.NET

确保您在项目目录中:

cd McpCalculatorServer
dotnet run

Java

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

锈

运行以下命令以格式化并运行服务器:

cargo fmt
cargo run

-8-使用检查器运行

检查器是一个很好的工具,可以启动您的服务器,并允许您与之交互,以便您可以测试它是否正常工作。让我们开始吧:

[!注意] 它在“command”字段中可能看起来不同,因为它包含用于在特定运行时运行服务器的命令/

TypeScript

npx @modelcontextprotocol/inspector node build/index.js

或将其添加到您的 package.json 像这样: "inspector": "npx @modelcontextprotocol/inspector node build/index.js" 然后跑 npm run inspector

Python封装了一个名为inspector的Node.js工具。可以这样称呼该工具:

mcp dev server.py

但是,它并没有实现该工具上可用的所有方法,因此建议您直接运行Node.js工具,如下所示:

npx @modelcontextprotocol/inspector mcp run server.py

如果您使用的工具或IDE允许您配置运行脚本的命令和参数, 确保设置 python 在 Command 现场和 server.py 作为 Arguments。这可确保脚本正确运行。

.NET

确保您在项目目录中:

cd McpCalculatorServer
npx @modelcontextprotocol/inspector dotnet run

Java

确保计算器服务器正在运行 运行检查员:

npx @modelcontextprotocol/inspector

在检查器web界面中:

  1. 选择“SSE”作为传输类型
  2. 将URL设置为: http://localhost:8080/sse
  3. 点击“连接”

您现在已连接到服务器 Java服务器测试部分现已完成

下一节将介绍与服务器的交互。

您应该看到以下用户界面:

  1. 通过选择“连接”按钮连接到服务器 连接到服务器后,您现在应该看到以下内容:
  1. 选择“工具”和“listTools”,您应该看到“添加”显示,选择“添加”并填写参数值。

您应该看到以下响应,即“添加”工具的结果:

恭喜,您已经成功创建并运行了第一台服务器!

锈

要使用MCP Inspector CLI运行Rust服务器,请使用以下命令:

npx @modelcontextprotocol/inspector cargo run --cli --method tools/call --tool-name add --tool-arg a=1 b=2

官方SDK

MCP提供多种语言的官方SDK:

关键要点

  • 使用特定语言的SDK设置MCP开发环境很简单
  • 构建MCP服务器涉及创建和注册具有清晰模式的工具
  • 测试和调试对于可靠的MCP实施至关重要

样品

作业

使用您选择的工具创建一个简单的MCP服务器:

  1. 用您喜欢的语言(.NET、Java、Python、TypeScript或Rust)实现该工具。
  2. 定义输入参数和返回值。
  3. 运行检查器工具以确保服务器按预期工作。
  4. 使用各种输入测试实现。

解决方案

解决方案

额外资源

下一个是什么

下一页: MCP客户端入门