Skip to content

Latest commit

 

History

History
1378 lines (1076 loc) · 38.5 KB

File metadata and controls

1378 lines (1076 loc) · 38.5 KB

開始使用 MCP

歡迎踏出使用模型上下文協議 (MCP) 的第一步!無論您是 MCP 的新手,還是希望加深理解,本指南將引導您完成基本的設置和開發過程。您將了解 MCP 如何實現 AI 模型與應用程式之間的無縫整合,並學習如何快速準備環境以構建和測試基於 MCP 的解決方案。

簡而言之:如果您開發 AI 應用程式,您可能知道可以向大型語言模型 (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 伺服器通常包括:

  • 伺服器配置:設置端口、身份驗證和其他設置
  • 資源:提供給 LLM 的數據和上下文
  • 工具:模型可以調用的功能
  • 提示:生成或結構化文本的模板

以下是 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 提供了幫助您測試和調試伺服器的工具:

  • Inspector 工具:這個圖形界面允許您連接到伺服器並測試工具、提示和資源。
  • curl:您也可以使用命令行工具如 curl 或其他能創建和運行 HTTP 命令的客戶端連接到伺服器。

使用 MCP Inspector

MCP Inspector 是一個可視化測試工具,幫助您:

  1. 發現伺服器功能:自動檢測可用的資源、工具和提示
  2. 測試工具執行:嘗試不同的參數並即時查看響應
  3. 查看伺服器元數據:檢查伺服器信息、架構和配置
# ex TypeScript, installing and running MCP Inspector
npx @modelcontextprotocol/inspector node build/index.js

運行上述命令後,MCP Inspector 將在您的瀏覽器中啟動本地網頁界面。您可以看到一個儀表板,顯示已註冊的 MCP 伺服器及其可用工具、資源和提示。界面允許您交互式測試工具執行、檢查伺服器元數據並查看即時響應,從而更輕鬆地驗證和調試 MCP 伺服器的實現。

以下是界面可能的樣子:

MCP Inspector 伺服器連接

常見設置問題及解決方案

問題 可能的解決方案
連接被拒絕 檢查伺服器是否正在運行以及端口是否正確
工具執行錯誤 檢查參數驗證和錯誤處理
身份驗證失敗 驗證 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>

Rust

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

Rust

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": {
    "start": "tsc && node ./build/index.js",
    "build": "tsc && 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"
  }
}

創建 tsconfig.json 文件,內容如下:

{
  "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

創建文件 server.py

touch server.py

.NET

安裝所需的 NuGet 套件:

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

Java

對於 Java Spring Boot 項目,項目結構會自動創建。

Rust

對於 Rust,當您運行 cargo init 時,會默認創建 src/main.rs 文件。打開該文件並刪除默認代碼。

-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/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/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/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/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/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

Rust

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 結構以創建伺服器的新實例,並實現伺服器處理程序以提供伺服器信息。

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

您的工具接收參數 ab,並運行一個函數,生成以下形式的響應:

{
  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,接收參數 ap,均為整數。
  • 創建了一個名為 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

工具已在前一步中創建。

Rust

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

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 Inspector 時,請使用 mcp dev server.py,它會自動啟動 Inspector 並提供所需的代理會話令牌。如果使用 mcp run server.py,您需要手動啟動 Inspector 並配置連接。

.NET

確保您在項目目錄中:

cd McpCalculatorServer
dotnet run

Java

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

Rust

運行以下命令以格式化並運行伺服器:

cargo fmt
cargo run

-8- 使用 Inspector 運行

Inspector 是一個很棒的工具,可以啟動您的伺服器並讓您與之交互,以測試其是否正常工作。讓我們啟動它:

Note

在 "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 允許配置運行腳本的命令和參數,請確保在 "Command" 欄位中設置 python,並在 "Arguments" 中設置 server.py。這樣可以確保腳本正確運行。

.NET

確保您在項目目錄中:

cd McpCalculatorServer
npx @modelcontextprotocol/inspector dotnet run

Java

確保您的計算器伺服器正在運行,然後運行 Inspector:

npx @modelcontextprotocol/inspector

在 Inspector 網頁界面中:

  1. 選擇 "SSE" 作為傳輸類型
  2. 將 URL 設置為:http://localhost:8080/sse
  3. 點擊 "Connect" 連接

你現在已成功連接到伺服器
Java 伺服器測試部分已完成

下一部分將介紹如何與伺服器互動。

你應該會看到以下的用戶界面:

連接

  1. 按下「連接」按鈕以連接到伺服器
    當你成功連接到伺服器後,應該會看到以下畫面:

    已連接

  2. 選擇「工具」並點擊「listTools」,你應該會看到「新增」出現,選擇「新增」並填寫參數值。

    你應該會看到以下回應,也就是「新增」工具的結果:

    執行新增工具的結果

恭喜你,成功建立並運行了你的第一個伺服器!

Rust

要使用 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 客戶端

免責聲明
本文件已使用人工智能翻譯服務 Co-op Translator 進行翻譯。儘管我們致力於提供準確的翻譯,請注意自動翻譯可能包含錯誤或不準確之處。原始語言的文件應被視為權威來源。對於重要信息,建議使用專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解釋概不負責。