MCP(모델 컨텍스트 프로토콜)는 AI 모델을 외부 도구 및 데이터 소스와 연결하는 표준 방법으로 빠르게 자리잡고 있습니다. MCP 채택이 증가함에 따라 개발자들은 강력하고 프로덕션에 즉시 사용할 수 있는 MCP 구현을 구축하려면 단순히 사양을 따르는 것 이상이 필요하다는 사실을 깨닫고 있습니다. 즉, 올바른 인프라가 필요합니다. 이 게시물에서는 Redis가 세 가지 MCP 사용 사례, 즉 Vercel의 SSE 구현에서 분산 서버리스 기능을 조정하고, 장기 실행 스트림에 대한 이벤트 재개를 활성화하고, Clerk를 통해 보안 OAuth 흐름을 관리하는 방법을 살펴보겠습니다.
MCP 전송 이해
예제를 살펴보기 전에 MCP가 통신을 처리하는 방법을 간략하게 살펴보겠습니다. MCP는 Stdio라는 두 가지 전송을 지원합니다. 로컬 서버 및 스트리밍 가능한 HTTP용 원격 서버용. 과거에는 원격 서버를 위한 SSE(Server-Sent Events) 전송도 있었지만 현재는 더 이상 사용되지 않습니다.
SSE에서 Streamable HTTP로의 전환은 MCP가 실시간 통신을 처리하는 방식의 발전을 나타내지만 기존의 많은 구현은 여전히 SSE 패턴에 의존합니다. Redis가 해당 모델의 주요 과제 중 하나를 해결하는 데 어떻게 도움이 되었는지 살펴보겠습니다.
사용 사례 1:Redis Pub/Sub를 사용한 SSE
Vercel CTO Malte가 MCP 핸들러를 구축했을 때 그는 전형적인 서버리스 문제에 직면했습니다. 각 요청이 다른 서버리스 기능에 의해 처리될 수 있는 경우 여러 엔드포인트 간에 어떻게 조정해야 할까요?
SSE 전송 모델에는 두 개의 중요한 엔드포인트가 있습니다:/sse 연결 유지 및 /message 클라이언트 메시지를 수신하기 위한 것입니다. 문제는 다음과 같습니다. Vercel과 같은 서버리스 환경에서는 이러한 엔드포인트가 완전히 격리됩니다. 그들은 메모리를 공유하지 않으며 /message에 대한 요청을 합니다. /sse을 처리하는 함수 인스턴스와 완전히 다른 함수 인스턴스에 의해 처리될 수 있습니다. .
해결책? Redis 게시/구독. Malte가 X에 대해 설명했듯이:

구현에서는 Redis 채널을 사용하여 엔드포인트 간을 조정합니다. 클라이언트가 /message에 메시지를 보낼 때 , 해당 엔드포인트는 /sse이 있는 Redis 채널에 게시합니다. 엔드포인트가 구독됩니다. /sse 엔드포인트는 요청을 처리하고 /message인 다른 채널을 통해 응답을 다시 게시합니다. 듣고 있습니다.

