MCP 리소스와 프롬프트 — 도구를 넘어서는 컨텍스트 노출

MCP에서 관심의 90퍼센트는 도구(tools)에 쏠립니다. 그러나 서버가 제공하는 나머지 두 프리미티브(primitive)는 다른 문제를 해결합니다. 리소스(resources)는 읽을 데이터를 노출하고, 프롬프트(prompts)는 재사용 가능한 템플릿을 슬래시 명령(slash-command)으로 노출합니다. 많은 서버는 읽기 작업을 도구로 감싸기보다 리소스를 사용해야 하며, 클라이언트 프롬프트 안에 워크플로(workflow)를 하드코딩하기보다 프롬프트를 사용해야 합니다. 이 lesson은 그 판단 규칙을 이름 붙이고 resources/*prompts/* 메시지를 살펴봅니다.

유형: Build
언어: Python (표준 라이브러리, 리소스 + 프롬프트 핸들러)
선수 학습: Phase 13 · 07 (MCP 서버)
소요 시간: 약 45분

학습 목표

  • 주어진 도메인(domain)의 기능을 도구, 리소스, 프롬프트 중 무엇으로 노출할지 결정합니다.
  • resources/list, resources/read, resources/subscribe를 구현하고 notifications/resources/updated를 처리합니다.
  • 인자 템플릿(argument template)을 가진 prompts/listprompts/get을 구현합니다.
  • 호스트(host)가 프롬프트를 슬래시 명령으로 보여주는 경우와 자동 주입되는 컨텍스트(auto-injected context)로 다루는 경우를 구분합니다.

문제

노트 앱을 위한 순진한 MCP 서버는 모든 것을 도구로 노출합니다. 예를 들어 notes_read, notes_list, notes_search가 모두 도구입니다. 이렇게 하면 모든 데이터 접근이 모델이 주도하는 도구 호출로 감싸집니다. 그 결과는 다음과 같습니다.

  • 컨텍스트가 도움이 될 수 있는 모든 질의마다 모델이 notes_read를 호출할지 결정해야 합니다.
  • 읽기 전용 콘텐츠를 구독(subscribe)하거나 호스트의 사이드 패널(side panel)로 스트리밍할 수 없습니다.
  • 클라이언트 UI, 예를 들어 Claude Desktop의 리소스 첨부 패널이나 Cursor의 "Include file" 선택기가 데이터를 표시할 수 없습니다.

올바른 분리는 다음과 같습니다. 데이터는 리소스로 노출하고, 변경을 일으키거나 계산된 작업은 도구로 노출하며, 재사용 가능한 여러 단계 워크플로는 프롬프트로 노출합니다. 각 프리미티브에는 각자의 사용자 경험(UX) 어포던스(affordance)와 접근 패턴(access pattern)이 있습니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.MCP 리소스와 프롬프트가 해결하는 핵심 과제는?

2.MCP 리소스와 프롬프트 이전의 주요 한계는?

0/2 답변 완료

개념

도구 vs 리소스 vs 프롬프트 — 판단 규칙

기능프리미티브
사용자가 데이터를 검색, 필터링, 변환하고 싶다tool
사용자가 호스트가 이 데이터를 컨텍스트로 포함하길 원한다resource
사용자가 다시 실행할 수 있는 템플릿화된 워크플로를 원한다prompt

가이드라인은 이렇습니다. 관련 질의마다 모델이 호출하면 도움이 되는 것은 도구입니다. 사용자가 대화에 첨부하면 도움이 되는 것은 리소스입니다. 전체 여러 단계 워크플로가 사용자가 재사용하고 싶은 단위라면 프롬프트입니다.

리소스

resources/list{resources: [{uri, name, mimeType, description?}]}를 반환합니다. resources/read{uri}를 받고 {contents: [{uri, mimeType, text | blob}]}를 반환합니다.

URI는 주소를 지정할 수 있는 것이라면 무엇이든 될 수 있습니다.

  • file:///Users/alice/notes/mcp.md
  • postgres://my-db/query/SELECT ...
  • notes://note-14 (사용자 정의 스킴)
  • memory://session-2026-04-22/recent (서버 전용)

contents[]는 텍스트와 바이너리를 모두 지원합니다. 바이너리는 mimeType과 함께 base64로 인코딩된 문자열인 blob을 사용합니다.

리소스 구독

기능(capabilities)에 {resources: {subscribe: true}}를 선언합니다. 클라이언트는 resources/subscribe {uri}를 호출합니다. 서버는 리소스가 바뀌면 notifications/resources/updated {uri}를 보냅니다. 클라이언트는 다시 읽습니다.

사용 사례는 디스크의 파일을 리소스로 노출하는 노트 서버입니다. 파일 감시기(file watcher)가 업데이트 알림을 트리거하고, Claude Desktop은 호스트 밖에서 편집된 파일을 다시 컨텍스트로 가져옵니다.

리소스 템플릿(2025-11-25 추가)

resourceTemplates를 사용하면 매개변수화된 URI 패턴을 노출할 수 있습니다. 예를 들어 id를 완성(completion) 대상으로 둔 notes://{id}입니다. 클라이언트는 리소스 선택기(resource picker)에서 ID를 자동완성할 수 있습니다.

프롬프트

prompts/list{prompts: [{name, description, arguments?}]}를 반환합니다. prompts/get{name, arguments}를 받고 {description, messages: [{role, content}]}를 반환합니다.

프롬프트는 호스트가 모델에 공급할 메시지 목록으로 채워지는 템플릿입니다. 예를 들어 code_review 프롬프트는 file_path 인자를 받아 세 개의 메시지 시퀀스를 반환합니다. 시스템 메시지, 파일 본문을 담은 사용자 메시지, 그리고 추론 템플릿을 포함한 어시스턴트 시작 메시지입니다.

호스트와 프롬프트

Claude Desktop, VS Code, Cursor는 채팅 UI에서 프롬프트를 슬래시 명령으로 노출합니다. 사용자가 /code_review를 입력하고 폼(form)에서 인자를 고릅니다. 서버의 프롬프트는 "사용자 단축 명령"과 "모델에 실제로 보내지는 전체 프롬프트" 사이의 계약입니다.

아직 모든 클라이언트가 프롬프트를 지원하는 것은 아닙니다. 기능 협상(capability negotiation)을 확인해야 합니다. 서버가 프롬프트 기능을 선언했더라도 클라이언트가 프롬프트를 지원하지 않으면 슬래시 명령은 보이지 않습니다.

"목록 변경" 알림

리소스와 프롬프트는 집합이 바뀌면 모두 notifications/list_changed를 내보냅니다. 노트 서버가 새 노트 20개를 가져왔다면 notifications/resources/list_changed를 내보냅니다. 클라이언트는 추가 항목을 반영하기 위해 resources/list를 다시 호출합니다.

콘텐츠 타입 관례

텍스트에는 mimeType: "text/plain", text/markdown, application/json을 사용합니다.
바이너리에는 image/png, application/pdf와 함께 blob 필드를 사용합니다.
MCP 앱(Lesson 14)에서는 ui:// URI에 text/html;profile=mcp-app을 사용합니다.

동적 리소스

리소스 URI가 반드시 정적 파일에 대응할 필요는 없습니다. notes://recent는 읽을 때마다 최신 노트 다섯 개를 반환할 수 있습니다. db://query/users/active는 매개변수화된 쿼리(parameterized query)를 실행할 수 있습니다. 서버는 콘텐츠를 자유롭게 동적으로 계산할 수 있습니다.

규칙은 이렇습니다. 클라이언트가 URI로 캐시(cache)할 수 있다면 URI는 안정적이어야 합니다. 계산이 일회성(one-shot)이라면 클라이언트 캐시가 오래된 값을 쓰지 않도록 URI에 타임스탬프(timestamp)나 임시값(nonce)을 포함해야 합니다.

구독과 폴링

구독을 지원하는 클라이언트는 notifications/resources/updated를 통해 서버 푸시(server push)를 받습니다. 구독 이전의 클라이언트나 이를 지원하지 않는 호스트는 다시 읽는 방식으로 폴링(polling)합니다. 둘 다 스펙을 준수합니다. 서버의 기능 선언이 무엇을 지원하는지 클라이언트에게 알려줍니다.

구독의 비용은 서버의 세션별 상태입니다. 누가 무엇을 구독하는지 보관해야 합니다. 구독 집합은 제한된 크기로 유지해야 하며, 연결이 끊긴 클라이언트는 타임아웃되어야 합니다.

프롬프트와 시스템 프롬프트

MCP의 프롬프트는 시스템 프롬프트(system prompt)가 아닙니다. 호스트의 시스템 프롬프트, 즉 호스트 자신의 운영 지침과 MCP 프롬프트, 즉 사용자가 호출하는 서버 제공 템플릿은 나란히 존재합니다. 잘 동작하는 클라이언트는 서버 프롬프트가 자신의 시스템 프롬프트를 덮어쓰도록 두지 않습니다. 계층적으로 쌓습니다.

사용해 보기

code/main.py는 Lesson 07의 노트 서버를 다음 기능으로 확장합니다.

  • resources/subscribe를 지원하는 노트별 리소스(notes://note-1 등)
  • 세 개의 메시지 템플릿으로 렌더링되는 review_note 프롬프트
  • 노트가 수정될 때 notifications/resources/updated를 내보내는 파일 감시기 시뮬레이션
  • 항상 최신 노트 다섯 개를 반환하는 notes://recent 동적 리소스

전체 흐름을 보려면 데모를 실행합니다.

산출물 만들기

이 lesson은 outputs/skill-primitive-splitter.md를 만듭니다. 제안된 MCP 서버가 주어지면, 이 스킬(skill)은 각 기능을 도구 / 리소스 / 프롬프트로 분류하고 그 이유를 제시합니다.

연습문제

  1. code/main.py를 실행합니다. 초기 리소스 목록을 관찰한 뒤 노트 편집을 트리거하고 notifications/resources/updated 이벤트가 발생하는지 확인합니다.

  2. resources/list_changed 발행기를 추가합니다. 새 노트가 생성되면 클라이언트가 다시 발견할 수 있도록 알림을 보냅니다.

  3. GitHub MCP 서버를 위한 프롬프트 세 개를 설계합니다. summarize_pr, triage_issue, release_notes를 만들고 각각 인자 스키마(argument schema)를 포함합니다. 프롬프트 본문은 추가 수정 없이 실행 가능해야 합니다.

  4. Lesson 07 서버의 기존 도구 하나를 골라 계속 도구로 남겨야 하는지, 아니면 리소스와 도구 쌍으로 나누어야 하는지 분류합니다. 한 문장으로 이유를 정당화합니다.

  5. 스펙의 server/resourcesserver/prompts 섹션을 읽습니다. resources/read에서 거의 채워지지 않지만 스펙상 지원되는 필드 하나를 찾습니다. 힌트: 리소스 콘텐츠의 _meta를 보세요.

핵심 용어

용어흔한 설명실제 의미
리소스(Resource)"노출된 데이터"호스트가 읽을 수 있는 URI 주소 지정 가능 콘텐츠
리소스 URI(Resource URI)"데이터 포인터"file://, notes:// 같은 스킴 접두어가 붙은 식별자
resources/subscribe"변경 감시"특정 URI에 대해 클라이언트가 선택적으로 받는 서버 푸시 업데이트
notifications/resources/updated"리소스 변경됨"구독 중인 리소스에 새 콘텐츠가 있음을 클라이언트에 알리는 신호
리소스 템플릿(Resource template)"매개변수화된 URI"호스트 선택기를 위한 완성 힌트를 가진 URI 패턴
프롬프트(Prompt)"슬래시 명령 템플릿"인자 슬롯(argument slot)을 가진 이름 있는 여러 메시지 템플릿
프롬프트 인자(Prompt arguments)"템플릿 입력"렌더링 전에 호스트가 수집하는 타입이 있는 매개변수
prompts/get"템플릿 렌더링"서버가 채워진 메시지 목록을 반환함
콘텐츠 블록(Content block)"타입이 있는 조각"`{type: text
슬래시 명령 UX(Slash-command UX)"사용자 단축 명령"호스트가 프롬프트를 /로 시작하는 명령으로 표시함

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

main
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

primitive-splitter

Categorize each capability in an MCP server draft as tool, resource, or prompt with rationale.

Skill

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.프로덕션에서 MCP 리소스와 프롬프트의 가장 중요한 설계 원칙은?

2.MCP 리소스와 프롬프트가 올바른 선택이 아닌 경우는?

3.MCP 리소스와 프롬프트는 AI 생태계에 어떻게 들어맞나요?

0/3 답변 완료

추가 문제 풀기

AI가 강의 내용을 바탕으로 새로운 문제를 생성합니다