Skip to main content
Glama
README.md
# TypeScript MCP Server (Streamable HTTP + stdio)

Next.js와 [`mcp-handler`](https://github.com/vercel/mcp-handler)로 동작하는 MCP(Model Context Protocol) 서버입니다. Vercel에 배포 가능한 Streamable HTTP 전송을 기본으로 하고, 로컬 디버깅용 stdio 진입점도 함께 제공합니다.

## 📁 프로젝트 구조

```
├── app/
│   ├── layout.tsx, page.tsx, globals.css   # 사용 방법을 안내하는 랜딩 페이지
│   ├── api/[transport]/route.ts            # MCP 엔드포인트 (/api/mcp)
│   └── api/server-info/route.ts            # server-info 리소스용 JSON 엔드포인트
├── src/
│   ├── mcp/register.ts                     # 도구/리소스/프롬프트 등록 (HTTP·stdio 공용)
│   └── stdio.ts                            # 로컬 stdio 진입점
├── next.config.ts
├── tsconfig.json                           # Next.js용
└── tsconfig.stdio.json                     # stdio 빌드용 (tsc → build/)
```

도구 정의는 전송 방식과 무관하게 [`src/mcp/register.ts`](src/mcp/register.ts) 한 곳에만 존재하고, 환경 차이(토큰 출처, 파일 저장 가능 여부, 리소스 URI)는 옵션으로 주입합니다.

## 🚀 시작하기

```bash
npm install
npm run dev          # http://localhost:3000 , MCP 엔드포인트는 /api/mcp
```

### 스크립트

| 명령 | 설명 |
| --- | --- |
| `npm run dev` | Next.js 개발 서버 (Streamable HTTP) |
| `npm run build` / `npm start` | Next.js 프로덕션 빌드/실행 |
| `npm run build:stdio` | stdio 진입점을 `build/stdio.js`로 컴파일 |
| `npm run start:stdio` | 컴파일된 stdio 서버 실행 |
| `npm run typecheck` | 두 tsconfig 모두 타입 검사 |

## 🔌 MCP 클라이언트 연결

### Streamable HTTP (권장)

`.cursor/mcp.json`에 URL과 헤더를 지정합니다. 이 파일은 토큰을 포함하므로 `.gitignore`에 등록되어 있습니다.

```json
{
    "mcpServers": {
        "My_MCP_Server_1": {
            "url": "https://<your-deployment>.vercel.app/api/mcp",
            "headers": {
                "x-hf-token": "hf_..."
            }
        }
    }
}
```

로컬 개발 중에는 `http://localhost:3000/api/mcp`를 사용하세요. stdio만 지원하는 클라이언트는 [`mcp-remote`](https://www.npmjs.com/package/mcp-remote)로 연결할 수 있습니다.

### stdio (로컬 디버깅)

```json
{
    "mcpServers": {
        "My_MCP_Server_1": {
            "command": "node",
            "args": ["/ABSOLUTE/PATH/TO/build/stdio.js"],
            "env": { "HF_TOKEN": "hf_..." }
        }
    }
}
```

## 🔑 HF_TOKEN 전달 (x-hf-token)

`generate-image` 도구는 HuggingFace Inference API를 사용하므로 토큰이 필요합니다. 토큰은 다음 순서로 결정됩니다.

1. 요청의 `x-hf-token` 커스텀 헤더 (클라이언트가 요청 단위로 전달, 서버에 저장되지 않음)
2. 서버 환경변수 `HF_TOKEN` (Vercel 프로젝트 환경변수 또는 stdio 실행 시 `env`)

헤더는 [`app/api/[transport]/route.ts`](app/api/[transport]/route.ts)에서 요청마다 읽어 도구 등록 시점에 주입합니다.

```ts
const handler = async (request: Request) => {
    const hfToken =
        request.headers.get('x-hf-token')?.trim() || process.env.HF_TOKEN
    // ...요청마다 createMcpHandler를 생성
}
```

토큰이 없으면 도구가 실패 대신 설정 안내 메시지를 반환합니다.

## 🛠️ 제공 기능

| 종류 | 이름 | 설명 |
| --- | --- | --- |
| Tool | `greet` | 이름과 언어로 인사말 생성 |
| Tool | `calculator` | 두 숫자와 연산자(+, -, *, /) 계산 |
| Tool | `get-time` | IANA timezone 또는 도시 이름으로 현재 시간 조회 |
| Tool | `geocode` | 도시/주소 → 위도·경도 (Nominatim) |
| Tool | `get-weather` | 도시/주소 → 현재 날씨 (Open-Meteo) |
| Tool | `generate-image` | 프롬프트 → 이미지 생성 (FLUX.1-schnell) |
| Tool | `get-server-info` | 서버 이름/버전/도구 목록 반환 |
| Resource | `server-info` | 서버 기본 정보 JSON |
| Prompt | `code-review` | 규칙 기반 코드 리뷰 프롬프트 |

### 전송 방식에 따른 차이

Vercel 서버리스 함수는 파일시스템이 읽기 전용이므로 다음 동작이 갈립니다.

| 항목 | HTTP (Vercel) | stdio (로컬) |
| --- | --- | --- |
| `generate-image` 결과 | base64 이미지로만 반환 | `generated-images/`에 저장 후 경로 반환 |
| `server-info` 리소스 URI | `https://<host>/api/server-info` | `~/.cursor/mcp-resources/.../server-info.json` |
| HF 토큰 출처 | `x-hf-token` 헤더 → `HF_TOKEN` | `HF_TOKEN` 환경변수 |

## ☁️ Vercel 배포

```bash
npx vercel
npx vercel env add HF_TOKEN     # 헤더 미전달 시 사용할 fallback (선택)
npx vercel --prod
```

배포 후 `https://<deployment>/api/mcp`를 클라이언트에 등록하면 됩니다. 인증이 필요하면 `mcp-handler`의 `withMcpAuth`로 OAuth를 추가할 수 있습니다.

## 🧪 로컬 테스트

```bash
npx @modelcontextprotocol/inspector
```

Inspector에서 전송 방식을 **Streamable HTTP**로 선택하고 `http://localhost:3000/api/mcp`에 연결합니다.

## 📦 주요 의존성

- `next`, `react`: HTTP 라우트 및 랜딩 페이지
- `mcp-handler`: MCP 서버를 Web 표준 Request 핸들러로 변환 (Streamable HTTP)
- `@modelcontextprotocol/sdk`: MCP 프로토콜 구현 (`mcp-handler@1.x`가 `1.26.0`을 요구하므로 버전 고정)
- `@huggingface/inference`: 이미지 생성
- `zod`: 입력/출력 스키마 정의

## 🔗 참고 자료

- [Deploy MCP servers to Vercel](https://vercel.com/docs/mcp/deploy-mcp-servers-to-vercel)
- [vercel/mcp-handler](https://github.com/vercel/mcp-handler)
- [Model Context Protocol 공식 문서](https://modelcontextprotocol.io/)
- [MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)

## 📄 라이선스

MIT