MCP Sampling AI 프로바이더
MCP Sampling AI 프로바이더
MCP Sampling AI 프로바이더 는 기존 클라이언트 구독(예: VS Code Copilot)을 활용해 MCP 서버가 AI SDK를 통해 AI 모델을 사용할 수 있게 해줘요. 이 프로바이더는 별도의 API 키나 구독 없이도 MCP 서버를 추론하고 의사결정할 수 있는 에이전틱 도구로 바꿔줘요.
이 프로바이더는 MCP의 sampling 기능을 통해 요청을 MCP 클라이언트로 전달하면서 LanguageModelV4를 구현해, 고유한 장점을 제공해요:
- 서버 측 AI 통합 (Server-Side AI Integration): MCP 서버가 AI SDK의 표준 인터페이스를 통해 직접 언어 모델을 호출할 수 있게 해줘요
- 직접 모델 관리 불필요 (No Direct Model Management): AI 요청을 MCP 클라이언트로 전달해 여러 API 키의 필요성을 없애요
- 모델 유연성 (Model Flexibility): MCP 클라이언트가 선호도(비용, 속도, 지능)에 따라 어떤 모델을 사용할지 결정하게 해줘요
- 원활한 AI SDK 호환성 (Seamless AI SDK Compatibility):
generateText,streamText,Output을 통한 구조화 출력, 실험적 도구 호출 지원 - 클라이언트 샘플링 지원 (Client Sampling Support): 내장 헬퍼로 어떤 MCP 클라이언트에든 샘플링 기능 추가
- 에이전틱 도구 (Agentic Tools): 단순한 MCP 도구를 추론하고 의사결정할 수 있는 지능형 에이전트로 변환
MCP Sampling에 대해 더 알아보려면 MCP 스펙을 참고하세요.
출처: 문서
본문
사전 요구 사항 (Prerequisites)
경고: 이 프로바이더는 특정 요구 사항이 있어요:
- MCP 서버 안에서 실행해야 함 - 독립형 AI SDK 프로바이더가 아니에요. MCP 클라이언트로 요청을 전달하는 방식으로 동작해요.
- 클라이언트가 MCP Sampling을 지원해야 함 - 연결된 MCP 클라이언트가 샘플링 기능을 구현해야 하며, 직접 구현할 수도 있어요(아래 클라이언트 샘플링 참고).
샘플링 지원 클라이언트 (Clients with Sampling Support)
더 많은 옵션은 MCP 클라이언트 전체 목록을 참고하세요.
대안: setupClientSampling()을 사용해 어떤 MCP 클라이언트에든 샘플링을 추가할 수 있어요(아래 예시 참고).
설정 (Setup)
MCP Sampling AI 프로바이더는 @mcpc-tech/mcp-sampling-ai-provider 모듈에서 사용할 수 있어요. 다음과 같이 설치할 수 있어요:
# pnpm
pnpm add @mcpc-tech/mcp-sampling-ai-provider
# npm
npm install @mcpc-tech/mcp-sampling-ai-provider
# yarn
yarn add @mcpc-tech/mcp-sampling-ai-provider
# bun
bun add @mcpc-tech/mcp-sampling-ai-provider
# deno
deno add jsr:@mcpc/mcp-sampling-ai-provider
프로바이더 인스턴스 (Provider Instance)
MCP Sampling 프로바이더 인스턴스를 만들려면 MCP 서버 인스턴스와 함께 createMCPSamplingProvider 함수를 사용하세요:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { createMCPSamplingProvider } from '@mcpc-tech/mcp-sampling-ai-provider';
// 샘플링 기능을 가진 MCP 서버 생성
const server = new Server(
{ name: 'my-agent', version: '1.0.0' },
{ capabilities: { sampling: {}, tools: {} } },
);
const provider = createMCPSamplingProvider({ server });
구성 (Configuration)
프로바이더는 다음 구성을 받아요:
-
server MCP Server instance
샘플링 기능이 활성화된 MCP Server 인스턴스예요.
언어 모델 (Language Models)
languageModel() 메서드로 언어 모델 인스턴스를 만들어요:
const model = provider.languageModel({
modelPreferences: {
hints: [{ name: 'gpt-5-mini' }],
costPriority: 0.5,
speedPriority: 0.8,
intelligencePriority: 0.9,
},
});
모델 선호도 (Model Preferences)
languageModel() 메서드는 선택적 모델 선호도를 받아요:
-
hints Array\<\{ name: string \}\>
모델 이름 힌트 배열 (예:
[{ name: "gpt-5-mini" }]). MCP 클라이언트에 선호 모델을 제안해요. -
costPriority number (0-1)
값이 높을수록 더 저렴한 모델을 선호해요. 기본값은 0이에요.
-
speedPriority number (0-1)
값이 높을수록 더 빠른 모델을 선호해요. 기본값은 0이에요.
-
intelligencePriority number (0-1)
값이 높을수록 더 강력한 모델을 선호해요. 기본값은 0이에요.
자세한 내용은 MCP 모델 선호도를 참고하세요.
예시 (Examples)
generateText
MCP 서버 도구에서 MCP Sampling 프로바이더로 텍스트를 생성해요:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { createMCPSamplingProvider } from '@mcpc-tech/mcp-sampling-ai-provider';
import { generateText } from 'ai';
// 샘플링 기능을 가진 MCP 서버 생성
const server = new Server(
{ name: 'translator', version: '1.0.0' },
{ capabilities: { sampling: {}, tools: {} } },
);
// 사용 가능한 도구 목록
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'translate',
description: 'Translate text to a target language using AI',
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'The text to translate',
},
target_lang: {
type: 'string',
description: 'The target language (e.g., "Spanish", "French")',
},
},
required: ['text', 'target_lang'],
},
},
],
};
});
// AI를 사용하는 번역 도구 등록
server.setRequestHandler(CallToolRequestSchema, async request => {
if (request.params.name === 'translate') {
// 서버에서 프로바이더 생성
const provider = createMCPSamplingProvider({ server });
// AI SDK로 텍스트 번역
const { text } = await generateText({
model: provider.languageModel({
modelPreferences: { hints: [{ name: 'gpt-5-mini' }] },
}),
prompt: `Translate to ${request.params.arguments?.target_lang}: ${request.params.arguments?.text}`,
});
return { content: [{ type: 'text', text }] };
}
});
// 연결 및 시작
const transport = new StdioServerTransport();
await server.connect(transport);
streamText
MCP Sampling 프로바이더로 텍스트 응답을 스트리밍해요:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { createMCPSamplingProvider } from '@mcpc-tech/mcp-sampling-ai-provider';
import { streamText } from 'ai';
const server = new Server(
{ name: 'ai-assistant', version: '1.0.0' },
{ capabilities: { sampling: {}, tools: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'generate-story',
description: 'Generate a story or poem using AI',
inputSchema: {
type: 'object',
properties: {},
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async request => {
if (request.params.name === 'generate-story') {
const provider = createMCPSamplingProvider({ server });
const result = streamText({
model: provider.languageModel({
modelPreferences: {
hints: [{ name: 'gpt-5-mini' }],
speedPriority: 0.9,
},
}),
prompt: 'Write a short poem about coding.',
});
const text = await result.text;
return { content: [{ type: 'text', text }] };
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
구조화 출력 (Structured Output)
MCP Sampling 프로바이더로 구조화 객체를 생성해요:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { createMCPSamplingProvider } from '@mcpc-tech/mcp-sampling-ai-provider';
import { generateText, Output } from 'ai';
import { z } from 'zod';
const server = new Server(
{ name: 'recipe-generator', version: '1.0.0' },
{ capabilities: { sampling: {}, tools: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'generate-recipe',
description: 'Generate a recipe using AI',
inputSchema: {
type: 'object',
properties: {},
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async request => {
if (request.params.name === 'generate-recipe') {
const provider = createMCPSamplingProvider({ server });
const recipeSchema = z.object({
recipe: z.object({
name: z.string(),
cuisine: z.string(),
ingredients: z.array(z.string()),
steps: z.array(z.string()),
}),
});
const { output } = await generateText({
model: provider.languageModel({
modelPreferences: { hints: [{ name: 'gpt-5-mini' }] },
}),
output: Output.object({ schema: recipeSchema }),
prompt: 'Generate a delicious lasagna recipe.',
});
return {
content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
};
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
도구 호출 (Tool Calling, 실험적)
MCP Sampling 프로바이더와 함께 도구를 사용해요. 참고: 이 기능은 시스템 프롬프트로 구현되어 네이티브 도구 지원만큼 안정적이지 않을 수 있어요:
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { createMCPSamplingProvider } from '@mcpc-tech/mcp-sampling-ai-provider';
import { generateText, isStepCount } from 'ai';
import { z } from 'zod';
const server = new Server(
{ name: 'weather-agent', version: '1.0.0' },
{ capabilities: { sampling: {}, tools: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'ask-weather',
description: 'Ask a weather-related question',
inputSchema: {
type: 'object',
properties: {
question: {
type: 'string',
description: 'The weather question to ask',
},
},
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async request => {
if (request.params.name === 'ask-weather') {
const provider = createMCPSamplingProvider({ server });
const result = await generateText({
model: provider.languageModel({
modelPreferences: { hints: [{ name: 'gpt-5-mini' }] },
}),
tools: {
getWeather: {
description: 'Get the weather for a location',
inputSchema: z.object({
city: z.string().describe('The city name'),
}),
execute: async ({ city }) => {
return `The weather in ${city} is sunny and 72°F`;
},
},
},
prompt:
request.params.arguments?.question ||
'What is the weather in San Francisco?',
stopWhen: isStepCount(5),
});
return { content: [{ type: 'text', text: result.text }] };
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
추가 예시 (Additional Examples)
더 완전한 작동 예시는 examples 디렉토리를 참고하세요:
- generate_text_example.ts - 기본 텍스트 생성
- stream_text_example.ts - 스트리밍 응답
- generate_object_example.ts - 구조화 출력
- client-sampling-example.ts - 클라이언트 샘플링 구현
클라이언트 샘플링 (Client Sampling, 네이티브 미지원 클라이언트용)
MCP 클라이언트가 네이티브로 샘플링을 지원하지 않으면 setupClientSampling을 모델 선호도와 함께 사용해 샘플링 기능을 추가할 수 있어요:
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import {
convertAISDKFinishReasonToMCP,
selectModelFromPreferences,
setupClientSampling,
} from '@mcpc-tech/mcp-sampling-ai-provider';
import { generateText } from 'ai';
const client = new Client(
{ name: 'my-client', version: '1.0.0' },
{ capabilities: { sampling: {} } },
);
setupClientSampling(client, {
handler: async params => {
const modelId = selectModelFromPreferences(params.modelPreferences, {
hints: {
'gpt-5': 'openai/gpt-5-mini',
'gpt-mini': 'openai/gpt-5-mini',
},
priorities: {
speed: 'openai/gpt-5-mini',
intelligence: 'openai/gpt-5-mini',
},
default: 'openai/gpt-5-mini',
});
const result = await generateText({
model: modelId,
messages: params.messages,
});
return {
model: modelId,
role: 'assistant',
content: { type: 'text', text: result.text },
stopReason: convertAISDKFinishReasonToMCP(result.finishReason),
};
},
});
const transport = new StdioClientTransport({
command: 'npx',
args: ['-y', 'example_mcp_server.ts'],
});
await client.connect(transport);
자세한 내용은 전체 예시를 참고하세요.
동작 원리 (How It Works)
요청 흐름은 간단해요:
- AI SDK가 언어 모델을 호출
- 프로바이더가 MCP
sampling/createMessage형식으로 변환 - MCP 클라이언트가 샘플링 요청 처리
- 프로바이더가 응답을 AI SDK 형식으로 다시 변환
MCP 클라이언트(예: VS Code, Claude Desktop)는 제공된 modelPreferences를 바탕으로 실제 사용할 모델을 결정해요.
제한 사항 (Limitations)
- 토큰 카운팅 없음: MCP는 토큰 사용 정보를 제공하지 않아요 (0 반환)
- 네이티브 스트리밍 없음: MCP 샘플링은 스트리밍을 지원하지 않아요 - 프로바이더가 먼저
doGenerate를 호출한 다음 완전한 응답을 스트림 이벤트로 발행해요 - 실험적 도구/JSON 지원: MCP 샘플링이 네이티브로 지원하지 않으므로 systemPrompt로 구현돼요