5장. LLM 외부 도구 연동
MCP 란 무엇인가
예전에는 휴대폰마다 충전기 단자가 달라서, 새 휴대폰을 사면 충전기도 새로 사야 했습니다. 단자를 USB-C 하나로 맞추자 어느 회사의 충전기든 꽂아 쓸 수 있게 됐습니다. AI 앱과 도구 사이에도 같은 일이 있었습니다. 앱마다 도구를 붙이는 방식이 달라서, 같은 "상품 찾기" 도구를 챗봇용, 코드 편집기용으로 따로 만들어야 했습니다. MCP 는 도구를 꽂는 단자를 맞춘 규격입니다.
왼쪽 파랑 상자는 규격이 없을 때입니다. 앱이 바뀔 때마다 같은 도구를 다시 짭니다. 오른쪽 보라 상자는 MCP 를 쓸 때입니다. 도구를 MCP 서버 하나로 만들어 두면, MCP 를 아는 앱(챗봇, 코드 편집기, 데스크톱 AI 앱)은 어디서든 꽂아 씁니다. 여기서 충전기가 MCP 서버, 휴대폰이 AI 앱, USB-C 단자가 MCP 규격입니다. 비유와 다른 점은, 충전기는 전기만 보내지만 MCP 서버는 도구 목록과 설명까지 함께 알려 주어서, 앱이 무슨 도구인지 미리 몰라도 받아 쓸 수 있다는 것입니다.
MCP 는 Anthropic 이 공개한 열린 규격(open protocol)입니다. 규격 문서와 여러 언어의 SDK(Software Development Kit, 개발 도구 모음)가 공개되어 있어 누구나 서버와 클라이언트를 만들 수 있습니다. 이 장에서는 파이썬 SDK 인 mcp 패키지(이 교안은 1.30 판)를 씁니다.
@tool 과 MCP 견주기
| 견줄 것 | @tool(LangChain 도구) | MCP 서버의 도구 |
|---|---|---|
| 사는 곳 | 우리 챗봇 프로그램 안 | 따로 도는 서버 프로그램 |
| 쓸 수 있는 앱 | 그 프로그램(LangChain)만 | MCP 를 아는 모든 앱 |
| 만드는 법 | @tool | @mcp.tool() |
| 부르는 법 | 함수처럼 바로 | 클라이언트가 요청을 보내 서버가 실행 |
| 어울리는 때 | 이 챗봇에서만 쓰는 작은 도구 | 여러 앱이 함께 쓸 도구, 남이 만든 도구 |
MCP 서버가 내놓는 세 가지
| 이름 | 원래 말 | 뜻 | 이 장에서 |
|---|---|---|---|
| 도구 | tools | 모델이 골라 부르는 함수 | find_products, read_file 을 만든다 |
| 자료 | resources | 앱이 읽어 가는 파일, 표 같은 자료 | 다루지 않는다 |
| 프롬프트 | prompts | 미리 만들어 둔 프롬프트 틀 | 다루지 않는다 |
짧은 예시
같은 함수 하나를 LangChain 도구와 MCP 도구로 각각 포장해 봅니다. 서버는 띄우지 않고, MCP 서버 객체에 등록된 도구 목록만 꺼내 봅니다.
import asyncio
from langchain_core.tools import tool
from mcp.server.fastmcp import FastMCP
def find_region(region: str) -> str:
"""지역 이름으로 구름다리여행 상품을 찾는다."""
return f"{region} 상품 목록"
# 포장 하나: LangChain 도구
lc_tool = tool(find_region)
# 포장 둘: MCP 서버의 도구. mcp.tool() 이 돌려준 데코레이터에 함수를 넣는다
mcp = FastMCP("demo")
mcp.tool()(find_region)
# list_tools 는 비동기 함수라 asyncio.run 으로 실행한다. 서버를 띄우지는 않는다
mcp_tools = asyncio.run(mcp.list_tools())
print("LangChain:", lc_tool.name, "|", lc_tool.description, "|", list(lc_tool.args))
for t in mcp_tools:
print("MCP :", t.name, "|", t.description, "|", list(t.inputSchema["properties"]))LangChain: find_region | 지역 이름으로 구름다리여행 상품을 찾는다. | ['region']
MCP : find_region | 지역 이름으로 구름다리여행 상품을 찾는다. | ['region']두 포장 모두 함수 이름, docstring, 인자에서 같은 세 가지(이름, 설명, 인자)를 뽑아냈습니다. 차이는 사는 곳입니다. LangChain 도구는 이 프로그램 안에서 바로 불리고, MCP 도구는 서버를 띄운 뒤 다른 프로그램(클라이언트)이 요청을 보내야 불립니다. 그 대신 MCP 도구는 LangChain 을 쓰지 않는 앱에서도 씁니다.
코드가 의미하는 것
이 코드는 같은 충전기 하나를 두 가지 단자로 포장해 보는 것입니다. 함수 하나를 LangChain 도구로 한 번, MCP 서버의 도구로 한 번 포장하고, 둘이 내놓는 이름표를 견줍니다.
| 코드 | 하는 일 | 챗봇에서 뜻하는 것 |
|---|---|---|
tool(find_region) | 데코레이터를 함수처럼 불러 도구로 바꾼다 | 함수 위에 @tool 을 얹는 것과 같습니다. 이 프로그램 안에서만 쓰는 포장입니다 |
FastMCP("demo") | 이름이 demo 인 MCP 서버 객체를 만든다 | 다른 앱이 꽂아 쓸 충전기 몸통입니다. 아직 켜지지 않았습니다 |
mcp.tool()(find_region) | 서버에 함수를 도구로 등록한다 | 함수 위에 @mcp.tool() 을 얹는 것과 같습니다. 같은 함수가 MCP 규격의 도구가 됩니다 |
asyncio.run(mcp.list_tools()) | 등록된 도구 목록을 비동기로 꺼낸다 | 클라이언트가 "도구 목록을 달라"고 할 때 서버가 내놓을 목록입니다 |
t.inputSchema["properties"] | MCP 도구의 인자 스키마를 읽는다 | LangChain 도구의 args 에 해당하는 칸입니다. 이름만 다르고 담긴 것은 같습니다 |
결과에서 읽을 것은 두 가지입니다.
- 두 줄이 똑같습니다. 이름
find_region, 설명, 인자['region']가 두 포장에서 같게 나왔습니다. 도구를 이루는 세 부분은 포장이 바뀌어도 그대로입니다. - 다른 점은 출력에 보이지 않는 곳에 있습니다. LangChain 도구는 이 프로그램이 바로 부르고, MCP 도구는 서버를 띄운 뒤 클라이언트의 요청으로 불립니다. 그 차이는 실습 4에서 서버를 실제로 켜 보면 드러납니다.
주의할 점
- MCP 는 모델이 아니라 "도구를 꽂는 방식"입니다. MCP 서버를 붙여도 도구를 고르는 것은 여전히 모델이고, 이 장에서는 OpenAI 모델이 고릅니다.
- 남이 만든 MCP 서버는 내 컴퓨터에서 프로그램으로 돕니다. 믿을 수 있는 곳의 서버만 쓰고, 어떤 파일과 서비스에 손대는지 먼저 읽어 봅니다. "도구를 맡길 때의 안전" 절에서 다시 봅니다.