리소스

리소스 (Resources)

서버가 클라이언트에게 리소스를 노출하는 표준화된 방법을 설명하는 페이지예요. 리소스는 언어 모델에 컨텍스트를 제공하는 데이터(파일, 데이터베이스 스키마, 애플리케이션 특정 정보 등)를 서버가 공유할 수 있게 해 주며, 각 리소스는 URI로 고유하게 식별돼요.

출처: 문서

본문

Model Context Protocol (MCP)은 서버가 클라이언트에게 리소스를 노출하는 표준화된 방법을 제공해요. 리소스는 서버가 언어 모델에 컨텍스트를 제공하는 데이터(파일, 데이터베이스 스키마, 애플리케이션 특정 정보 등)를 공유할 수 있게 해 줘요. 각 리소스는 URI로 고유하게 식별돼요.

참고 (Note): 간결함을 위해 이 페이지의 요청 예시는 _meta 요청 메타데이터(io.modelcontextprotocol/protocolVersion, io.modelcontextprotocol/clientInfo, io.modelcontextprotocol/clientCapabilities)를 생략해요. 모든 요청은 MUST 필수 _meta 필드를 포함해야 해요. _meta를 참조하세요.

사용자 상호작용 모델 (User Interaction Model)

MCP의 리소스는 **애플리케이션 주도(application-driven)**로 설계됐어요. 호스트 애플리케이션이 자신의 필요에 따라 컨텍스트를 어떻게 통합할지 결정해요.

예를 들어 애플리케이션은:

  • 트리 또는 목록 뷰에서 명시적 선택을 위한 UI 요소로 리소스를 노출할 수 있다
  • 사용자가 사용 가능한 리소스를 검색하고 필터링하게 할 수 있다
  • 휴리스틱이나 AI 모델의 선택에 기반해 자동 컨텍스트 포함을 구현할 수 있다

(리소스 컨텍스트 선택기 예시 이미지)

하지만 구현자는 자신의 필요에 맞는 어떤 인터페이스 패턴으로든 리소스를 노출할 자유가 있어요. 프로토콜 자체는 특정 사용자 상호작용 모델을 강제하지 않아요.

기능 (Capabilities)

리소스를 지원하는 서버는 MUST resources 기능을 선언해야 해요:

{
  "capabilities": {
    "resources": {
      "listChanged": true,
      "subscribe": true
    }
  }
}

이 기능은 두 가지 선택적 특징을 지원해요:

  • listChanged: 사용 가능한 리소스 목록이 바뀔 때 서버가 알림을 보낼지 여부.
  • subscribe: 서버가 resourceSubscriptions 필터를 사용해 subscriptions/listen을 통해 요청된 리소스에 대한 리소스별 업데이트 알림을 지원하는지 여부.

서버는 두 특징을 독립적으로, 함께, 또는 둘 다 없이 광고할 수 있어요.

listChanged도 subscribe도 지원하지 않는 서버는 이를 생략할 수 있어요:

{
  "capabilities": {
    "resources": {}
  }
}

resources 기능을 선언하는 서버는 MUST resources/list 요청에 요청한 클라이언트에게 현재 사용 가능한 리소스 집합으로 응답해야 해요. 이 집합은 MAY 비어 있을 수 있고 MAY 시간이 지나며 바뀔 수 있지만(List Changed Notification 참조), 연결별로 또는 연결의 다른 요청의 부수 효과로 MUST NOT 달라지면 안 돼요. 이 집합은 MAY 요청에 제시된 권한 부여에 따라 달라질 수 있어요. 예를 들어 호출자의 부여된 범위가 허용하는 리소스만 반환하는 것은, 자격 증명이 요청별 입력이지 연결 상태가 아니기 때문에 허용돼요.

프로토콜 메시지 (Protocol Messages)

리소스 나열하기 (Listing Resources)

사용 가능한 리소스를 발견하려면 클라이언트는 resources/list 요청을 보내요. 이 작업은 pagination과 caching을 지원해요.

요청:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "resources/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resultType": "complete",
    "resources": [
      {
        "uri": "file:///project/src/main.rs",
        "name": "main.rs",
        "title": "Rust Software Application Main File",
        "description": "Primary application entry point",
        "mimeType": "text/x-rust",
        "icons": [
          {
            "src": "https://example.com/rust-file-icon.png",
            "mimeType": "image/png",
            "sizes": ["48x48"]
          }
        ]
      }
    ],
    "nextCursor": "next-page-cursor",
    "ttlMs": 300000,
    "cacheScope": "public"
  }
}

리소스 읽기 (Reading Resources)

