번역 자료 / / 2025. 5. 22. 11:40

MCP 클라이언트 개발자를 위한 퀵스타트

MCP 클라이언트 개발자를 위한 퀵스타트

원문: https://modelcontextprotocol.io/quickstart/client

모든 MCP 서버와 통합할 수 있는 자체 클라이언트를 구축하는 방법을 알아보세요.

이 튜토리얼에서는 MCP 서버에 연결할 수 있는 LLM 기반 챗봇 클라이언트를 구축하는 방법을 배울 것입니다. 첫 번째 서버를 구축하는 기본 사항을 안내하는 서버 퀵스타트를 먼저 살펴보는 것이 도움이 됩니다.

이 튜토리얼의 전체 코드는 여기에서 찾을 수 있습니다.

시스템 요구사항

시작하기 전에 시스템이 다음 요구사항을 충족하는지 확인하세요:

  • Mac 또는 Windows 컴퓨터
  • 최신 Python 버전 설치
  • 최신 버전의 uv 설치

환경 설정하기

먼저 uv로 새 Python 프로젝트를 생성합니다:

# 프로젝트 디렉토리 생성
uv init mcp-client
cd mcp-client

# 가상 환경 생성
uv venv

# 가상 환경 활성화
# Windows의 경우:
.venv\Scripts\activate
# Unix 또는 MacOS의 경우:
source .venv/bin/activate

# 필요한 패키지 설치
uv add mcp anthropic python-dotenv

# 기본 파일 제거
# Windows의 경우:
del main.py
# Unix 또는 MacOS의 경우:
rm main.py

# 메인 파일 생성
touch client.py

API 키 설정하기

Anthropic Console에서 Anthropic API 키가 필요합니다.

API 키를 저장할 .env 파일을 생성합니다:

# .env 파일 생성
touch .env

.env 파일에 키를 추가합니다:

ANTHROPIC_API_KEY=<API 키 입력>

.gitignore.env를 추가합니다:

echo ".env" >> .gitignore

ANTHROPIC_API_KEY를 안전하게 보관하세요!

클라이언트 생성하기

기본 클라이언트 구조

먼저 import를 설정하고 기본 클라이언트 클래스를 생성합니다:

import asyncio
from typing import Optional
from contextlib import AsyncExitStack

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

from anthropic import Anthropic
from dotenv import load_dotenv

load_dotenv()  # .env 파일에서 환경 변수 로드

class MCPClient:
    def __init__(self):
        # 세션 및 클라이언트 객체 초기화
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        self.anthropic = Anthropic()
    # 이 부분에 메서드가 추가됩니다

서버 연결 관리

다음으로 MCP 서버에 연결하는 메서드를 구현합니다:

async def connect_to_server(self, server_script_path: str):
    """MCP 서버에 연결합니다

    Args:
        server_script_path: 서버 스크립트 경로 (.py 또는 .js)
    """
    is_python = server_script_path.endswith('.py')
    is_js = server_script_path.endswith('.js')
    if not (is_python or is_js):
        raise ValueError("서버 스크립트는 .py 또는 .js 파일이어야 합니다")

    command = "python" if is_python else "node"
    server_params = StdioServerParameters(
        command=command,
        args=[server_script_path],
        env=None
    )

    stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
    self.stdio, self.write = stdio_transport
    self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))

    await self.session.initialize()

    # 사용 가능한 도구 나열
    response = await self.session.list_tools()
    tools = response.tools
    print("\n서버에 연결되었습니다. 사용 가능한 도구:", [tool.name for tool in tools])

쿼리 처리 로직

이제 쿼리를 처리하고 도구 호출을 처리하는 핵심 기능을 추가합니다:

async def process_query(self, query: str) -> str:
    """Claude와 사용 가능한 도구를 사용하여 쿼리 처리"""
    messages = [
        {
            "role": "user",
            "content": query
        }
    ]

    response = await self.session.list_tools()
    available_tools = [{
        "name": tool.name,
        "description": tool.description,
        "input_schema": tool.inputSchema
    } for tool in response.tools]

    # 초기 Claude API 호출
    response = self.anthropic.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1000,
        messages=messages,
        tools=available_tools
    )

    # 응답 처리 및 도구 호출 처리
    final_text = []

    assistant_message_content = []
    for content in response.content:
        if content.type == 'text':
            final_text.append(content.text)
            assistant_message_content.append(content)
        elif content.type == 'tool_use':
            tool_name = content.name
            tool_args = content.input

            # 도구 호출 실행
            result = await self.session.call_tool(tool_name, tool_args)
            final_text.append(f"[도구 {tool_name}을(를) 인자 {tool_args}로 호출 중]")

            assistant_message_content.append(content)
            messages.append({
                "role": "assistant",
                "content": assistant_message_content
            })
            messages.append({
                "role": "user",
                "content": [
                    {
                        "type": "tool_result",
                        "tool_use_id": content.id,
                        "content": result.content
                    }
                ]
            })

            # Claude에서 다음 응답 가져오기
            response = self.anthropic.messages.create(
                model="claude-3-5-sonnet-20241022",
                max_tokens=1000,
                messages=messages,
                tools=available_tools
            )

            final_text.append(response.content[0].text)

    return "\n".join(final_text)

대화형 채팅 인터페이스

이제 채팅 루프와 정리 기능을 추가합니다:

async def chat_loop(self):
    """대화형 채팅 루프 실행"""
    print("\nMCP 클라이언트가 시작되었습니다!")
    print("쿼리를 입력하거나 '종료'를 입력하여 나가세요.")

    while True:
        try:
            query = input("\n쿼리: ").strip()

            if query.lower() == '종료':
                break

            response = await self.process_query(query)
            print("\n" + response)

        except Exception as e:
            print(f"\n오류: {str(e)}")

