2025년 3월 28일 금요일

인공지능 AI 에이전트 표준 프로토콜 MCP 사용, 분석 및 개발

이 글은 앤트로픽(Anthropic. 클로드 개발사)의 인공지능 AI 에이전트 표준 프로토콜 MCP(Model Context Protocol) 사용하는 방법을 간략히 설명한다. 
개념

MCP는 애플리케이션이 LLM에 컨텍스트를 제공하는 방식을 표준화한 개방형 프로토콜이다. USB-C 포트처럼, 다양한 도구와 데이터를 LLM에 연결하는 통합된 인터페이스 역할을 한다. LLM 기반 에이전트와 워크플로우 구축을 지원하며, 유연한 통합, 데이터 보호, 공급업체 간 전환성을 제공한다.  
애트로픽 MCP 소개

이 글은 주로 다음 문서를 참고하였다.

MCP 개념 
아키텍처 구조
MCP는 호스트-클라이언트-서버 구조로 구성되며, 로컬 및 원격 데이터를 안전하게 연결할 수 있는 아키텍처를 따른다. 호스트는 서버에서 제공해 주는 파일관리, 웹서칭, 계산 등의 도구를 연결해 LLM을 통해 추론, CoT, 도구 호출, 생성 등의 역할을 담당한다.   
MCP 구조

각 구성요소의 역할은 다음과 같다.
  • MCP 호스트는 MCP 프로토콜을 통해 서비스에 액세스할 수 있는 애플리케이션이다. Claude 데스크톱 앱, AI 에이전트/CLI, 커서 IDE 등이 이에 해당하며, LLM(로컬 또는 원격)을 활용하여 다양한 작업을 수행한다.  
  • MCP 클라이언트는 MCP 서버와 연결하기 위해 호스트 애플리케이션과 통합된 클라이언트이다.  
  • MCP 서버는 MCP 프로토콜을 통해 특정 기능을 노출하는 응용 프로그램 또는 프로그램이다. 서버는 Docker 컨테이너, JVM, Node.js(UV/UVX) 프로세스에서 실행될 수 있으며, MCP 커뮤니티에서 제공하는 사전 구축된 서버를 활용할 수도 있다.  
  • 로컬 데이터 소스는 로컬 시스템에 존재하는 데이터베이스 또는 파일 시스템이다.  
  • 원격 서비스는 웹 API를 통해 액세스할 수 있는 GitHub, Brave Search와 같은 외부 리소스이다.
MCP를 이용하면, 서버, 클랑이언트, 로컬에 있는 파일, 폴더, 앱에 접근해 이를 LLM(Large Language Model)으로 컨트롤할 수 있다. 

MCP 구조를 구성하는 호스트와 서버는 다음과 같은 도구들을 통해 구성해 활용한다.
MCP는 전형적인 호스트-서버 프로토콜(TCP/IP와 유사)을 따른다. 서버의 실행 모드는  SSE(server sent event)와 stdio(표준입출력) 모드가 있다. SSE는 네트웍으로 연결해 도구를 호출할 수 잇도록 한다. stdio는 로컬 자체에서 도구를 호출할 수 있도록 한다.

도구 호출 및 정보 교환 프로토콜은 JSON-RPC 포맷을 따르며, 예를 들어 도구 호출 시 다음과 같이 호스트-서버 간 정보를 주고 받는다. 
# 호출
{
  "jsonrpc": "2.0",
  "id": "call-1",
  "method": "callTool",
  "params": {
    "name": "create_record",
    "arguments": {
      "title": "New record",
      "content": "Record content"
    }
  }
}

# 응답
{
  "jsonrpc": "2.0",
  "id": "call-1",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Created New Record"
      }
    ]
  }
}

호스트와 서버 도구 간 검색 및 호출 방법
MCP의 도구는 서버가 호스트에 연결된 클라이언트 요청을 받아 실행 가능한 기능을 외부에 노출하고, LLM이 작업을 수행하는 데 활용할 수 있도록 설계된 요소이다. 도구는 클라이언트를 통해 검색 가능하며(`tools/list`), 작업 수행 요청은 `tools/call` 엔드포인트를 통해 전달된다. 

