seunghui-mcp-server
TypeScript MCP Server (Vercel 배포용)
Model Context Protocol (MCP) 서버 보일러플레이트입니다. Next.js App Router 위에서
mcp-handler로 Streamable HTTP 엔드포인트를
제공하며, 같은 도구 정의를 재사용하는 stdio 진입점도 함께 유지합니다.
HTTP 엔드포인트:
POST /api/mcpstdio 진입점:
src/mcp/stdio.ts이미지 생성 토큰:
x-hf-token요청 헤더 우선, 없으면HF_TOKEN환경변수로 폴백
📁 프로젝트 구조
├── app/
│ ├── api/mcp/route.ts # Streamable HTTP 엔드포인트
│ ├── layout.tsx # 루트 레이아웃
│ ├── page.tsx # 서버 안내 페이지
│ └── globals.css
├── src/mcp/
│ ├── metadata.ts # 서버 이름/버전, 헤더 이름, 기능 목록 (단일 출처)
│ ├── server.ts # registerAll() - 도구/리소스/프롬프트 등록
│ └── stdio.ts # stdio 진입점
├── next.config.ts
├── tsconfig.json
└── .env.exampleapp/api/mcp/route.ts와 src/mcp/stdio.ts는 둘 다 registerAll()을 호출하므로
도구를 한 번만 정의하면 두 트랜스포트가 함께 갱신됩니다.
🚀 시작하기
npm install
npm run devhttp://localhost:3000에서 안내 페이지를, http://localhost:3000/api/mcp에서
MCP 엔드포인트를 확인할 수 있습니다.
스크립트
명령 | 설명 |
| Next.js 개발 서버 |
| 프로덕션 빌드 |
| 빌드 결과 실행 |
| stdio 트랜스포트로 MCP 서버 실행 (tsx) |
| 타입 검사 |
🔑 HF_TOKEN 전달 방식
generate-image 도구는 HuggingFace Inference API를 사용합니다. 토큰은 다음 순서로 찾습니다.
요청의
x-hf-token헤더 (HTTP 트랜스포트)서버의
HF_TOKEN환경변수
헤더를 쓰면 클라이언트마다 자기 토큰을 사용할 수 있어 서버에 비밀값을 두지 않아도 됩니다.
stdio로 실행할 때는 HTTP 요청이 없으므로 항상 HF_TOKEN 환경변수를 사용합니다.
구현은 src/mcp/server.ts의 resolveHfToken()에 있으며, MCP SDK v2가 도구 콜백의
두 번째 인자로 넘겨주는 컨텍스트에서 원본 Request를 꺼내 씁니다.
const resolveHfToken = (ctx: ServerContext): string | undefined =>
ctx.http?.req?.headers.get(HF_TOKEN_HEADER)?.trim() || process.env.HF_TOKEN로컬에서 환경변수를 쓰려면 .env.example을 .env.local로 복사한 뒤 값을 채우세요.
▲ Vercel 배포
저장소를 Vercel에 연결하면 Next.js 프로젝트로 자동 인식됩니다.
(선택) 서버 기본 토큰을 두려면 프로젝트 설정 → Environment Variables에
HF_TOKEN을 추가합니다. 클라이언트가 항상x-hf-token헤더를 보낸다면 설정하지 않아도 됩니다.배포 후 엔드포인트는
https://seunghui-mcp-server.vercel.app/api/mcp입니다.
app/api/mcp/route.ts는 Node 런타임과 maxDuration = 60을 지정합니다. 이미지 생성처럼
오래 걸리는 도구가 있다면 플랜에 맞춰 값을 조정하세요.
mcp-handler2.x는 stateless로 동작하므로 Redis가 필요 없고, 레거시 HTTP+SSE 트랜스포트는 제공하지 않습니다. 엔드포인트 경로는 라우트 파일 위치로 결정됩니다.
🔧 MCP 클라이언트 연결
HTTP (배포 후 또는 로컬 개발 서버)
.cursor/mcp.json:
{
"mcpServers": {
"typescript-mcp-server": {
"url": "https://seunghui-mcp-server.vercel.app/api/mcp",
"headers": {
"x-hf-token": "hf_xxxxxxxxxxxxxxxx"
}
}
}
}Streamable HTTP를 지원하지 않는 stdio 전용 클라이언트는
mcp-remote를 경유할 수 있습니다.
{
"mcpServers": {
"typescript-mcp-server": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://seunghui-mcp-server.vercel.app/api/mcp",
"--header",
"x-hf-token:hf_xxxxxxxxxxxxxxxx"
]
}
}
}stdio (로컬)
{
"mcpServers": {
"typescript-mcp-server": {
"command": "npx",
"args": ["tsx", "src/mcp/stdio.ts"],
"cwd": "/ABSOLUTE/PATH/TO/YOUR/PROJECT",
"env": { "HF_TOKEN": "hf_xxxxxxxxxxxxxxxx" }
}
}
}
.cursor/mcp.json은 토큰을 담을 수 있어.gitignore에 포함되어 있습니다.
🧪 MCP Inspector로 테스트
npm run dev
npx @modelcontextprotocol/inspectorhttp://127.0.0.1:6274접속왼쪽 드롭다운에서 Streamable HTTP 선택
URL에
http://localhost:3000/api/mcp입력Configuration에서 커스텀 헤더
x-hf-token을 추가하면generate-image테스트 가능Connect → List Tools
🛠️ 도구 추가하기
src/mcp/server.ts의 registerAll() 안에 등록하면 HTTP와 stdio 양쪽에 동시에 반영됩니다.
MCP SDK v2는 inputSchema/outputSchema에 Zod 객체 스키마를 그대로 받습니다.
server.registerTool(
'roll-dice',
{
description: 'N면체 주사위를 굴립니다.',
inputSchema: z.object({
sides: z.number().int().min(2).describe('주사위 면 수')
})
},
async ({ sides }) => {
const value = 1 + Math.floor(Math.random() * sides)
return { content: [{ type: 'text', text: `🎲 ${value}` }] }
}
)HTTP 요청 정보가 필요하면 두 번째 인자 ctx에서 ctx.http?.req로 접근합니다.
stdio 실행 시에는 ctx.http가 undefined이므로 항상 옵셔널 체이닝으로 다루세요.
새 도구를 추가하면 src/mcp/metadata.ts의 TOOLS 목록에도 넣어 주세요.
server-info 리소스 텍스트와 안내 페이지가 이 목록을 함께 사용합니다.
📦 주요 의존성
mcp-handler: MCP 서버를 Web 표준
Request핸들러로 변환 (Vercel 어댑터)@modelcontextprotocol/server: MCP TypeScript SDK v2 서버 패키지
next / react: HTTP 라우트 호스팅
zod: 도구 입출력 스키마
@huggingface/inference: 이미지 생성
tsx: stdio 진입점 실행
🔗 참고 자료
📄 라이선스
MIT