
FastMCP 4 (MCP 2026-07-28)에서 무엇이 바뀌었나? MCP 초보자도 알 수 있는 주요 변경 사항과 이행 포인트
요약
FastMCP 4 업데이트를 통해 변경된 MCP(Model Context Protocol)의 통신 메커니즘과 서버 설계 방식을 설명합니다. MCP의 기본 개념인 Host, Client, Server 관계와 Tool, Resource, Prompt의 역할을 정리하고 FastMCP 프레임워크의 활용법을 다룹니다.
핵심 포인트
- MCP는 AI 애플리케이션과 외부 데이터를 연결하는 표준 규격임
- FastMCP 4의 핵심 변화는 Tool 작성 방식이 아닌 내부 통신 엔진의 변화임
- MCP 서버는 Tool(실행), Resource(참조), Prompt(템플릿)를 제공함
- AI가 Tool을 정확히 호출할 수 있도록 엄격한 docstring 작성이 필수적임
지난 기사에서는 Woodstock MCP를 사용하여, AI와의 대화로부터 미국 주식 종목 조사, 그리고 그대로 발주까지 수행할 수 있는 메커니즘을 소개했습니다.
그 과정에서 "MCP 자체가 새로운 규격이기 때문에, SDK 업데이트를 추종하며 구현을 진행해야 하는 부분도 있었다"라고 적었으나, 곧바로 큰 업데이트가 찾아왔습니다. 바로 FastMCP 4입니다.
이번에는 FastMCP 4의 What's New를 바탕으로, 무엇이 바뀌었는지, 그리고 그로 인해 MCP 서버의 설계를 어떻게 다시 생각해야 하는지를 정리합니다.
MCP를 처음 접하는 분들도 읽을 수 있도록, 우선 MCP와 FastMCP의 기본부터 설명하겠습니다.
애초에 MCP란 무엇인가
MCP (Model Context Protocol)는 AI 애플리케이션과 외부 데이터 및 처리를 연결하기 위한 공통 규칙입니다. 공식 문서에서는 "AI 애플리케이션을 위한 USB-C"와 같은 것이라고 설명되어 있습니다.
AI마다, 서비스마다 전용 연동 방식을 만드는 것이 아니라, MCP라는 공통 형식을 통해 기능이나 데이터를 공개함으로써 MCP에 대응하는 AI 애플리케이션에서 이용하기 쉬워집니다.
여기서 중요한 점은 MCP가 AI 모델 그 자체가 아니라는 점입니다. LLM이 사고하는 부분이 아니라, LLM을 탑재한 애플리케이션이 외부 세계와 상호작용하는 방법을 표준화하고 있습니다.
Host (호스트), Client (클라이언트), Server (서버)의 관계
**MCP Host (호스트)**는 사용자가 조작하는 AI 애플리케이션이나 IDE입니다. LLM과의 대화나 여러 MCP 연결을 통합합니다 -
**MCP Client (클라이언트)**는 호스트 내부에서 특정 MCP 서버와의 통신을 담당하는 부품입니다 -
**MCP Server (서버)**는 AI 애플리케이션이 사용하게 하고 싶은 데이터나 처리를 공개하는 프로그램입니다
"서버"라는 이름이지만, 반드시 클라우드 상에서 동작하는 것은 아닙니다. 수중에 있는 PC에서 기동하는 로컬 프로세스도 MCP 서버입니다.
MCP 서버가 공개하는 3가지 기본 요소
| 요소 | 역할 | 예 |
|---|---|---|
| Tool | AI가 호출할 수 있는 처리 | API 검색, 계산, 발주, 파일 업데이트 |
| Resource | 컨텍스트로서 참조하는 데이터 | 문서, DB 스키마, 설정, API 응답 |
| Prompt | 재사용 가능한, 인수가 포함된 지시 템플릿 | 코드 리뷰, 회의 요약, 종목 조사 방법 |
외우는 방법으로는, Tool은 "한다", Resource는 "읽는다", Prompt는 "요청 방법을 재사용한다" 입니다.
Tool이 "모델 주도"로 호출된다고 해서 무조건적으로 실행을 허가할 필요는 없습니다. 호스트 측의 승인 UI나 권한 설정, 서버 측의 인증·검증과 조합하여 안전성을 담보합니다.
FastMCP는 무엇을 해주는가
MCP는 통신의 사양입니다. 그 사양을 Python에서 다루기 쉽게 만드는 프레임워크가 FastMCP입니다.
예를 들어, 다음 Python 함수는 MCP의 Tool로서 공개할 수 있습니다.
from fastmcp import FastMCP
mcp = FastMCP("stock-research")
@mcp.tool
...
FastMCP는 함수 이름, 타입 힌트 (Type Hint), docstring으로부터 Tool의 설명과 입력 스키마를 생성하며, 입력 검증 및 MCP 통신 처리를 담당합니다.
지난 기사에서도 언급했지만, docstring은 단순한 인간용 주석이 아닙니다. AI는 Tool의 이름, 설명, 인수 스키마를 읽고 "언제, 어떤 인수로 호출할지"를 판단합니다. 따라서 공개하는 Tool의 설명은 API 문서 이상으로 엄격하게 작성해야 합니다.
우선 결론
FastMCP 4의 가장 큰 변화는 Tool의 작성 방식이 아니라, 그 아래에 있는 통신 메커니즘입니다.
내부 엔진을 MCP Python SDK v2로 교체하여, 기존의 "연결을 유지하는 방식"과 새로운 "요청마다 완결되는 방식"을 모두 다룰 수 있게 되었습니다.
변경의 전체 모습은 다음 3가지 점입니다.
- 하나의 서버로 신구(新舊) MCP 클라이언트 모두에 대응할 수 있다
- 상태, 추가 질문, 장시간 처리를 연결에 의존하지 않고 명시적으로 다룰 수 있다
- 인증, 입력 보완, 캐시, 보안 등 본番 운용을 위한 기능이 강화되었다
대부분의 FastMCP 3 서버는 그대로 동작할 수 있도록 호환성이 마련되어 있습니다. 다만, 연결에 상태(state)를 유지하고 있거나, Tool 실행 도중에 클라이언트로 추가 요청을 보내는 경우에는 설계를 재검토해야 합니다.
FastMCP 4의 주요 변경 사항
지금부터 FastMCP 4의 변경 사항을 순서대로 살펴보겠습니다.
1. MCP Python SDK v2로 이행
FastMCP 4의 토대는 안정화된 MCP Python SDK v2입니다. 요청 처리(request processing), 프로토콜 타입(protocol type), 미들웨어(middleware) 등 통신 계층이 대폭 재구축되었습니다.
Python 코드상의 필드명은 camelCase에서 snake_case로 변경됩니다.
| FastMCP 3까지의 표기 | FastMCP 4에서의 표기 |
|---|---|
inputSchema | input_schema |
mimeType | mime_type |
isError | is_error |
이는 Python 상의 속성명(attribute name) 변경입니다. 네트워크 상의 JSON까지 snake_case로 바뀐다는 의미는 아닙니다.
FastMCP가 반환하는 주요 객체에는 호환 브리지(compatibility bridge)가 있어, 기존의 camelCase로 읽더라도 현재로서는 경고(warning)와 함께 동작합니다. 다만, 이 호환 기능은 향후 삭제될 예정입니다. 새로 작성하는 코드는 snake_case를 따르는 것이 안전합니다.
또한, 프로토콜 타입의 실체는 독립된 mcp_types 패키지로 이동했습니다. MCP SDK v2에서는 기존과 같이 mcp.types에서도 이용할 수 있습니다. 반면, fastmcp.types는 FastMCP 고유의 타입만을 다루기 때문에, 그곳에서 프로토콜 타입을 불러오고 있다면 임포트(import) 경로를 변경해야 합니다.
겉으로 보이는 건물은 크게 변하지 않았더라도, 배관과 전기 설비를 통째로 교체한 것과 같은 업데이트라고 생각하면 이해하기 쉬울 것입니다.
2. 신구 프로토콜을 하나의 서버에서 처리 가능
MCP에는 현재 크게 두 가지 '세대'가 있습니다.
- 기존의, 연결 시작 시
initialize를 수행하는 세션 기반(session-based) 방식 2026-07-28이후의, 요청마다 메타데이터를 보내는 세션리스(sessionless) 방식
FastMCP 4 서버는 두 방식 모두를 제공하며 호환성을 갖추고 있습니다. 접속한 클라이언트에 따라 이용할 방식을 자동으로 협상(negotiation)합니다.
FastMCP Client의 기본값도 기존 방식 고정에서 mode="auto"로 변경되었습니다.
from fastmcp import Client
# 새로운 방식을 시도하고, 미지원 시 기존 방식으로 폴백(fallback)한다
client = Client("https://example.com/mcp", mode="auto")
...
이 덕분에 새로운 클라이언트와 오래된 클라이언트를 위해 별도의 MCP 서버를 준비할 필요가 없습니다.
한편, mode="auto"에 의해 새로운 세션리스 방식이 이전보다 자연스럽게 선택될 것입니다. 코드가 단순히 실행되는지뿐만 아니라, 다음에 설명할 상태 관리나 중간 확인 동작까지 테스트해야 합니다.
curl로 핸드셰이크(handshake) 변화 확인하기
SDK를 사용하면 숨겨지는 부분이기 때문에, 실제 HTTP 요청을 curl로 비교해 보겠습니다.
기존 방식과 새로운 방식의 흐름은 다음과 같이 바뀌었습니다.
기존 방식 (2025-06-18)
initialize
↓ Mcp-Session-Id 획득
...
새로운 방식은 핸드셰이크가 짧아진 것이 아닙니다. 세션을 만드는 핸드셰이크 자체를 없앤 것입니다.
server/discover는 서버의 대응 버전이나 기능을 사전에 확인하기 위한 선택적(optional) 요청입니다. 세션을 생성하지 않습니다. 대응 버전을 알고 있는 경우에는 처음부터 tools/call을 보낼 수 있습니다. 자세한 응답 형식은 MCP의 Discovery 사양에서 확인할 수 있습니다.
이하에서는 MCP 엔드포인트를 http://localhost:8180/mcp로, 호출할 Tool을 get_account라고 가정합니다. 인증을 사용하지 않는 로컬 서버에서는 Authorization 헤더를 삭제해 주세요.
기존 방식 (2025-06-18)의 curl
먼저 initialize를 보내고, -i
-i로 표시된 응답 헤더에서 Mcp-Session-Id를 가져옵니다.
curl -i -N --location 'http://localhost:8180/mcp' \
--header 'Authorization: Bearer <YOUR_JWT>' \
--header 'Content-Type: application/json' \
...
그다음, 가져온 Session ID를 붙여 notifications/initialized를 보냅니다.
curl --location 'http://localhost:8180/mcp' \
--header 'Authorization: Bearer <YOUR_JWT>' \
--header 'Mcp-Session-Id: <SESSION_ID>' \
...
FastMCP 4.0.0b1에서의 검증에서는, 이 알림(notification)이 수락되면 HTTP 202가 반환되었습니다.
이후의 Tool 호출에도 동일한 Session ID를 붙입니다.
curl -N --location 'http://localhost:8180/mcp' \
--header 'Authorization: Bearer <YOUR_JWT>' \
--header 'Mcp-Session-Id: <SESSION_ID>' \
...
FastMCP 4.0.0b1에 대해서도, 이 기존 방식으로 initialize, notifications/initialized, tools/call이 동작하는 것을 확인할 수 있었습니다. FastMCP 4가 새로운 방식만 사용하게 된 것은 아닙니다.
새로운 방식에서는 다음과 같습니다.
1. 서버의 대응 상황을 확인하기 (임의)
먼저, server/discover를 호출해 봅니다.
curl -i -N --location 'http://localhost:8180/mcp' \
--header 'Authorization: Bearer <YOUR_JWT>' \
--header 'Content-Type: application/json' \
...
FastMCP 4.0.0b1을 로컬에서 실행하여 테스트한 결과, HTTP 200과 Content-Type: application/json이 반환되었습니다. JSON을 정렬하면 다음과 같은 내용입니다.
{
"jsonrpc": "2.0",
"id": "discover-1",
...
capabilities나 serverInfo의 내용은 서버에 따라 달라집니다. 여기서 확인하고 싶은 점은, supportedVersions에 2026-07-28이 있고, 응답 헤더에 Mcp-Session-Id가 없다는 것입니다.
2. Session ID 없이 Tool 호출하기
notifications/initialized를 보내지 않고, 그대로 Tool을 호출합니다.
curl -i -N --location 'http://localhost:8180/mcp' \
--header 'Authorization: Bearer <YOUR_JWT>' \
--header 'Content-Type: application/json' \
...
검증용 get_account에서는 Session ID 없이 다음과 같은 응답이 반환되었습니다.
{
"jsonrpc": "2.0",
"id": 2,
...
새로운 방식에서는 클라이언트 정보를 처음에 한 번만 보내는 것이 아니라, 각 요청의 params._meta에 담습니다.
| 항목 | 역할 |
|---|---|
io.modelcontextprotocol/protocolVersion | 이 요청에서 사용할 MCP 버전 |
io.modelcontextprotocol/clientCapabilities | 이 요청에서 클라이언트가 제공할 수 있는 기능 |
io.modelcontextprotocol/clientInfo | 클라이언트 이름과 버전. 필수 사항은 아니지만 전송이 권장됨 |
새로운 방식(2026-07-28)의 Streamable HTTP 사양에서는, JSON 내용에 대응하는 HTTP 헤더도 필요합니다.
| 헤더 | 필요한 상황 | 내용 |
|---|---|---|
Accept | 모든 POST | application/json, text/event-stream 둘 다 지정 |
MCP-Protocol-Version | 모든 POST | _meta 내의 버전과 일치시킴 |
Mcp-Method | 모든 JSON-RPC 요청 | JSON의 method와 일치시킴 |
Mcp-Name | tools/call, resources/read, prompts/get | JSON의 params.name 또는 params.uri와 일치시킴 |
Authorization | 인증이 필요한 서버 | JWT 등을 매번 전송 |
헤더와 JSON의 값이 일치하지 않을 경우, 서버는 -32020 HeaderMismatch로 거부합니다. 실제 검증에서도 Mcp-Method의 누락과 버전 불일치는 HTTP 400을, Accept를 application/json으로만 설정하면 HTTP 406을 반환했습니다.
응답은 application/json뿐만 아니라, 처리 중인 알림을 포함하는 text/event-stream이 될 수도 있습니다. curl의 -N 옵션은 SSE (Server-Sent Events)를 버퍼링하지 않고 표시하기 위한 옵션입니다.
즉, 새로운 방식에서는 "먼저 연결 상태를 만들고 그 상태를 Session ID로 참조하는" 것이 아니라, 인증 정보, 프로토콜 버전, 클라이언트 능력을 포함하는 자기 완결적인(self-contained) HTTP 요청을 매번 보내는 형태가 되었습니다.
3. 세션리스(Sessionless)화와 명시적인 상태 관리
새로운 2026-07-28 프로토콜에서는 각 요청이 독립적입니다. 이전 연결에 담았던 값이 다음 호출로 자동 유지되지 않습니다.
여기서 "스테이트리스(Stateless)하므로 상태를 가질 수 없다"고 생각하는 것은 옳지 않습니다.
연결 그 자체에 상태를 두지 않을 뿐, 장바구니, 대화, 설정 등의 상태는 ID나 인증된 사용자에게 연결하여 서버 측 스토리지에 저장할 수 있습니다.
FastMCP 4에서는 두 가지 형태가 준비되어 있습니다.
UserSession: 인증된 사용자마다 하나의 상태 영역을 가짐. Tool에 자동으로 주입되며, 호출 측에서 ID를 전달할 필요 없음SessionId: 한 명의 사용자가 여러 개의 장바구니, 대화, 워크플로우를 가질 경우, ID를 명시적으로 전달
UserSession을 사용하는 예시는 다음과 같습니다.
from fastmcp import FastMCP
from fastmcp.server.sessions import UserSession
mcp = FastMCP("assistant")
...
UserSession은 사용자를 식별하기 위한 인증이 필요합니다. SessionId는 인증 없이도 사용할 수 있지만, 이 경우 "ID를 가지고 있다는 사실 자체가 권한이 되는" Bearer Handle 방식입니다. 여러 테넌트(Tenant)를 안전하게 분리하려면 인증이 필수적입니다. 인증된 상태라면 ID는 사용자별로 분리되며, 다른 사용자가 동일한 ID를 전달하더라도 해당 상태에 접근할 수 없습니다.
참고로, 위의 get → 업데이트 → set 과정은 설명을 위한 간단한 예시입니다. 동일한 상태에 동시에 쓰기를 수행할 가능성이 있는 주문이나 장바구니의 경우 경합(Contention)이 발생할 수 있으므로, 데이터베이스 트랜잭션이나 락(Lock) 등을 통해 정합성을 지켜야 합니다.
여러 레플리카(Replica)에서 구동하는 경우에는 Redis와 같이 상태를 공유할 수 있는 스토리지를 선택해야 합니다. 역으로 말하면, 연결 대상을 고정하는 스티키 세션(Sticky Session)에 의존하지 않고, 일반적인 로드 밸런서 뒤에서 수평 확장(Horizontal Scaling)하기가 더 쉬워졌습니다.
저희가 지난번에 소개한 Woodstock MCP는 Cloud Run에서 구동하며, PostgreSQL과 Redis로 상태를 외부에 저장하고 있습니다. 새로운 방식은 이러한 구성과 궁합이 좋은 반면, 대화나 진행 중인 처리를 인스턴스의 메모리에 두지 않는 것이 이전보다 더욱 중요해졌습니다.
4. 실행 도중의 상호작용은 "새로운 요청"이 됩니다
기존의 세션 기반 방식에서는 Tool 실행 중에 서버가 클라이언트로 콜백을 보내 추가 입력을 요청할 수 있었습니다.
하지만 세션리스 (Sessionless) 방식에는 연결 중인 클라이언트로 추가 요청을 보낼 수 있는 백채널 (Backchannel)이 없습니다. 따라서 FastMCP 4에서는 중간 과정의 상호작용도 독립적인 요청 (Request)과 응답 (Response)으로 명시합니다.
예를 들어, Elicitation은 Tool 실행 중에 사용자에게 추가 질문이나 확인을 요청하는 메커니즘입니다. 새로운 방식에서는 Tool이 "이 입력이 필요합니다"라는 InputRequiredResult를 반환합니다. 클라이언트는 사용자의 답변을 받은 뒤, 그 답변을 포함하여 다시 한번 Tool을 호출합니다. 첫 번째 호출을 대기 상태로 유지하지 않는, 가드 패턴 (Guard Pattern)이라고 불리는 형태입니다.
명령형 방식인 ctx.sample(), ctx.sample_step(), ctx.list_roots()도 서버 API에서 삭제되었습니다. Sampling은 서버가 클라이언트 측의 LLM에 생성을 요청하는 메커니즘이며, Roots는 클라이언트가 공개하는 작업 디렉토리 목록입니다.
Elicitation, Sampling, Roots라는 프로토콜 상의 능력 그 자체는 InputRequiredResult를 반환하는 가드 패턴 (Guard Pattern)을 통해 이용할 수 있습니다. 다만 2026-07-28 사양에서는 Sampling과 Roots, Logging이 비권장 (Deprecated)되었습니다. 새로 구축하는 경우, Sampling은 서버에서 LLM 프로바이더의 API를 직접 호출하고, Roots는 Tool 인자 (Argument), Resource URI, 서버 설정 등을 통해 필요한 범위를 명시하는 방법을 검토합니다.
기존 방식에서는 ctx.elicit()을 사용하고, 새로운 방식에서는 가드 패턴 (Guard Pattern)을 사용합니다. 신구 버전 클라이언트를 모두 지원하는 서버에서는 어떤 방식으로 호출되었는지에 따라 처리를 분기합니다.
이전 글에서 소개했던 것과 같은 "발주 전 확인"을 엄격한 Elicitation으로 구현하는 경우, 이 변경 사항의 영향을 받습니다. 확인을 기다리는 연결을 유지하는 것이 아니라, 확인이 필요한 상태를 반환하고 다음 호출에서 재개할 수 있도록 설계해야 합니다.
발주와 같은 중요한 작업에서는 답변뿐만 아니라 대상 주문, 사용자, 기한, 일회용 토큰 등을 서버 측에서 검증해야 합니다. 연결이 아니라, 업무상의 상태 그 자체를 신뢰 경계 (Trust Boundary)로 삼는다는 개념입니다.
FastMCP는 라운드 (Round) 간에 인계되는 request_state를 자동으로 암호학적으로 보호합니다. 다만, Cloud Run과 같은 다중 레플리카 (Replica) 구성에서는 모든 레플리카에 공통된 request_state_security 키 링 (Keyring)을 설정해야 합니다. 기본 키는 프로세스마다 다르기 때문에, 다음 요청이 다른 레플리카에 도달하면 재개에 실패합니다.
5. Background Tasks가 옵트인 (Opt-in) 확장 기능이 되었습니다
백테스트, 영상 처리, 대량 데이터 집계 등 수십 초에서 수 분이 소요되는 Tool을 일반적인 요청으로 계속 기다리는 것은 클라이언트와 서버 모두에게 다루기 까다로운 일입니다.
FastMCP 4에서는 장시간 처리를 io.modelcontextprotocol/tasks라는 옵트인 (Opt-in) 확장 기능으로 취급합니다. 이 확장 사양 자체는 집필 시점 기준으로 실험적 (Experimental) 단계입니다.
- 서버가 처리를 수락하고 Task ID를 반환함
- 클라이언트가 주기적으로 상태를 확인함
- 완료 후 결과를 가져옴
FastMCP 3부터 사용되어 온 Docket 기반 실행 엔진과 @mcp.tool(task=True)라는 표기법은 계승되었습니다. 다만 FastMCP 4에서는 추가 패키지와 확장 기능 등록이 필요합니다.
pip install "fastmcp[tasks]==4.0.0b1"
import asyncio
from fastmcp import FastMCP
from fastmcp_tasks import TasksExtension
...
몇 가지 주의 사항이 있습니다.
- Task로 지정할 수 있는 것은
asyncTool뿐입니다. - Resource나 Prompt에는
task=를 붙일 수 없습니다. TasksExtension을 등록하지 않고task=True를 사용하면 실행 시 에러가 발생합니다.- Background Tasks는 새로운 프로토콜 기능이며,
mode="legacy"에서는 동기 (Synchronous) 방식으로 실행됩니다. - 운영 환경에서 재시작 내성 (Restart Resilience)이나 수평 확장 (Horizontal Scaling)이 필요하다면, 인메모리 (In-memory)가 아닌 Redis나 Valkey를 백엔드로 사용해야 합니다.
FastMCP Client는 대응하는 Task의 상태를 내부적으로 확인하기 때문에, 일반적인 client.call_tool(...)과 동일한 형태로 최종 결과를 받을 수 있습니다. 서버와 클라이언트를 별도의 프로세스로 실행하는 경우에는 클라이언트 측에서도 fastmcp-tasks를 설치하고, import fastmcp_tasks를 통해 Task 대응을 활성화해야 합니다.
Woodstock MCP에서 연산량이 많은 처리로 분리해 둔 백테스트(Backtest)는 바로 이 메커니즘과 궁합이 좋은 영역입니다. 별도의 독자적인 진행 상황 확인 API를 만들지 않고도, MCP의 공통 형식을 통해 Task ID, 진행 상황, 결과를 다룰 수 있게 됩니다. 다만, 확장 기능(Extension)을 지원하지 않는 클라이언트에서는 동기 실행(Synchronous execution)이 되므로, 타임아웃이나 폴백(Fallback) 설계는 여전히 필요합니다.
6. 확장 API (Extension API)로 프로토콜 기능 추가 가능
Background Tasks를 뒷받침하는 것이 바로 새로운 Extension API입니다.
Extension에는 io.modelcontextprotocol/tasks와 같은 역 DNS (Reverse DNS) 형식의 이름을 붙입니다. 클라이언트와 서버는 대응하는 기능을 서로 제시하며, 양측이 모두 이해할 수 있는 경우에만 해당 Extension을 사용합니다.
FastMCP.add_extension()을 통해 다음과 같은 횡단적(Cross-cutting) 기능을 추가할 수 있습니다.
- 독자적인 요청 메서드 (Request method)
tools/call에 대한 개입- 시작 및 종료 시의 처리
- 컴포넌트 목록, Context, 인증 정보(Credentials)를 사용하는 처리
MCP 본체에 직접 패치를 적용하는 것이 아니라, 대응하는 상대방 사이에서만 유효한 플러그인으로서 추가할 수 있게 되었다고 이해하면 쉽습니다.
7. Prompt와 Resource Template에 입력 후보 반환 가능
FastMCP 4에서는 @mcp.completion을 통해 입력 후보를 반환할 수 있게 되었습니다.
예를 들어, 먼저 GitHub의 owner를 선택하면, 다음 repo에는 해당 소유자의 리포지토리만을 후보로 반환하는 식의 보완(Completion)이 가능합니다. 핸들러(Handler)는 입력 중인 값뿐만 아니라, 이미 선택된 다른 인자(Argument)도 참조할 수 있습니다.
대상은 **Prompt의 인자와 Resource Template의 파라미터(Parameter)**입니다. 모든 Tool 인자에 대한 범용적인 입력 보완은 아닙니다.
AI가 자연어로부터 값을 추측할 뿐만 아니라, 서버가 올바른 후보를 제시할 수 있기 때문에 리포지토리 이름, 환경 이름, 종목 코드 등 선택지가 정해져 있는 입력에서 특히 유용합니다.
8. 기업용 인증 및 Machine-to-Machine 인증 강화
FastMCP 4에서는 사람이 조작하는 AI뿐만 아니라, 기업 내 에이전트나 백엔드 서비스로부터의 이용을 상정한 인증 및 인가(Authorization) 기능이 추가되었습니다.
- Identity Assertion: 기업의 IdP가 서명한 본인 확인 정보를 에이전트가 제시하고, 서버가 단기 토큰(Short-lived Token)을 발행합니다. Keycloak, Cognito, Auth0 등 프로바이더마다 다른 클레임(Claim)에서 Role이나 Group을 추출하여 인가하는
require_roles를 지원합니다. - Client Credentials: 정기 실행, 백엔드, MCP 서버 간 통신 등 사람이 없는 클라이언트를 OAuth 2.0 Client Credentials 방식으로 인증합니다.
- Incremental Authorization: 스코프(Scope) 부족 시, 무엇이 부족한지를 구체적으로 반환합니다.
- DCR (Dynamic Client Registration)의
application_type대응: Native App과 Web App의 Redirect URI 검증을 분리합니다.
Identity Assertion은 사내 에이전트가 사용자를 대신하여 업무 API에 접근하는 'On-Behalf-Of' 유스케이스에 적합합니다. 반면, 야간 배치(Batch) 작업처럼 사용자가 존재하지 않는 처리는 Client Credentials가 적합합니다.
참고로, STDIO는 클라이언트가 로컬 프로세스를 기동하여 표준 입출력으로 통신하는 방식입니다. STDIO에는 OAuth 개념이 없기 때문에, HTTP용 인증·인가를 Tool에 설정하더라도 해당 체크는 적용되지 않습니다. 실운영에서는 통신 방식까지 포함하여 설계해야 합니다.
9. 캐시, 보안, Gateway 연동
세세한 변경처럼 보이지만, 운영 환경에서는 중요한 개선 사항들이 포함되어 있습니다.
응답 캐시 (Response Cache)
서버가 응답에 유효 기간(TTL)과 공유 범위(Scope)에 대한 힌트를 추가하여, 대응하는 클라이언트가 이를 재사용할 수 있게 되었습니다.
from fastmcp import FastMCP
mcp = FastMCP("market-data", cache_ttl=30, cache_scope="public")
Redis 등을 사용하는 KeyValueResponseCacheStore도 준비되어 있어, 여러 클라이언트나 프록시 간에 캐시를 공유할 수 있습니다.
클라이언트 측 캐시는 기본적으로 비활성화되어 있으며, cache=True 또는 CacheConfig를 통한 활성화가 필요합니다. 공유 캐시를 사용하는 경우에는 partition이 필수이며, 인증이 필요한 데이터의 경우 검증된 인증 정보로부터 얻은 사용자 ID나 테넌트 ID를 사용하여 분리합니다.
Resource Template의 경로 검사
Resource Template의 파라미터에 포함된 다음과 같은 값들을 핸들러 실행 전에 기본적으로 거부합니다.
..을 사용한 패스 트래버설 (Path Traversal) - 절대 경로- Null Byte
이는 마운트된 서버나 프록시를 통한 Resource에도 적용됩니다. 정당한 유스케이스에서 이러한 값을 허용하고 싶다면 명시적인 예외 설정이 필요합니다.
사양 준수 에러 코드
존재하지 않는 Resource에 대한 에러 코드가 -32002에서 -32602 (INVALID_PARAMS)로 변경되었습니다. 메시지가 아닌 숫자 코드를 보고 분기 처리를 하는 클라이언트는 수정이 필요합니다.
Gateway Routing Headers
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기