다음은 도구를 기술하는 메타데이터이다.
{
  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
  }
}
 
도구는 단순한 계산부터 복잡한 API 연동까지 다양할 수 있고, 고유한 이름과 설명을 통해 식별되고 사용된다.  

도구는 다음과 같이 정의, 호출된다. 
app = Server("example-server")

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="calculate_sum",
            description="Add two numbers together",
            inputSchema={
                "type": "object",
                "properties": {
                    "a": {"type": "number"},
                    "b": {"type": "number"}
                },
                "required": ["a", "b"]
            }
        )
    ]

@app.call_tool()
async def call_tool(
    name: str,
    arguments: dict
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    if name == "calculate_sum":
        a = arguments["a"]
        b = arguments["b"]
        result = a + b
        return [types.TextContent(type="text", text=str(result))]
    raise ValueError(f"Tool not found: {name}")

MCP 도구를 구현할 때는 다음과 같은 권장사항을 따르는 것이 좋다.  

도구는 명확한 이름과 설명을 갖추고, 매개변수는 JSON 스키마로 상세히 정의하며, 사용 예제를 포함해 모델이 이해하고 활용할 수 있도록 한다. 작업의 안정성과 신뢰성을 위해 오류 처리와 유효성 검사를 구현하고, 긴 작업은 진행 상황 보고를 포함하며, 원자성을 유지해야 한다.  
반환 값 구조는 문서화하고, 적절한 시간 초과와 리소스 사용 제한을 설정하며, 디버깅 및 모니터링을 위한 로깅 기능도 포함해야 한다.

MCP 사용 및 개발
기본 MCP 사용 환경 준비
파이썬 MCP Claude 기반 실습을 위해 다음을 설치한다. 
터미널에서 다음을 패키지들을 설치한다.
pip install mcp pydantic-ai fastmcp tavily-python 

이제, MCP 실행 방법을 살펴본다. 일단, 다음 MCP Quickstart에 있는 파일 system 도구를 설치해 본다. 
설치는 해당 MCP 도구 설명 링크에 다음처럼 나와 있다.
파일 관리 MCP 서버 도구의 경우
Firecrawl 클롤러 MCP 서버 도구의 경우

해당 MCP 서버 설정하는 메뉴를 선택한다. 이는 클로드 데스크탑 실행 후 파일>설정>개발자>설정편집 메뉴에 있다.
클로드 데스크탑의 해당 설정 메뉴
MCP 설정 JSON 파일

다음과 같이 클로드 데스크탑의 MCP 설정 파일인 claude_desktop_config.json을 편집기로 오픈한 후, 다음과 같이 MCP 도구를 추가하고, 클로드를 다시 리부팅한다. 
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"C:\\Users\\<사용자계정 폴더명>\\Desktop",
"C:\\Users\\<사용자계정 폴더명>\\Downloads"
]
},
}
}

참고로, 설치된 서버 도구의 경로는 절대 경로를 입력하고, 사용자 계정별로 정확한 폴더명을 사용한다. 경로 상 '\'는 '\\'로 입력하도록 한다.  

재부팅하면, 해당 MCP 도구가 다음과 같이 활성화되어 있을 것이다.

혹시 제대로 실행되지 않으면, 클로드 데스크탑이 설치된 폴더 아래 log파일을 확인한다. 그럼, 서버 도구 별로 에러 원인을 확인할 수 있다(보통 잘못된 경로, 키, 토큰 한계 오버플로우 등 문제).

이제 다음과 같이 클로드에서 파일을 생성, 추가, 삭제하는 등의 프롬프트를 입력해 본다.

난 톰이야. 개발자야. 요즘 시티팝에 대해 흥미가 있어. 유명한 시티팝 가수를 알려줘. 그 정보를 리스트해서 REPORT.TXT 란 이름으로 내 폴더에 저장해줘.

