LY Corporation Tech Blog

LY Corporation과 LY Corporation Group(LINE Plus, LINE Taiwan and LINE Vietnam)의 기술과 개발 문화를 알립니다.

MCP 개념 및 LINE Messaging API를 활용한 MCP 서버 구축 사례 소개

들어가며

최근 Anthropic에서 Claude LLM을 통해 모델 컨텍스트 프로토콜(Model Context Protocol, 이하 MCP)을 발표했습니다. MCP는 대형 언어 모델(large language model, 이하 LLM)이 외부 데이터 소스나 기능을 사용할 수 있도록 돕는 프로토콜로, Anthropic에서 누구나 사용할 수 있는 오픈 프로토콜로 공개했습니다(참고). 이에 따라 많은 서비스에서 MCP를 지원하기 시작했고, 많은 사용자가 MCP를 사용해 LLM과 외부 서비스를 연결하는 방법에 관심을 갖기 시작했습니다.

이번 글에서는 많은 관심을 받고 있는 MCP의 개념과 아키텍처를 설명하고, LINE Messaging API를 활용해 MCP 서버를 구현하는 방법을 소개하겠습니다.

MCP 소개

MCP는 LLM이 외부 기능을 사용할 수 있도록 지원하는 프로토콜입니다. 아래는 LLM만 단독으로 사용하는 경우와 MCP를 활용한 경우를 비교한 그림입니다.

image

예를 들어 LINE의 오픈소스 라이브러리인 Armeria에서 특정 코드를 검색하고 싶을 때 LLM 애플리케이션에 프롬프트를 작성해 요청하면, LLM 애플리케이션은 실제 GitHub에 접속해서 Armeria 라이브러리를 조사하는 것이 아니라 기존에 학습한 모델을 바탕으로 응답할 것입니다. AI 할루시네이션이 발생할 수 있는 상황이죠. 

반면 GitHub MCP를 사용하면 LLM 애플리케이션이 GitHub에 접속해 실제 Armeria 리포지터리에서 해당 코드를 검색한 뒤 검색 결과를 기준으로 응답합니다. 다만 이를 위해서는 외부 서비스인 GitHub에서 MCP 서버를 제공해야 하며, 사용하는 LLM 애플리케이션에서도 이 MCP를 사용해 호출해야 하는데요. 이와 같이 LLM 애플리케이션에서 외부 기능을 사용할 수 있도록 정의한 프로토콜을 MCP라고 합니다(참고로 GitHub은 실제로 GitHub MCP를 제공하고 있습니다).

아키텍처

MCP는 기본적으로 호스트의 클라이언트가 서버와 연결되는 클라이언트-서버 아키텍처를 따릅니다. 

image

이 아키텍처는 호스트, 클라이언트, 서버, 이 세 가지 주체로 구성되며, 각 주체의 역할은 다음과 같습니다.

  • 호스트: MCP를 사용하는 주체인 LLM 애플리케이션을 가리키며, 사용자의 요청을 받아 응답하는 애플리케이션입니다. 이후 예제에서 'Claude 데스크톱 애플리케이션'이 호스트에 해당합니다.
  • 클라이언트: 호스트의 내부 모듈로 MCP 서버에 요청을 전송한 뒤 응답을 받아 호스트에게 전달합니다.
  • 서버: 호스트 외부에 존재하며 MCP 클라이언트로부터 받은 요청을 처리하고 응답하는 애플리케이션입니다.

구성 요소

MCP 호스트가 사용할 수 있는 요소는 다양합니다. 그중 가장 핵심적인 요소인 툴과 리소스를 소개하겠습니다.

툴(tools)은 MCP의 핵심 요소로 외부 기능을 실행할 수 있도록 MCP 서버가 제공하는 요소입니다. MCP 서버는 실행할 수 있는 툴 목록을 확인할 수 있는 엔드포인트인 tools/list와, 원하는 툴을 호출할 수 있는 엔드포인트인 tools/call를 제공합니다. MCP 호스트는 사용자 프롬프트에 대한 응답을 처리하는 과정에서 외부 기능 호출이 필요한 경우 MCP 클라이언트를 통해 MCP 서버가 제공하는 툴을 사용합니다. 

예를 들어 GitHub MCP 서버에서는 create_pull_request라는 툴을 제공하며, 사용자는 프롬프트를 통해 이 툴을 이용해 새로운 PR을 만들 수 있습니다.

리소스

리소스(resources) 역시 MCP의 핵심 요소로, MCP 서버가 제공할 수 있는 다양한 형태의 데이터나 콘텐츠를 의미합니다. 리소스는 파일 내용이나 데이터베이스 레코드, API 응답 등 다양한 형태로 존재할 수 있습니다. MCP 클라이언트는 MCP 서버에 사용할 수 있는 리소스 목록을 요청해 받은 뒤, 다시 필요한 리소스를 요청해서 데이터를 가져올 수 있습니다. MCP 클라이언트가 가져온 데이터는 MCP 호스트로 전달되며, MCP 호스트는 이 데이터를 사용자의 프롬프트 응답에 활용할 수 있습니다.