async def cleanup(self):
    """리소스 정리"""
    await self.exit_stack.aclose()

메인 진입점

마지막으로 메인 실행 로직을 추가합니다:

async def main():
    if len(sys.argv) < 2:
        print("사용법: python client.py <서버_스크립트_경로>")
        sys.exit(1)

    client = MCPClient()
    try:
        await client.connect_to_server(sys.argv[1])
        await client.chat_loop()
    finally:
        await client.cleanup()

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

전체 client.py 파일은 여기에서 찾을 수 있습니다.

주요 구성 요소 설명

1. 클라이언트 초기화

  • MCPClient 클래스는 세션 관리 및 API 클라이언트로 초기화됩니다
  • 적절한 리소스 관리를 위해 AsyncExitStack 사용
  • Claude 상호 작용을 위한 Anthropic 클라이언트 구성

2. 서버 연결

  • Python 및 Node.js 서버 모두 지원
  • 서버 스크립트 유형 검증
  • 적절한 통신 채널 설정
  • 세션 초기화 및 사용 가능한 도구 나열

3. 쿼리 처리

  • 대화 컨텍스트 유지
  • Claude의 응답 및 도구 호출 처리
  • Claude와 도구 간의 메시지 흐름 관리
  • 결과를 일관된 응답으로 결합

4. 대화형 인터페이스

  • 간단한 명령줄 인터페이스 제공
  • 사용자 입력 처리 및 응답 표시
  • 기본 오류 처리 포함
  • 정상적인 종료 허용

5. 리소스 관리

  • 리소스의 적절한 정리
  • 연결 문제에 대한 오류 처리
  • 정상적인 종료 절차

일반적인 사용자 정의 지점

  1. 도구 처리

    • 특정 도구 유형을 처리하도록 process_query()를 수정
    • 도구 호출에 대한 사용자 지정 오류 처리 추가
    • 도구별 응답 형식 구현
  2. 응답 처리

    • 반환 데이터 형식 사용자 정의
    • 응답에 추가 컨텍스트 또는 메타데이터 추가
    • 특정 서버 및 도구에 맞게 최적화
  3. 모델 통합

    • 다른 LLM 공급자 또는 모델로 전환
    • 모델 매개변수 조정
    • 서버 기능에 기반한 최적 모델 선택
  4. 오류 처리

    • 일반적인 문제에 대한 자세한 사용자 피드백 제공
    • 재시도 전략 구현
    • 서버 및 모델 오류에 대한 대체 흐름

클라이언트 실행하기

임의의 MCP 서버로 클라이언트를 실행하려면:

python client.py path/to/server.py

서버 퀵스타트에서 날씨 튜토리얼을 계속 진행하는 경우, 명령은 다음과 같을 수 있습니다: python client.py path/to/weather.py

클라이언트는 다음을 수행합니다:

  1. 지정된 서버에 연결
  2. 사용 가능한 도구 나열
  3. 다음을 수행할 수 있는 대화형 채팅 세션 시작:
    • 쿼리 입력
    • 도구 실행 확인
    • Claude의 응답 받기

작동 방식

다음은 상위 수준 워크플로우 스키마입니다:

쿼리를 제출할 때:

  1. 클라이언트는 서버에서 사용 가능한 도구 목록을 가져옵니다
  2. 도구 설명과 함께 쿼리가 Claude에 전송됩니다
  3. Claude는 사용할 도구(있는 경우)를 결정합니다
  4. 클라이언트는 서버를 통해 요청된 도구 호출을 실행합니다
  5. 결과가 Claude에 다시 전송됩니다
  6. Claude는 자연어 응답을 제공합니다
  7. 응답이 사용자에게 표시됩니다

문제 해결

서버 경로 문제

  • 서버 스크립트 경로가 올바른지 다시 확인하세요
  • 상대 경로가 작동하지 않는 경우 절대 경로를 사용하세요
  • Windows 사용자의 경우 경로에 슬래시(/) 또는 이스케이프된 백슬래시(\)를 사용해야 합니다
  • 필요한 런타임이 설치되어 있는지 확인하세요(Java는 java, Node.js는 npm, Python은 uv)
  • 서버 파일이 올바른 확장자를 가지고 있는지 확인하세요(Java는 .jar, Node.js는 .js, Python은 .py)

올바른 경로 사용 예:

# 상대 경로
python client.py ./server.py

# 절대 경로
python client.py /Users/username/projects/mcp-server/server.py

# Windows 경로(두 형식 모두 작동)
python client.py C:/projects/mcp-server/server.py
python client.py C:\\projects\\mcp-server\\server.py

응답 시간

  • 첫 번째 응답은 최대 30초까지 소요될 수 있습니다
  • 이는 다음 작업이 진행되는 동안 정상적인 현상입니다:
    • 서버 초기화
    • Claude가 쿼리 처리
    • 도구 실행 중
  • 이후 응답은 일반적으로 더 빠릅니다
  • 이 초기 대기 시간 동안 프로세스를 중단하지 마세요

일반적인 오류 메시지

다음과 같은 메시지가 표시되는 경우:

  • Connection refused: 서버가 실행 중이고 경로가 올바른지 확인하세요
  • Tool execution failed: 도구에 필요한 환경 변수가 설정되어 있는지 확인하세요
  • ANTHROPIC_API_KEY is not set: 환경 변수를 확인하세요

이 튜토리얼의 전체 코드는 여기에서 찾을 수 있습니다.

다음 단계


번역: https://modelcontextprotocol.io/quickstart/client

원문 출처 및 최신 정보는 위 링크를 참고하세요.

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유