Skip to content

Latest commit

 

History

History
1379 lines (1077 loc) · 41.2 KB

File metadata and controls

1379 lines (1077 loc) · 41.2 KB

Introdução ao MCP

Bem-vindo aos seus primeiros passos com o Model Context Protocol (MCP)! Quer seja novo no MCP ou esteja a procurar aprofundar o seu conhecimento, este guia irá orientá-lo no processo essencial de configuração e desenvolvimento. Descubra como o MCP permite uma integração perfeita entre modelos de IA e aplicações, e aprenda a preparar rapidamente o seu ambiente para criar e testar soluções baseadas no MCP.

Resumo: Se desenvolve aplicações de IA, sabe que pode adicionar ferramentas e outros recursos ao seu LLM (modelo de linguagem grande) para torná-lo mais inteligente. No entanto, se colocar essas ferramentas e recursos num servidor, as capacidades da aplicação e do servidor podem ser utilizadas por qualquer cliente, com ou sem um LLM.

Visão Geral

Esta lição fornece orientações práticas para configurar ambientes MCP e criar as suas primeiras aplicações MCP. Aprenderá a configurar as ferramentas e frameworks necessários, construir servidores MCP básicos, criar aplicações anfitriãs e testar as suas implementações.

O Model Context Protocol (MCP) é um protocolo aberto que padroniza como as aplicações fornecem contexto aos LLMs. Pense no MCP como uma porta USB-C para aplicações de IA - oferece uma forma padronizada de conectar modelos de IA a diferentes fontes de dados e ferramentas.

Objetivos de Aprendizagem

No final desta lição, será capaz de:

  • Configurar ambientes de desenvolvimento para MCP em C#, Java, Python, TypeScript e Rust
  • Construir e implementar servidores MCP básicos com funcionalidades personalizadas (recursos, prompts e ferramentas)
  • Criar aplicações anfitriãs que se conectam a servidores MCP
  • Testar e depurar implementações MCP

Configuração do Ambiente MCP

Antes de começar a trabalhar com MCP, é importante preparar o seu ambiente de desenvolvimento e compreender o fluxo de trabalho básico. Esta secção irá orientá-lo nos passos iniciais de configuração para garantir um início tranquilo com MCP.

Pré-requisitos

Antes de mergulhar no desenvolvimento MCP, certifique-se de que tem:

  • Ambiente de Desenvolvimento: Para a linguagem escolhida (C#, Java, Python, TypeScript ou Rust)
  • IDE/Editor: Visual Studio, Visual Studio Code, IntelliJ, Eclipse, PyCharm ou qualquer editor de código moderno
  • Gestores de Pacotes: NuGet, Maven/Gradle, pip, npm/yarn ou Cargo
  • Chaves de API: Para quaisquer serviços de IA que planeia utilizar nas suas aplicações anfitriãs

Estrutura Básica de um Servidor MCP

Um servidor MCP normalmente inclui:

  • Configuração do Servidor: Configuração de porta, autenticação e outras definições
  • Recursos: Dados e contexto disponibilizados aos LLMs
  • Ferramentas: Funcionalidades que os modelos podem invocar
  • Prompts: Modelos para gerar ou estruturar texto

Aqui está um exemplo simplificado em 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);

No código acima:

  • Importamos as classes necessárias do SDK MCP para TypeScript.
  • Criamos e configuramos uma nova instância de servidor MCP.
  • Registamos uma ferramenta personalizada (calculator) com uma função de manipulação.
  • Iniciamos o servidor para escutar pedidos MCP.

Testar e Depurar

Antes de começar a testar o seu servidor MCP, é importante compreender as ferramentas disponíveis e as melhores práticas para depuração. Testes eficazes garantem que o servidor se comporta conforme esperado e ajudam a identificar e resolver problemas rapidamente. A secção seguinte descreve abordagens recomendadas para validar a sua implementação MCP.

O MCP fornece ferramentas para ajudar a testar e depurar os seus servidores:

  • Ferramenta Inspector, uma interface gráfica que permite conectar-se ao servidor e testar ferramentas, prompts e recursos.
  • curl, também pode conectar-se ao servidor usando uma ferramenta de linha de comando como curl ou outros clientes que podem criar e executar comandos HTTP.

Utilizar o MCP Inspector

O MCP Inspector é uma ferramenta visual de teste que ajuda a:

  1. Descobrir Capacidades do Servidor: Detetar automaticamente recursos, ferramentas e prompts disponíveis
  2. Testar Execução de Ferramentas: Experimentar diferentes parâmetros e ver respostas em tempo real
  3. Visualizar Metadados do Servidor: Examinar informações do servidor, esquemas e configurações
# ex TypeScript, installing and running MCP Inspector
npx @modelcontextprotocol/inspector node build/index.js

Ao executar os comandos acima, o MCP Inspector irá lançar uma interface web local no seu navegador. Pode esperar ver um painel que exibe os servidores MCP registados, as ferramentas, recursos e prompts disponíveis. A interface permite testar interativamente a execução de ferramentas, inspecionar metadados do servidor e visualizar respostas em tempo real, facilitando a validação e depuração das implementações do servidor MCP.

