MCP Sever 개발 (FastAPI-MCP)
목차
FastAPI-MCP
MCP 서버를 만드는데 MCP Python SDK를 사용해도 되지만
FastAPI API 서버의 모든 엔드포인트를 MCP Tool로 변환해주는 라이브러리 FastAPI-MCP를 사용하기로 했다.
FastAPI-MCP 특징
- 직접 통합 : FastAPI 앱에 MCP 서버를 직접 마운트
- 설정 불필요 : FastAPI 앱을 지정하기만 하면 바로 작동
- 자동 탐색 : 모든 FastAPI 엔드포인트를 자동으로 탐지하고 MCP 도구로 변환
- 요청 및 응답 모델의 스키마 보존
- Swagger 문서 그대로 엔드포인트 문서 보존
- 유연한 배포 : MCP 서버를 동일한 앱에 마운트하거나 별도로 배포 가능
FastAPI-MCP 사용 방법
uv add fastapi-mcp
로 필요한 라이브러리를 설치
기본 사용 방법
1
2
3
4
5
6
7
8
9
10
11
12
13
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
app = FastAPI()
mcp = FastApiMCP(
app,
name="My API MCP",
description="My API description",
base_url="http://localhost:8000",
)
mcp.mount()
Tool 이름 지정
FastAPI-MCP는 FastAPI에 라우트에 정의된 operation_id를 MCP 도구 이름으로 사용
operation_id를 명시하지 않으면 FastAPI가 자동으로 생성하지만 다소 알아보기가 어려울 수 있음
1
2
3
4
5
6
7
8
9
# 자동 생성된 operation_id ("read_user_users__user_id__get")
@app.get("/users/{user_id}")
async def read_user(user_id: int):
return {"user_id": user_id}
# 명시적 operation_id ("get_user_info")
@app.get("/users/{user_id}", operation_id="get_user_info")
async def read_user(user_id: int):
return {"user_id": user_id}
더 명확하고 직관적인 도구 이름으로 만드려면 FastAPI 라우트 정의에 operation_id를 명시적으로 추가하는 것을 권장하고 있음
고급 사용 방법
FastAPI-MCP는 MCP 서버를 생성하고 구성하는 방식을 사용자 정의할 수 있는 다양한 방법을 제공하는데 아래는 사용 패턴 예시
스키마 설명 커스터마이징
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
app = FastAPI()
mcp = FastApiMCP(
app,
name="My API MCP",
base_url="http://localhost:8000",
describe_all_responses=True, # Tool 설명에 가능한 모든 응답 스키마 포함
describe_full_response_schema=True # Tool 설명에 전체 JSON 스키마 포함
)
mcp.mount()
노출할 Endpoint 선택 제어
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
app = FastAPI()
# 특정 operation만 포함
mcp = FastApiMCP(
app,
include_operations=["get_user", "create_user"]
)
# 특정 operation 제외
mcp = FastApiMCP(
app,
exclude_operations=["delete_user"]
)
# 특정 태그가 붙은 operation만 포함
mcp = FastApiMCP(
app,
include_tags=["users", "public"]
)
# 특정 태그가 붙은 operation 제외
mcp = FastApiMCP(
app,
exclude_tags=["admin", "internal"]
)
# operation ID + 태그 결합 사용 (포함 모드)
mcp = FastApiMCP(
app,
include_operations=["user_login"],
include_tags=["public"]
)
mcp.mount()
필터링 시 주의사항
- include_operations와 exclude_operations는 동시에 사용할 수 없음
- include_tags와 exclude_tags도 동시에 사용할 수 없음
- operation 필터링과 tag 필터링은 함께 사용할 수 있음
- 필터 조합 시 greedy 방식이 적용되며 둘 중 하나라도 매칭되면 포함됨
FastAPI 앱과 MCP 서버를 별도로 배포하기
MCP 서버는 반드시 동일한 FastAPI 앱에서 실행될 필요는 없음
하나의 FastAPI 앱에서 MCP 서버를 생성하고, 이를 다른 앱에 마운트할 수 있음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
# API 앱 정의
api_app = FastAPI()
# ... api_app에 엔드포인트 정의 ...
# MCP 서버를 위한 별도 앱
mcp_app = FastAPI()
# 기존 API 앱으로부터 MCP 서버 생성
mcp = FastApiMCP(
api_app,
base_url="http://api-host:8001",
)
# MCP 서버를 별도 앱에 마운트
mcp.mount(mcp_app)
# 이제 두 앱을 별도로 실행 가능:
# uvicorn main:api_app --host api-host --port 8001
# uvicorn main:mcp_app --host mcp-host --port 8000
MCP 서버 생성 후 엔드포인트 추가
MCP 서버를 생성한 이후 FastAPI 앱에 엔드포인트를 추가한 경우 새 엔드포인트를 포함시키기 위해 MCP 서버를 갱신해야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from fastapi import FastAPI
from fastapi_mcp import FastApiMCP
app = FastAPI()
# ... 초기 엔드포인트 정의 ...
# MCP 서버 생성
mcp = FastApiMCP(app)
mcp.mount()
# MCP 생성 후 새 엔드포인트 추가
@app.get("/new/endpoint/", operation_id="new_endpoint")
async def new_endpoint():
return {"message": "Hello, world!"}
# 새 엔드포인트를 MCP 서버에 반영
mcp.setup_server()
SSE를 이용한 MCP 서버 연결
Cursor와 같이 SSE를 지원하는 MCP 클라이언트를 통해 연결
- 애플리케이션 실행
- Cursor > Settings > MCP로 이동한 후, MCP 서버 엔드포인트의 URL(http://localhost:8000/mcp)을 sse 방식으로 입력
mcp-proxy stdio를 이용한 MCP 서버 연결
Claude Desktop처럼 SSE 방식을 지원하지 않는 경우 사용 방법
- 애플리케이션 실행
uv tool install mcp-proxy
를 이용해서mcp-proxy
를 설치- Claude Desktop의 MCP 설정 파일(claude_desktop_config.json)에 다음 내용을 추가
```json { “mcpServers”: { “my-api-mcp-proxy”: { “command”: “mcp-proxy”, “args”: [“http://127.0.0.1:8000/mcp”] } } }
```
FastAPI-MCP 프로젝트는 MIT License로 공개 및 배포되고 있어서 상업적 사용에 제약이 없음