FastMCP 가이드: Python·TypeScript로 MCP 서버 구축하고 배포하는 방법
FastMCP는 Model Context Protocol(MCP) 서버를 비교적 적은 코드로 만들 수 있게 돕는 프레임워크입니다. 일반 함수를 AI 에이전트가 호출할 수 있는 도구로 등록하고, 데이터베이스나 기존 API를 MCP 인터페이스로 연결할 때 특히 유용합니다.
2026년 9월 기준으로 FastMCP라는 이름은 Python 생태계의 fastmcp와 Prefect가 관리하는 TypeScript 라이브러리 @prefecthq/fastmcp-ts에서 각각 사용됩니다. 두 구현 모두 MCP의 도구·리소스·프롬프트 개념을 감싸지만 설치 패키지와 세부 API는 다르므로 프로젝트 언어에 맞는 문서를 선택해야 합니다.
FastMCP로 만들 수 있는 MCP 서버는 무엇인가요?
MCP 서버는 LLM이나 MCP 호스트가 외부 기능과 데이터에 접근하도록 연결하는 중간 계층입니다. MCP 사양에서 서버가 제공하는 대표 구성 요소는 실행 가능한 도구, 모델에 제공할 데이터를 나타내는 리소스, 반복적인 작업 지침을 정의하는 프롬프트입니다.
- 도구: 데이터 조회, 주문 생성, 사내 API 호출처럼 실행이 필요한 기능
- 리소스: 설정 파일, 문서, 사용자 정보처럼 읽어야 하는 데이터
- 프롬프트: 코드 리뷰, 보고서 작성 등 정해진 입력 형식을 가진 작업 템플릿
FastMCP의 핵심은 함수와 타입 정보를 바탕으로 MCP 등록 코드를 줄이는 것입니다. Python에서는 데코레이터 패턴을, TypeScript에서는 스키마 객체와 등록 메서드를 사용합니다.
Python FastMCP 설치와 첫 번째 도구 만들기
Python 프로젝트에서는 가상환경을 만든 뒤 FastMCP 패키지를 설치하는 방식이 일반적입니다. 패키지 버전은 프로젝트의 Python 버전과 배포 환경에 맞춰 고정하는 편이 안전합니다.
python -m venv .venv
source .venv/bin/activate
pip install fastmcp
Windows PowerShell에서는 가상환경 활성화 명령이 다를 수 있습니다. 설치가 끝나면 server.py 파일을 만들고 도구를 등록합니다.
from fastmcp import FastMCP
mcp = FastMCP("Inventory Server")
@mcp.tool
def find_product(product_id: str) -> dict:
"""상품 ID로 재고 정보를 조회합니다."""
# 실제 프로젝트에서는 DB 또는 사내 API를 호출합니다.
return {
"product_id": product_id,
"stock": 12,
"available": True,
}
if __name__ == "__main__":
mcp.run()
@mcp.tool 데코레이터가 붙은 함수는 MCP 도구로 등록됩니다. 함수 이름은 도구 이름으로 활용되고, 매개변수 타입과 문서 문자열은 클라이언트가 도구를 이해하는 데 사용됩니다. 실제 DB 연결에서는 연결 객체를 전역으로 무리하게 만들기보다 앱 수명주기와 커넥션 풀을 고려해 관리해야 합니다.
기존 DB와 커스텀 API를 도구에 연결하는 방법
FastMCP가 DB를 자동으로 안전한 도구로 바꿔주는 것은 아닙니다. 개발자가 모델에게 공개할 작업의 범위와 입력 검증, 권한 확인, 반환 데이터를 직접 설계해야 합니다. 특히 자연어를 그대로 SQL 문자열에 연결하는 방식은 피하고, 허용된 필드와 조건을 명시적으로 제한해야 합니다.
from fastmcp import FastMCP
import os
import httpx
mcp = FastMCP("Order Server")
@mcp.tool
def get_order(order_id: str) -> dict:
"""주문 번호에 해당하는 주문 상태를 조회합니다."""
if not order_id.startswith("ORD-"):
raise ValueError("올바른 주문 번호 형식이 아닙니다.")
response = httpx.get(
f"{os.environ['ORDER_API_BASE']}/orders/{order_id}",
headers={"Authorization": f"Bearer {os.environ['ORDER_API_TOKEN']}"},
timeout=10.0,
)
response.raise_for_status()
data = response.json()
return {
"order_id": data["id"],
"status": data["status"],
"updated_at": data["updated_at"],
}
API 키는 소스 코드에 넣지 말고 환경변수나 시크릿 관리 시스템에서 주입합니다. 주문 수정·결제·삭제처럼 부작용이 있는 도구는 조회 도구와 분리하고, 사용자 확인이나 별도 권한 검사를 추가하는 것이 좋습니다.
STDIO와 Streamable HTTP 중 무엇을 선택할까요?
| 상황 | 권장 전송 방식 | 특징 |
|---|---|---|
| 로컬 개발, 데스크톱 클라이언트 | STDIO | 프로세스의 표준 입력·출력을 사용하며 설정이 단순합니다. |
| 사내 공용 서비스, 원격 에이전트 | Streamable HTTP | URL로 접근하고 여러 클라이언트가 서버를 공유할 수 있습니다. |
| 구형 클라이언트 호환 | 레거시 SSE 검토 | 새 프로젝트의 기본 선택보다는 호환성 용도로 확인합니다. |
로컬 테스트는 기본 STDIO 실행으로 충분합니다. 원격 연결이 필요하면 HTTP 전송을 사용합니다.
if __name__ == "__main__":
mcp.run(transport="http", host="0.0.0.0", port=8000)
FastMCP 문서에서는 네트워크 기반 배포에 Streamable HTTP를 사용하도록 안내합니다. 기존 FastAPI 서비스에 MCP를 함께 제공해야 한다면 FastMCP의 HTTP 앱을 기존 ASGI 애플리케이션에 마운트하는 구조를 검토할 수 있습니다. 이때 세션 수명주기를 위해 FastMCP 앱의 lifespan을 상위 애플리케이션에 전달해야 하는 경우가 있습니다.
TypeScript FastMCP로 MCP 서버 구축하기
TypeScript에서는 Prefect의 @prefecthq/fastmcp-ts 패키지를 사용할 수 있습니다. 입력값은 Zod 같은 Standard Schema 호환 라이브러리로 정의하고, server.tool, server.resource, server.prompt 메서드로 구성 요소를 등록합니다.
npm install @prefecthq/fastmcp-ts zod
import { FastMCP } from '@prefecthq/fastmcp-ts/server'
import { z } from 'zod'
const server = new FastMCP({
name: 'inventory-server',
version: '1.0.0',
})
server.tool(
{
name: 'find_product',
description: '상품 ID로 재고를 조회합니다.',
input: z.object({
productId: z.string().min(1),
}),
},
async ({ productId }) => {
return {
productId,
stock: 12,
available: true,
}
},
)
await server.run()
TypeScript 구현은 입력 스키마가 코드에 명시되므로 잘못된 형식의 요청을 초기 단계에서 차단하기 쉽습니다. HTTP로 실행하려면 프로젝트와 사용 중인 FastMCP 버전에 맞춰 server.run({ transport: 'http', port: 3000 }) 형태를 검토합니다.
개발 중 도구 목록과 호출을 확인하는 방법
서버가 실행됐다고 해서 도구 등록이 제대로 끝난 것은 아닙니다. 도구 이름, 설명, 입력 스키마가 클라이언트에 어떻게 보이는지 확인해야 합니다.
Python FastMCP는 CLI로 서버 파일을 실행할 수 있습니다.
fastmcp run server.py:mcp
fastmcp run server.py:mcp --transport http --port 8000
TypeScript FastMCP는 CLI를 사용해 로컬 파일의 도구를 조회하거나 특정 도구를 호출할 수 있습니다.
npx fastmcp inspect --file server.ts
npx fastmcp call find_product --file server.ts productId=SKU-100
이 단계에서는 정상 응답뿐 아니라 빈 값, 존재하지 않는 ID, 권한이 없는 요청, 외부 API 지연과 오류도 함께 확인해야 합니다. 모델이 이해하기 쉬운 도구 설명을 작성하는 것도 중요합니다. 이름만 모호하게 정하기보다 대상과 결과를 설명하는 편이 좋습니다.
프로덕션 배포 전에 점검할 보안과 운영 항목
- 민감한 DB 테이블과 관리 기능을 도구 목록에서 분리합니다.
- 모든 외부 입력에 타입·길이·허용값 검증을 적용합니다.
- API 키와 DB 비밀번호를 환경변수 또는 시크릿 저장소로 관리합니다.
- HTTP 배포에서는 TLS, 인증, CORS 허용 출처를 명확히 설정합니다.
- 도구 호출 로그에 토큰·개인정보·비밀번호가 남지 않도록 필터링합니다.
- 실패 응답은 내부 스택트레이스를 노출하지 않고 재시도 가능한 오류와 사용자 입력 오류를 구분합니다.
- 여러 인스턴스로 수평 확장할 때 세션 저장 방식과 로드밸런서 구성을 함께 점검합니다.
FastMCP의 Streamable HTTP는 기본 설정에서 서버 측 세션을 사용할 수 있습니다. 여러 인스턴스에 요청을 분산하는 환경에서는 세션이 특정 프로세스의 메모리에만 남아 요청이 다른 인스턴스로 전달될 때 문제가 생길 수 있으므로, 무상태 모드나 공유 저장소 등 공식 배포 문서의 확장 방식을 확인해야 합니다.
FastMCP 개발을 시작할 때의 권장 순서
- 모델이 실제로 수행해야 할 업무를 한 문장으로 정의합니다.
- 조회용 도구 하나를 먼저 만들고 입력·출력 스키마를 고정합니다.
- 로컬 STDIO 환경에서 도구 목록과 오류 응답을 확인합니다.
- 기존 DB나 API 연결을 추가하되 권한과 입력 검증을 분리합니다.
- 원격 연결이 필요할 때 Streamable HTTP와 인증을 적용합니다.
- 부작용이 있는 작업은 승인 절차와 감사 로그를 추가한 뒤 배포합니다.
FastMCP는 MCP 서버의 반복적인 등록 코드를 줄여주는 도구이지, 데이터 권한과 운영 책임까지 대신하는 플랫폼은 아닙니다. 따라서 작은 조회 도구로 구조를 검증한 다음, 필요한 기능만 단계적으로 확장하는 방식이 가장 안전합니다.
유익한 정보 감사합니다:)