Aqui está uma captura de ecrã de como pode parecer:

Conexão ao servidor MCP Inspector

Problemas Comuns de Configuração e Soluções

Problema Solução Possível
Conexão recusada Verifique se o servidor está em execução e se a porta está correta
Erros na execução de ferramentas Revise a validação de parâmetros e o tratamento de erros
Falhas de autenticação Verifique as chaves de API e permissões
Erros de validação de esquema Certifique-se de que os parâmetros correspondem ao esquema definido
Servidor não inicia Verifique conflitos de porta ou dependências ausentes
Erros de CORS Configure os cabeçalhos CORS adequados para pedidos de origem cruzada
Problemas de autenticação Verifique a validade do token e permissões

Desenvolvimento Local

Para desenvolvimento e teste local, pode executar servidores MCP diretamente na sua máquina:

  1. Iniciar o processo do servidor: Execute a aplicação do servidor MCP
  2. Configurar rede: Certifique-se de que o servidor está acessível na porta esperada
  3. Conectar clientes: Utilize URLs de conexão local como http://localhost:3000
# Example: Running a TypeScript MCP server locally
npm run start
# Server running at http://localhost:3000

Construir o seu primeiro Servidor MCP

Já abordámos os Conceitos Básicos numa lição anterior, agora é hora de colocar esse conhecimento em prática.

O que um servidor pode fazer

Antes de começar a escrever código, vamos lembrar-nos do que um servidor pode fazer:

Um servidor MCP pode, por exemplo:

  • Aceder a ficheiros e bases de dados locais
  • Conectar-se a APIs remotas
  • Realizar cálculos
  • Integrar-se com outras ferramentas e serviços
  • Fornecer uma interface de utilizador para interação

Ótimo, agora que sabemos o que podemos fazer, vamos começar a programar.

Exercício: Criar um servidor

Para criar um servidor, precisa seguir estes passos:

  • Instalar o SDK MCP.
  • Criar um projeto e configurar a estrutura do projeto.
  • Escrever o código do servidor.
  • Testar o servidor.

-1- Criar projeto

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

Para Java, crie um projeto 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

Extraia o ficheiro zip:

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

Adicione a seguinte configuração completa ao seu ficheiro 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- Adicionar dependências

Agora que criou o seu projeto, vamos adicionar as dependências:

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- Criar ficheiros do projeto

TypeScript

Abra o ficheiro package.json e substitua o conteúdo pelo seguinte para garantir que pode construir e executar o servidor:

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

Crie um tsconfig.json com o seguinte conteúdo:

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

Crie um diretório para o seu código fonte:

mkdir src
touch src/index.ts

Python

Crie um ficheiro server.py

touch server.py

.NET

Instale os pacotes NuGet necessários:

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

Java

Para projetos Java Spring Boot, a estrutura do projeto é criada automaticamente.

Rust

Para Rust, um ficheiro src/main.rs é criado por padrão quando executa cargo init. Abra o ficheiro e elimine o código padrão.

-4- Criar código do servidor

TypeScript

Crie um ficheiro index.ts e adicione o seguinte código:

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

Agora tem um servidor, mas ele não faz muito. Vamos corrigir isso.

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

Para Java, crie os componentes principais do servidor. Primeiro, modifique a classe principal da aplicação:

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

Crie o serviço de calculadora 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);
    }
}

Componentes opcionais para um serviço pronto para produção:

Crie uma configuração de inicialização 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");
        };
    }
}

Crie um controlador de saúde 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);
    }
}

Crie um manipulador de exceções 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; }
    }
}

Crie um banner personalizado src/main/resources/banner.txt:

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

Rust

Adicione o seguinte código ao topo do ficheiro src/main.rs. Isto importa as bibliotecas e módulos necessários para o seu servidor 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;

O servidor de calculadora será simples e poderá somar dois números. Vamos criar uma estrutura para representar o pedido de calculadora.

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

Em seguida, crie uma estrutura para representar o servidor de calculadora. Esta estrutura irá conter o router de ferramentas, que é usado para registar ferramentas.

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

Agora, podemos implementar a estrutura Calculator para criar uma nova instância do servidor e implementar o manipulador do servidor para fornecer informações sobre o servidor.

#[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()
        }
    }
}

Finalmente, precisamos implementar a função principal para iniciar o servidor. Esta função irá criar uma instância da estrutura Calculator e servi-la através de entrada/saída padrão.

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

O servidor está agora configurado para fornecer informações básicas sobre si mesmo. A seguir, adicionaremos uma ferramenta para realizar somas.

-5- Adicionar uma ferramenta e um recurso

Adicione uma ferramenta e um recurso adicionando o seguinte código:

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 sua ferramenta recebe os parâmetros a e b e executa uma função que produz uma resposta no formato:

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

O seu recurso é acessado através de uma string "greeting" e recebe um parâmetro name, produzindo uma resposta semelhante à da ferramenta:

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

