byteforce

CPN 한국어 자습서 · 외부 문서 한국어 미러

MCP 문서 · Develop

MCP 클라이언트 구축

Build an MCP client · 원문: modelcontextprotocol.io/docs/develop/build-client

아래는 원문을 한국어로 옮긴 미러입니다. 코드·명령은 원문 그대로이며, 가장 최신 정보는 하단 원문 링크에서 확인하세요.

모든 MCP 서버와 통합할 수 있는 클라이언트를 직접 만들어 봅니다.

이 튜토리얼에서는 MCP 서버에 연결하는 LLM 기반 챗봇 클라이언트를 구축하는 방법을 배웁니다.

시작하기 전에 MCP 서버 구축 튜토리얼을 먼저 살펴보면 클라이언트와 서버가 어떻게 통신하는지 이해하는 데 도움이 됩니다.

Python

이 튜토리얼의 완성된 코드는 여기서 확인할 수 있습니다.

시스템 요구사항

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

환경 설정

uv로 새 Python 프로젝트를 만듭니다.

코드 · 명령
# macOS/Linux
# 프로젝트 디렉터리 생성
uv init mcp-client
cd mcp-client

# 가상환경 생성
uv venv

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

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

# 보일러플레이트 파일 제거
rm main.py

# 메인 파일 생성
touch client.py
코드 · 명령
# Windows
uv init mcp-client
cd mcp-client
uv venv
.venv\Scripts\activate
uv add mcp anthropic python-dotenv
del main.py
new-item client.py

API 키 설정

Anthropic Console에서 Anthropic API 키를 발급받아야 합니다.

키를 저장할 .env 파일을 만듭니다.

코드 · 명령
echo "ANTHROPIC_API_KEY=your-api-key-goes-here" > .env

.gitignore.env를 추가합니다.

코드 · 명령
echo ".env" >> .gitignore

주의: ANTHROPIC_API_KEY를 안전하게 보관하세요!

클라이언트 생성

기본 클라이언트 구조

먼저 임포트를 설정하고 기본 클라이언트 클래스를 만듭니다.

코드 · 명령
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()  # load environment variables from .env

class MCPClient:
    def __init__(self):
        # Initialize session and client objects
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        self.anthropic = Anthropic()
    # methods will go here

서버 연결 관리

MCP 서버에 연결하는 메서드를 구현합니다.

코드 · 명령
async def connect_to_server(self, server_script_path: str):
    """Connect to an MCP server

    Args:
        server_script_path: Path to the server script (.py or .js)
    """
    is_python = server_script_path.endswith('.py')
    is_js = server_script_path.endswith('.js')
    if not (is_python or is_js):
        raise ValueError("Server script must be a .py or .js file")

    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()

    # List available tools
    response = await self.session.list_tools()
    tools = response.tools
    print("\nConnected to server with tools:", [tool.name for tool in tools])

쿼리 처리 로직

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

코드 · 명령
async def process_query(self, query: str) -> str:
    """Process a query using Claude and available tools"""
    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]

    # Initial Claude API call
    response = self.anthropic.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1000,
        messages=messages,
        tools=available_tools
    )

    # Process response and handle tool calls
    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

            # Execute tool call
            result = await self.session.call_tool(tool_name, tool_args)
            final_text.append(f"[Calling tool {tool_name} with args {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
                    }
                ]
            })

            # Get next response from Claude
            response = self.anthropic.messages.create(
                model="claude-sonnet-4-20250514",
                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):
    """Run an interactive chat loop"""
    print("\nMCP Client Started!")
    print("Type your queries or 'quit' to exit.")

    while True:
        try:
            query = input("\nQuery: ").strip()

            if query.lower() == 'quit':
                break

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

        except Exception as e:
            print(f"\nError: {str(e)}")

async def cleanup(self):
    """Clean up resources"""
    await self.exit_stack.aclose()

메인 진입점

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

코드 · 명령
async def main():
    if len(sys.argv) < 2:
        print("Usage: python client.py <path_to_server_script>")
        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. 클라이언트 초기화

2. 서버 연결

3. 쿼리 처리

4. 대화형 인터페이스

5. 리소스 관리

클라이언트 실행

MCP 서버와 함께 클라이언트를 실행합니다.

코드 · 명령
uv run client.py path/to/server.py # python server
uv run client.py path/to/build/index.js # node server

참고: 서버 퀵스타트의 날씨 튜토리얼을 이어서 진행하는 경우 명령어는 다음과 비슷할 수 있습니다: python client.py .../quickstart-resources/weather-server-python/weather.py

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

  1. 지정된 서버에 연결합니다.
  2. 사용 가능한 도구를 나열합니다.
  3. 대화형 채팅 세션을 시작합니다. * 쿼리 입력 * 도구 실행 확인 * Claude의 응답 수신

동작 원리

쿼리를 제출하면 다음이 진행됩니다.

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

모범 사례

  1. 오류 처리 * 도구 호출을 항상 try-catch 블록으로 감싸세요. * 의미 있는 오류 메시지를 제공하세요. * 연결 문제를 정상적으로 처리하세요.

  2. 리소스 관리 * 적절한 정리를 위해 AsyncExitStack을 사용하세요. * 완료 후 연결을 닫으세요. * 서버 연결 해제를 처리하세요.

  3. 보안 * API 키를 .env에 안전하게 저장하세요. * 서버 응답을 검증하세요. * 도구 권한에 주의하세요.

문제 해결

서버 경로 문제

코드 · 명령
# 상대 경로
uv run client.py ./server/weather.py

# 절대 경로
uv run client.py /Users/username/projects/mcp-server/weather.py

# Windows 경로
uv run client.py C:/projects/mcp-server/weather.py

응답 시간

일반적인 오류 메시지

TypeScript

이 튜토리얼의 완성된 코드는 여기서 확인할 수 있습니다.

시스템 요구사항

환경 설정

코드 · 명령
# macOS/Linux
mkdir mcp-client-typescript
cd mcp-client-typescript
npm init -y
npm install @anthropic-ai/sdk @modelcontextprotocol/sdk dotenv
npm install -D @types/node typescript
touch index.ts

package.json 업데이트:

코드 · 명령
{
  "type": "module",
  "scripts": {
    "build": "tsc && chmod 755 build/index.js"
  }
}

tsconfig.json 생성:

코드 · 명령
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["index.ts"],
  "exclude": ["node_modules"]
}

클라이언트 실행 (TypeScript)

코드 · 명령
# TypeScript 빌드
npm run build

# 클라이언트 실행
node build/index.js path/to/server.py # python server
node build/index.js path/to/build/index.js # node server

다음 단계

원문(영어): https://modelcontextprotocol.io/docs/develop/build-client · 본 문서는 학습용 한국어 번역이며 원본의 권리는 원저작자(Model Context Protocol)에게 있습니다.

원문(영어): https://modelcontextprotocol.io/docs/develop/build-client