예를 들어 GitHub MCP 서버에서는 repo://{owner}/{repo}/contents{/path*} API 리소스를 통해 특정 리포지터리의 소스 코드를 제공합니다. 

작동 방식

MCP는 어떻게 구현하느냐에 따라서 다양한 방식으로 작동할 수 있는데요. 이 글에서는 아래 그림과 함께 가장 기초적인 방식을 알아보겠습니다.

image

  1. MCP 호스트가 실행될 때 MCP 클라이언트를 통해 MCP 서버의 tools/list 엔드포인트를 호출해 사용 가능한 툴 목록을 받아옵니다.
  2. 사용자가 MCP 호스트에게 프롬프트를 보냅니다.
  3. MCP 호스트는 사용자의 프롬프트와 사전에 받아온 툴 목록을 LLM 모델로 전달합니다. LLM 모델은 툴 목록 중 사용이 필요하다고 판단된 툴들을 사용하겠다고 응답합니다.
  4. MCP 호스트는 MCP 클라이언트를 통해 MCP 서버의 tools/call 엔드포인트로 해당 툴 사용을 요청합니다.
  5. MCP 호스트는 MCP 서버의 툴 응답과 기존 사용자의 프롬프트를 다시 LLM 모델로 전달하고, LLM 모델은 이를 기반으로 최종 응답을 생성합니다.
  6. MCP 호스트는 LLM 모델로부터 받은 최종 응답을 가공해 사용자에게 전달합니다.

LINE Messaging API와 함께 하는 MCP 활용 사례

이제 LINE의 Messaging API를 활용해 MCP를 직접 사용해 보겠습니다. LINE은 LINE 공식 계정(Official Account, OA)을 위한 Messaging API를 제공하고 있으며, 이를 통해 공식 계정을 친구로 등록한 사용자에게 메시지를 보내는 등의 행동을 할 수 있는데요. 이를 활용해 MCP 서버를 구축해 보겠습니다. MCP 공식 사용자 가이드의 For Server Developers 문서와 LINE Developers 사이트의 Messaging API 문서를 함께 참고하시면 좋을 것 같습니다.

사전 준비

LINE Messaging API를 활용해 MCP 서버를 구축하기 위해서는 다음 준비가 필요합니다.

LINE Messaging API 사용 준비까지 완료됐다면 발급받은 채널 액세스 토큰을 사용해 API가 정상적으로 작동하는지 확인합니다. 이 글에서는 셸(shell)에서 확인하겠습니다. 다음과 같이 앞서 발급받은 채널 액세스 토큰을 Authorization 헤더에 넣고 broadcast API를 호출합니다(broadcast API의 사양은 LINE Messaging API 공식 가이드의 Send broadcast message 문서를 참고하세요). 

curl -v -X POST https://api.line.me/v2/bot/message/broadcast \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer {Channel Access Token}" \
-H "X-Line-Retry-Key: ${uuidgen}" \
-d '{
    "messages": [
        {
            "type": "text",
            "text": "Hello, world"
        }
    ]
}'

위 명령어를 실행했을 때 미리 친구로 추가해 둔 공식 계정으로부터 메시지가 오면 성공입니다!

MCP 서버 개발

이제 본격적으로 MCP 서버를 개발해 보겠습니다. 먼저 MCP 공식 사용자 가이드를 참고해 uv를 설치한 후 Python 프로젝트를 생성하고 main.py를 만듭니다.

# 프로젝트를 위한 새 디렉토리 생성
uv init line-mcp
cd line-mcp

# 가상 환경 생성 및 활성화
uv venv
source .venv/bin/activate

# 의존성 설치
uv add "mcp[cli]" httpx

# 서버 파일 생성
touch main.py

이후 아래 Python 코드를 main.py에 추가합니다. 아래 코드는 broadcast_message라는 툴을 제공하는 간단한 MCP 서버를 만드는 코드입니다. MCP 클라이언트가 broadcast_message 툴을 통해 메시지를 전송하면, 전달받은 메시지를 모든 친구에게 보내도록 LINE Messaging API 중 'https://api.line.me/v2/bot/message/broadcast' 엔드포인트를 호출합니다.

# main.py
import os
import uuid
import httpx
from mcp.server.fastmcp import FastMCP

# FastMCP 서버 초기화
# "line" 채널을 사용하고, httpx, xmltodict를 의존성으로 추가
mcp = FastMCP("line", dependencies=["httpx", "xmltodict"])

