Skip to content

Latest commit

 

History

History
1378 lines (1076 loc) · 49.4 KB

File metadata and controls

1378 lines (1076 loc) · 49.4 KB

Початок роботи з MCP

Ласкаво просимо до ваших перших кроків із Model Context Protocol (MCP)! Незалежно від того, чи ви новачок у MCP, чи хочете поглибити свої знання, цей посібник проведе вас через основні етапи налаштування та розробки. Ви дізнаєтеся, як MCP забезпечує безшовну інтеграцію між AI-моделями та додатками, а також як швидко підготувати середовище для створення та тестування рішень на основі MCP.

Коротко: Якщо ви створюєте AI-додатки, ви знаєте, що можете додавати інструменти та інші ресурси до вашої LLM (великої мовної моделі), щоб зробити її більш обізнаною. Однак, якщо ви розмістите ці інструменти та ресурси на сервері, можливості додатка та сервера можуть використовуватися будь-яким клієнтом з LLM або без нього.

Огляд

Цей урок надає практичні рекомендації щодо налаштування середовищ MCP та створення ваших перших додатків MCP. Ви дізнаєтеся, як налаштувати необхідні інструменти та фреймворки, створювати базові MCP-сервери, створювати хост-додатки та тестувати ваші реалізації.

Model Context Protocol (MCP) — це відкритий протокол, який стандартизує спосіб, у який додатки надають контекст LLM. Уявіть MCP як порт USB-C для AI-додатків — він забезпечує стандартизований спосіб підключення AI-моделей до різних джерел даних та інструментів.

Навчальні цілі

До кінця цього уроку ви зможете:

  • Налаштувати середовища розробки для MCP у C#, Java, Python, TypeScript та Rust
  • Створювати та розгортати базові 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 файл 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/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}!`
    }]
  })
);

Ваш інструмент приймає параметри 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

Інструменти вже були створені на попередньому кроці.

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- Запуск за допомогою інспектора

Інспектор — це чудовий інструмент, який може запустити ваш сервер і дозволяє взаємодіяти з ним, щоб перевірити, чи він працює. Давайте його запустимо:

Note

У полі "command" може бути інша команда, оскільки вона містить команду для запуску сервера з вашим конкретним середовищем виконання.

TypeScript

npx @modelcontextprotocol/inspector node build/index.js

або додайте це до вашого package.json так: "inspector": "npx @modelcontextprotocol/inspector node build/index.js" і потім виконайте npm run inspector.

Python використовує Node.js-інструмент під назвою inspector. Можна викликати цей інструмент так:

mcp dev server.py

Однак він не реалізує всі методи, доступні в інструменті, тому рекомендується запускати інструмент Node.js безпосередньо, як показано нижче:

npx @modelcontextprotocol/inspector mcp run server.py

Якщо ви використовуєте інструмент або IDE, що дозволяє налаштовувати команди та аргументи для запуску скриптів, переконайтеся, що в полі Command встановлено python, а в полі Argumentsserver.py. Це забезпечить правильний запуск скрипта.

.NET

Переконайтеся, що ви у вашій директорії проекту:

cd McpCalculatorServer
npx @modelcontextprotocol/inspector dotnet run

Java

Переконайтеся, що сервер калькулятора запущений. Потім запустіть інспектор:

npx @modelcontextprotocol/inspector

У веб-інтерфейсі інспектора:

  1. Виберіть "SSE" як тип транспорту
  2. Встановіть URL: http://localhost:8080/sse
  3. Натисніть "Connect" Підключення

Ви тепер підключені до сервера
Розділ тестування Java-сервера завершено

Наступний розділ стосується взаємодії з сервером.

Ви повинні побачити такий інтерфейс користувача:

Підключення

  1. Підключіться до сервера, натиснувши кнопку "Connect".
    Після підключення до сервера ви повинні побачити наступне:

    Підключено

  2. Оберіть "Tools" і "listTools", ви повинні побачити "Add". Виберіть "Add" і заповніть значення параметрів.

    Ви повинні побачити наступну відповідь, тобто результат роботи інструменту "add":

    Результат виконання add

Вітаємо, ви успішно створили та запустили свій перший сервер!

Rust

Щоб запустити сервер Rust за допомогою MCP Inspector CLI, використовуйте наступну команду:

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

Офіційні SDK

MCP надає офіційні SDK для кількох мов:

  • C# SDK - Підтримується у співпраці з Microsoft
  • Java SDK - Підтримується у співпраці з Spring AI
  • TypeScript SDK - Офіційна реалізація TypeScript
  • Python SDK - Офіційна реалізація Python
  • Kotlin SDK - Офіційна реалізація Kotlin
  • Swift SDK - Підтримується у співпраці з Loopwork AI
  • Rust SDK - Офіційна реалізація Rust

Основні висновки

  • Налаштування середовища розробки MCP є простим завдяки SDK для конкретних мов.
  • Створення серверів MCP включає створення та реєстрацію інструментів із чіткими схемами.
  • Тестування та налагодження є важливими для надійної реалізації MCP.

Приклади

Завдання

Створіть простий сервер MCP з інструментом на ваш вибір:

  1. Реалізуйте інструмент на вашій улюбленій мові (.NET, Java, Python, TypeScript або Rust).
  2. Визначте вхідні параметри та значення, що повертаються.
  3. Запустіть інструмент інспектора, щоб переконатися, що сервер працює належним чином.
  4. Протестуйте реалізацію з різними вхідними даними.

Рішення

Рішення

Додаткові ресурси

Що далі

Далі: Початок роботи з клієнтами MCP

Відмова від відповідальності:
Цей документ було перекладено за допомогою сервісу автоматичного перекладу Co-op Translator. Хоча ми прагнемо до точності, звертаємо вашу увагу, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критично важливої інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникли внаслідок використання цього перекладу.