2. MCP Server 및 Client 구현하기
- 시나리오
- MCP Host에서 사용자가 특정 지역의 날씨를 요청한다.
- LLM은 사용자 요청을 분석하여 도구가 필요한지 분석하여 MCP Client에게 도구 목록을 요청한다.
- 도구 목록 중 지역 좌표와 관련된 도구가 있는지 확인하고 MCP Client에게 필요한 도구를 요청한다.
- MCP Client는 요청한 도구가 정의된 MCP Server에게 도구를 요청한다.
- MCP Server는 전달받은 시, 구, 동의 데이터를 이용하여 SQLite DB로부터 nx, ny 격자 좌표를 가져오는 도구를 실행한다.
- 결괏값을 LLM이 인식할 수 있는 텍스트 포맷으로 MCP Client에게 전달한다.
- MCP Client는 LLM에게 실행 결과를 제공한다.
- LLM은 받은 격자 좌표를 이용하여 날씨 정보를 가져오는 도구가 있는지 MCP Client에게 요청한다.
- MCP Client는 날씨정보 도구가 정의된 MCP Server에게 도구를 요청한다.
- MCP Server는 전달받은 nx, ny 격자 좌표를 이용하여 기상청 Open API를 이용하여 각종 예보값을 가져오는 도구를 실행한다.
- 결괏값을 LLM이 인식할 수 있는 텍스트 포맷으로 MCP Client에게 전달한다.
- MCP Client는 LLM에게 실행 결과를 제공하고 데이터를 합쳐 답변을 생성한다.
- MCP Host는 사용자에게 생성된 답변을 보여준다.
- MCP 서버 코드 구현하기
시나리오중 MCP Server와 관련된 도구, 리소스, 프롬프트를 구현하려고 합니다.
구현하기 전에 MCP Python SDK을 읽어보시면 코드를 이해하는데 도움이 됩니다.
Cursor 편집기에서 src/server.py 파일을 생성합니다. 그리고 오른쪽 상단의 +버튼을 클릭하여 대화 내용을 초기화해 줍니다.
그리고 아래 프롬프트를 채팅창에 입력합니다. 첫 질문은 전체 구조를 만드는 과정으로 되도록 상세하게 구현 내용을 입력하는 게 좋습니다.
여기서는 지역에 해당하는 좌표 정보를 가져오는 함수와 좌표에 해당하는 날씨 정보를 가져오는 함수를 구현합니다. 또한 위에서 언급한 기상청 Open API의 요청과 응답 정보를 알고 있기 때문에 포함시키겠습니다.
마지막으로 Server를 구현하는 예시코드도 추가하겠습니다. 그러면 사용자가 의도한 코드가 생성될 확률이 높습니다.
mcp 모듈을 이용하여 MCP Server를 구현하려고 해. tool에 사용되는 함수 get_grid_location는 입력 파라미터로 city(시), gu(구), dong(동)을 입력받아 data/weather_grid.db의 SQLite DB로부터 조회하여 level1, level2, level3, grid_x, grid_y 값을 가져와
"City(시): 서울시, Gu(구)): 서초구, Dong(동): 양재1동, Nx: 61, Ny: 125"와 같은 텍스트 포맷으로 return 하면 돼.
또다른 tool에 사용하는 함수 get_forecast는 입력 파라미터로 city(시), gu(구), dong(동), nx(X 좌표), ny(Y 좌표)를 입력받아 기상청 Open API인 http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst?serviceKey={service_key}&numOfRows=60&pageNo=1&dataType=json&base_date={base_date}&base_time={base_time}&nx={nx}&ny={ny} 를 요청하여 응답값을 가져오도록 해줘. API의 {service_key}는 .env 파일에서 KO_WEATHER_API_KEY 에서 가져오고, {base_date}는 현재 날짜(포맷 : YYYYMMDD)을, {base_time}은 현재 정시시간(HHMM), {nx}, {ny}는 입력 파라미터로 적용해주면 돼. 응답값중 category, fcstDate, fcstTime, fcstValue를 출력해줘.
리소스는 MCP Server에서 LLM에 데이타와 컨텐츠를 노출시키는 데 사용되고, 프롬프트는 재사용 가능한 프롬프트 템플릿 및 워크플로를 만들어 LLM과 상호작용하는 역활을 하니 이 함수도 자세히 정의해줘. 도구, 리소스 및 프롬프트는 각각 FastMCP 모듈의 @tool, @resource, @prompt 데코레이터로 정의해줘.
마지막으로 각 함수와 파라미터는 외부에서 도구를 요청할 때 참고하니 설명을 자세하게 추가해줘. 그외 붎필요한 기능은 추가하지말아줘.
아래는 예시코드야.
# server.py
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
아래 이미지는 위의 프롬프트를 AI Agent에게 입력하여 받은 응답 화면입니다. Accept All를 클릭하여 Agent 가 생성한 모든 코드를 적용해 줍니다.
이제 server.py 코드를 분석해 보겠습니다.
- FastMCP 초기화
- get_grid_location 도구 함수 정의
- weather_grid.db 경로 설정
- SQLite DB 연결
- 입력된 시, 구, 동 값으로 쿼리 하여 필요한 항목 가져오기
- 텍스트 포맷으로 응답
- get_forecast 도구 함수 정의
- 공공데이터포탈의 인증키 정보 가져오기
- 현재 날짜와 시간 가져오기
- Open API 요청
- 응답값 출력
- weather_categories 리소스 함수
- 날씨 도구를 사용하는 방법 제공
- weather_forecast_prompt 프롬프트 함수
- 프롬프트 정의
코드에는 특별한 문제나 오류는 없는 것 같습니다. 다만, 노란색 라인으로 표시된 모듈을 설치하겠습니다.
uv add requests python-dotenv "mcp[cli]"
마지막으로 @mcp. tool, @mcp. resource, @mcp. prompt에 name, description, uri를 추가 보완하도록 하겠습니다.
"@mcp.tool, @mcp.resource, @mcp.prompt"에 "name, description"를 좀더 상세히 내용을 채워주고 @mcp.resource에는 uri도 추가해줘.
위의 이미지처럼 name, description, uri 가 추가된 것을 확인할 수 있습니다. @mcp. resource의 uri는 weather://instructions으로 변경합니다.
그리고. env 파일을 열어서 KO_WEATHER_API_KEY에 인증키를 입력합니다.
이제 생성한 코드가 제대로 동작하는지 테스트하기 위해 MCP Client 코드를 구현하겠습니다.
- MCP Client 코드 구현하기
이번에는 src/client.py 파일을 생성하고 clienMCP Python SDK의 Writing MCP Clients 코드를 이용하여 Cursor AI Agent에게 질문하여 MCP Client 코드를 구현하겠습니다.
@server.py 코드를 참조하여 아래 예시코드 처럼 구현해줘.
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="python", # Executable
args=["example_server.py"], # Optional command line arguments
env=None, # Optional environment variables
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(
read, write
) as session:
# Initialize the connection
await session.initialize()
# List available prompts
prompts = await session.list_prompts()
# Get a prompt
prompt = await session.get_prompt(
"example-prompt", arguments={"arg1": "value"}
)
# List available resources
resources = await session.list_resources()
# List available tools
tools = await session.list_tools()
# Read a resource
content, mime_type = await session.read_resource("file://some/path")
# Call a tool
result = await session.call_tool("tool-name", arguments={"arg1": "value"})
if __name__ == "__main__":
import asyncio
asyncio.run(run())
아래 이미지는 위의 프롬프트를 AI Agent에게 입력하여 받은 응답 화면입니다. Accept All를 클릭하여 Cursor Agent 가 생성한 모든 코드를 적용해 줍니다.
이제 client.py 파일을 분석해 보겠습니다.
- client 세션 초기화
- 프롬프트 목록 가져오기 및 질의하기
- 리소스 목록 가져오기 및 질의하기
- 도구 목록 가져오기
- get_grid_location과 get_forecast 도구 실행해서 결과 가져오기
- MCP Client 테스트하기
테스트하기 전에 아래 코드의 command의 python 경로를 수정해야 합니다.
server_params = StdioServerParameters(
command=".venv/bin/python", # Executable
args=["src/server.py"], # Path to the server script
env=None, # Optional environment variables
)
수정한 후 client.py를 터미널에서 실행합니다.
uv run src/client.py
혹시나 오류가 발생하면 오류 내용을 복사하여 Cursor Agent에게 수정 요청을 합니다.
필요시 Cursor Agent에게 기능별로 코드를 리팩토링 요청해 보세요. 저는 Open API 요청과 응답에 해당하는 코드를 api.py로, http 요청하는 코드를 utils.py로 옮겨 코드를 간결하게 정리하였습니다.
완성된 코드는 https://github.com/jikime/py-mcp-ko-weather에서 확인할 수 있습니다.
'Cook AI' 카테고리의 다른 글
MCP 도구 요청 플로우 (0) | 2025.04.16 |
---|---|
기상청 Open API를 활용한 날씨 MCP 서버를 만들어보자. (3) (1) | 2025.04.16 |
기상청 Open API를 활용한 날씨 MCP 서버를 만들어보자. (1) (0) | 2025.04.16 |
Model Context Protocol (MCP)란 무엇인가? (1) | 2025.04.14 |
LangChain MCP 어댑터를 사용하여 SSE 서버 포트 변경하는 방법 (1) | 2025.04.11 |