리소스 내용을 검색하려면 클라이언트는 resources/read 요청을 보내요. 이 작업은 caching을 지원해요.

요청:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "resources/read",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "resultType": "complete",
    "contents": [
      {
        "uri": "file:///project/src/main.rs",
        "mimeType": "text/x-rust",
        "text": "fn main() {\n    println!(\"Hello world!\");\n}"
      }
    ],
    "ttlMs": 60000,
    "cacheScope": "private"
  }
}

서버는 MAY 단일 resources/read 요청에 여러 리소스 내용을 반환할 수 있어요. 예를 들어 서버는 디렉터리 리소스를 읽을 때 여러 파일의 내용을 반환할 수 있어요.

서버는 MAY 리소스를 읽기 전에 추가 입력이 필요함을 나타내기 위해 resources/read에 InputRequiredResult로 응답할 수도 있어요. 이는 다중 왕복 요청 메커니즘을 따라요. 요청을 재시도할 때 클라이언트는 요청 파라미터에 inputResponses와, 서버가 제공했다면 requestState를 포함해요.

또는 uri의 스킴이 https://이면 클라이언트는 웹에서 리소스를 직접 가져올 수 있어요. 더 자세한 내용은 Common URI Schemes 섹션을 참조하세요.

리소스 템플릿 (Resource Templates)

리소스 템플릿은 서버가 URI 템플릿을 사용해 매개변수화된 리소스를 노출할 수 있게 해 줘요. 인자는 completion API를 통해 자동 완성될 수 있어요. 이 작업은 pagination과 caching을 지원해요.

요청:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/templates/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}

응답:

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "resultType": "complete",
    "resourceTemplates": [
      {
        "uriTemplate": "file:///{path}",
        "name": "Project Files",
        "title": "📁 Project Files",
        "description": "Access files in the project directory",
        "mimeType": "application/octet-stream",
        "icons": [
          {
            "src": "https://example.com/folder-icon.png",
            "mimeType": "image/png",
            "sizes": ["48x48"]
          }
        ]
      }
    ],
    "nextCursor": "next-page-cursor",
    "ttlMs": 300000,
    "cacheScope": "public"
  }
}

목록 변경 알림 (List Changed Notification)

사용 가능한 리소스 목록이 바뀌면, listChanged 기능을 선언한 서버는 SHOULD 알림을 보내야 해요:

{
  "jsonrpc": "2.0",
  "method": "notifications/resources/list_changed"
}

구독 (Subscriptions)

클라이언트는 notifications.resourceSubscriptions에 리소스 URI를 나열한 subscriptions/listen 요청을 보내 특정 리소스에 대한 변경 알림을 구독해요. 서버는 감시 중인 리소스가 바뀔 때마다 결과 스트림에서 notifications/resources/updated를 전달해요.

{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "_meta": { "io.modelcontextprotocol/subscriptionId": 4 },
    "uri": "file:///project/src/main.rs"
  }
}

전체 프로토콜 메커니즘(수신 확인, subscriptionId 상관, 취소)은 구독 (Subscriptions)을 참조하세요.

메시지 흐름 (Message Flow)

sequenceDiagram
    participant Client
    participant Server

    Note over Client,Server: Resource Discovery
    Client->>Server: resources/list
    Server-->>Client: List of resources

    Note over Client,Server: Resource Template Discovery
    Client->>Server: resources/templates/list
    Server-->>Client: List of resource templates

    Note over Client,Server: Resource Access
    Client->>Server: resources/read
    Server-->>Client: Resource contents

    Note over Client,Server: Subscribe to changes
    Client->>Server: subscriptions/listen (resourceSubscriptions)
    Server--)Client: notifications/subscriptions/acknowledged

    Note over Client,Server: Resource updated
    Server--)Client: notifications/resources/updated
    Client->>Server: resources/read
    Server-->>Client: Updated contents

데이터 타입 (Data Types)

Resource

리소스 정의는 다음을 포함해요:

  • uri: 리소스의 고유 식별자
  • name: 리소스의 이름.
  • title: 표시용 선택적 사람이 읽을 수 있는 리소스 이름.
  • description: 선택적 설명
  • icons: 사용자 인터페이스에 표시하기 위한 선택적 아이콘 배열
  • mimeType: 선택적 MIME 타입
  • size: 선택적 바이트 단위 크기

리소스 내용 (Resource Contents)

리소스는 텍스트 또는 바이너리 데이터를 담을 수 있어요:

텍스트 콘텐츠 (Text Content)

{
  "uri": "file:///example.txt",
  "mimeType": "text/plain",
  "text": "Resource content"
}

바이너리 콘텐츠 (Binary Content)

