Галоўная / Артыкулы / Практычныя прытамулі: 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-кліент, який іх аднаходзіць і выкананае — без жадных ваказаў пра інструменты з боку кліента.

Для практычнага кярэкстання, перад зменым коду неабходна ясная інструкцыя: паказаць, што ўваходзіцца, хто являецца адпаведным адпаведальнікам за крок і якія критэрыя завершэння. Аперацыёныя працавнікі должны магчыма ўвайсці знову у крок, выкарыстоўваючы вядомую точку контролю, без неабясненага адгадвання скрытых станоў. Конфігурацыю трэба захаваць праз аддзел ад коду прыкладнення. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, якое працавнікі можуць пераглядаць, не чытаючы весь ланцуг задач. Калі наступны крок — гэта код або вызов інструмента, лепш выкарыстоўваць структураваныя выходны дадзеныя з перакананнем ў схэме, чым вольныя тэкстовыя апісанні.

Проблема

Для стадіі «Проблема» неабяжна ўзначыць вхідныя даны, адпаведальнага за крок і крэтыры завершэння пры перадзеі коду. Аперацыйныя працавнікі павінны магчымае перазапускаць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Неабяжна задокументаваць як шлях успеху, так і шлях вярнення. Перапрыбуткі, людзкіе перакрыцця і обробка некоректных паведамленняў є часткай продукту, а не чымсь, што дадаецца пазней.

Шта такое 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

Справакі

Чэрніця кантролю