No código acima:

  • Definimos uma ferramenta add que recebe os parâmetros a e p, ambos inteiros.
  • Criámos um recurso chamado greeting que recebe o parâmetro name.

.NET

Adicione isto ao seu ficheiro Program.cs:

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

Java

As ferramentas já foram criadas no passo anterior.

Rust

Adicione uma nova ferramenta dentro do bloco impl Calculator:

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

-6- Código final

Vamos adicionar o último código necessário para que o servidor possa iniciar:

TypeScript

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

Aqui está o código completo:

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

Crie um ficheiro Program.cs com o seguinte conteúdo:

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

A sua classe principal completa da aplicação deve parecer com isto:

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

O código final para o servidor Rust deve parecer com isto:

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- Testar o servidor

Inicie o servidor com o seguinte comando:

TypeScript

npm run build

Python

mcp run server.py

Para usar o MCP Inspector, utilize mcp dev server.py, que lança automaticamente o Inspector e fornece o token de sessão proxy necessário. Se usar mcp run server.py, precisará iniciar manualmente o Inspector e configurar a conexão.

.NET

Certifique-se de que está no diretório do seu projeto:

cd McpCalculatorServer
dotnet run

Java

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

Rust

Execute os seguintes comandos para formatar e executar o servidor:

cargo fmt
cargo run

-8- Executar usando o inspector

O inspector é uma ótima ferramenta que pode iniciar o seu servidor e permite interagir com ele para testar se funciona. Vamos iniciá-lo:

Note

Pode parecer diferente no campo "command", pois contém o comando para executar um servidor com o seu runtime específico.

TypeScript

npx @modelcontextprotocol/inspector node build/index.js

ou adicione ao seu package.json assim: "inspector": "npx @modelcontextprotocol/inspector node build/index.js" e depois execute npm run inspector

Python utiliza uma ferramenta Node.js chamada inspector. É possível chamar essa ferramenta assim:

mcp dev server.py

No entanto, não implementa todos os métodos disponíveis na ferramenta, por isso é recomendado executar diretamente a ferramenta Node.js como abaixo:

npx @modelcontextprotocol/inspector mcp run server.py

Se estiver a usar uma ferramenta ou IDE que permite configurar comandos e argumentos para executar scripts, certifique-se de definir python no campo Command e server.py como Arguments. Isto garante que o script é executado corretamente.

.NET

Certifique-se de que está no diretório do seu projeto:

cd McpCalculatorServer
npx @modelcontextprotocol/inspector dotnet run

Java

Certifique-se de que o servidor de calculadora está em execução. Depois, execute o inspector:

npx @modelcontextprotocol/inspector

Na interface web do inspector:

  1. Selecione "SSE" como o tipo de transporte
  2. Defina o URL como: http://localhost:8080/sse
  3. Clique em "Connect" Conectar

Agora está ligado ao servidor
A secção de testes do servidor Java está concluída

A próxima secção é sobre interagir com o servidor.

Deverá ver a seguinte interface de utilizador:

Conectar

  1. Ligue-se ao servidor selecionando o botão "Conectar".
    Assim que estiver ligado ao servidor, deverá ver o seguinte:

    Ligado

  2. Selecione "Ferramentas" e "listarFerramentas". Deverá ver a opção "Adicionar" aparecer. Selecione "Adicionar" e preencha os valores dos parâmetros.

    Deverá ver a seguinte resposta, ou seja, um resultado da ferramenta "adicionar":

    Resultado de executar adicionar

Parabéns, conseguiu criar e executar o seu primeiro servidor!

Rust

Para executar o servidor Rust com o MCP Inspector CLI, utilize o seguinte comando:

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

SDKs Oficiais

O MCP fornece SDKs oficiais para várias linguagens:

  • C# SDK - Mantido em colaboração com a Microsoft
  • Java SDK - Mantido em colaboração com a Spring AI
  • TypeScript SDK - A implementação oficial em TypeScript
  • Python SDK - A implementação oficial em Python
  • Kotlin SDK - A implementação oficial em Kotlin
  • Swift SDK - Mantido em colaboração com a Loopwork AI
  • Rust SDK - A implementação oficial em Rust

Pontos-chave

  • Configurar um ambiente de desenvolvimento MCP é simples com os SDKs específicos para cada linguagem.
  • Construir servidores MCP envolve criar e registar ferramentas com esquemas claros.
  • Testar e depurar são etapas essenciais para implementações MCP fiáveis.

Exemplos

Tarefa

Crie um servidor MCP simples com uma ferramenta à sua escolha:

  1. Implemente a ferramenta na sua linguagem preferida (.NET, Java, Python, TypeScript ou Rust).
  2. Defina os parâmetros de entrada e os valores de retorno.
  3. Execute a ferramenta de inspeção para garantir que o servidor funciona como esperado.
  4. Teste a implementação com vários inputs.

Solução

Solução

Recursos Adicionais

O que vem a seguir

Próximo: Introdução aos Clientes MCP

Aviso Legal:
Este documento foi traduzido utilizando o serviço de tradução por IA Co-op Translator. Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.