{
  "uri": "file:///example.png",
  "mimeType": "image/png",
  "blob": "base64-encoded-data"
}

Annotation (Annotations)

리소스, 리소스 템플릿, 콘텐츠 블록은 클라이언트에게 리소스를 사용하거나 표시하는 방법에 대한 힌트를 제공하는 선택적 annotation을 지원해요:

  • audience: 이 리소스의 의도된 대상(들)을 나타내는 배열. 유효한 값은 "user"와 "assistant". 예를 들어 ["user", "assistant"]는 둘 다에게 유용한 콘텐츠를 나타낸다.
  • priority: 이 리소스의 중요도를 나타내는 0.0부터 1.0까지의 숫자. 1은 "가장 중요"(사실상 필수), 0은 "가장 덜 중요"(전적으로 선택)를 의미한다.
  • lastModified: 리소스가 마지막으로 수정된 시각을 나타내는 ISO 8601 형식 타임스탬프 (예: "2025-01-12T15:00:58Z").

annotation이 있는 리소스 예시:

{
  "uri": "file:///project/README.md",
  "name": "README.md",
  "title": "Project Documentation",
  "mimeType": "text/markdown",
  "annotations": {
    "audience": ["user"],
    "priority": 0.8,
    "lastModified": "2025-01-12T15:00:58Z"
  }
}

클라이언트는 이 annotation을 다음에 사용할 수 있어요:

  • 의도된 대상에 따라 리소스 필터링
  • 컨텍스트에 포함할 리소스 우선순위 지정
  • 수정 시간 표시 또는 최신순 정렬

공통 URI 스킴 (Common URI Schemes)

프로토콜은 몇 가지 표준 URI 스킴을 정의해요. 이 목록은 완전하지 않으며, 구현은 선택적으로 추가·커스텀 URI 스킴을 항상 자유롭게 사용할 수 있어요.

https://

웹에서 사용 가능한 리소스를 나타내는 데 사용돼요.

서버는 SHOULD 이 스킴을 클라이언트가 리소스를 MCP 서버를 통하지 않고 웹에서 직접 가져와 로드할 수 있을 때만 사용해야 해요. 즉 서버가 리소스를 읽을 필요가 없을 때요.

다른 사용 사례에서는, 서버가 인터넷으로 리소스 내용을 내려받을 것이더라도, SHOULD 다른 URI 스킴을 선호하거나 커스텀 스킴을 정의하는 것이 좋아요.

file://

파일시스템처럼 동작하는 리소스를 식별하는 데 사용돼요. 하지만 리소스가 실제 물리 파일시스템에 매핑될 필요는 없어요.

MCP 서버는 MAY inode/directory 같은 XDG MIME 타입으로 file:// 리소스를 식별해, 표준 MIME 타입이 없는 일반 파일이 아닌 파일(디렉터리 같은)을 나타낼 수 있어요.

git://

Git 버전 관리 통합.

커스텀 URI 스킴 (Custom URI Schemes)

커스텀 URI 스킴은 MUST 위 안내를 고려해 RFC3986을 따라야 해요.

오류 처리 (Error Handling)

요청된 리소스가 존재하지 않으면, 서버는 MUST 코드 -32602 (Invalid Params)의 JSON-RPC 오류를 반환해야 해요. 서버는 SHOULD 내부 오류에 대해 -32603을 반환해야 해요.

하위 호환성을 위해 클라이언트는 SHOULD -32002도 리소스 없음 오류로 수용해야 해요. 이전 프로토콜 버전이 이 코드를 사용했기 때문이다.

서버는 MUST NOT 존재하지 않는 리소스에 대해 빈 contents 배열을 반환해서는 안 돼요. 빈 배열은 모호해요. 리소스가 존재하지만 내용이 없거나, 존재하지 않는다는 뜻일 수 있거든요.

오류 예시:

{
  "jsonrpc": "2.0",
  "id": 5,
  "error": {
    "code": -32602,
    "message": "Resource not found",
    "data": {
      "uri": "file:///nonexistent.txt"
    }
  }
}

보안 고려 사항 (Security Considerations)

  1. 서버는 MUST 모든 리소스 URI를 검증해야 한다
  2. 민감한 리소스에는 SHOULD 접근 통제가 구현되어야 한다
  3. 바이너리 데이터는 MUST 제대로 인코딩되어야 한다
  4. 리소스 권한은 SHOULD 작업 전에 확인되어야 한다
  5. 서버는 MUST file:// 리소스를 제공할 때 디렉터리 순회 공격을 막기 위해 파일 경로를 살균(sanitize)해야 한다

더 알아보기 (Learn more)