데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      에이닷 MCP 기반 API 통합과 적용 사례

      mistinto 25.05.26
      6,870 10 1
      DEVOTEE 요약
      본 블로그는 기존 REST API를 Model Context Protocol(MCP) 표준 구조로 통합하여 LLM 기반 애플리케이션에서 더욱 효율적으로 활용할 수 있도록 한 사례를 다룹니다. MCP는 Host, Client, Server로 구성되어 있으며 각 요소가 JSON-RPC 2.0 통신 규약을 따르며, Tool 추상화 및 그룹화, 다양한 전송 방식(SSE, Streamable HTTP 등) 지원을 통해 구조적 일관성과 확장성을 제공합니다. 이를 통해 LLM 애플리케이션 개발 과정에서 복잡도를 줄이고, API 연동 및 관리 효율성을 향상시킬 수 있었습니다.
      DEVOTEE 추천 블로그

      개요

      저희 팀은 내부적으로 ‘대화 요약 데이터’, ‘사용자 프로파일’, ‘서비스 사용 이력’ 등 다양한 도메인의 REST API를 이미 구현하여 여러 시스템에서 활용하고 있었습니다.

      그러나 이러한 API를 LLM 기반 어플리케이션에서 직접 호출하여 사용하도록 하다 보니 몇 가지 문제점이 드러났습니다.

      • API를 사용하는 각 어플리케이션이 API 명세와 파라미터 정보를 별도로 관리하게 되어, 명세의 일관성이 떨어졌습니다.

      • LLM에서 사용할 Tool로 추상화하는 작업이 반복적으로 발생했습니다.

      • Tool 구성과 연동이 복잡하고 시간이 많이 소요되어 개발 속도와 효율성에도 부정적인 영향을 끼쳤습니다.

        이러한 문제를 해결하기 위해, 저희는 기존 API들을 Model Context Protocol(MCP) 기반의 표준 구조로 빠르고 유연하게 통합할 수 있는 방안을 설계하고 구현하게 되었습니다.


      Model Context Protocol

      MCP(Model Context Protocol)는 LLM 기반 애플리케이션과 외부의 데이터 또는 도구를 연결해주는 표준화된 프로토콜입니다.

      이를 통해 LLM이 다양한 외부 기능을 일관된 방식으로 호출할 수 있도록 지원합니다.

      image.png

      MCP는 세 가지 주요 구성 요소로 이루어져 있습니다

      • Host

        • LLM이 포함된 애플리케이션으로, Client를 통해 필요한 기능을 요청합니다.

      • Client

        • Host와 Server 사이의 통신을 중개하는 역할을 하며, 요청과 응답을 관리합니다.

      • Server

        • 기능(capability)을 선언하고, 요청된 Tool, Prompt, Resource 등을 실제로 실행 및 반환합니다.

      이러한 구조를 기반으로 MCP는 다양한 기능을 안정적이고 확장 가능한 방식으로 연결할 수 있으며, 이를 위해 Client와 Server는 공통의 통신 규약(JSON-RPC 2.0)을 따릅니다.


      MCP Server

      MCP에서 이루어지는 모든 통신은 JSON-RPC 2.0 포맷을 기반으로 하며, 이때 사용되는 요청(Request)과 응답(Response)의 형식은 아래와 같습니다.

      • Request

      {
        jsonrpc: "2.0";
        id: string | number;
        method: string;
        params?: {
          [key: string]: unknown;
        };
      }
      • Response

      {
        jsonrpc: "2.0";
        id: string | number;
        result?: {
          [key: string]: unknown;
        }
        error?: {
          code: number;
          message: string;
          data?: unknown;
        }
      }

      Client와 Server는 초기화부터 종료까지의 명확한 생명주기(lifecycle)를 따라 상호작용하며, 아래와 같은 3단계로 구성됩니다.

      image.png

      • Initialization Phase

        • Client는 Server에 초기화를 요청합니다. (method: initialize)

        • Server는 해당 요청에 대한 응답으로, 지원 가능한 capabilities 정보와 protocolVersion을 제공합니다.

        • 이후 Client는 초기화 응답을 정상적으로 수신했음을 알리는 알림 메시지를 Server로 전달합니다. (method: notifications/initialized)

      • Operation Phase

        • Tool 정보 조회 및 Tool 실행 요청 등 다양한 상호작용을 반복적으로 처리합니다.

      • Shutdown Phase

        • Client와 Server 간의 연결을 정리하고, 통신 세션을 정상적으로 종료합니다.

      또한, MCP는 다양한 통신 환경을 고려해 다음과 같은 Transport 방식을 지원합니다:

      • stdio

      • sse (Server-Sent Events)

      • streamable http (도입일: 2025-03-26)


      MCP JAVA SDK

      MCP의 규격을 충족하기 위해 Python, TypeScript, Java 등 다양한 언어용 SDK가 제공되며, 이 중에서 MCP Java SDK를 선택 했습니다.

      이 SDK는 Server, Session, Transport 등 MCP의 핵심 계층을 모두 구현할 수 있도록 구성되어 있습니다.


      Java SDK를 통해 MCP Server를 구성하면, Tool의 정의부터 등록, 실행까지 모두 표준화된 방식으로 처리할 수 있습니다.

      image.png

      • MCP Server

        • MCP Server는 제공 가능한 기능(capabilities)과 세션(session)을 관리합니다.

        • Client의 요청은 MCP Session을 통해 처리됩니다.

      • MCP Session

        • 초기화 단계(initialization phase)와 운영 단계(operation phase)에 해당하는 로직과 처리를 담당합니다.

      • MCP Transport

        • JSON-RPC 메시지의 직렬화/역직렬화 처리를 포함하여, stdio, sse, streamable-http와 같은 Transport 스펙을 구현합니다.

      MCP Server는 생성 시, 제공 가능한 기능(capabilities)과 함께 이를 처리할 Tool, Prompt, Resource 등의 구현체를 함께 등록해야 합니다.

      아래는 Spring 기반 프로젝트에서 MCP Tool을 구성하는 예시입니다.

      @SpringBootApplication
      public class McpServerApplication {
          public static void main(String[] args) {
              SpringApplication.run(McpServerApplication.class, args);
          }
      
          @Bean
          public List<ToolCallback> weatherTools(WeatherService weatherService) {
              return List.of(ToolCallbacks.from(weatherService));
          }
      }
      @Service
      public class WeatherService {
          @Tool(description = "Get weather forecast for a specific latitude/longitude")
          public String getWeatherForecastByLocation(double latitude, double longitude) {
              // Implementation using weather.gov API
          }
      
          @Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g., CA, NY)")
          public String getAlerts(String state) {
              // Implementation using weather.gov API
          }
      }

      @Tool 어노테이션은 MCP Server에 ToolCallback 형태로 등록되며,

      이는 Tool 구현 메서드에 대한 핸들러(handler) 역할과 함께, Tool의 설명(description) 으로도 활용됩니다.


      MCP Client와 Server 간의 Tool 실행 흐름은 아래와 같습니다

      image.png


      MCP 통합 API 서버 개발

      MCP 통합 API 서버는 기존에 운영 중이던 다양한 API들을 Model Context Protocol(MCP) 표준에 맞춰 손쉽고 빠르게 통합 제공하는 것을 목표로 설계 및 구현되었습니다.

      주요 특징은 다음과 같습니다.

      1. Transport 다중 지원

        • SSE 및 Streamable HTTP 기반의 Transport 방식을 지원하여 다양한 통신 환경에 대응합니다.

      2. 유연한 API 연동 구조

        • 기존의 REST API, DSL 기반 명세, MCP STDIO, MCP SSE 방식 등 다양한 연동 방식을 지원합니다.

      3. MCP API Group 기능

        • 관련된 Tool들을 논리적으로 묶어 그룹화할 수 있으며, 이를 McpServerGroup을 통해 하나의 MCP 서버 엔드포인트로 각각 제공할 수 있습니다.

          image.png

          이러한 구조 덕분에 복잡한 API 연동도 단일한 프로토콜로 손쉽게 해결할 수 있습니다.


      Transport 다중 지원

      SSE (Server-Sent Events)

      SSE(Server-Side Emitter) 방식은 연결 유지 기반의 실시간 통신 모델로 아래와 같은 구조로 메시지를 주고받습니다:

      image.png

      • Client는 SSE 기반 통신을 위해 두 개의 endpoint를 사용합니다

        • 하나는 SSE 연결용, 다른 하나는 메시지 전달용입니다.

      • Client의 operation 요청은 메시지 전달용 endpoint를 통해 전송되며, Server의 응답은 SSE 연결을 통해 실시간으로 전달됩니다.

      • 이 방식은 stateful 통신 모델로, Server는 SSE connection 상태를 지속적으로 관리해야 합니다.

      • 따라서 클라이언트 요청은 동일한 SSE connection을 유지하고 있는 MCP Server로 정확하게 라우팅되어야 합니다.

      Streamable HTTP

      Streamable HTTP는 SSE 방식의 한계를 보완하기 위해 도입된 신규 스펙이며, MCP 공식 사양 2025-03-26에 정의되어 있습니다.

      이 방식은 Stateful과 Stateless 양쪽 방식을 모두 지원하며, MCP Server는 필요에 따라 상태 관리를 선택적으로 구현할 수 있습니다.


      Streamable HTTP(Stateless)의 주요 특징

      • MCP Client와 Server는 단일 endpoint를 통해 전체 Lifecycle을 처리합니다.

      • SSE와 달리 지속적인 연결이 유지되지 않으며, 각 요청은 독립적으로 처리됩니다.

      • 인증 및 세션 관리는 요청 단위로 수행되며, Server는 상태를 저장하지 않습니다.

      • Server는 MCP Client가 지정한 connection을 통해 결과를 즉시 반환합니다.

      MCP 통합 API 서버에서는 단일 endpoint를 기반으로 한 Streamable HTTP 방식을 구현함으로써, 보다 확장성 있는 구조를 구성할 수 있었습니다.


      API 연동 Adapter

      MCP Server에서 Tool 제공 방식

      MCP Server에서 Tool을 제공하기 위해서는 두 가지 구성 요소가 필요합니다

      1. Tool Specification: LLM에게 기능의 구조와 파라미터를 설명합니다.

      2. Tool 구현체(Adapter): 실제 API 호출 또는 비즈니스 로직을 수행하는 핸들러입니다.

      Tool Specification

      Tool Specification은 MCP에서 LLM에게 기능을 설명하는 역할을 하며, 아래와 같은 JSON 스키마 구조를 따릅니다

      {
       name: string;          // Unique identifier for the tool
       description?: string;  // Human-readable description
       inputSchema: {         // JSON Schema for the tool's parameters
         type: "object",
         properties: { ... }  // Tool-specific parameters
       },
       annotations?: {        // Optional hints about tool behavior
         title?: string;      // Human-readable title for the tool
         readOnlyHint?: boolean;    // If true, the tool does not modify its environment
         destructiveHint?: boolean; // If true, the tool may perform destructive updates
         idempotentHint?: boolean;  // If true, repeated calls with same args have no additional effect
         openWorldHint?: boolean;   // If true, tool interacts with external entities
       }
      }

      참고: API 명세서는 LLM을 통해 JSON 기반 Adapter 파일로 변경되어 사용됩니다.

      Tool 구현체 (Adapter)

      Tool 구현체는 실제 API 호출 로직을 담당하며, 입력을 DSL(Domain Specific Language)을 통해 매핑하고, 결과를 JSON-RPC 형식으로 반환하는 구조입니다.

      ToolCallback 인터페이스를 상속받아 구현되며, 실제 API 호출은 call 메서드 내에서 수행됩니다.

      이를 통해 MCP Client의 요청에 따라 MCP Server 또는 Session 내에서 유연하게 실행될 수 있습니다.

      package org.springframework.ai.tool;
      import org.springframework.ai.chat.model.ToolContext;
      import org.springframework.ai.model.function.FunctionCallback;
      import org.springframework.ai.tool.definition.ToolDefinition;
      import org.springframework.ai.tool.metadata.ToolMetadata;
      import org.springframework.lang.Nullable;
      
      public interface ToolCallback extends FunctionCallback {
          ToolDefinition getToolDefinition();
          default ToolMetadata getToolMetadata() {
              return ToolMetadata.builder().build();
          }
          String call(String toolInput);
          default String call(String toolInput, @Nullable ToolContext tooContext) {
              if (tooContext != null && !tooContext.getContext().isEmpty()) {
                  throw new UnsupportedOperationException("Tool context is not supported!");
              } else {
                  return this.call(toolInput);
              }
          }
      }

      Adapter JSON 구조

      Tool Specification과 실제 Tool 구현체가 호출할 API에 대한 명세는 아래와 같은 Adapter JSON 형식으로 관리하고 있습니다.

      [
        {
          "api" : {
            "type" : "HTTP",
            "http" : {
              "url" : "http://localhost:5000/weather/{userId}",
              "method": "GET",
              "timeout" : "2s"
      
            },
            "rest-api" : "/v1/weather",
            "requestExpression" : "{ #.userId : #.variables.userId }",
            "responseExpression" : "{#:#}"
          },
          "tool" : {
            "name": "get_weather",
            "description": "Get weather alerts for a US state. Input is Two-letter US state code (e.g. CA, NY)",
            "inputSchema":
              {
                "$schema": "https://json-schema.org/draft/2020-12/schema",
                "type": "object",
                "properties": {
                  "state": {
                    "type": "string",
                    "description": "US state code"
                  }
                },
                "required": [
                  "state"
                ]
              }
          }
        }
      ]
      `

      Adapter JSON은 MCP에서 외부 API를 Tool 형태로 추상화하기 위한 메타 정보이며, 다음과 같은 구조를 가집니다

      • api

        • 실제 호출할 API에 대한 정보를 포함하며, DSL(Domain Specific Language) 기반으로 파라미터를 매핑합니다.

        • DSL은 ANTLR4 기반으로 구성되어 런타임 시점에 계산 및 변환을 수행합니다.

      • tool

        • MCP Server가 MCP Client에 제공할 기능을 설명하는 스펙 정보로, tool의 이름(name), 설명(description), 입력 파라미터(inputSchema) 등의 정의를 포함합니다.


      MCP API Group

      Adapter JSON으로 정의된 Tool은 실제 MCP 통합 시스템에서 여러 개의 논리적인 그룹으로 묶어 운영합니다.

      각 그룹은 고유한 endpoint를 갖고 있으며, MCP Client는 이를 통해 필요한 기능만 선택적으로 호출할 수 있습니다.

      [{
        "name" : "toolbox",
        "tools" : ["get_weather"]
      },
      {
        "name" : "weather",
        "tools" : ["get_weather"]
      }]

      아래와 같이 논리적 그룹으로 여러 Tool이 재사용 되고 이를 그룹 단위로 Endpoint를 노출하게 됩니다.

      image.png

      이러한 구조를 통해 시스템은 관리가 쉬워지고, 기능별로 적절한 접근 제어와 버전 관리를 수행할 수 있습니다.


      Langchain MCP Adapters

      지금까지 설명한 구조를 기반으로, MCP Client는 sse 및 streamable http 방식을 통해 MCP 통합 API서버와 연결되어 유연하게 Tool을 사용할 수 있게 되었습니다.


      LangChain MCP Adapters를 사용하면, LangGraph 기반의 에이전트에서도 MCP로 제공되는 API를 손쉽게 통합할 수 있습니다.

      아래는 MultiServerMCPClient를 사용해 MCP 통합 API서버에 Group별로 Tool을 호출하는 예제입니다

      import os
      
      from langchain_mcp_adapters.client import MultiServerMCPClient
      from langchain_openai import ChatOpenAI
      from langgraph.prebuilt import create_react_agent
      import asyncio
      
      model = ChatOpenAI()
      async def main():
          async with MultiServerMCPClient(
              {
                  "toolbox" :{
                      "url" : "http://{mcp-server}/mcp/toolbox/streamable",
                      "transport" : "streamable_http", # sse or streamable_http
                  },
                  "weather" :{
                      "url" : "http://{mcp-server}/mcp/weather/streamable",
                      "transport" : "streamable_http", # sse or streamable_http
                  }
              }
          ) as client:
              tools = client.get_tools()
              agent = create_react_agent(model, tools=client.get_tools(), debug=True)
              response = await agent.ainvoke({"messages": "what is the weather in nyc?"})
              messages = response["messages"]
              final_message = messages[-1]
              print(final_message.content)
      
      if __name__ == "__main__":
          asyncio.run(main())

      이처럼 LangChain 기반 워크플로우에서도 MCP를 통해 다양한 API를 표준화된 Tool로 활용할 수 있습니다.


      결론

      MCP 통합 API 서버를 도입함으로써, 기존에 REST API로만 제공되던 데이터를LLM 어플리케이션에서 보다 빠르고 유연하게 통합할 수 있게 되었습니다.

      Tool 추상화, Group 기반 Endpoint 관리, 다양한 Transport 지원 등은에이전트 개발 효율성과 유지보수성을 크게 향상시켰습니다.

      이 글이 유사한 고민을 하고 있는 분들께 실용적인 인사이트와 영감이 되길 바랍니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      mistinto 님의 최신 블로그

      더보기

      DEVOTEE 추천 블로그

      동영상 기고하기