MCP Agent system의 역할 분담 및 플로우

Ruah·2025년 4월 4일
0

호스트 앱 구성 요소와 역할

1. MCP 서버

  • 특정 기능(도구)을 구현하고 노출
  • 데이터 소스와 연결하여 정보 검색
  • 각 도구에 대한 타입 정의와 검증 제공
# MCP 서버 초기화
mcp = FastMCP(
    "Weather_server",
    instructions="날씨 정보를 제공하는 도우미",
    host="0.0.0.0",
    port=8005,
)

# 도구 구현
@mcp.tool()
async def get_forecast(latitude: float, longitude: float) -> str:
    """특정 위치의 날씨 예보 가져오기"""
    # 외부 API 호출 로직...
    return "포맷된 날씨 정보"

2. 백엔드 서버

  • MCP 서버들과 연결 관리
  • 프론트엔드를 위한 API 제공
  • 채팅 기록 및 세션 관리
  • 사용자 인증 및 권한 관리
  • MCP 도구 호출 오케스트레이션

예시 (main.py):

# FastAPI 앱 초기화 및 MCP 서버 연결 관리
@asynccontextmanager
async def lifespan(app: FastAPI):
    # MCP 서버 시작 및 연결
    weather_py_path = os.path.join(os.path.dirname(__file__), "../mcp/weather.py")
    server_params = StdioServerParameters(command=sys.executable, args=[weather_py_path])
    
    # 연결 초기화 및 관리
    async with stdio_client(server_params) as (read_stream, write_stream):
        weather_mcp_session = ClientSession(read_stream, write_stream)
        await weather_mcp_session.initialize()
        yield
        # 종료 시 연결 정리
# 채팅 API 엔드포인트
@app.post("/api/chat", response_model=ChatResponse)
async def api_chat(message: dict = Body(...)):
    # 채팅 기록 관리
    user_id = "default"
    if user_id not in chat_histories:
        chat_histories[user_id] = ChatHistory()
    
    # 사용자 메시지 처리
    user_message = message.get("message", "")
    
    # 봇 응답 생성 (MCP 도구 호출 포함)
    bot_response = generate_bot_response(user_message, chat_histories[user_id].messages)
    
    # 응답 반환
    return ChatResponse(response=bot_response)

3. 프론트엔드

  • 사용자 인터페이스 제공
  • 메시지 입력 및 표시
  • 백엔드 API와 통신
  • 대화 상태 관리

예시 (ChatContainer.tsx, useChat.ts):

// 채팅 컨테이너 (ChatContainer.tsx)
const ChatContainer: React.FC = () => {
  const { messages, isLoading, sendMessage } = useChat([
    { id: 1, text: '안녕하세요!', isUser: false, timestamp: new Date() },
  ]);
  
  return (
    <div className={styles.chatContainer}>
      <div className={styles.messagesContainer}>
        {messages.map((message) => (
          <ChatMessage key={message.id} message={message} />
        ))}
      </div>
      <ChatInput onSend={sendMessage} isLoading={isLoading} />
    </div>
  );
};
// 채팅 로직 (useChat.ts)
const sendMessage = useCallback(async (text: string) => {
  // 사용자 메시지 UI에 추가
  const userMessage = { id: Date.now(), text, isUser: true };
  setMessages(prev => [...prev, userMessage]);
  
  try {
    // 백엔드 API 호출
    const response = await apiSendMessage(text);
    
    // 봇 응답 UI에 추가
    const botMessage = {
      id: Date.now() + 1,
      text: response.response,
      isUser: false
    };
    setMessages(prev => [...prev, botMessage]);
  } catch (error) {
    // 오류 처리
  }
}, []);

전체 데이터 흐름

1. 시스템 초기화

  • 백엔드 서버 시작
  • MCP 서버(들) 시작 및 연결
  • 프론트엔드 로딩 및 백엔드 연결

2. 사용자 메시지 처리

  • 사용자가 프론트엔드에서 메시지 입력
  • 프론트엔드는 메시지를 백엔드로 전송 (/api/chat API 호출)
  • 백엔드는 메시지 수신 및 처리 시작

3. MCP 도구 호출 프로세스

  • 백엔드는 메시지 분석 후 적절한 MCP 도구 결정
  • 백엔드는 stdio를 통해 MCP 서버에 도구 호출 요청
  • MCP 서버는 도구 실행 (외부 API 호출 등)
  • MCP 서버는 결과를 백엔드로 반환
  • 백엔드는 결과를 처리하고 응답 생성

4. 응답 반환

  • 백엔드는 최종 응답을 프론트엔드로 반환
  • 프론트엔드는 응답을 UI에 표시
  • 대화 상태 업데이트

주요 통신 채널

1. MCP 서버 ↔ 백엔드: stdio 통신

[MCP 서버] <== stdio ==> [백엔드]

2. 백엔드 ↔ 프론트엔드: HTTP/WebSocket 통신

[백엔드] <== HTTP/WebSocket ==> [프론트엔드]

구현의 장점

  1. 분리된 책임: 각 구성 요소는 명확한 책임을 가짐
  2. 확장성: 여러 MCP 서버를 쉽게 추가 가능
  3. 중앙 관리: 백엔드에서 모든 통신 오케스트레이션
  4. 유연성: 다양한 도구와 기능을 쉽게 통합 가능
  5. 보안: 민감한 API 키와 로직이 백엔드에 안전하게 보관

이 아키텍처는 특히 여러 도구와 데이터 소스를 필요로 하는 복잡한 애플리케이션에서 강점을 발휘하며, 중앙 집중식 관리와 확장 가능한 구조를 제공한다.

profile
집요한 주니어 개발자의 호되게 당했던 기록

0개의 댓글