MCP 클라이언트 개발자를 위한 퀵스타트
모든 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. 리소스 관리
- 리소스의 적절한 정리
- 연결 문제에 대한 오류 처리
- 정상적인 종료 절차
일반적인 사용자 정의 지점
도구 처리
- 특정 도구 유형을 처리하도록
process_query()
를 수정 - 도구 호출에 대한 사용자 지정 오류 처리 추가
- 도구별 응답 형식 구현
- 특정 도구 유형을 처리하도록
응답 처리
- 반환 데이터 형식 사용자 정의
- 응답에 추가 컨텍스트 또는 메타데이터 추가
- 특정 서버 및 도구에 맞게 최적화
모델 통합
- 다른 LLM 공급자 또는 모델로 전환
- 모델 매개변수 조정
- 서버 기능에 기반한 최적 모델 선택
오류 처리
- 일반적인 문제에 대한 자세한 사용자 피드백 제공
- 재시도 전략 구현
- 서버 및 모델 오류에 대한 대체 흐름
클라이언트 실행하기
임의의 MCP 서버로 클라이언트를 실행하려면:
python client.py path/to/server.py
서버 퀵스타트에서 날씨 튜토리얼을 계속 진행하는 경우, 명령은 다음과 같을 수 있습니다: python client.py path/to/weather.py
클라이언트는 다음을 수행합니다:
- 지정된 서버에 연결
- 사용 가능한 도구 나열
- 다음을 수행할 수 있는 대화형 채팅 세션 시작:
- 쿼리 입력
- 도구 실행 확인
- Claude의 응답 받기
작동 방식
다음은 상위 수준 워크플로우 스키마입니다:
쿼리를 제출할 때:
- 클라이언트는 서버에서 사용 가능한 도구 목록을 가져옵니다
- 도구 설명과 함께 쿼리가 Claude에 전송됩니다
- Claude는 사용할 도구(있는 경우)를 결정합니다
- 클라이언트는 서버를 통해 요청된 도구 호출을 실행합니다
- 결과가 Claude에 다시 전송됩니다
- Claude는 자연어 응답을 제공합니다
- 응답이 사용자에게 표시됩니다
문제 해결
서버 경로 문제
- 서버 스크립트 경로가 올바른지 다시 확인하세요
- 상대 경로가 작동하지 않는 경우 절대 경로를 사용하세요
- 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
: 환경 변수를 확인하세요
이 튜토리얼의 전체 코드는 여기에서 찾을 수 있습니다.
다음 단계
- 예제 서버: 공식 MCP 서버 및 구현 갤러리 확인하기
- 클라이언트: MCP 통합을 지원하는 클라이언트 목록 보기
- LLM으로 MCP 구축하기: Claude와 같은 LLM을 사용하여 MCP 개발 속도를 높이는 방법 알아보기
- 핵심 아키텍처: MCP가 클라이언트, 서버 및 LLM을 연결하는 방법 이해하기
번역: https://modelcontextprotocol.io/quickstart/client
원문 출처 및 최신 정보는 위 링크를 참고하세요.