다음과 같이 바탕화면에 REPORT.TXT 가 내용 정리되 저장된다. 

firecrawl MCP 도구를 이용해 여행 뉴스를 결과는 다음과 같다. 

토큰 한계로 인해 에러가 발생할 수도 있으니 이때는 이를 고려해 프롬프트를 다시 수정 입력한다.  
예. 이제 여름이야. firecrawl 를 이용해서 여행 뉴스를 한개 검색해 알려줘.

파이썬 MCP Claude 기반 계산기 도구 개발
mcp-simple-calc.py란 이름으로 서버를 다음과 같이 코딩한다.
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("simple-calc")

# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
    """Calc and Add two numbers"""
    return a + b

다음과 같이 Claude 서버에 설치한다. 
mcp install mcp-simple-calc.py

MCP 검사기로 테스트한다.
mcp dev mcp-simple-calc.py

Claude 데스크탑을 재부팅하고, 도구 표시가 있는 지 확인한다.

다음과 같이 개발자 도구가 제대로 설치되었는지 확인한다. 없다면, 컴퓨터 재부팅한후 다시 Claude 데스크탑 실행한다. 
설정 편집 버튼(파일>설정>개발자>설정편집)을 클릭하면, 다음과 같이 설치된 것을 확인할 수 있다. 
설정편집
참고로, 에러가 발생한 도구는 느낌표로 표시되므로 로그를 확인해 본다. 그리고, 아래 설정파일에서 에러를 수정하면 된다. 
에러로그 확인
수정 후 정상 동작되는 서버

이제 프롬프트를 입력해 제대로 실행되는 지 확인한다. MCP 도구를 검색해 계산 결과를 출력해 준다.

네이버 날씨 MCP 도구 개발
다음과 같이 코딩하고, mcp-weather.py 로 저장한다.
from typing import Any
import requests
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP
import sys

mcp = FastMCP("weather")

# 네이버 날씨 정보 도구
@mcp.tool()
def get_naver_weather(region: str) -> str:
    """
    네이버 날씨에서 특정 지역 날씨 정보를 가져옴.

    Args:
        region: 조회할 지역명 (예: 서울, 부산)
    """
    try:
        search_url = f"https://search.naver.com/search.naver?query={region}+날씨"
        headers = {
            "User-Agent": "Mozilla/5.0"
        }
        response = requests.get(search_url, headers=headers, verify=False)
        soup = BeautifulSoup(response.text, "html.parser")

        temperature = soup.select_one(".temperature_text > strong")
        status = soup.select_one(".weather_main")

        if not temperature or not status:
            return f"[{region}]의 날씨 정보를 불러올 수 없습니다. 지역명을 확인해 주세요."

        temp_text = temperature.get_text(strip=True)
        status_text = status.get_text(strip=True)

        return f"{region}의 현재 날씨는 '{status_text}'이며, 기온은 {temp_text}입니다."

    except Exception as e:
        print(e)
        return f"[오류] 날씨 정보를 가져오는 중 문제가 발생했습니다: {str(e)}"

# get_naver_weather('서울')

if __name__ == "__main__":
    print("MCP 서버 시작", file=sys.stderr)
    mcp.run()


클로드 파일>설정>개발자>설정편집에서 다음과 같이 해당 weather도구를 추가한다. 참고로, 파이썬 경로는 where 명령을 이용해 경로 확인 후 설정한다. 소스파일도 해당 경로 확인 후 설정한다.
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "C:\\Users\\MAC\\Desktop",
        "C:\\Users\\MAC\\Downloads"
      ]
    },
    "weather": {
      "command": "C:\\Users\\MAC\\.conda\\envs\\venv_lmm\\python.exe",
  "args": [
    "F:\\projects\\ai\\5-1.agent\\mcp-weather.py"
  ]
    }
  }
}

클로드를 재부팅하고, 프롬프트를 입력한다.
"네이버로 서울의 날씨를 검색해"

