아키텍처

아키텍처 (Architecture)

Model Context Protocol (MCP)이 어떤 구조로 클라이언트·호스트·서버를 배치하고, 요청이 어떻게 처리되는지 전반적인 아키텍처를 설명하는 페이지예요. MCP는 무상태(stateless) 프로토콜로, 매 요청이 자기 완결적이며 자체 프로토콜 버전과 기능을 담고 있어요.

출처: 문서

본문

Model Context Protocol (MCP)은 각 호스트가 여러 클라이언트 인스턴스를 실행할 수 있는 클라이언트-호스트-서버 아키텍처를 따르는데요. MCP는 무상태(stateless) 프로토콜이에요. 즉 모든 요청이 자기 완결적이고, 자체 프로토콜 버전과 기능(capabilities)을 갖고 있어요. 이 아키텍처 덕분에 사용자는 명확한 보안 경계를 유지하고 관심사를 분리하면서도, 여러 애플리케이션에 걸쳐 AI 기능을 통합할 수 있어요. JSON-RPC 위에 구축된 MCP는 클라이언트와 서버 사이의 컨텍스트 교환과 샘플링(sampling) 조정에 초점을 맞춘 프로토콜이에요.

핵심 구성 요소 (Core Components)

graph LR
    subgraph "Application Host Process"
        H[Host]
        C1[Client 1]
        C2[Client 2]
        C3[Client 3]
        H --> C1
        H --> C2
        H --> C3
    end

    subgraph "Local machine"
        S1[Server 1<br>Files & Git]
        S2[Server 2<br>Database]
        R1[("Local<br>Resource A")]
        R2[("Local<br>Resource B")]

        C1 --> S1
        C2 --> S2
        S1 <--> R1
        S2 <--> R2
    end

    subgraph "Internet"
        S3[Server 3<br>External APIs]
        R3[("Remote<br>Resource C")]

        C3 --> S3
        S3 <--> R3
    end

호스트 (Host)

호스트 프로세스는 컨테이너이자 조정자(coordinator) 역할을 해요:

  • 여러 클라이언트 인스턴스를 만들고 관리해요
  • 클라이언트 연결 권한과 수명주기(lifecycle)를 제어해요
  • 보안 정책과 동의 요구사항을 강제해요
  • 사용자 승인 결정을 처리해요
  • AI/LLM 통합과 샘플링을 조정해요
  • 클라이언트에 걸친 컨텍스트 집계(context aggregation)를 관리해요

클라이언트 (Clients)

각 클라이언트는 호스트가 만들고 정확히 한 서버와 통신해요:

  • 정확히 하나의 서버와 통신해요
  • 모든 요청에 프로토콜 버전과 기능을 첨부해요
  • 프로토콜 메시지를 양방향으로 라우팅해요
  • 구독(subscriptions)과 알림(notifications)을 관리해요
  • 서버 사이의 보안 경계를 유지해요

호스트 애플리케이션은 여러 클라이언트를 만들고 관리하며, 각 클라이언트는 특정 서버와 1:1 관계를 가져요.

서버 (Servers)

서버는 전문화된 컨텍스트와 기능을 제공해요:

  • MCP 프리미티브를 통해 리소스, 도구, 프롬프트를 노출해요
  • 초점이 좁은 책임으로 독립적으로 동작해요
  • 응답 안의 InputRequiredResult를 통해 클라이언트 입력(샘플링, elicitation, roots)을 요청해요
  • 보안 제약을 존중해야 해요
  • 로컬 프로세스일 수도 있고 원격 서비스일 수도 있어요

설계 원칙 (Design Principles)

MCP는 아키텍처와 구현을 결정짓는 몇 가지 핵심 설계 원칙 위에 구축돼요:

  1. 서버는 극도로 만들기 쉬워야 한다

    • 호스트 애플리케이션이 복잡한 오케스트레이션 책임을 처리한다
    • 서버는 특정하고 잘 정의된 기능에 집중한다
    • 단순한 인터페이스가 구현 오버헤드를 최소화한다
    • 명확한 분리가 유지보수 가능한 코드를 가능하게 한다
  2. 서버는 고도로 조합 가능(composable)해야 한다

    • 각 서버는 격리된 상태에서 초점이 맞춰진 기능을 제공한다
    • 여러 서버를 매끄럽게 결합할 수 있다
    • 공유 프로토콜이 상호운용성(interoperability)을 가능하게 한다
    • 모듈형 설계가 확장성(extensibility)을 지원한다
  3. 서버는 전체 대화를 읽을 수 없고, 다른 서버를 "들이다볼" 수 없어야 한다

    • 서버는 필요한 컨텍스트 정보만 받는다
    • 전체 대화 기록은 호스트에 남는다
    • 각 서버는 격리를 유지한다
    • 서버 간 상호작용은 호스트가 통제한다
    • 호스트 프로세스가 보안 경계를 강제한다
  4. 기능은 서버와 클라이언트에 점진적으로 추가될 수 있다

    • 핵심 프로토콜은 최소한의 필수 기능을 제공한다
    • 추가 기능은 필요에 따라 협상될 수 있다
    • 서버와 클라이언트는 독립적으로 진화한다
    • 프로토콜은 미래 확장성을 위해 설계되었다
    • 하위 호환성(backwards compatibility)이 유지된다

기능 협상 (Capability Negotiation)

Model Context Protocol은 요청마다 클라이언트와 서버가 지원하는 기능을 선언하는 기능 기반 협상(capability-based negotiation) 체계를 사용해요. 클라이언트는 모든 요청의 _meta.io.modelcontextprotocol/clientCapabilities에 자체 기능을 포함해요. 서버는 server/discover에 대한 응답으로 기능을 광고하는데, 클라이언트는 어떤 요청보다 먼저 이걸 호출해 미리 기능을 확인할 수 있어요.

  • 서버는 도구 지원, 리소스 구독, 프롬프트 템플릿 같은 기능을 선언해요
  • 클라이언트는 샘플링 지원, elicitation 처리 같은 기능을 선언해요
  • 양측 모두 상호작용 내내 선언된 기능을 존중해야 해요
  • 추가 기능은 프로토콜 확장을 통해 협상될 수 있어요
sequenceDiagram
    participant Host
    participant Client
    participant Server

    opt Discovery
        Client->>Server: server/discover
        Server-->>Client: supported versions + capabilities
    end

    loop Client Requests
        Host->>Client: User- or model-initiated action
        Client->>Server: Request (with _meta: version, clientCapabilities)
        alt Server requires client input
            Server-->>Client: InputRequiredResult (e.g. sampling/createMessage)
            Client->>Host: Forward to AI
            Host-->>Client: AI response
            Client->>Server: Original request (with input)
        end
        Server-->>Client: Response
        Client-->>Host: Update UI or respond to model
    end

    opt Subscriptions
        Client->>Server: subscriptions/listen (toolsListChanged, resourceSubscriptions, …)
        Server--)Client: notifications/subscriptions/acknowledged
        loop Stream
            Server--)Client: notifications/* (tagged with subscriptionId)
        end
    end

각 기능은 요청별로 특정 프로토콜 기능을 열어줘요. 예를 들면:

  • 구현된 서버 기능은 서버의 기능(capabilities)에 광고되어야 해요
  • 리소스 업데이트 알림을 받으려면 원하는 리소스 URI로 subscriptions/listen 스트림을 열어야 해요
  • 도구 호출에는 서버가 도구 기능을 선언해야 해요

이 기능 협상 덕분에 클라이언트와 서버는 프로토콜 확장성을 유지하면서도 지원되는 기능을 명확히 이해할 수 있어요.

더 알아보기 (Learn more)