Головна / Статті / Практичні поради: Spring AI + MCP: зробіть ваші Java-інструменти доступними для будь-якого клієнта AI (навіть

Практичні поради: Spring AI + MCP: зробіть ваші Java-інструменти доступними для будь-якого клієнта AI (навіть

Покрокова інструкція з практичних нотаток: Spring AI + MCP: Зробіть свої Java-інструменти доступними для будь-якого клієнта AI (включаючи контракти, перевірки та слоти для коду для команд, які використовують цю схему).

2111 слів

У цьому посібнику детально описано процес створення системи від сировини до готового продукту для: Spring AI + MCP: надання доступу до ваших Java-інструментів будь-якому клієнту AI (навіть Claude Desktop). Основна увага приділяється конкретним крокам виконання, чітким перевіркам та коду, який можна просто додати до репозиторію, не здогадуючись про його призначення.

Практичний посібник з протоколу Model Context Protocol (MCP) разом із Spring AI 2.0. Створіть сервер MCP, який надає доступ до інструментів оплати через SSE, а також окремий клієнт AI, який їх виявляє та використовує — без жодних визначень інструментів з боку клієнта.

У практичному посібнику A необхідно перед зміною коду визначити вхідні дані, виконавця кроку та критерії завершення. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Конфігурацію слід тримати окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Коли наступним кроком є написання коду чи виклик інструменту, краще використовувати структуровані результати з перевіркою схеми, ніж вільний текст.

Проблема

На етапі «Проблема» необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Необхідно документувати як шлях успішного виконання, так і шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації. Аутентифікація відбувається на шлюзі, а повторна авторизація — на рівні обробки даних. Один лише токен-носій не є межею окремого тенантства.

Що таке MCP?

На етапі «Що таке MCP» необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Краще використовувати невеликі, тестовані одиниці коду замість об’ємних скриптів. Коли крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану структуру обробки даних. Аутентифікуйтеся біля шлюзу та повторно авторизуйтесь на рівні обробки даних. Один лише токен-носій не є межею окремого тенанту.

Що ми створюємо

На етапі «Що ми створюємо» необхідно визначити вхідні дані, відповідальну особу за крок та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Призначте назви елементів, визначте критерії успіху та не допускайте мовчазного часткового завершення. Аутентифікуйтеся біля шлюзу та повторно авторизуйтесь на рівні обробки даних. Один лише токен-носій не є межею території користувача.

Попередні вимоги

На етапі передумов необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Записуйте час виконання та витрати на токени чи запити поруч із функціональними результатами. Візуалізація витрат заздалегідь запобігає несподіваним рахункам під час переходу з демо-середовища у спільні середовища. Аутентифікуйтеся біля шлюзу та повторно авторизуйтесь на рівні обробки даних. Один лише токен-носій не є межею окремого тенанту. На етапі передумов необхідно визначити вхідні дані, власника кроку та критерії завершення перед зміною коду. Оператори повинні мати можливість перезапустити крок з відомої точки контролю, не намагаючись вгадати прихований стан. Документуйте як успішний, так і відновлювальний сценарії роботи разом. Повторні спроби, людські контрольні точки та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої оптимізації.

Налаштування проекту

Під час виконання етапу налаштування проекту спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Якщо якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих даних пошук помилок займає години.

Parent POM

Під час роботи над етапом Parent POM спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Цей перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як контракт між вхідними даними та перевіреними результатами. Призначте назви елементів, визначте критерії успіху та не допускайте беззвучного часткового виконання. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих записів дебагування займає години.

<groupId>com.anupam</groupId>
<artifactId>spring-ai-mcp</artifactId>
<packaging>pom</packaging>
<properties>
    <java.version>21</java.version>
    <spring-ai.version>2.0.0</spring-ai.version>
</properties>
<modules>
    <module>mcp-server</module>
    <module>mcp-client</module>
</modules>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Частина 1: Створення сервера MCP

Під час роботи над Частиною 1 «Створення сцени» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Записуйте час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ. Фіксуйте назву інструменту, хеш аргументів, затримку та результат кожного виклику. Без цих записів дебагування агента може займати години.

Залежності сервера

Під час роботи над етапом залежностей сервера спочатку запишіть умови використання: необхідні вхідні дані, сигнал про успішне виконання та наслідки часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Тримайте конфігурацію окремо від коду додатку. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих записів дебагування займає години.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
    </dependency>
</dependencies>

Конфігурація сервера

Під час роботи над етапом налаштування сервера спочатку запишіть умови використання: необхідні параметри вхідних даних, сигнал про успішну роботу та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Фіксуйте назву інструменту, хеш аргументів, час відгуку та результат кожного виклику. Без цих записів дебагування займає години.

spring:
  ai:
    mcp:
      server:
        name: payment-tools-server
        version: 1.0.0
        description: "MCP server exposing payment lookup and exchange rate tools"
   server:
     port: 8081

Визначення інструментів за допомогою @Tool

Під час роботи над етапом «Визначення інструментів за допомогою інструменту» спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям перед об’ємними скриптами. Коли якийсь крок зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність дій. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих даних налагодження агента займає години.

@Component
public class PaymentMcpTools {
    @Tool(description = "Get the current status and details of a payment by its transaction ID")
    public PaymentInfo getPaymentStatus(
            @ToolParam(description = "Transaction ID, e.g. TXN-9042") String transactionId) {
        PaymentInfo info = payments.get(transactionId);
        if (info == null) {
            throw new RuntimeException("Payment not found: " + transactionId);
        }
        return info;
    }
    @Tool(description = "Get the current exchange rate between two currencies. " +
            "Supported: USD, EUR, GBP, JPY, INR, CAD, AUD")
    public ExchangeRate getExchangeRate(
            @ToolParam(description = "Source currency code, e.g. USD") String from,
            @ToolParam(description = "Target currency code, e.g. EUR") String to) {
        // ... conversion logic
        return new ExchangeRate(from, to, rate, LocalDateTime.now());
    }
    @Tool(description = "Calculate the total amount in a target currency for a given payment")
    public String convertPaymentAmount(
            @ToolParam(description = "Transaction ID") String transactionId,
            @ToolParam(description = "Target currency code") String targetCurrency) {
        PaymentInfo payment = getPaymentStatus(transactionId);
        ExchangeRate rate = getExchangeRate(payment.currency(), targetCurrency);
        BigDecimal converted = payment.amount().multiply(rate.rate());
        return String.format("%s %s = %s %s", payment.amount(), payment.currency(),
                converted, targetCurrency);
    }
}

Запустіть сервер

Під час виконання етапу «Запуск сервера» спочатку запишіть умови договору: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Розглядайте цей етап як договір між вхідними даними та перевіреними результатами. Дайте назви елементам, визначте критерії успіху та не допускайте беззвучного часткового виконання. Фіксуйте назву інструменту, хеш аргументів, час відгуку та результат кожного виклику. Без цих записів дебагування займає години.

cd mcp-server
./mvnw spring-boot:run

Частина 2: Створення клієнта MCP

Під час роботи над Частиною 2 «Створення сцени» спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Запишіть час виконання та витрати на токени або запити поруч із функціональними результатами. Відображення витрат заздалегідь запобігає несподіваним рахункам, коли процес переходить від демо-версії до спільних середовищ. Записуйте назву інструменту, хеш аргументів, затримку та результат кожного виклику. Без цих записів дебагування агента може займати години.

Залежності клієнта

Під час роботи над етапом залежностей клієнта спочатку запишіть умови взаємодії: необхідні вхідні дані, сигнал про успішне виконання та наслідки часткової невдачі. Такий перелік допомагає зберігати чесність у подальших змінах коду. Тримайте конфігурацію окремо від коду програми. Файли середовища, сховища конфіденційних даних та флаги функцій мають знаходитися в одному місці, де оператори можуть їх перевіряти, не читаючи весь код. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих записів дебагування займає години.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-mcp-client</artifactId>
    </dependency>
</dependencies>

Конфігурація клієнта

Під час роботи над етапом налаштування клієнта спочатку запишіть умови контракту: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Одночасно задокументуйте шлях успішного виконання та шлях відновлення. Повторні спроби, людський контроль та обробка некоректних повідомлень є частиною продукту, а не етапом подальшої доробки. Фіксуйте назву інструменту, хеш аргументів, час відгуку та результат кожного виклику. Без цих записів дебагування агента займає години.

spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-4o
          temperature: 0.3
   mcp:
      client:
        sse:
          connections:
            payment-tools:
              url: http://localhost:8081
    server:
      port: 8080

Підключення інструментів MCP до ChatClient

Під час роботи над інструментами Wire MCP, які потрапляють у стадію розробки, спочатку запишіть контракт: необхідні вхідні дані, сигнал про успіх та те, що відбувається у разі часткової невдачі. Такий перелік допомагає зберігати чесність пізніших змін у коді. Віддавайте перевагу невеликим, тестованим одиницям коду перед об’ємними скриптами. Коли якась крок виконання зазнає невдачі, причина має вказувати на конкретну відповідальність, а не на заплутану послідовність операцій. Фіксуйте назву інструменту, хеш аргументів, час виконання та результат кожного виклику. Без цих записів налагодження працює агента займає години.

@Configuration
public class AiConfig {
    @Bean
    public ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider mcpTools) {
        return ChatClient.builder(chatModel)
                .defaultSystem("""
                        You are a helpful payments assistant. You have access to tools
                        provided by an MCP server. Use them to look up payment status,
                        get exchange rates, and convert payment amounts.
                        """)
                .defaultTools(mcpTools)
                .build();
    }
}

Контролер (не потрібні знання інструментів)

@RestController
@RequestMapping("/api/v1/assistant")
public class AssistantController {
    private final ChatClient chatClient;
    public AssistantController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    @PostMapping("/chat")
    public ResponseEntity<ChatResponse> chat(@Valid @RequestBody ChatRequest request) {
        String answer = chatClient.prompt()
                .user(request.message())
                .call()
                .content();
        return ResponseEntity.ok(ChatResponse.of(answer));
    }
}

Тестування

1. Запустіть обидві програми

# Terminal 1 — MCP Server
cd mcp-server
./mvnw spring-boot:run

# Terminal 2 - MCP Client
cd mcp-client
export OPENAI_API_KEY=sk-your-key-here
./mvnw spring-boot:run

2. Здійсніть запит через клієнта

curl -X POST http://localhost:8080/api/v1/assistant/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "What is the status of payment TXN-9042?"}'
{
  "answer": "Payment TXN-9042 has been completed. It was $250.00 USD sent from Alice Johnson to Bob Smith on August 20, 2026.",
  "timestamp": "2026-08-22T11:00:00"
}

3. Використовуйте інструмент, який поєднує інші інструменти

curl -X POST http://localhost:8080/api/v1/assistant/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Convert TXN-9043 amount to EUR"}'
{
  "answer": "Payment TXN-9043 is $1,200.50 USD. At the current rate of 0.92, that equals approximately €1,104.46 EUR.",
  "timestamp": "2026-08-22T11:00:05"
}

MCP проти локальних інструментів: коли використовувати кожен

Поєднання локальних та MCP-інструментів

chatClient.prompt()
    .user(question)
    .tools(localTools, mcpTools)  // Both in one call
    .call()
    .content();

Варіанти транспортування

Прикладstdio (підключення до сервера MCP на основі npm):

spring:
  ai:
    mcp:
      client:
        stdio:
          connections:
            filesystem:
              command: npx
              args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

Аспекти безпеки

// Only allow specific tools from the MCP server
@Bean
McpToolFilter mcpToolFilter() {
    return (serverName, toolName) ->
            Set.of("getPaymentStatus", "getExchangeRate").contains(toolName);
}

Поширені проблеми

Повний приклад роботи

git clone https://github.com/AnupamSinha/spring-boot-examples/tree/main/06-ai-mcp
cd spring-ai-mcp

# Terminal 1 - Start server
cd mcp-server && ../mvnw spring-boot:run
# Terminal 2 - Start client
cd mcp-client && export OPENAI_API_KEY=sk-... && ../mvnw spring-boot:run

Посилання

Чек-лист для експлуатації