# 환경 변수에서 CHANNEL_ACCESS_TOKEN 가져오기
# LINE Developer Console에서 얻은 토큰을 설정합니다.
CHANNEL_ACCESS_TOKEN = os.environ.get("CHANNEL_ACCESS_TOKEN")

@mcp.tool(
    name="broadcast_message",
    description="LINE Messaging API를 사용하여 메시지를 브로드캐스트합니다. 'messages' 매개 변수는 최대 5개의 메시지를 허용합니다. 지원되는 메시지 유형:\n"
                "- 텍스트 메시지: {'type': 'text', 'text': '안녕하세요, 세계'}\n"
)
def broadcast_message(messages: list):
    # HTTP 요청 헤더 설정
    # Content-Type: JSON 형식
    # Authorization: LINE API 인증을 위한 Bearer 토큰
    # X-Line-Retry-Key: 중복 요청을 방지하기 위한 고유 키(UUID 사용)
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {CHANNEL_ACCESS_TOKEN}",
        "X-Line-Retry-Key": str(uuid.uuid4()),
    }
    # LINE Messaging API에 HTTP POST 요청 보내기
    # 브로드캐스트 엔드포인트를 사용하여 입력된 메시지를 모든 친구에게 보냅니다.
    with httpx.Client() as client:
        response = client.post(
            "https://api.line.me/v2/bot/message/broadcast",
            headers=headers,
            json={"messages": messages},
        )
    return response.text

if __name__ == "__main__":
    # FastMCP 서버를 stdio 전송 방식으로 실행
    mcp.run(transport="stdio")

프로젝트가 잘 생성됐는지 확인하기 위해 다음 명령을 실행해 MCP 서버를 구동합니다. 잘 작동하면 MCP 서버 구축이 완료된 것입니다.

uv run main.py

Claude 데스크톱 애플리케이션에 MCP 서버 설정

Claude 데스크톱 애플리케이션(MCP 호스트)에서 MCP 서버를 사용하기 위해서는 해당 서버 정보를 호스트에 등록해야 합니다. MCP 호스트에 등록하기 위해서는 설정 파일을 수정해야 하는데요. MCP 공식 사용자 가이드를 참고해 claude_desktop_config.json 설정 파일을 열어 앞서 작업한 MCP 서버(line-mcp)를 추가합니다.

{
    "mcpServers": {
        "line-mcp": {
            "command": "uv",
            "args": [
                "--directory",
                "/{Project Parent Location}/line-mcp",
                "run",
                "main.py"
            ],
            "env": {
                "CHANNEL_ACCESS_TOKEN": "{channel_access_token}"
            }
        }
    }
}

위와 같이 설정하면 Claude 데스크톱 애플리케이션 실행 시 설정한 정보에 따라 구축한 MCP 서버가 자동으로 실행됩니다. 위 설정 파일에 어떤 정보를 입력했고 입력된 정보가 어떤 역할을 하는지 간략히 살펴보겠습니다.  

  • mcpServersline-mcp 추가('line-mcp'라는 이름으로 MCP 서버 등록)
  • commanduv의 경로 입력(서버 실행 명령어 입력)
    • 만약 macOS에서 uv가 제대로 작동하지 않는 경우 셸에서 which uv 실행해 uv 경로 확인 후 해당 경로 입력
  • args에 실행할 프로젝트의 위치와 실행 파일 입력
  • envCHANNEL_ACCESS_TOKEN 설정 추가 후 발급받은 채널 액세스 토큰 입력

설정 파일 저장 후 Claude 데스크톱 애플리케이션을 실행합니다. 제대로 설정한 경우 아래 그림과 같이 망치 표시와 함께 사용할 수 있는 MCP 툴이 있다는 것을 확인할 수 있습니다. 

image

MCP 사용하기

이제 본격적으로 저희가 구축한 MCP 서버와 Claude 데스크톱 애플리케이션을 사용해 MCP를 사용해 보려고 합니다. 이를 위해 다음과 같은 상황이라고 가정하겠습니다.

"우리는 '오이시'라는 일본 초밥집을 운영하는 사장님이며, 마케팅에 LINE 공식 계정을 사용합니다."

저희 공식 계정을 친구로 추가한 고객들에게 초밥을 홍보하는 메시지를 보내기 위해서 LINE Messaging API에서 제공하는 broadcast API를 이용하려고 합니다. 아래 프롬프트를 사용해 고객들에게 초밥을 홍보하는 메시지를 전송해 보겠습니다.

나는 초밥집 '오이시'의 사장님이야. 고객들에게 초밥을 홍보하는 메시지를 보내줘.

프롬프트를 입력하면 MCP 호스트는 내부적으로 broadcast_message 툴을 사용합니다. 'Claude 데스크톱 애플리케이션'의 UI에서 플러그 모양과 함께 툴이 사용된 것을 확인할 수 있으며, 실제로 공식 계정으로부터 메시지가 전송되는 것을 확인할 수 있습니다.

