my-mcp-server
by dcjames-park
README.md
# TypeScript MCP Server 보일러플레이트 (Vercel 배포용)
Model Context Protocol (MCP) 서버를 TypeScript로 개발하고 Vercel에 배포할 수 있는 보일러플레이트입니다.
Next.js App Router 위에서 [`mcp-handler`](https://github.com/vercel/mcp-handler)로 **Streamable HTTP** 전송을 제공하며, 로컬 개발용 **stdio** 진입점도 함께 유지합니다.
## 📁 프로젝트 구조
```
typescript-mcp-server-boilerplate/
├── src/
│ ├── mcp/
│ │ └── tools.ts # tool / resource / prompt 등록 (HTTP·stdio 공용)
│ ├── stdio.ts # 로컬 stdio 진입점
│ └── app/
│ ├── api/mcp/route.ts # Streamable HTTP 엔드포인트
│ ├── layout.tsx
│ └── page.tsx # 엔드포인트 안내 랜딩 페이지
├── build/ # stdio 빌드 결과물 (build:stdio 실행 시 생성)
├── next.config.ts
├── tsconfig.json # Next.js용
├── tsconfig.stdio.json # stdio 빌드 전용
└── .env.example
```
## 🚀 시작하기
### 1. 의존성 설치
```bash
npm install
```
### 2. 환경변수 설정
```bash
cp .env.example .env.local
```
`.env.local`에 [HuggingFace 액세스 토큰](https://huggingface.co/settings/tokens)을 넣습니다. HTTP로 연결할 때는 클라이언트가 `x-hf-token` 헤더로 토큰을 보낼 수 있으므로 이 값은 선택 사항(폴백)입니다.
### 3. 개발 서버 실행
```bash
npm run dev
```
MCP 엔드포인트: `http://localhost:3000/api/mcp`
### 4. MCP Inspector로 테스트
```bash
npx @modelcontextprotocol/inspector
```
인스펙터에서 전송 방식을 **Streamable HTTP**로 선택하고 위 URL을 입력합니다. `generate-image`를 테스트하려면 Headers에 `x-hf-token`을 추가하세요.
## 🔑 HF_TOKEN 주입 방식
`generate-image` 도구만 HuggingFace 토큰이 필요합니다. 토큰은 다음 우선순위로 결정됩니다.
1. 요청의 `x-hf-token` 헤더 (클라이언트가 자기 토큰을 사용)
2. 서버의 `HF_TOKEN` 환경변수 (헤더가 없을 때 폴백)
`createMcpHandler`는 tool 핸들러에 원본 요청 헤더를 노출하지 않기 때문에, 요청마다 핸들러를 생성해 헤더 값을 등록 클로저로 전달합니다.
```ts
// src/app/api/mcp/route.ts
const handler = async (request: Request) => {
const hfToken = request.headers.get('x-hf-token') ?? process.env.HF_TOKEN
return createMcpHandler(
(server) => registerAll(server, { hfToken, transport: 'http' }),
{ serverInfo: SERVER_INFO }
)(request)
}
export { handler as GET, handler as POST }
```
## 🔧 MCP 클라이언트 연결
### 로컬 개발 서버
`./.cursor/mcp.json`:
```json
{
"mcpServers": {
"my-mcp-server": {
"url": "http://localhost:3000/api/mcp",
"headers": {
"x-hf-token": "hf_xxxxxxxxxxxxxxxxxxxx"
}
}
}
}
```
### 배포된 서버
```json
{
"mcpServers": {
"my-mcp-server": {
"url": "https://<your-app>.vercel.app/api/mcp",
"headers": {
"x-hf-token": "hf_xxxxxxxxxxxxxxxxxxxx"
}
}
}
}
```
> **주의**: `.cursor/mcp.json`은 git에 추적되는 파일입니다. 실제 토큰을 커밋하지 않도록 주의하세요.
Streamable HTTP를 지원하지 않는 stdio 전용 클라이언트는 [`mcp-remote`](https://www.npmjs.com/package/mcp-remote)로 연결할 수 있습니다.
```json
{
"mcpServers": {
"my-mcp-server": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://<your-app>.vercel.app/api/mcp",
"--header",
"x-hf-token:hf_xxxxxxxxxxxxxxxxxxxx"
]
}
}
}
```
## ☁️ Vercel 배포
```bash
npx vercel
```
또는 GitHub 저장소를 Vercel 프로젝트에 연결하면 됩니다. 추가 설정 없이 `/api/mcp` 라우트가 Vercel Function으로 배포됩니다.
- 클라이언트가 항상 `x-hf-token`을 보낸다면 서버 환경변수는 필요 없습니다.
- 폴백을 두려면 Vercel 프로젝트 Settings → Environment Variables에 `HF_TOKEN`을 추가하세요.
- 이미지 생성은 시간이 걸리므로 라우트에 `maxDuration = 60`을 지정해 두었습니다.
- Vercel Function의 응답 크기 제한(4.5MB)이 있으므로 `num_inference_steps`를 과도하게 올리지 마세요.
## 🖥️ stdio로 실행하기
HTTP 없이 기존처럼 로컬 프로세스로 붙이려면:
```bash
npm run build:stdio
node build/stdio.js
```
```json
{
"mcpServers": {
"my-mcp-server": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/YOUR/PROJECT/build/stdio.js"],
"env": {
"HF_TOKEN": "hf_xxxxxxxxxxxxxxxxxxxx"
}
}
}
}
```
이 경우 헤더를 쓸 수 없으므로 `HF_TOKEN` 환경변수가 유일한 토큰 출처입니다.
## 🛠️ 개발 가이드
모든 tool / resource / prompt는 `src/mcp/tools.ts`의 `registerAll()` 안에서 등록합니다. HTTP 라우트와 stdio 진입점이 같은 함수를 호출하므로 한 곳만 수정하면 양쪽에 반영됩니다.
### Tool 추가하기
`inputSchema`에는 raw shape이 아니라 **`z.object()`로 감싼 스키마**를 넘깁니다 (MCP SDK v2 방식).
```ts
server.registerTool(
'reverse-text',
{
description: '입력한 문자열을 뒤집어 반환합니다.',
inputSchema: z.object({
text: z.string().min(1).describe('뒤집을 문자열')
}),
outputSchema: textOutputSchema
},
async ({ text }) => textResult([...text].reverse().join(''))
)
```
### 외부 비밀값이 필요한 Tool
`registerAll(server, options)`의 `options`로 값을 받아 클로저에서 사용하면, HTTP에서는 요청 헤더로 stdio에서는 환경변수로 주입할 수 있습니다.
```ts
export type RegisterOptions = {
hfToken?: string
transport?: 'stdio' | 'http'
}
```
### Resource 추가하기
```ts
server.registerResource(
'app-settings',
'config://settings',
{
title: '애플리케이션 설정',
description: '애플리케이션의 현재 설정 정보',
mimeType: 'application/json'
},
async (uri) => ({
contents: [
{
uri: uri.href,
mimeType: 'application/json',
text: JSON.stringify({ theme: 'dark' }, null, 2)
}
]
})
)
```
## 🧰 제공 도구
| 이름 | 설명 |
| ---------------- | ------------------------------------------------- |
| `greet` | 이름과 언어로 인사말 반환 |
| `calculator` | 두 숫자와 연산자로 사칙연산 |
| `get-time` | 타임존별 현재 시간 |
| `geocode` | 도시명을 위도/경도로 변환 (Open-Meteo) |
| `get-weather` | 좌표로 현재 날씨 및 예보 (Open-Meteo) |
| `generate-image` | 프롬프트로 이미지 생성 (HuggingFace FLUX.1-schnell) |
Resource `server://info`, Prompt `code-review`도 함께 제공합니다.
## 📦 주요 의존성
- **@modelcontextprotocol/server**: MCP TypeScript SDK v2
- **mcp-handler**: MCP 서버를 웹 표준 HTTP 핸들러로 변환
- **next / react / react-dom**: App Router 기반 호스팅
- **zod**: 스키마 검증
- **@huggingface/inference**: HuggingFace Inference API 클라이언트
## 🔧 스크립트
| 스크립트 | 설명 |
| --------------------- | ----------------------------------- |
| `npm run dev` | Next.js 개발 서버 실행 |
| `npm run build` | Next.js 프로덕션 빌드 |
| `npm run start` | 프로덕션 서버 실행 |
| `npm run build:stdio` | stdio 서버를 `build/`로 컴파일 |
| `npm run start:stdio` | 컴파일된 stdio 서버 실행 |
| `npm run typecheck` | HTTP·stdio 양쪽 타입 검사 |
## 🔗 참고 자료
- [Model Context Protocol 공식 문서](https://modelcontextprotocol.io/)
- [Deploy MCP servers to Vercel](https://vercel.com/docs/mcp/deploy-mcp-servers-to-vercel)
- [vercel/mcp-handler](https://github.com/vercel/mcp-handler)
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [Zod 문서](https://zod.dev/)
## 📄 라이선스
MIT
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues