01 First Server

Module
Getting Started
Progress
5%

Getting Started with MCP

Welcome to your first steps with the Model Context Protocol (MCP)!

Whether you're new to MCP or looking to deepen your understanding, this guide will walk you through the essential setup and development process.

You'll discover how MCP enables seamless integration between AI models and applications, and learn how to quickly get your environment ready for building and testing MCP-powered solutions.

> TLDR; If you build AI apps, you know that you can add tools and other resources to your LLM (large language model), to make the LLM more knowledgeable.

However if you place those tools and resources on a server, the app and the server capabilities can be used by any client with/without an LLM.

Overview

This lesson provides practical guidance on setting up MCP environments and building your first MCP applications.

You'll learn how to set up the necessary tools and frameworks, build basic MCP servers, create host applications, and test your implementations.

The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs.

Think of MCP like a USB-C port for AI applications - it provides a standardized way to connect AI models to different data sources and tools.

Learning Objectives

By the end of this lesson, you will be able to:

  • Set up development environments for MCP in C#, Java, Python, TypeScript, and Rust
  • Build and deploy basic MCP servers with custom features (resources, prompts, and tools)
  • Create host applications that connect to MCP servers
  • Test and debug MCP implementations
  • Setting Up Your MCP Environment

    Before you begin working with MCP, it's important to prepare your development environment and understand the basic workflow. This section will guide you through the initial setup steps to ensure a smooth start with MCP.

    Prerequisites

    Before diving into MCP development, ensure you have:

  • Development Environment: For your chosen language (C#, Java, Python, TypeScript, or Rust)
  • IDE/Editor: Visual Studio, Visual Studio Code, IntelliJ, Eclipse, PyCharm, or any modern code editor
  • Package Managers: NuGet, Maven/Gradle, pip, npm/yarn, or Cargo
  • API Keys: For any AI services you plan to use in your host applications
  • Basic MCP Server Structure

    An MCP server typically includes:

  • Server Configuration: Setup port, authentication, and other settings
  • Resources: Data and context made available to LLMs
  • Tools: Functionality that models can invoke
  • Prompts: Templates for generating or structuring text
  • Here's a simplified example in 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);
    
    

    In the preceding code we:

  • Import the necessary classes from the MCP TypeScript SDK.
  • Create and configure a new MCP server instance.
  • Register a custom tool (calculator) with a handler function.
  • Start the server to listen for incoming MCP requests.
  • Testing and Debugging

    Before you begin testing your MCP server, it's important to understand the available tools and best practices for debugging.

    Effective testing ensures your server behaves as expected and helps you quickly identify and resolve issues.

    The following section outlines recommended approaches for validating your MCP implementation.

    MCP provides tools to help you test and debug your servers:

  • Inspector tool, this graphical interface allows you to connect to your server and test your tools, prompts and resources.
  • curl, you can also connect to your server using a command line tool like curl or other clients than can create and run HTTP commands.
  • Using MCP Inspector

    The MCP Inspector is a visual testing tool that helps you:

    1. Discover Server Capabilities: Automatically detect available resources, tools, and prompts

    2. Test Tool Execution: Try different parameters and see responses in real-time

    3. View Server Metadata: Examine server info, schemas, and configurations

    
    # ex TypeScript, installing and running MCP Inspector
    
    npx @modelcontextprotocol/inspector node build/index.js
    
    

    When you run the above commands, the MCP Inspector will launch a local web interface in your browser.

    You can expect to see a dashboard displaying your registered MCP servers, their available tools, resources, and prompts.

    The interface allows you to interactively test tool execution, inspect server metadata, and view real-time responses, making it easier to validate and debug your MCP server implementations.

    Here's a screenshot of what it can look like:

    Common Setup Issues and Solutions

    | Issue | Possible Solution |

    |-------|-------------------|

    | Connection refused | Check if server is running and port is correct |

    | Tool execution errors | Review parameter validation and error handling |

    | Authentication failures | Verify API keys and permissions |

    | Schema validation errors | Ensure parameters match the defined schema |

    | Server not starting | Check for port conflicts or missing dependencies |

    | CORS errors | Configure proper CORS headers for cross-origin requests |

    | Authentication issues | Verify token validity and permissions |

    Local Development

    For local development and testing, you can run MCP servers directly on your machine:

    1. Start the server process: Run your MCP server application

    2. Configure networking: Ensure the server is accessible on the expected port

    3. Connect clients: Use local connection URLs like http://localhost:3000

    
    # Example: Running a TypeScript MCP server locally
    
    npm run start
    
    # Server running at http://localhost:3000
    
    

    Building your first MCP Server

    We've covered Core concepts in a previous lesson, now it's time to put that knowledge to work.

    What a server can do

    Before we start writing code, let's just remind ourselves what a server can do:

    An MCP server can for example:

  • Access local files and databases
  • Connect to remote APIs
  • Perform computations
  • Integrate with other tools and services
  • Provide a user interface for interaction
  • Great, now that we know what we can do for it, let's start coding.

    Exercise: Creating a server

    To create a server, you need to follow these steps:

  • Install the MCP SDK.
  • Create a a project and set up the project structure.
  • Write the server code.
  • Test the server.
  • -1- Create project

    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

    For Java, create a Spring Boot project:

    
    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
    
    

    Extract the zip file:

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

    Add the following complete configuration to your *pom.xml* file:

    
    <?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- Add dependencies

    Now that you have your project created, let's add dependencies next:

    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- Create project files

    TypeScript

    Open the *package.json* file and replace the content with the following to ensure you can build and run the server:

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

    Create a *tsconfig.json* with the following content:

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

    Create a directory for your source code:

    
    mkdir src
    
    touch src/index.ts
    
    
    Python

    Create a file *server.py*

    
    touch server.py
    
    
    .NET

    Install the required NuGet packages:

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

    For Java Spring Boot projects, the project structure is created automatically.

    Rust

    For Rust, a *src/main.rs* file is created by default when you run cargo init. Open the file and delete the default code.

    -4- Create server code

    TypeScript

    Create a file *index.ts* and add the following code:

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

    Now you have a server, but it doesn't do much, let' fix that.

    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

    For Java, create the core server components. First, modify the main application class:

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

    Create the calculator service *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);
    
        }
    
    }
    
    

    Optional components for a production-ready service:

    Create a startup configuration *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");
    
            };
    
        }
    
    }
    
    

    Create a health controller *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);
    
        }
    
    }
    
    

    Create an exception handler *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; }
    
        }
    
    }
    
    

    Create a custom banner *src/main/resources/banner.txt*:

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

    Rust

    Add the following code to the top of the *src/main.rs* file. This imports the necessary libraries and modules for your MCP server.

    
    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;
    
    

    The calculator server will be a simple one that can add two numbers together. Let's create a struct to represent the calculator request.

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

    Next, create a struct to represent the calculator server. This struct will hold the tool router, which is used to register tools.

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

    Now, we can implement the Calculator struct to create a new instance of the server and implement the server handler to provide server information.

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

    Finally, we need to implement the main function to start the server.

    This function will create an instance of the Calculator struct and serve it over standard input/output.

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

    The server is now set up to provide basic information about itself. Next, we will add a tool to perform addition.

    -5- Adding a tool and a resource

    Add a tool and a resource by adding the following code:

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

    Your tool takes parameters a and b and runs a function that produces a response on the form:

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

    Your resource is accessed through a string "greeting" and takes a parameter name and produces a similar response to the tool:

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

    In the preceding code we've:

  • Defined a tool add that takes parameters a and b, both integers.
  • Created a resource called greeting that takes parameter name.
  • .NET

    Add this to your Program.cs file:

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

    The tools have already been created in the previous step.

    Rust

    Add a new tool inside the impl Calculator block:

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

    -6- Final code

    Let's add the last code we need so the server can start:

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

    Here's the full code:

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

    Create a Program.cs file with the following content:

    
    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

    Your complete main application class should look like this:

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

    The final code for the Rust server should look like this:

    
    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- Test the server

    Start the server with the following command:

    TypeScript
    
    npm run build
    
    
    Python
    
    mcp run server.py
    
    

    > To use MCP Inspector, use mcp dev server.py which automatically launches the Inspector and provides the required proxy session token.

    If using mcp run server.py, you’ll need to manually start the Inspector and configure the connection.

    .NET

    Make sure you're in your project directory:

    
    cd McpCalculatorServer
    
    dotnet run
    
    
    Java
    
    ./mvnw clean install -DskipTests
    
    java -jar target/calculator-server-0.0.1-SNAPSHOT.jar
    
    
    Rust

    Run the following commands to format and run the server:

    
    cargo fmt
    
    cargo run
    
    

    -8- Run using the inspector

    The inspector is a great tool that can start up your server and lets you interact with it so you can test that it works. Let's start it up:

    > [!NOTE]

    > it might look different in the "command" field as it contains the command for running a server with your specific runtime/

    TypeScript
    
    npx @modelcontextprotocol/inspector node build/index.js
    
    

    or add it to your *package.json* like so: "inspector": "npx @modelcontextprotocol/inspector node build/index.js" and then run npm run inspector

    Python

    Python wraps a Node.js tool called inspector. It's possible to call said tool like so:

    
    mcp dev server.py
    
    

    However, it doesn't implement all the methods available on the tool so you're recommended to run the Node.js tool directly like below:

    
    npx @modelcontextprotocol/inspector mcp run server.py
    
    

    If you're using a tool or IDE that allows you to configure commands and arguments for running scripts,

    make sure to set python in the Command field and server.py as Arguments.

    This ensures the script runs correctly.

    .NET

    Make sure you're in your project directory:

    
    cd McpCalculatorServer
    
    npx @modelcontextprotocol/inspector dotnet run
    
    
    Java

    Ensure you calculator server is running

    The run the inspector:

    
    npx @modelcontextprotocol/inspector
    
    

    In the inspector web interface:

    1. Select "SSE" as the transport type

    2. Set the URL to: http://localhost:8080/sse

    3. Click "Connect"

    You're now connected to the server

    The Java server testing section is completed now

    The next section it's about interacting with the server.

    You should see the following user interface:

    1. Connect to the server by selecting the Connect button

    Once you connect to the server, you should now see the following:

    !Connected

    1. Select "Tools" and "listTools", you should see "Add" show up, select "Add" and fill in the parameter values.

    You should see the following response, i.e a result from "add" tool:

    !Result of running add

    Congrats, you've managed to create and run your first server!

    Rust

    To run the Rust server with the MCP Inspector CLI, use the following command:

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

    Official SDKs

    MCP provides official SDKs for multiple languages:

  • C# SDK - Maintained in collaboration with Microsoft
  • Java SDK - Maintained in collaboration with Spring AI
  • TypeScript SDK - The official TypeScript implementation
  • Python SDK - The official Python implementation
  • Kotlin SDK - The official Kotlin implementation
  • Swift SDK - Maintained in collaboration with Loopwork AI
  • Rust SDK - The official Rust implementation
  • Key Takeaways

  • Setting up an MCP development environment is straightforward with language-specific SDKs
  • Building MCP servers involves creating and registering tools with clear schemas
  • Testing and debugging are essential for reliable MCP implementations
  • Samples

  • Java Calculator
  • .Net Calculator
  • JavaScript Calculator
  • TypeScript Calculator
  • Python Calculator
  • Rust Calculator
  • Assignment

    Create a simple MCP server with a tool of your choice:

    1. Implement the tool in your preferred language (.NET, Java, Python, TypeScript, or Rust).

    2. Define input parameters and return values.

    3. Run the inspector tool to ensure the server works as intended.

    4. Test the implementation with various inputs.

    Solution

    Additional Resources

  • Build Agents using Model Context Protocol on Azure
  • Remote MCP with Azure Container Apps (Node.js/TypeScript/JavaScript)
  • .NET OpenAI MCP Agent
  • What's next

    Next: Getting Started with MCP Clients

    MCP μ‹œμž‘ν•˜κΈ°

    Model Context Protocol (MCP)와 ν•¨κ»˜ν•˜λŠ” 첫 κ±ΈμŒμ— μ˜€μ‹  것을 ν™˜μ˜ν•©λ‹ˆλ‹€! MCPκ°€ μ²˜μŒμ΄λ“  이해도λ₯Ό λ†’μ΄κ³ μž ν•˜λ“ , 이 κ°€μ΄λ“œλŠ” ν•„μˆ˜ μ„€μ • 및 개발 과정을 μ•ˆλ‚΄ν•©λ‹ˆλ‹€. MCPκ°€ AI λͺ¨λΈκ³Ό μ• ν”Œλ¦¬μΌ€μ΄μ…˜ κ°„μ˜ μ›ν™œν•œ 톡합을 μ–΄λ–»κ²Œ κ°€λŠ₯ν•˜κ²Œ ν•˜λŠ”μ§€ μ‚΄νŽ΄λ³΄κ³ , MCP 기반 μ†”λ£¨μ…˜ ꡬ좕 및 ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ ν™˜κ²½μ„ λΉ λ₯΄κ²Œ μ€€λΉ„ν•˜λŠ” 방법을 배우게 λ©λ‹ˆλ‹€.

    > TLDR; AI μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ κ°œλ°œν•œλ‹€λ©΄ LLM(λŒ€ν˜• μ–Έμ–΄ λͺ¨λΈ)에 도ꡬ와 기타 λ¦¬μ†ŒμŠ€λ₯Ό μΆ”κ°€ν•˜μ—¬ LLM을 더 λ˜‘λ˜‘ν•˜κ²Œ λ§Œλ“€ 수 μžˆλ‹€λŠ” 것을 μ•„μ‹€ κ²λ‹ˆλ‹€. ν•˜μ§€λ§Œ 도ꡬ와 λ¦¬μ†ŒμŠ€λ₯Ό μ„œλ²„μ— λ°°μΉ˜ν•˜λ©΄ μ•±κ³Ό μ„œλ²„ κΈ°λŠ₯은 LLM이 μžˆλ“  μ—†λ“  λͺ¨λ“  ν΄λΌμ΄μ–ΈνŠΈκ°€ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    κ°œμš”

    이 μˆ˜μ—…μ€ MCP ν™˜κ²½ μ„€μ •κ³Ό 첫 MCP μ• ν”Œλ¦¬μΌ€μ΄μ…˜ ꡬ좕에 κ΄€ν•œ μ‹€μš©μ μΈ μ•ˆλ‚΄λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€. ν•„μš”ν•œ 도ꡬ 및 ν”„λ ˆμž„μ›Œν¬ μ„€μ •, κΈ°λ³Έ MCP μ„œλ²„ ꡬ좕, 호슀트 μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 생성, κ΅¬ν˜„ ν…ŒμŠ€νŠΈ 방법을 배우게 λ©λ‹ˆλ‹€.

    Model Context Protocol (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";
    
    
    
    // MCP μ„œλ²„λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€
    
    const server = new McpServer({
    
      name: "Demo",
    
      version: "1.0.0"
    
    });
    
    
    
    // μΆ”κ°€ 도ꡬλ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€
    
    server.tool("add",
    
      { a: z.number(), b: z.number() },
    
      async ({ a, b }) => ({
    
        content: [{ type: "text", text: String(a + b) }]
    
      })
    
    );
    
    
    
    // 동적 인사말 λ¦¬μ†ŒμŠ€λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€
    
    server.resource(
    
      "file",
    
      // 'list' λ§€κ°œλ³€μˆ˜λŠ” λ¦¬μ†ŒμŠ€κ°€ μ‚¬μš© κ°€λŠ₯ν•œ νŒŒμΌμ„ λ‚˜μ—΄ν•˜λŠ” 방식을 μ œμ–΄ν•©λ‹ˆλ‹€. undefined둜 μ„€μ •ν•˜λ©΄ 이 λ¦¬μ†ŒμŠ€μ˜ λͺ©λ‘ ν‘œμ‹œκ°€ λΉ„ν™œμ„±ν™”λ©λ‹ˆλ‹€.
    
      new ResourceTemplate("file://{path}", { list: undefined }),
    
      async (uri, { path }) => ({
    
        contents: [{
    
          uri: uri.href,
    
          text: `File, ${path}!`
    
        }]
    
      })
    
    );
    
    
    
    // 파일 λ‚΄μš©μ„ μ½λŠ” 파일 λ¦¬μ†ŒμŠ€λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€
    
    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}`
    
          }
    
        }]
    
      })
    
    );
    
    
    
    // stdinμ—μ„œ λ©”μ‹œμ§€λ₯Ό λ°›κ³  stdout으둜 λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•˜κΈ° μ‹œμž‘ν•©λ‹ˆλ‹€
    
    const transport = new StdioServerTransport();
    
    await server.connect(transport);
    
    

    μœ„ μ½”λ“œμ—μ„œ μš°λ¦¬λŠ”:

  • MCP TypeScript SDKμ—μ„œ ν•„μš”ν•œ 클래슀λ₯Ό κ°€μ Έμ™”μŠ΅λ‹ˆλ‹€.
  • μƒˆ MCP μ„œλ²„ μΈμŠ€ν„΄μŠ€λ₯Ό 생성 및 κ΅¬μ„±ν–ˆμŠ΅λ‹ˆλ‹€.
  • ν•Έλ“€λŸ¬ ν•¨μˆ˜κ°€ μžˆλŠ” μ‚¬μš©μž μ§€μ • 도ꡬ(calculator)λ₯Ό λ“±λ‘ν–ˆμŠ΅λ‹ˆλ‹€.
  • MCP μš”μ²­μ„ μˆ˜μ‹ ν•˜λ„λ‘ μ„œλ²„λ₯Ό μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€.
  • ν…ŒμŠ€νŠΈ 및 디버깅

    MCP μ„œλ²„λ₯Ό ν…ŒμŠ€νŠΈν•˜κΈ° 전에 이용 κ°€λŠ₯ν•œ 도ꡬ 및 디버깅 λͺ¨λ²” 사둀λ₯Ό μ΄ν•΄ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. 효과적인 ν…ŒμŠ€νŠΈλŠ” μ„œλ²„κ°€ μ˜ˆμƒλŒ€λ‘œ μž‘λ™ν•˜λŠ”μ§€ ν™•μΈν•˜κ³  문제λ₯Ό μ‹ μ†νžˆ νŒŒμ•… 및 ν•΄κ²°ν•˜λŠ” 데 도움이 λ©λ‹ˆλ‹€. λ‹€μŒ μ„Ήμ…˜μ—μ„œ MCP κ΅¬ν˜„μ„ κ²€μ¦ν•˜κΈ° μœ„ν•œ ꢌμž₯ 방법을 μ„€λͺ…ν•©λ‹ˆλ‹€.

    MCPλŠ” μ„œλ²„ ν…ŒμŠ€νŠΈ 및 디버깅을 λ„μ™€μ£ΌλŠ” 도ꡬλ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€:

  • Inspector 도ꡬ: 이 κ·Έλž˜ν”½ μΈν„°νŽ˜μ΄μŠ€λŠ” μ„œλ²„μ— μ—°κ²°ν•˜μ—¬ 도ꡬ, ν”„λ‘¬ν”„νŠΈ, λ¦¬μ†ŒμŠ€λ₯Ό ν…ŒμŠ€νŠΈν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • curl: μ»€λ§¨λ“œ 라인 도ꡬ인 curlμ΄λ‚˜ λ‹€λ₯Έ HTTP λͺ…령을 생성 및 μ‹€ν–‰ν•  수 μžˆλŠ” ν΄λΌμ΄μ–ΈνŠΈλ‘œλ„ μ„œλ²„μ— μ—°κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • MCP Inspector μ‚¬μš©ν•˜κΈ°

    1. μ„œλ²„ κΈ°λŠ₯ 탐색: μ‚¬μš© κ°€λŠ₯ν•œ λ¦¬μ†ŒμŠ€, 도ꡬ, ν”„λ‘¬ν”„νŠΈ μžλ™ 감지

    2. 도ꡬ μ‹€ν–‰ ν…ŒμŠ€νŠΈ: λ‹€μ–‘ν•œ λ§€κ°œλ³€μˆ˜λ‘œ μ‹€μ‹œκ°„ 응닡 확인

    3. μ„œλ²„ 메타데이터 쑰회: μ„œλ²„ 정보, μŠ€ν‚€λ§ˆ, ꡬ성 κ²€ν† 

    
    # 예제 TypeScript, MCP Inspector μ„€μΉ˜ 및 μ‹€ν–‰
    
    npx @modelcontextprotocol/inspector node build/index.js
    
    

    μœ„ λͺ…λ Ήμ–΄λ₯Ό μ‹€ν–‰ν•˜λ©΄ MCP Inspectorκ°€ λΈŒλΌμš°μ €μ—μ„œ 둜컬 μ›Ή μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€. λ“±λ‘λœ MCP μ„œλ²„, μ‚¬μš© κ°€λŠ₯ν•œ 도ꡬ, λ¦¬μ†ŒμŠ€ 및 ν”„λ‘¬ν”„νŠΈ λŒ€μ‹œλ³΄λ“œλ₯Ό λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. 이 μΈν„°νŽ˜μ΄μŠ€λ‘œ 도ꡬ μ‹€ν–‰ ν…ŒμŠ€νŠΈ, μ„œλ²„ 메타데이터 쑰사, μ‹€μ‹œκ°„ 응닡 확인 등이 κ°€λŠ₯ν•΄ MCP μ„œλ²„ κ΅¬ν˜„ 검증 및 디버깅이 μˆ˜μ›”ν•΄μ§‘λ‹ˆλ‹€.

    λ‹€μŒμ€ ν™”λ©΄ μ˜ˆμ‹œμž…λ‹ˆλ‹€:

    일반적인 μ„€μ • 문제 및 ν•΄κ²°μ±…

    | 문제 | κ°€λŠ₯ν•œ ν•΄κ²°μ±… |

    |-------------------------|--------------------------------------------|

    | μ—°κ²° 거뢀됨 | μ„œλ²„ μ‹€ν–‰ μ—¬λΆ€ 및 포트 확인 |

    | 도ꡬ μ‹€ν–‰ 였λ₯˜ | λ§€κ°œλ³€μˆ˜ 검증 및 였λ₯˜ 처리 κ²€ν†  |

    | 인증 μ‹€νŒ¨ | API ν‚€ 및 κΆŒν•œ 확인 |

    | μŠ€ν‚€λ§ˆ 검증 였λ₯˜ | λ§€κ°œλ³€μˆ˜κ°€ μ •μ˜λœ μŠ€ν‚€λ§ˆμ™€ μΌμΉ˜ν•˜λŠ”μ§€ 확인|

    | μ„œλ²„κ°€ μ‹œμž‘λ˜μ§€ μ•ŠμŒ | 포트 좩돌 λ˜λŠ” λˆ„λ½λœ 쒅속성 점검 |

    | CORS 였λ₯˜ | ꡐ차 좜처 μš”μ²­μ— μ μ ˆν•œ CORS 헀더 ꡬ성 |

    | 인증 문제 | 토큰 μœ νš¨μ„± 및 κΆŒν•œ 확인 |

    둜컬 개발

    둜컬 개발 및 ν…ŒμŠ€νŠΈμš©μœΌλ‘œ, MCP μ„œλ²„λ₯Ό μžμ‹ μ˜ λ¨Έμ‹ μ—μ„œ 직접 μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€:

    1. μ„œλ²„ ν”„λ‘œμ„ΈμŠ€ μ‹œμž‘: MCP μ„œλ²„ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‹€ν–‰

    2. λ„€νŠΈμ›Œν‚Ή ꡬ성: μ„œλ²„κ°€ μ˜ˆμƒ ν¬νŠΈμ—μ„œ μ ‘κ·Ό κ°€λŠ₯ν•˜κ²Œ μ„€μ •

    3. ν΄λΌμ΄μ–ΈνŠΈ μ—°κ²°: http://localhost:3000 같은 둜컬 μ—°κ²° URL μ‚¬μš©

    
    # μ˜ˆμ‹œ: TypeScript MCP μ„œλ²„λ₯Ό λ‘œμ»¬μ—μ„œ μ‹€ν–‰ν•˜κΈ°
    
    npm run start
    
    # μ„œλ²„κ°€ http://localhost:3000 μ—μ„œ μ‹€ν–‰ μ€‘μž…λ‹ˆλ‹€
    
    

    첫 번째 MCP μ„œλ²„ κ΅¬μΆ•ν•˜κΈ°

    이전 μˆ˜μ—…μ—μ„œ 핡심 κ°œλ…μ„ λ‹€λ€˜μœΌλ‹ˆ 이제 κ·Έ 지식을 μ‹€μŠ΅ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

    μ„œλ²„κ°€ ν•  수 μžˆλŠ” 일

    코딩을 μ‹œμž‘ν•˜κΈ° 전에 μ„œλ²„μ˜ 역할을 상기해 λ΄…μ‹œλ‹€:

    MCP μ„œλ²„λŠ” 예λ₯Ό λ“€μ–΄:

  • 둜컬 파일 및 λ°μ΄ν„°λ² μ΄μŠ€ μ ‘κ·Ό
  • 원격 API μ—°κ²°
  • 계산 μˆ˜ν–‰
  • λ‹€λ₯Έ 도ꡬ 및 μ„œλΉ„μŠ€ 톡합
  • μƒν˜Έμž‘μš©μ„ μœ„ν•œ μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€ 제곡
  • μ’‹μŠ΅λ‹ˆλ‹€, 무엇을 ν•  수 μžˆλŠ”μ§€ μ•Œμ•˜μœΌλ‹ˆ 코딩을 μ‹œμž‘ν•΄ λ΄…μ‹œλ‹€.

    μ—°μŠ΅: μ„œλ²„ λ§Œλ“€κΈ°

    μ„œλ²„λ₯Ό λ§Œλ“€λ €λ©΄ λ‹€μŒ 단계λ₯Ό λ”°λ₯΄μ„Έμš”:

  • MCP SDK μ„€μΉ˜
  • ν”„λ‘œμ νŠΈ 생성 및 ꡬ쑰 μ„€μ •
  • μ„œλ²„ μ½”λ“œ μž‘μ„±
  • μ„œλ²„ ν…ŒμŠ€νŠΈ
  • -1- ν”„λ‘œμ νŠΈ μƒμ„±ν•˜κΈ°

    TypeScript
    
    # ν”„λ‘œμ νŠΈ 디렉토리λ₯Ό μƒμ„±ν•˜κ³  npm ν”„λ‘œμ νŠΈλ₯Ό μ΄ˆκΈ°ν™”ν•˜μ‹­μ‹œμ˜€
    
    mkdir calculator-server
    
    cd calculator-server
    
    npm init -y
    
    
    Python
    
    # ν”„λ‘œμ νŠΈ 디렉토리 생성
    
    mkdir calculator-server
    
    cd calculator-server
    
    # Visual Studio Codeμ—μ„œ 폴더 μ—΄κΈ° - λ‹€λ₯Έ 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
    
    

    μ••μΆ• 파일 ν’€κΈ°:

    
    unzip calculator-server.zip -d calculator-server
    
    cd calculator-server
    
    # μ„ νƒμ μœΌλ‘œ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” ν…ŒμŠ€νŠΈ 제거
    
    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
    
    # 아직 μ„€μΉ˜ν•˜μ§€ μ•Šμ€ 경우 TypeScriptλ₯Ό 전역에 μ„€μΉ˜ν•˜μ„Έμš”
    
    npm install typescript -g
    
    
    
    # MCP SDK와 μŠ€ν‚€λ§ˆ 검증을 μœ„ν•΄ Zodλ₯Ό μ„€μΉ˜ν•˜μ„Έμš”
    
    npm install @modelcontextprotocol/sdk zod
    
    npm install -D @types/node typescript
    
    
    Python
    
    # 가상 ν™˜κ²½μ„ λ§Œλ“€κ³  쒅속성을 μ„€μΉ˜ν•©λ‹ˆλ‹€
    
    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": {
    
        "build": "tsc",
    
        "start": "npm run build && node ./build/index.js",
    
      },
    
      "keywords": [],
    
      "author": "",
    
      "license": "ISC",
    
      "description": "A simple calculator server using Model Context Protocol",
    
      "dependencies": {
    
        "@modelcontextprotocol/sdk": "^1.16.0",
    
        "zod": "^3.25.76"
    
      },
    
      "devDependencies": {
    
        "@types/node": "^24.0.14",
    
        "typescript": "^5.8.3"
    
      }
    
    }
    
    

    *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";
    
     
    
    // MCP μ„œλ²„ 생성
    
    const server = new McpServer({
    
      name: "Calculator MCP Server",
    
      version: "1.0.0"
    
    });
    
    

    μ„œλ²„κ°€ μƒμ„±λ˜μ—ˆμœΌλ‚˜ ν•  일이 λ§Žμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 고쳐 λ΄…μ‹œλ‹€.

    Python
    
    # server.py
    
    from mcp.server.fastmcp import FastMCP
    
    
    
    # MCP μ„œλ²„ 생성
    
    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;
    
            }
    
    
    
            // κ²Œν„°
    
            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;
    
    

    계산기 μ„œλ²„λŠ” 두 숫자λ₯Ό λ”ν•˜λŠ” κ°„λ‹¨ν•œ μ„œλ²„κ°€ 될 κ²ƒμž…λ‹ˆλ‹€. 계산기 μš”μ²­μ„ λ‚˜νƒ€λ‚΄λŠ” structλ₯Ό λ§Œλ“€μ–΄ λ΄…μ‹œλ‹€.

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

    λ‹€μŒμœΌλ‘œ 계산기 μ„œλ²„λ₯Ό λ‚˜νƒ€λ‚΄λŠ” structλ₯Ό λ§Œλ“­λ‹ˆλ‹€. 이 structλŠ” 도ꡬ λΌμš°ν„°λ₯Ό λ³΄μœ ν•˜λ©° 도ꡬ 등둝에 μ‚¬μš©λ©λ‹ˆλ‹€.

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

    이제 Calculator structλ₯Ό κ΅¬ν˜„ν•˜μ—¬ μ„œλ²„ μƒˆ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜κ³  μ„œλ²„ 정보λ₯Ό μ œκ³΅ν•˜λŠ” ν•Έλ“€λŸ¬λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

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

    λ§ˆμ§€λ§‰μœΌλ‘œ μ„œλ²„λ₯Ό μ‹œμž‘ν•˜λŠ” main ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•©λ‹ˆλ‹€. 이 ν•¨μˆ˜λŠ” Calculator struct μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€κ³  ν‘œμ€€ μž…μΆœλ ₯으둜 μ„œλ²„λ₯Ό μš΄μ˜ν•©λ‹ˆλ‹€.

    
    #[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
    
    # λ§μ…ˆ 도ꡬ μΆ”κ°€
    
    @mcp.tool()
    
    def add(a: int, b: int) -> int:
    
        """Add two numbers"""
    
        return a + b
    
    
    
    
    
    # 동적 인사말 λ¦¬μ†ŒμŠ€ μΆ”κ°€
    
    @mcp.resource("greeting://{name}")
    
    def get_greeting(name: str) -> str:
    
        """Get a personalized greeting"""
    
        return f"Hello, {name}!"
    
    

    μœ„ μ½”λ“œμ—μ„œ μš°λ¦¬λŠ”:

  • a와 bλΌλŠ” μ •μˆ˜ λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” add 도ꡬλ₯Ό μ •μ˜ν–ˆμŠ΅λ‹ˆλ‹€.
  • name λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” greeting λ¦¬μ†ŒμŠ€λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
  • .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
    
    // stdinμ—μ„œ λ©”μ‹œμ§€ μˆ˜μ‹ μ„ μ‹œμž‘ν•˜κ³  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";
    
    
    
    // MCP μ„œλ²„ 생성
    
    const server = new McpServer({
    
      name: "Calculator MCP Server",
    
      version: "1.0.0"
    
    });
    
    
    
    // μΆ”κ°€ 도ꡬ μΆ”κ°€
    
    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}!`
    
        }]
    
      })
    
    );
    
    
    
    // stdinμ—μ„œ λ©”μ‹œμ§€ μˆ˜μ‹  μ‹œμž‘ 및 stdout으둜 λ©”μ‹œμ§€ 전솑 μ‹œμž‘
    
    const transport = new StdioServerTransport();
    
    server.connect(transport);
    
    
    Python
    
    # server.py
    
    from mcp.server.fastmcp import FastMCP
    
    
    
    # MCP μ„œλ²„ 생성
    
    mcp = FastMCP("Demo")
    
    
    
    
    
    # μΆ”κ°€ 도ꡬ μΆ”κ°€
    
    @mcp.tool()
    
    def add(a: int, b: int) -> int:
    
        """Add two numbers"""
    
        return a + b
    
    
    
    
    
    # 동적 인사말 λ¦¬μ†ŒμŠ€ μΆ”κ°€
    
    @mcp.resource("greeting://{name}")
    
    def get_greeting(name: str) -> str:
    
        """Get a personalized greeting"""
    
        return f"Hello, {name}!"
    
    
    
    # 메인 μ‹€ν–‰ 블둝 - μ„œλ²„λ₯Ό μ‹€ν–‰ν•˜λ €λ©΄ ν•„μš”ν•©λ‹ˆλ‹€
    
    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

    Python은 Node.js 도ꡬ인 inspectorλ₯Ό λž˜ν•‘ν•©λ‹ˆλ‹€. λ‹€μŒκ³Ό 같이 ν•΄λ‹Ή 도ꡬλ₯Ό ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€:

    
    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

    계산기 μ„œλ²„κ°€ μ‹€ν–‰ 쀑인지 ν™•μΈν•˜μ„Έμš”

    그런 λ‹€μŒ μΈμŠ€νŽ™ν„°λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€:

    
    npx @modelcontextprotocol/inspector
    
    

    μΈμŠ€νŽ™ν„° μ›Ή μΈν„°νŽ˜μ΄μŠ€μ—μ„œ:

    1. 전솑 μœ ν˜•μœΌλ‘œ "SSE"λ₯Ό μ„ νƒν•˜μ„Έμš”

    2. URL을 http://localhost:8080/sse둜 μ„€μ •ν•˜μ„Έμš”

    3. "Connect"λ₯Ό ν΄λ¦­ν•˜μ„Έμš”

    이제 μ„œλ²„μ— μ—°κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€

    Java μ„œλ²„ ν…ŒμŠ€νŠΈ μ„Ήμ…˜μ΄ μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€

    λ‹€μŒ μ„Ήμ…˜μ€ μ„œλ²„μ™€ μƒν˜Έμž‘μš©ν•˜λŠ” 방법에 κ΄€ν•œ λ‚΄μš©μž…λ‹ˆλ‹€.

    λ‹€μŒκ³Ό 같은 μ‚¬μš©μž μΈν„°νŽ˜μ΄μŠ€κ°€ 보일 κ²ƒμž…λ‹ˆλ‹€:

    1. "Connect" λ²„νŠΌμ„ μ„ νƒν•˜μ—¬ μ„œλ²„μ— μ—°κ²°ν•˜μ„Έμš”

    μ„œλ²„μ— μ—°κ²°λ˜λ©΄ λ‹€μŒ 화면이 λ³΄μž…λ‹ˆλ‹€:

    !Connected

    1. "Tools"μ—μ„œ "listTools"λ₯Ό μ„ νƒν•˜μ„Έμš”. "Add"κ°€ ν‘œμ‹œλ˜λ©΄ "Add"λ₯Ό μ„ νƒν•˜κ³  λ§€κ°œλ³€μˆ˜ 값을 μž…λ ₯ν•˜μ„Έμš”.

    λ‹€μŒκ³Ό 같은 응닡, 즉 "add" λ„κ΅¬μ˜ κ²°κ³Όκ°€ ν‘œμ‹œλ©λ‹ˆλ‹€:

    !Result of running add

    μΆ•ν•˜ν•©λ‹ˆλ‹€, 첫 번째 μ„œλ²„λ₯Ό μ„±κ³΅μ μœΌλ‘œ λ§Œλ“€κ³  μ‹€ν–‰ν–ˆμŠ΅λ‹ˆλ‹€!

    Rust

    MCP μΈμŠ€νŽ™ν„° CLI둜 Rust μ„œλ²„λ₯Ό μ‹€ν–‰ν•˜λ €λ©΄ λ‹€μŒ λͺ…λ Ήμ–΄λ₯Ό μ‚¬μš©ν•˜μ„Έμš”:

    
    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 κ΅¬ν˜„
  • μ£Όμš” μš”μ 

  • 언어별 SDKλ₯Ό 톡해 MCP 개발 ν™˜κ²½μ„ κ°„λ‹¨νžˆ ꡬ좕할 수 μžˆμŠ΅λ‹ˆλ‹€
  • MCP μ„œλ²„ ꡬ좕은 λͺ…ν™•ν•œ μŠ€ν‚€λ§ˆλ₯Ό κ°€μ§„ 도ꡬλ₯Ό μƒμ„±ν•˜κ³  λ“±λ‘ν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€
  • ν…ŒμŠ€νŠΈ 및 디버깅은 μ‹ λ’°ν•  수 μžˆλŠ” MCP κ΅¬ν˜„μ— ν•„μˆ˜μ μž…λ‹ˆλ‹€
  • μƒ˜ν”Œ

  • Java Calculator
  • .Net Calculator
  • JavaScript Calculator
  • TypeScript Calculator
  • Python Calculator
  • Rust Calculator
  • 과제

    μ„ νƒν•œ 도ꡬλ₯Ό μ‚¬μš©ν•˜μ—¬ κ°„λ‹¨ν•œ MCP μ„œλ²„λ₯Ό λ§Œλ“œμ„Έμš”:

    1. μ„ ν˜Έν•˜λŠ” μ–Έμ–΄(.NET, Java, Python, TypeScript, Rust)둜 도ꡬλ₯Ό κ΅¬ν˜„ν•˜μ„Έμš”.

    2. μž…λ ₯ λ§€κ°œλ³€μˆ˜μ™€ λ°˜ν™˜ 값을 μ •μ˜ν•˜μ„Έμš”.

    3. μΈμŠ€νŽ™ν„° 도ꡬλ₯Ό μ‹€ν–‰ν•˜μ—¬ μ„œλ²„κ°€ μ œλŒ€λ‘œ μž‘λ™ν•˜λŠ”μ§€ ν™•μΈν•˜μ„Έμš”.

    4. λ‹€μ–‘ν•œ μž…λ ₯으둜 κ΅¬ν˜„μ„ ν…ŒμŠ€νŠΈν•˜μ„Έμš”.

    μ†”λ£¨μ…˜

    μΆ”κ°€ λ¦¬μ†ŒμŠ€

  • Azureμ—μ„œ Model Context Protocol을 μ‚¬μš©ν•˜μ—¬ μ—μ΄μ „νŠΈ λΉŒλ“œν•˜κΈ°
  • 원격 MCP with Azure Container Apps (Node.js/TypeScript/JavaScript)
  • .NET OpenAI MCP μ—μ΄μ „νŠΈ
  • λ‹€μŒ 단계

    λ‹€μŒ: MCP ν΄λΌμ΄μ–ΈνŠΈ μ‹œμž‘ν•˜κΈ°

    ---

    λ©΄μ±… μ‘°ν•­:

    이 λ¬Έμ„œλŠ” AI λ²ˆμ—­ μ„œλΉ„μŠ€ Co-op Translatorλ₯Ό μ‚¬μš©ν•˜μ—¬ λ²ˆμ—­λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

    정확성을 μœ„ν•΄ λ…Έλ ₯ν•˜κ³  μžˆμœΌλ‚˜ μžλ™ λ²ˆμ—­μ—λŠ” 였λ₯˜λ‚˜ 뢀정확성이 포함될 수 μžˆμŒμ„ μœ μ˜ν•΄ μ£Όμ‹œκΈ° λ°”λžλ‹ˆλ‹€.

    원본 λ¬Έμ„œκ°€ μ›μ–΄λ‘œ 된 곡식 μžλ£Œμž„μ„ μ°Έκ³ ν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

    μ€‘μš”ν•œ 정보에 λŒ€ν•΄μ„œλŠ” μ „λ¬Έ 인간 λ²ˆμ—­κ°€μ˜ λ²ˆμ—­μ„ ꢌμž₯ν•©λ‹ˆλ‹€.

    λ³Έ λ²ˆμ—­ μ‚¬μš©μœΌλ‘œ 인해 λ°œμƒν•˜λŠ” λͺ¨λ“  μ˜€ν•΄λ‚˜ μ˜€μ—­μ— λŒ€ν•΄ λ‹Ήμ‚¬λŠ” μ±…μž„μ„ μ§€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

    MCP Academy — microsoft/mcp-for-beginners