image

위 작동 과정을 조금 더 자세히 살펴보면 다음과 같습니다.

  1. 사용자가 Claude 데스크톱 애플리케이션(MCP 호스트)을 실행하는 순간 설정 파일에 작성된 command 설정을 통해 MCP 서버가 실행됩니다.
  2. MCP 호스트가 MCP 클라이언트를 통해 MCP 서버의 tools/list 엔드포인트를 호출해 사용 가능한 툴 목록을 받아옵니다.
  3. MCP 호스트는 사용자가 입력한 프롬프트를 사용 가능한 툴의 목록과 함께 LLM 모델에게 전달합니다.
  4. LLM 모델은 사용자가 입력한 프롬프트 중 '메시지를 보내'라는 부분에서 broadcast_message 툴을 사용하기로 결정하고 MCP 호스트에게 해당 툴을 사용하도록 전달합니다.
  5. MCP 호스트는 broadcast_message 툴의 description에 명시된 형식에 맞게 요청을 생성한 뒤 MCP 클라이언트를 통해 MCP 서버에 해당 툴을 호출합니다.
  6. MCP 서버는 tools/call 엔드포인트를 통해 요청을 받아 정의된 툴을 실행하며 LINE Messaging API에 요청을 전송합니다.

MCP 응용하기

다른 MCP 서버를 추가로 사용해 보다 다양한 사용 사례를 만들어 보겠습니다.

이번에는 날씨에 따라 먹고 싶은 초밥이 다를 수 있으므로 그날의 날씨에 맞는 초밥을 홍보하는 메시지를 전송해 볼 텐데요. 날씨 정보를 얻기 위해 저희가 구축한 MCP 서버가 아닌 다른 MCP 서버를 사용해 보겠습니다. MCP GitHub의 servers 리포지터리에는 사용할 수 있는 여러 종류의 MCP 서버가 안내돼 있는데요. 날씨 검색을 위해 그중 Brave Search를 사용하겠습니다. Brave Search는 검색 엔진으로, MCP를 통해 검색할 수 있는 툴을 제공합니다. 참고로 이 툴을 사용하기 위해서는 Brave Search 회원 가입 후 API 키를 발급받아야 합니다. 자세한 방법은 MCP GitHub의 Brave Search MCP Server를 참고하시기 바랍니다.

준비를 마친 뒤 아래 프롬프트를 통해 고객들에게 초밥을 홍보하는 메시지를 전송해 보겠습니다.

나는 초밥집 '오이시'의 사장님이야. 내일 날씨에 어울리는 초밥을 홍보하는 메시지를 보내줘

위 프롬프트를 입력하면 MCP 호스트가 날씨에 맞는 초밥을 홍보하는 메시지를 보내는 것을 확인할 수 있습니다.

image

위 작동 과정을 조금 더 자세히 살펴보면 다음과 같습니다.

  1. MCP 호스트는 사용자가 입력한 프롬프트를 사용 가능한 툴 목록과 함께 LLM 모델에게 전달합니다.
  2. LLM 모델은 사용자가 입력한 프롬프트 중 '내일 날씨'라는 부분에서 brave MCP 서버의 brave_web_search 툴을 사용하기로 결정하고 MCP 호스트에게 해당 툴을 사용하도록 전달합니다.
  3. MCP 호스트가 MCP 클라이언트를 통해 해당 툴을 호출하고, brave MCP 서버는 내부적으로 지정된 검색 엔진에서 날씨 정보를 검색해 응답합니다.
  4. MCP 호스트는 날씨 정보를 활용해 날씨에 맞는 초밥을 홍보하는 메시지를 작성합니다.
  5. MCP 호스트는 앞서 구축한 line-mcp MCP 서버의 broadcast_message 툴을 호출합니다
  6. line-mcp MCP 서버는 최종적으로 LINE Messaging API를 이용해 LINE 공식 계정을 친구로 등록한 사용자들에게 메시지를 전송합니다.  

마치며

어떠신가요? MCP의 세계가 매우 흥미롭지 않나요? LLM을 외부 서비스와 함께 사용할 수 있다면 더욱 강력한 도구가 될 것이며, 생산성 또한 더욱 향상될 것입니다. 이와 같은 기대 속에 점점 더 많은 MCP 서비스가 생겨나고 있으며, OpenAI와 같은 다른 LLM 모델 제공자도 MCP를 도입하거나 자체 프로토콜을 구축할 것으로 보입니다.

LINE GitHub에서는 필요하신 분들이 편히 사용하실 수 있도록 아래와 같이 공식적으로 제작한 MCP 서버를 제공하고 있습니다. 

이 글을 읽는 독자분들도 직접 MCP를 활용한 애플리케이션을 사용해 보셔서 MCP의 힘을 느껴보시기를 바라며 이만 마치겠습니다.