이 패턴은 Redis를 격리된 서버리스 기능 간의 격차를 해소하는 메시지 버스로 효과적으로 전환하여 마치 동일한 프로세스의 일부인 것처럼 함께 작업할 수 있도록 합니다. SSE는 이제 Streamable HTTP를 선호하여 더 이상 사용되지 않지만(새로운 MCP 구현은 최신 전송을 사용해야 함을 의미) 이는 격리된 서버리스 기능 간의 조정을 위해 Redis를 사용하는 훌륭한 예로 남아 있습니다.
사용 사례 2:재개를 위한 이벤트 저장소
MCP Streamable HTTP 전송의 가장 강력한 기능 중 하나는 재개 가능성에 대한 지원입니다. 이 기능을 사용하면 클라이언트는 연결이 끊어진 경우 중단된 부분부터 스트림을 계속할 수 있습니다. 이는 네트워크 중단이 불가피한 프로덕션 애플리케이션에 매우 중요합니다.
MCP 스트림 이해
재개성이 중요한 이유를 이해하려면 MCP 스트림이 무엇으로 구성되어 있는지 이해해야 합니다. 간단한 도구 호출과 같은 일부 작업은 단일 응답을 반환합니다. 그러나 도구는 server.sendLoggingMessage와 같은 메서드를 사용하여 실행 중에 여러 이벤트를 반환할 수도 있습니다. 이러한 다중 이벤트 스트림에서는 재개성이 중요합니다. 클라이언트 연결이 중간에 끊어지면 다시 시작하는 대신 중단된 부분부터 다시 시작할 수 있어야 합니다.
Redis로 EventStore 구현
MCP SDK는 storeEvent의 두 가지 메서드가 필요한 EventStore 인터페이스를 정의합니다. 이벤트 추가 및 replayEventsAfter 특정 이벤트 ID에서 시작하는 이벤트를 검색합니다. SDK에는 인메모리 구현이 포함되어 있지만 프로덕션 용도로 사용하려면 영구 저장소가 필요합니다.
다음은 EventStore의 Redis 기반 구현입니다:
import { Redis } from '@upstash/redis';
import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
import { EventStore } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
export class RedisEventStore implements EventStore {
private redis: Redis;
constructor(params: ConstructorParameters<typeof Redis>[0]) {
this.redis = new Redis(params);
}
/**
* Stores an event in a Redis Stream
* Implements EventStore.storeEvent
*/
async storeEvent(streamId: string, message: JSONRPCMessage): Promise<string> {
const eventId = await this.redis.xadd(`stream:${streamId}`, '*', {
message: JSON.stringify(message),
});
return eventId;
}
/**
* Replays events that occurred after a specific event ID
* Implements EventStore.replayEventsAfter
*/
async replayEventsAfter(
lastEventId: string,
{ send }: { send: (eventId: string, message: JSONRPCMessage) => Promise<void> }
): Promise<string> {
if (!lastEventId) {
return '';
}
// Extract the stream ID from the lastEventId
const streamId = lastEventId.split('-')[0]; // Assuming the stream ID is part of the key
if (!streamId) {
return '';
}
let nextId = lastEventId;
while (true) {
// Fetch events from the stream starting AFTER the next ID (exclusive)
const events = await this.redis.xrange(`stream:${streamId}`, `(${nextId}`, '+', 10);
// Convert the returned object to an array of entries
const eventEntries = Object.entries(events);
if (eventEntries.length === 0) {
break; // No more events to replay
}
for (const [eventId, fields] of eventEntries) {
// Ensure fields.message exists and parse it
if (fields && typeof fields === 'object' && 'message' in fields && typeof fields.message === 'string') {
const message = JSON.parse(fields.message) as JSONRPCMessage;
await send(eventId, message);
nextId = eventId; // Update the next ID to the current event ID
}
}
}
return streamId;
}
} 이 구현에서는 이 사용 사례에 완벽한 Redis Streams를 사용합니다.
한계
알아야 할 한 가지 중요한 주의 사항이 있습니다. 도구가 여러 이벤트를 보낼 때 streamId는 _GET_stream로 설정됩니다. 이며 이 상수는 다양한 스트림과 사용자 간에 동일하게 유지됩니다. 이는 두 명의 사용자가 여러 이벤트를 보내는 동일한 도구를 동시에 사용하는 경우 해당 이벤트가 동일한 스트림에서 혼합될 수 있음을 의미합니다.
공식 저장소에서 이에 대한 문제를 열었습니다. 해상도에 따라 구현을 조정해야 할 수도 있으며, 필요한 경우 이에 따라 이 게시물을 업데이트하겠습니다.
사용 사례 3:사무원의 MCP OAuth 구현
MCP 사양에는 인증 및 권한 부여에 대한 지원이 포함되어 있어 MCP 서버가 클라이언트를 안전하게 인증하고 리소스에 대한 액세스를 제어할 수 있습니다. 이 사양은 OAuth 2.0을 포함한 여러 인증 체계를 지원합니다. 이는 기존 ID 공급자와 통합하고 도구 및 데이터에 대한 사용자 범위 액세스를 활성화하는 데 특히 유용합니다.
Clerk는 MCP SDK에서 OAuthClientProvider 인터페이스를 구현하여 MCP용 포괄적인 OAuth 클라이언트를 구축했습니다. 이들 구현은 MCP 애플리케이션에서 Redis의 또 다른 중요한 사용 사례를 보여줍니다. MCP 도구를 시작하고 싶다면 훌륭한 시작점을 제공하는 데모 저장소를 확인하세요.
OAuth에서 스토리지가 중요한 이유
Clerk가 mcp-tools에서 설명했듯이 저장소, 영구 저장소는 두 가지 주요 이유로 MCP OAuth 구현에 필수적입니다:
- OAuth 흐름은 여러 엔드포인트에 걸쳐 있습니다. - 초기화, OAuth 콜백 및 MCP 요청은 모두 공유 메모리 없이 다양한 서버리스 기능으로 처리될 수 있습니다.
- MCP 연결은 장기 실행 - 인메모리 스토리지에 의존하면 애플리케이션이 확장됨에 따라 메모리 요구 사항이 부풀려지고 서버를 다시 시작하면 모든 세션이 무효화됩니다.
Redis에 저장되는 내용
Clerk의 Redis 저장소는 OAuth 흐름에서 특정 목적을 가진 세 가지 유형의 데이터를 관리합니다.
PKCE 검증자 (pkce_verifier_<...> ) OAuth 흐름을 시작할 때 저장되고 사용자가 액세스 권한을 부여한 후 다시 읽습니다. 이는 PKCE(코드 교환용 증명 키) 흐름의 일부로, 흐름을 시작한 애플리케이션이 흐름을 완료하는 애플리케이션과 동일하도록 보장하여 공용 클라이언트에서 OAuth에 대한 추가 보안을 제공합니다(RFC 7636에 정의됨).
{
"value": "XoYQ...",
"created_at": "2025-10-03T06:27:06.928Z",
"updated_at": "2025-10-03T06:27:06.928Z"
}
세션 데이터 (session_<...> ) MCP 세션의 모든 구성과 상태를 저장합니다. 처음에는 MCP 엔드포인트, OAuth 구성 및 클라이언트 자격 증명이 포함됩니다. 사용자가 액세스 권한을 부여하면 액세스 및 새로 고침 토큰으로 업데이트됩니다. 마지막으로 authComplete 흐름이 완료되면 플래그가 추가됩니다.
{
"value": {
"mcpEndpoint": "http://localhost:3001/mcp",
"oauthRedirectUrl": "http://localhost:3000/oauth_callback",
"oauthScopes": "openid profile email",
"mcpClientName": "Clerk MCP Demo",
"mcpClientVersion": "0.0.1",
"oauthClientUri": "http://example.com",
"oauthPublicClient": false,
"clientId": "8Yb2...",
"clientSecret": "64YG..."
},
"created_at": "2025-10-03T06:27:06.882Z",
"updated_at": "2025-10-03T06:27:06.882Z"
}
상태 매개변수 (state_<...> )이는 OAuth 상태 매개변수를 세션 ID에 매핑하므로 상태 ID를 사용하여 세션 데이터를 가져올 수 있습니다.
{
"value": "dX61...",
"created_at": "2025-10-03T06:27:03.585Z",
"updated_at": "2025-10-03T06:27:03.585Z"
} 이 아키텍처를 통해 OAuth 흐름은 보안 및 세션 무결성을 유지하면서 분산된 서버리스 기능 전반에서 원활하게 작동할 수 있습니다.
Redis가 MCP에 완벽한 이유
세 가지 예 모두에서 Redis를 MCP 인프라에 이상적인 선택으로 만드는 공통 패턴을 볼 수 있습니다.
낮은 지연 시간 :MCP 작업은 종종 빨라야 합니다. Redis의 인메모리 아키텍처는 실시간 AI 상호작용에 필요한 응답 시간을 제공합니다.
Pub/Sub 기능 :Vercel의 구현에서 보았듯이 Redis Pub/Sub는 전체 메시지 대기열의 복잡성 없이 분산된 구성 요소 간의 우아한 조정을 가능하게 합니다.
풍부한 데이터 구조 :이벤트 스트림용 스트림, 세션 데이터용 해시, 상태용 단순 키-값 쌍입니다. Redis는 각 사용 사례에 적합한 데이터 구조를 제공합니다.
내장된 만료 :TTL을 통한 자동 정리. OAuth 토큰, 이벤트 스트림 및 세션 데이터는 모두 수동 가비지 수집 없이 자동으로 만료될 수 있습니다.
서버리스 친화적 :Upstash Redis와 같은 솔루션을 사용하면 사용하지 않을 때 0으로 확장되는 완전 관리형 서버리스 Redis를 얻을 수 있습니다. 다양한 작업 부하가 있을 수 있는 MCP 구현에 적합합니다.
MCP 사양 기능을 넘어서:더 넓은 AI 생태계의 Redis
우리는 MCP 사양에 명시적으로 정의된 기능에 중점을 두었지만 Redis의 유틸리티는 AI 강화와 관련하여 우리가 탐색한 패턴을 훨씬 뛰어넘습니다. 최근 블로그 게시물에서는 다음과 같은 몇 가지 패턴을 보여줍니다.
- AI SDK 통합 - Redis를 사용하여 Vercel AI SDK 개선
- 채팅 기록 - 메시지 기록 유지
우리의 사례 외에도 커뮤니티는 AI 애플리케이션을 위한 인상적인 Redis 기반 도구를 구축했습니다. Midday의 ai-sdk-tools 제품군에는 이 예에 표시된 것처럼 Redis를 사용하여 AI SDK 도구 결과를 캐시하는 도구 결과 캐싱 패키지가 포함되어 있어 성능을 대폭 향상하고 비용을 절감합니다.

MCP 서버, AI 에이전트 또는 전체 AI 애플리케이션을 구축하는 경우 Redis는 시스템을 프로덕션에 즉시 사용할 수 있고 확장 가능하며 고성능으로 만드는 인프라 계층을 제공합니다.
결론
모델 컨텍스트 프로토콜은 아직 초기 단계이지만 AI 애플리케이션을 위한 필수 인프라로 빠르게 자리잡고 있습니다. 이 세 가지 예를 통해 살펴본 것처럼 Redis는 다음을 통해 MCP 구현을 강력하고 프로덕션에 즉시 사용할 수 있도록 만드는 데 중요한 역할을 합니다.
- 속도 및 유연성 :속도, 유연성, 서버리스 친화적인 아키텍처의 조합
- 비용 절감 :비용이 많이 드는 API 호출 및 계산을 줄이는 캐싱 기능
서버 측이든 클라이언트 측이든 MCP를 사용하여 구축하는 경우 Redis는 MCP 기반 AI 애플리케이션의 완벽한 동반자로서 도구 키트에 있어야 합니다. Upstash Redis를 사용하면 사용하지 않을 때 0으로 확장되는 전 세계적으로 사용 가능한 서버리스 Redis를 몇 초 만에 시작할 수 있습니다.