그럼 다음과 같이 도구가 검색된다. 허용을 클릭하면 개발된 도구가 실행되어 정보를 얻고 적절히 답해준다.

결과는 다음과 같다.

별도 MCP 서버 클라이언트 개발
mcp-simple-calc-server.py란 이름으로 서버를 다음과 같이 코딩한다.
from mcp.server.fastmcp import FastMCP
import math

# instantiate an MCP server client
mcp = FastMCP("Hello World")

@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return int(a + b)

@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"

if __name__ == "__main__":
mcp.run(transport="stdio")

터미널에서 다음과 같이 MCP 서버 명령을 실행한다.
mcp dev mcp-simple-calc-server.py

만약, npm error code SELF_SIGNED_CERT_IN_CHAIN 에러가 발생한다면, 방화벽 때문이니 다른 네트웍에서 시도하거나, 해당 방화벽 옵션을 꺼야 한다. 서버가 제대로 실행되면, 다음 명령이 성공할 것이다.
curl -i http://localhost:5173/sse

서버가 실행되었다면, http://localhost:5173/#roots 링크에 접속한다. 접속에 성공했다면 MCP 기반 등록된 도구들 리스트 확인 및 도구 호출이 가능하다.
MCP 기반 등록된 도구들 리스트 확인 및 호출 모습

다음과 같이 mcp_client.py 클라이언트를 코딩한다.
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.sse import sse_client
from mcp.client.stdio import stdio_client

async def run():
    async with sse_client(url="http://localhost:5173/sse") as streams:
        async with ClientSession(*streams) as session:
            await session.initialize()
            tools = await session.get_tools()
            print(tools)

            result = await session.run("calculate power 2, 4?")
            print(result.data)

if __name__ == "__main__":
    import asyncio
    asyncio.run(run())

만약 stdio 방식을 사용하면, 다음과 같이 서버를 지정하고 stdio_client를 사용한다.
server_params = StdioServerParameters(
    command="python",  # Executable
    args=["F:\\projects\\mcp_agent\\mcp-server-client\\mcp_server.py"],  # Optional command line arguments
    env=None,  # Optional environment variables
)

...
    async with stdio_client(server_params) as streams:

pydantic_ai를 이용한 클라이언트 코드는 다음과 같다. 
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerHTTP
from dotenv import load_dotenv
import os, asyncio

load_dotenv()

server = MCPServerHTTP(url='http://localhost:5173/sse')  # Ensure the server URL is correct and supports SSE 
agent = Agent('openai:gpt-4o', mcp_servers=[server])  

result = agent.run_sync('calculate power 2, 4?')
print(result.data)

클라이언트가 정상적으로 실행된다면, 해당 프롬프트에 대한 적절한 도구를 LLM이 MCP 프로토콜을 통해 찾고 호출해 결과를 리턴할것이다.

부록: Ollama MCP-CLI 기반 실습
이 장은 Ollama, mcp-cli 도구를 이용해 MCP 서버에 등록된 도구를 호출하는 방법을 간략히 실습한다. 
터미널에서 다음 명령을 실행한다.

mcp서버 실헹에 필요한 UV(fast Python package and project manager)를 설치한다.
pip install uv
uv sync --reinstall

다음과 같이 Ollama를 실행한다.
ollama run llama3.2

새로운 터미널 창에서 다음 명령을 실행한다.
uv run mcp-cli chat --server filesystem --provider ollama --model llama3.2

결론
MCP는 경량 프로토콜이라 개발 및 사용이 편리하다. 향후, 이런 방식이 AI에이전트 개발 시 대세가 될 것이라 생각한다. 물론, 기업에서 자동화 등을 위한 최적화된 개발 분야에서는 LLM을 직접 조작해야 한다. 하지만, 대중적으로 사용되는 도구는 다음과 같이 MCP + 노코드(nocode) 형태가 될 것이다. 

레퍼런스

댓글 없음:

댓글 쓰기