๐ [Project] AI ๋ด ์ง์ ๋ง๋ค๊ธฐ: MCP ์๋ฒ์ ์์ฑ, ๋ณด์๊ณผ ์ธ์ฆ์ ์ค๋ฌด ์ ๋ต
๐ก๏ธ ๋ณด์ ์ ๋ต: "์ด๋ฏธ ์๋ ๊ฒ์ ํ์ฉํ๋ผ" (DRF Token์ ์ฌ๋ฐ๊ฒฌ)
API๋ฅผ ๋์ค์๊ฒ ๊ณต๊ฐํ๊ฑฐ๋ ํน์ ๊ธฐ๋ฅ์ ์ธ๊ฐ๋ ์ฌ์ฉ์์๊ฒ๋ง ๋ ธ์ถํ๋ ๊ฒ์ ๋ฐ์ดํฐ ๋ณด์์ ํต์ฌ์ ๋๋ค. ์ ๋ FastAPI์ ์์ฒด ์ธ์ฆ(OAuth2.0, JWT ๋ฑ)์ ์๋ก ๊ตฌ์ถํ๋ ๋์ , ๋ฉ์ธ ํ๋ก์ ํธ์ธ Django REST Framework(DRF)์ AuthToken์ ํ์ฉํ๊ธฐ๋ก ํ์ต๋๋ค.
-
์ด์ 1: ์์กด์ฑ ์ต์ํ:
fastapi[all]์ ์ค์นํ์ฌ ๋ถํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋น๋ํ๋ฅผ ์ด๋ํ๊ธฐ๋ณด๋ค, ํ์ฌ ์์คํ ์์ ๊ฐ์ฅ ๊ฐ๋ฒผ์ด ๊ฒฝ๋ก๋ฅผ ์ ํํ์ต๋๋ค. -
์ด์ 2: ํตํฉ ๊ด๋ฆฌ: ์ฌ์ฉ์์ ์ธ์ฆํค๋ ์ด๋ฏธ Django DB์ ์กด์ฌํฉ๋๋ค. ์ด๋ฅผ ํ์ฉํ๋ฉด API ์๋ฒ์ ๋ฉ์ธ ์๋ฒ ๊ฐ์ ์ธ์ฆ ์ฒด๊ณ๋ฅผ ์ด์ค์ผ๋ก ๊ด๋ฆฌํ ํ์๊ฐ ์์ด ํจ์จ์ ์ ๋๋ค.
๐ก ์ธ์ฌ์ดํธ: ์ข์ ์ง๋ฌธ์๊ฐ AI๋ฅผ ์ด๊ธด๋ค
๊ฐ๋ฐ ๊ณผ์ ์์ ์ ๊ฐ ๋๋ ์ ์, ํด๋ก๋(Claude)๋ ์ ๋ฏธ๋์ด(Gemini) ๊ฐ์ AI๊ฐ ์ฝ๋๋ฅผ ์ง์ฃผ๋๋ผ๋ '์ ๊ธฐ์ ๊ฒฐํฉ'์ ์ฌ์ ํ ์ธ๊ฐ์ ๋ชซ์ด๋ผ๋ ๊ฒ์ ๋๋ค.
ํนํ "AI๊ฐ ๋ฑ์ด์ฃผ๋ ์ค๋ฅ๋ ํ์ต์ ๊ธฐํ"๋ผ๋ ์ ์ ๊ฐ์กฐํ๊ณ ์ถ์ต๋๋ค. ์ฝ๋๋ฅผ ๋๋ฌด ์๋ฒฝํ๊ฒ ์ง์ฃผ๋ AI๋ ์คํ๋ ค ์ด๋ณด ๊ฐ๋ฐ์์๊ฒ '๋ '์ด ๋ ์ ์์ต๋๋ค. ์ค๋ฅ๋ฅผ ์ง์ ๋ง์ฃผํ๊ณ , "์ ์ด ์ฝ๋๊ฐ ๋์ํ์ง ์๋์ง"๋ฅผ ์ง์ํ๊ฒ ๋ฌป๋ ๊ณผ์ ์์ ์ฐ๋ฆฌ์ 'ํ๋ก๊ทธ๋๋ฐ ์์'์ด ๊ธธ๋ฌ์ง๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด ์์์ด ๋ท๋ฐ์นจ๋์ด์ผ๋ง AI์๊ฒ ๋ ์๋ฆฌํ๊ณ ์ฐฝ์์ ์ธ ์ง๋ฌธ์ ๋์ง๋ '์ข์ ์ง๋ฌธ์'๊ฐ ๋ ์ ์์ต๋๋ค.
๐ป ์ค์ ์ฝ๋: fastapi-mcp ์ธ์ฆ ๊ตฌํ (Authorization)
์ด์ ์ค์ ๊ตฌํ๋ ์ฝ๋์ ํต์ฌ์ ์ง์ด๋ณด๊ฒ ์ต๋๋ค. ์ผ๋ฐ์ ์ธ ๊ฒ์์ผ๋ก๋ ์ฐพ๊ธฐ ํ๋ fastapi-mcp ๊ณต์ ๋ฌธ์ ๊ธฐ๋ฐ์ ์ค์ ์
๋๋ค.
1. MCP ์๋ฒ ์ธก: ์์กด์ฑ ์ฃผ์ (Dependency Injection)
์๋ฒ๋ ํ๊ฒฝ๋ณ์์ ์ ์ฅ๋ AUTH_TOKEN๊ณผ ํด๋ผ์ด์ธํธ๊ฐ ๋ณด๋ธ ํค๋๋ฅผ ๋์กฐํฉ๋๋ค. FastApiMCP ๊ฐ์ฒด ์์ฑ ์ auth_config ํ๋ผ๋ฏธํฐ๋ฅผ ํตํด ์ด๋ฅผ ์์ ๊ฒ์ฆํ๋๋ก ์ค์ ํ์ต๋๋ค.
# MCP ์๋ฒ์ธก ์ค์ ์์ from fastapi import Depends, Header, HTTPException from fastapi_mcp import FastApiMCP, AuthConfig def validate_drf_token(authorization: str = Header(...)): # "Token <your_token>" ํ์์์ ํ ํฐ๊ฐ ์ถ์ถ ๋ฐ ๊ฒ์ฆ ๋ก์ง if not authorization == f"Token {MY_AUTH_TOKEN}": raise HTTPException(status_code=401, detail="Invalid Token") mcp = FastApiMCP( app, auth_config=AuthConfig( dependencies=[Depends(validate_drf_token)], ), ) mcp.mount_http(mount_path="/mcp") 2. MCP ํด๋ผ์ด์ธํธ ์ธก: ํค๋ ์ค์ด ๋ณด๋ด๊ธฐ
ํด๋ผ์ด์ธํธ(TradeNPU_AI)์์๋ ์์ฒญ์ ๋ณด๋ผ ๋ StreamableHttpTransport์ headers ํ๋ผ๋ฏธํฐ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ๋ด์ ์ ์กํฉ๋๋ค.
# MCP ํด๋ผ์ด์ธํธ์ธก ์ค์ ์์ from mcp import Client from mcp.client.http import StreamableHttpTransport transport = StreamableHttpTransport( url=MCP_SERVER_URL, headers={ "Authorization": f"Token {drf_token}", } ) mcp_client = Client(transport=transport) ๐งญ ๊ฒฐ๋ก : ๋ก์ปฌ์ ๋์ด ์๊ฒฉ์ผ๋ก ๊ฐ๋ ์ง๊ฒ๋ค๋ฆฌ
์ธ์ฆ ๊ณผ์ ๊น์ง ์ฑ๊ณต์ ์ผ๋ก ํตํฉํ๋ฉฐ, ์ด์ '๋ด ์ง์'์ ํ๋ฝ๋ ์ฌ์ฉ์์๊ฒ๋ง ๋ฐ์ํ๋ ๋ ๋ ํ ๊ฐ๋๊ฐ ๋์์ต๋๋ค. ๋น์ฅ์ ์ ๋ง ์ฌ์ฉํ๋ ๋ก์ปฌ ํ๊ฒฝ์ด์ง๋ง, ์ด ๊ตฌ์กฐ๋ ์ธ์ ๋ ์๊ฒฉ ์๋ฒ๋ก ํ์ฅํ์ฌ ์ ์ฒด ์ฌ์ฉ์์๊ฒ ๊ฐ๋ฐฉํ ์ ์๋ ํ์ค ๊ท๊ฒฉ์ด ๋ฉ๋๋ค.
๊ธฐ์ ์ ๋๊ด์ ํด๊ฒฐํ๋ ๊ณผ์ ์์ ์ป์ ํ๋ก๊ทธ๋๋ฐ ๊ทผ์ก์ ๋ค์ ๋จ๊ณ์ธ '๋ ๋ณต์กํ ๋๊ตฌ(Tool) ๊ฐ๋ฐ'์ ์ํ ์์คํ ์์ฐ์ด ๋ ๊ฒ์ ๋๋ค.
๐ก ์๋ด: ์ด ํฌ์คํ ์ ๊ธฐ์กด ๋ค์ด๋ฒ ๋ธ๋ก๊ทธ์ '๊ฐ๋ฐ์ฉ MCP ๋ก์ปฌ์๋ฒ ๋ง๋ค๊ธฐ' 3, 4ํ์ฐจ๋ฅผ ํตํฉํ ๊ธฐ๋ก์ ๋๋ค. FastAPI ๊ธฐ๋ฐ MCP ์๋ฒ์ DRF ์ธ์ฆํค๋ฅผ ์ ๋ชฉํ์ฌ ๋ณด์์ ๊ฐํํ๋ ๋ฐฉ๋ฒ๊ณผ, AI์ ํ์ ํ๋ 'ํ๋ช ํ ์ง๋ฌธ์'์ ํ๋์ ๋ํด ๋ค๋ฃน๋๋ค.