MCP와 LangGraph 에이전트
실습 개요
이번 실습은 MCP (Model Context Protocol) 기반의 도구 서버들과 AI 에이전트를 포함한 Python 프로젝트 실습입니다. VS Code에서 GitHub Copilot의 에이전트 모드와 연동하여, 외부 도구(예: 계산기, 날씨 정보)를 AI가 활용할 수 있도록 구성합니다. VS Code, Miniconda, Python, GitHub Copilot 환경은 AI 모델이 플러그인처럼 동작하는 외부 툴을 사용해 더욱 풍부한 기능을 수행할 수 있게 해줍니다.
폴더 구조 설명
프로젝트의 기본 폴더 (mcp-dev/) 아래에는 다음과 같은 주요 디렉토리와 파일들이 있습니다:
agents/react_agent_demo.py– LangGraph를 활용한 ReAct 에이전트 예제 코드입니다. 이 에이전트는 LLM(Large Language Model)의 ReAct(Reasoning and Acting) 패턴을 구현하여, 질문에 답하기 위해 필요한 경우 외부 도구를 사용합니다. 예를 들어 수학 계산이나 날씨 정보를 얻을 때, 아래의 MCP 서버들을 호출하도록 설계되어 있습니다.servers/math_server.py– 수학 도구 MCP 서버로, 안전하게 산술 수식을 평가해 결과를 반환하는 역할을 합니다. (예: “3*(5+2) - 10/2” 같은 표현식을 계산)servers/weather_server.py– 날씨 정보 MCP 서버로, OpenWeatherMap API를 사용하여 현재 날씨나 예보를 가져오는 역할을 합니다..env– 환경 변수 설정 파일입니다. OpenAI API 키, OpenWeatherMap API 키 등의 민감한 정보를 저장합니다. (예: OPENAI_API_KEY, OPENWEATHER_API_KEY 등) VS Code나 코드에서 이 파일을 로드하여 키 값을 사용합니다..vscode/mcp.json– VS Code에서 MCP 서버들을 인식하고 연결하기 위한 설정 파일입니다. 이 JSON 파일에는 프로젝트에서 사용하는 MCP 서버들의 종류와 실행 방법이 명시되어 있어, VS Code의 MCP 통합이 해당 서버들을 자동으로 관리할 수 있도록 도와줍니다 (MCP 연결 설정).
위 구조를 통해, 에이전트 코드는 필요한 도구(계산기나 날씨)를 MCP 프로토콜로 호출하고 결과를 받아 사용할 수 있습니다. 다음으로 각 구성 요소의 내용과 역할을 자세히 살펴보겠습니다.
Python 개발 환경 설정 (Miniconda)
프로젝트는 Miniconda로 관리되는 Python 가상환경에서 개발 및 실행됩니다. Miniconda를 사용하면 프로젝트마다 격리된 패키지 환경을 만들 수 있어 충돌 없이 실험하기에 좋습니다.
가상환경 생성 및 활성화: 먼저 Miniconda를 통해 Python 3 환경을 생성합니다. 예를 들면 터미널에서 conda create -n mcp-env python=3.12 명령으로 새로운 환경을 만들고, conda activate mcp-env로 활성화합니다.
필요 패키지 설치: 가상환경 활성화 후, 필요한 라이브러리를 설치합니다. 이 프로젝트의 주요 의존성은 fastmcp, httpx, python-dotenv, lang 등이 있습니다. 예시:
conda install langgraph langchain-openai langchain-mcp-adapters fastmcp python-dotenv httpx
| 패키지 | 용도 |
|---|---|
| langgraph | ReAct 패턴 그래프를 구성하고 실행하는 핵심 라이브러리 |
| langchain-openai | OpenAI GPT 모델을 LangChain/LangGraph에서 사용하기 위한 모듈 |
| langchain-mcp-adapters | MCP 서버의 Tools를 LangChain/LangGraph 에이전트에서 사용하기 위한 어댑터 |
| fastmcp | MCP 서버 구현 및 구동하기 위한 모듈 |
| python-dotenv | .env 파일에서 OPENAI_API_KEY 등 환경변수 로드 |
| httpx | (weather MCP 서버의 경우) 비동기 HTTP 요청용 |
VS Code 환경 설정: VS Code에서 방금 만든
mcp-env가상환경의 Python 인터프리터를 선택합니다. 또한.env파일을 VS Code가 자동으로 읽도록 설정되어 있으면 (예: Python 확장의 환경 변수 설정), 실행 시 환경변수가 적용됩니다.GitHub Copilot 확장: VS Code에 GitHub Copilot이 설치되어 있다면, 이 프로젝트에서 에이전트 모드에 사용됩니다. Copilot 에이전트 모드는 VS Code의 채팅 인터페이스를 통해 AI가 코드를 이해하고 MCP 서버를 호출하는 등 지원해주는 기능입니다. (이 기능을 활용하려면 Copilot이 MCP 통합을 지원하고, 본 프로젝트의 MCP 서버들이 설정되어 있어야 합니다.)
GitHub Copilot을 통한 개발 보조
Copilot의 에이전트 모드를 사용하면, AI가 현재 코드베이스와 연결된 MCP 툴들을 이해하고 개발 흐름을 도와줄 수 있습니다. 예컨대, “서울의 날씨를 알려줘”라고 Copilot Chat에 입력하면, Copilot이 weather MCP 서버를 호출해 실제 날씨 정보를 가져오는 식입니다. 이러한 에이전트 기능은 .vscode/mcp.json 설정을 통해 가능해집니다 (아래 MCP 설정 부분 참고). 개발자는 Copilot에게 자연어로 명령을 내리고, Copilot은 필요한 MCP 툴을 알아서 사용하여 결과를 제공합니다.
Math 서버 (servers/math_server.py)
이 파일은 간단한 수학 계산기 MCP 서버를 구현한 코드입니다. 주요 내용은 입력으로 받은 수식(Expression)을 파싱하고 안전하게 평가한 뒤 결과를 반환하는 것입니다.
- 현재 실행 중인 스크립트가 어느 위치에 있더라도 프로젝트 루트에 있는 .env 파일을 찾아, 거기에 정의된 환경 변수를 무조건 덮어써서 (override=True) os.environ[“변수명”] 으로 코드 어디에서든 접근할 수 있게 만듭니다.
from pathlib import Path from dotenv import load_dotenv PROJECT_ROOT = Path(__file__).resolve().parents[1] ENV_PATH = PROJECT_ROOT / ".env" load_dotenv(dotenv_path=ENV_PATH, override=True) FastMCP("math")로 MCP 서버 인스턴스를 생성합니다."math"라는 이름은 이 MCP 툴의 식별자이며, 나중에 VS Code나 에이전트에서 이 이름으로 서버를 찾게 됩니다.from fastmcp import FastMCP mcp = FastMCP("math")OPS딕셔너리는 허용된 연산자를 AST 노드 타입과 Python 연산 함수로 매핑한 것입니다. 예를 들어ast.Add는operator.add(덧셈),ast.Sub는operator.sub(뺄셈) 등으로 연결되어 있습니다. 이렇게 허용 목록에 있는 연산만 사용할 수 있게 제한함으로써,eval을 남용했을 때 발생할 수 있는 보안 문제를 방지합니다.import ast, operator as op OPS = { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.FloorDiv: op.floordiv, ast.Mod: op.mod, ast.Pow: op.pow, ast.USub: op.neg, ast.UAdd: op.pos, ast.BitXor: op.xor }_eval_ast(node)함수: 파이썬 AST(Abstract Syntax Tree)의 노드를 재귀적으로 평가합니다.- 숫자 노드 (
ast.Num또는ast.Constant타입)이면 숫자 값을 그대로 반환합니다. - 이항 연산(
ast.BinOp) 노드이면, 왼쪽과 오른쪽 피연산자를 재귀 호출로 계산하고, 연산자 노드(node.op)의 타입에 따라OPS에서 해당 연산 함수를 가져와 적용합니다. 예를 들어3*(5+2)라면 BinOp 노드로서 좌측은3, 우측은(5+2)의 결과7을 얻고, 연산자는Mult이므로 곱셈을 수행합니다. - 단항 연산(
ast.UnaryOp) 노드이면, 피연산자를 계산한 뒤,+,-같은 단항 연산을 적용합니다. - 이 외에 지원하지 않는 노드 타입이 오면 예외를 발생시켜 “허용되지 않은 표현식“이라고 에러를 냅니다. 이 함수 덕분에,
import나 함수 호출 같은 파이썬 코드 실행은 전혀 허용되지 않고 오직 사칙연산, 거듭제곱(**), 나머지(%), 정수 나눗셈(//) 등의 안전한 계산만 가능하게 됩니다.def _eval_ast(node): if isinstance(node, ast.Num): # py<=3.7 return node.n if isinstance(node, ast.Constant): # py>=3.8 if isinstance(node.value, (int, float)): return node.value raise ValueError("숫자만 허용됩니다.") if isinstance(node, ast.BinOp): left = _eval_ast(node.left) right = _eval_ast(node.right) fn = OPS.get(type(node.op)) if not fn: raise ValueError(f"허용되지 않은 연산자: {type(node.op).__name__}") return fn(left, right) if isinstance(node, ast.UnaryOp): operand = _eval_ast(node.operand) fn = OPS.get(type(node.op)) if not fn: raise ValueError(f"허용되지 않은 단항 연산자: {type(node.op).__name__}") return fn(operand) raise ValueError(f"허용되지 않은 표현식: {type(node).__name__}")
- 숫자 노드 (
@mcp.tool데코레이터:FastMCP라이브러리의 기능으로, 아래에 정의된 함수를 MCP 프로토콜로 외부에 노출하는 역할을 합니다. 즉eval(expression: str) -> dict함수가 MCP 툴로 등록되어, 외부에서"eval"이라는 툴을 호출하면 이 함수를 실행하게 됩니다.eval(expression: str) -> dict함수: 실제로 외부 호출이 들어올 때 실행되는 함수입니다. 전달받은 문자열 수식을 파싱하여 AST를 만들고 (ast.parse사용), 그 AST의 루트 노드(tree.body)를_eval_ast함수를 통해 계산합니다.- 계산이 성공하면
{"value": 계산결과}형태의 딕셔너리를 반환하고, - 중간에 잘못된 표현이나 예외가 발생하면
{"error": 에러메시지}형태로 반환합니다.
@mcp.tool def eval(expression: str) -> dict: """ 안전한 수식 평가(사칙연산/거듭제곱/나머지/정수나눗셈). 예) "3*(5+2) - 10/2" """ try: tree = ast.parse(expression, mode="eval") value = _eval_ast(tree.body) return {"value": value} except Exception as e: return {"error": str(e)}- 계산이 성공하면
if __name__ == "__main__": mcp.run(): 이 부분은 스크립트를 직접 실행했을 때 MCP 서버를 기동하는 코드입니다.mcp.run()을 호출하면 기본 설정(STDIO 모드)으로 MCP 서버가 실행됩니다. STDIO 모드란 서버가 터미널 표준 입출력을 통해 VS Code와 통신하는 방식입니다. 즉, VS Code가 이 프로세스를 시작하고 표준입출력으로 명령/응답을 주고받는 구조입니다. Math 서버의 경우 로컬에서 가볍게 계산을 처리하므로 STDIO 방식으로 충분히 처리 가능하고, VS Code MCP 설정 파일에서 이 서버를"stdio"타입으로 등록하게 됩니다.if __name__ == "__main__": mcp.run()
요약: Math MCP 서버는 사칙연산 계산기 역할을 합니다. 제한된 파이썬 AST 해석을 통해 문자열 수식을 안전하게 계산하며, VS Code Copilot이나 에이전트가 수학 문제를 해결해야 할 때 이 툴을 호출할 수 있습니다.
Weather 서버 (servers/weather_server.py)
이 파일은 날씨 정보 제공 MCP 서버입니다. OpenWeatherMap의 API를 호출하여 현재 날씨와 예보 정보를 반환하는 도구들을 정의하고 있습니다. Weather MCP 서버는 HTTP 프로토콜을 사용하여 VS Code 또는 에이전트와 통신합니다. 주요 내용을 살펴보겠습니다:
- .env 파일의 환경변수 정보를 로딩합니다.
from pathlib import Path from dotenv import load_dotenv PROJECT_ROOT = Path(__file__).resolve().parents[1] ENV_PATH = PROJECT_ROOT / ".env" load_dotenv(dotenv_path=ENV_PATH, override=True) FastMCP("weather")로 MCP 서버 인스턴스를 생성합니다. 이름은"weather"로, 이 서버의 툴들은weather.네임스페이스를 갖게 됩니다.from fastmcp import FastMCP mcp = FastMCP("weather")- 환경변수 설정: 코드 상단에서 .env 파일을 로드하고 (
load_dotenv), 함수_require_key()를 통해 OpenWeatherMap API 키(OPENWEATHER_API_KEY)가 설정되어 있는지 확인합니다. 만약 키가 없으면 에러를 발생시켜서 API 호출이 진행되지 않도록 합니다. 따라서 이 서버를 실행하기 전에.env에 유효한 API 키를 반드시 넣어두어야 합니다.import os def _require_key() -> str: key = os.getenv("OPENWEATHER_API_KEY") if not key: raise RuntimeError("환경변수 OPENWEATHER_API_KEY가 설정되어 있지 않습니다.") return key - HTTP 요청 함수:
async def _get_json(url, params)는 내부적으로httpx라이브러리를 사용하여 비동기로 HTTP GET 요청을 보내고 JSON 응답을 받아옵니다. OpenWeatherMap API는 네트워크 지연이 있을 수 있으므로httpx.AsyncClient로 비동기 호출을 하여 효율적으로 처리합니다. (타임아웃은 10초로 설정)import httpx async def _get_json(url: str, params: Dict[str, Any]) -> Dict[str, Any]: timeout = httpx.Timeout(10.0) async with httpx.AsyncClient(timeout=timeout) as client: r = await client.get(url, params=params) r.raise_for_status() return r.json() - 시간대에 따른 ISO 8601 형식 문자열 반환: UNIX 타임스탬프(
unix_ts)에 주어진 초 단위 시차(offset_seconds)를 적용해 해당 시간대의ISO 8601형식 문자열로 변환합니다.from datetime import datetime, timezone, timedelta def _iso_from_unix_with_offset(unix_ts: int, offset_seconds: int) -> str: tz = timezone(timedelta(seconds=offset_seconds)) return datetime.fromtimestamp(unix_ts, tz).isoformat() 도구 1)
weather.current(...): 현재 날씨 정보를 가져오는 MCP 툴 함수입니다.- 매개변수:
city(도시명, 필수),country(국가 코드, 선택),units(단위계, 기본"metric"섭씨),lang(언어, 기본"kr"한국어). 도시와 국가 코드를 조합해 쿼리를 만들고, OpenWeatherMap의 Current Weather API 엔드포인트 (/data/2.5/weather)를 호출합니다. - OpenWeatherMap에서 응답받은 JSON 데이터에서 주요 값들을 추출합니다: 도시 이름, 국가코드, 위경도 좌표, 기온(
temp), 체감기온(feels_like), 습도, 기압, 바람 속도/방향 등의 날씨 상세 정보와 날씨 설명(description), 아이콘 코드 등을 꺼냅니다. - API가 반환한 시간값(
dt)와 타임존 오프셋을 이용해 현지 기준 시간(time_local)을 ISO 형식으로 변환해 주고 있습니다. ```python from typing import Optional, Dict, Any
@mcp.tool async def current( city: str, country: Optional[str] = None, units: str = “metric”, lang: str = “kr” ) -> Dict[str, Any]: “”” OpenWeatherMap ‘Current Weather’ 호출. city=”Seoul”, country=”KR” 형태 권장(국가코드 생략 가능). “”” key = _require_key() q = f”{city},{country}” if country else city params = {“q”: q, “appid”: key, “units”: units, “lang”: lang} url = “https://api.openweathermap.org/data/2.5/weather”
try: data = await _get_json(url, params) except httpx.HTTPStatusError as e: return {"error": f"HTTP {e.response.status_code}: {e.response.text}"} except Exception as e: return {"error": str(e)} weather = (data.get("weather") or [{}])[0] main = data.get("main", {}) wind = data.get("wind", {}) sys = data.get("sys", {}) coord = data.get("coord", {}) tz_offset = data.get("timezone", 0) dt_unix = data.get("dt") iso_time = _iso_from_unix_with_offset(dt_unix, tz_offset) if dt_unix else None return { "city": data.get("name"), "country": sys.get("country"), "coord": {"lat": coord.get("lat"), "lon": coord.get("lon")}, "temperature": main.get("temp"), "feels_like": main.get("feels_like"), "humidity": main.get("humidity"), "pressure": main.get("pressure"), "wind_speed": wind.get("speed"), # metric: m/s, imperial: mph "wind_deg": wind.get("deg"), "weather": weather.get("description"), "icon": weather.get("icon"), "time_local": iso_time, "units": units, "source": "openweathermap", } ``` - 마지막으로 이러한 정보들을 딕셔너리로 정리하여 반환합니다. - 예시 출력: ```json { "city": "Seoul", "country": "KR", "coord": {"lat": 37.57, "lon": 126.98}, "temperature": 28.5, "feels_like": 28.0, "humidity": 62, "pressure": 1013, "wind_speed": 1.5, "wind_deg": 350, "weather": "맑음", // 한국어로 날씨 설명 (lang="kr"인 경우) "icon": "01n", "time_local": "2025-07-12T09:09:23+09:00", "units": "metric", "source": "openweathermap" } ``` 만약 도시 이름을 잘못 입력했거나 API 응답에 오류가 있으면, ```{"error": "HTTP 404: ..."}```와 같이 에러 메시지를 반환합니다.- 매개변수:
도구 2)
weather.forecast(...): 며칠치의 날씨 예보를 가져오는 MCP 툴 함수입니다.- 매개변수:
city,country(현재와 동일),days(예보 일수, 기본 3일),units,lang. - OpenWeatherMap의 5일/3시간 예보 API (
/data/2.5/forecast)를 호출합니다. 이 API는 최대 5일치, 3시간 간격의 예보 데이터를 제공합니다. 코드에서는 days 값이 1보다 작으면 1로, 5보다 크면 5로 자동 교정하여 요청합니다. - 받아온 예보 리스트(
list)를 날짜별로 그룹화합니다. API 응답에는 예보 시간이 UNIX 타임스탬프로 나오는데, 이를 도시의 시간대에 맞춰 변환하고 날짜(YYYY-MM-DD)별로 묶습니다. - 각 날짜 그룹에 대해 다음을 계산합니다:
- 평균 기온 (
temp_avg): 그 날 모든 예측의 기온 값들의 평균. - 최저 기온 (
temp_min): 그 날 예보 중 가장 낮은 기온. - 최고 기온 (
temp_max): 그 날 예보 중 가장 높은 기온. - 대표 날씨 (
weather): 그 날 예보들 중 가장 빈도 높게 나타난 날씨 상태를 선택 (예: 하루 중 대부분이 “비”였다면 “비”로 표시).
- 평균 기온 (
- 이렇게 요약된 하루치 정보를
summaries리스트에 추가합니다. 예를 들어, 3일 예보라면days: [ {date: "2025-07-12", temp_avg:..., temp_min:..., temp_max:..., weather:"흐림"}, {date: "2025-07-13", ...}, {date: "2025-07-14", ...} ]형태로 반환될 것입니다. - 결과 딕셔너리는 도시명, 국가코드, 좌표와 함께 이러한
days리스트를 포함합니다. ```python from typing import List from collections import defaultdict, Counter
@mcp.tool async def forecast( city: str, country: Optional[str] = None, days: int = 3, units: str = “metric”, lang: str = “kr” ) -> Dict[str, Any]: “”” OpenWeatherMap ‘5 day / 3 hour’ 예보를 일자별 요약으로 반환. - 각 날짜별 평균/최저/최고 기온과 대표 날씨(최빈값) 제공 “”” key = _require_key() days = 1 if days < 1 else 5 if days > 5 else days
q = f"{city},{country}" if country else city params = {"q": q, "appid": key, "units": units, "lang": lang} url = "https://api.openweathermap.org/data/2.5/forecast" try: data = await _get_json(url, params) except httpx.HTTPStatusError as e: return {"error": f"HTTP {e.response.status_code}: {e.response.text}"} except Exception as e: return {"error": str(e)} lst: List[Dict[str, Any]] = data.get("list", []) city_info = data.get("city", {}) tz_offset = city_info.get("timezone", 0) name = city_info.get("name") or city country_code = city_info.get("country") coord = city_info.get("coord", {}) by_date: Dict[str, List[Dict[str, Any]]] = defaultdict(list) for item in lst: dt_unix = item.get("dt") if dt_unix is None: continue iso = _iso_from_unix_with_offset(dt_unix, tz_offset) local_date = iso[:10] by_date[local_date].append(item) summaries = [] for d in sorted(by_date.keys())[:days]: items = by_date[d] temps = [it.get("main", {}).get("temp") for it in items if it.get("main")] temp_min = min([it.get("main", {}).get("temp_min") for it in items if it.get("main")], default=None) temp_max = max([it.get("main", {}).get("temp_max") for it in items if it.get("main")], default=None) descs = [ (it.get("weather") or [{}])[0].get("description") for it in items ] cnt = Counter([x for x in descs if x]) desc = cnt.most_common(1)[0][0] if cnt else None summaries.append({ "date": d, "temp_avg": (sum(t for t in temps if t is not None) / len(temps)) if temps else None, "temp_min": temp_min, "temp_max": temp_max, "weather": desc, }) return { "city": name, "country": country_code, "coord": {"lat": coord.get("lat"), "lon": coord.get("lon")}, "units": units, "days": summaries, "source": "openweathermap", } ```- 매개변수:
if __name__ == "__main__": mcp.run(..., transport="http", host="127.0.0.1", port=8000, path="/mcp"): Weather 서버는 HTTP 방식으로 동작하도록 설정되어 있습니다.transport="http"와port=8000설정에 의해, 로컬호스트 8000번 포트에서 HTTP 서버로 실행됩니다. 경로는 /mcp로 지정되어, http://127.0.0.1:8000/mcp가 이 MCP 서버의 엔드포인트가 됩니다. VS Code에서는 이 서버와 HTTP 스트림으로 통신하게 됩니다.if __name__ == "__main__": mcp.run(transport="http", host="127.0.0.1", port=8000, path="/mcp")
요약: Weather MCP 서버는 실시간 날씨 정보 제공자 역할을 합니다. OpenWeatherMap API를 통해 외부 데이터를 가져오며, 현재 날씨와 며칠 간의 예보를 간단히 질의할 수 있도록 도구 함수를 노출합니다. VS Code나 AI 에이전트는 이 서버를 통해 최신 날씨 정보를 얻어와 답변에 활용할 수 있습니다.
VS Code MCP 설정 (.vscode/mcp.json)
.vscode/mcp.json 파일은 VS Code에서 MCP 서버들을 관리하기 위한 설정 파일입니다. 이 JSON 설정을 통해 VS Code는 워크스페이스에 어떤 MCP 서버들이 있고 어떻게 연결할지 알 수 있습니다. 우리 프로젝트의 mcp.json은 다음과 같은 정보를 담고 있습니다:
{
"servers": {
"math": {
"type": "stdio",
"command": "${env:USERPROFILE}/miniconda3/envs/mcp_dev/python.exe",
"args": ["${workspaceFolder}/servers/math_server.py"],
"envFile": "${workspaceFolder}/.env"
},
"weather": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp"
}
}
}
math서버 설정:type: "stdio"로 지정되어 있으며, VS Code가 이 MCP 서버를 실행할 때python servers/math_server.py명령을 사용하도록 설정합니다.envFile옵션으로.env경로를 지정하여, 실행 시 환경변수 (특히 OPENWEATHER_API_KEY 등)도 로드되도록 합니다. 이 설정을 통해 VS Code는 필요 시 수학 서버를 자동으로 시작하고, 표준 입출력을 통해 명령을 주고받습니다.weather서버 설정:type: "http"로 지정되어 있으며, 이는 VS Code가 HTTP 프로토콜로 이미 실행 중인 서버에 연결함을 의미합니다.url필드에 Weather MCP 서버가 리슨하는 URL (http://127.0.0.1:8000/mcp)을 넣어, VS Code가 해당 HTTP 스트림에 접속하게 합니다. 이 방식은 VS Code가 프로세스를 직접 실행하지 않고, 외부에서 이미 실행 중인 서버에 연결만 수행합니다. (Weather 서버는 앞서 별도 터미널에서 실행해야 함)
mcp.json 활용: VS Code에서 이 파일을 열면, 서버별로 Start, Stop 등의 버튼이 나타나 쉽게 서버를 제어할 수 있습니다. 또한 Copilot Chat 패널이나 명령 팔레트에서 MCP 서버 목록을 보고 연결상태를 확인할 수 있습니다. 이 설정 덕분에 GitHub Copilot의 에이전트는 math와 weather라는 두 가지 툴을 인식하며, 필요에 따라 eval이나 weather.current 같은 함수를 호출할 수 있게 됩니다.
예를 들어, Copilot Chat에 “3(5+2) - 10/2 계산해줘” 라고 물어보면, Copilot 에이전트가 math 서버의 eval 툴을 사용해 계산하고 16.0이라는 결과를 가져와 답변할 것입니다. 또 “서울 내일 날씨 알려줘”* 라고 하면 weather 서버의 forecast 툴을 호출하여 서울의 내일 날씨 정보를 얻은 후 사용자에게 알려줄 수 있습니다. 이 모든 통신이 MCP 표준 형식으로 이루어지며, 개발자는 별도의 REST API 구현 없이 MCP 툴 함수만으로 AI와 도구의 연결을 구성할 수 있습니다.
프로젝트 실행 방법
이제 프로젝트를 실제로 실행하는 방법을 단계별로 정리하겠습니다.
- 환경 변수 설정 (.env): 먼저 프로젝트 루트의
.env파일에 필요한 키값을 설정해야 합니다. 최소한 다음 항목들이 필요합니다:OPENAI_API_KEY=<your_openai_api_key>: OpenAI API 키 (에이전트가 OpenAI의 모델을 사용할 경우 필요).OPENWEATHER_API_KEY=<your_openweather_api_key>: OpenWeatherMap API 키 (Weather MCP 서버용).- 그 밖에 필요한 값이 있다면 추가로 기입합니다. (.env 파일은 실행 시 자동으로 로드되거나, 위의 envFile 설정을 통해 VS Code가 전달합니다.)
의존성 패키지 설치: (앞서 언급한 가상환경 설정이 완료되었다는 가정 하에) 필요한 패키지가 설치되지 않았다면, 앞서 언급한
fastmcp,httpx,python-dotenv등을 설치합니다.- MCP 서버 실행: VS Code에서 터미널을 두 개 열어 각각 다음을 실행합니다.
- Math 서버 실행:
python servers/math_server.py이 명령을 실행하면 math MCP 서버가 시작됩니다. 출력으로 별다른 로그가 표시되지 않을 수 있는데, 백그라운드에서 VS Code 또는 클라이언트의 명령을 기다리는 상태입니다. 제대로 실행되었다면 터미널은 입력 대기 상태로 유지됩니다. - Weather 서버 실행: 별도의 터미널에서
python servers/weather_server.py이 명령을 실행하면 weather MCP 서버가 127.0.0.1:8000 포트에서 시작됩니다. 성공적으로 실행되면 터미널이 종료되지 않고 서버가 계속 구동되며, 로그로 “Running on http://127.0.0.1:8000/mcp” 같은 메시지가 나옵니다 (FastMCP 라이브러리가 이런 정보를 출력함). 이 역시 입력을 받지 않고 백그라운드에서 대기합니다. - VS Code를 통한 실행: 위처럼 수동으로 실행하지 않고, VS Code의 MCP 패널을 이용해 실행할 수도 있습니다. VS Code의 명령 팔레트에서 “MCP: Start Server” 명령을 쓰거나,
.vscode/mcp.json편집 화면에서 서버별 실행 버튼을 눌러math서버를 시작할 수 있습니다.weather서버는 type: “http”로 정의돼 있어 수동으로 먼저 실행한 후 “Connect” 버튼을 눌러야 할 것입니다.
- Math 서버 실행:
연결 확인: VS Code에서 GitHub Copilot이 활성화되어 있고, MCP 서버 설정이 올바르면 Copilot의 MCP 아이콘 또는 패널에 두 서버가 Running 상태로 표시됩니다. 만약 math 서버에 Stopped로 나온다면 해당 항목에서 Start를 눌러보세요. Weather 서버는 Start 대신 Connect로 나타날 수 있습니다.
- Weather 서버의 동작을 간단히 테스트해보고 싶다면, 브라우저나 curl로 API를 호출해 볼 수 있습니다. 예를 들어 다음과 같이 현재 날씨를 질의할 수 있습니다 (윈도우의 경우 Powershell에서 따옴표 이스케이프 주의):
curl "http://127.0.0.1:8000/mcp?tool=weather.current&args={\"city\":\"Seoul\",\"country\":\"KR\",\"lang\":\"kr\"}"응답으로 JSON 데이터가 나타나면 서버가 정상 동작 중인 것입니다. (테스트 후엔 한글 인코딩 문제로 터미널에 깨진 글자가 보일 수 있지만, VS Code 내 통신에는 문제가 없습니다.)
- Weather 서버의 동작을 간단히 테스트해보고 싶다면, 브라우저나 curl로 API를 호출해 볼 수 있습니다. 예를 들어 다음과 같이 현재 날씨를 질의할 수 있습니다 (윈도우의 경우 Powershell에서 따옴표 이스케이프 주의):
에이전트(react_agent_demo.py) 실행: 모든 MCP 서버가 준비되었으면, 이제 에이전트를 실행해볼 차례입니다.
agents/react_agent_demo.py파일을 실행하면 (예:python agents/react_agent_demo.py), 이 스크립트는 OpenAI LLM을 이용해 대화형 에이전트를 구동합니다. 콘솔에서 질문을 입력받아 답을 출력하거나, 미리 정의된 질문에 대해 reasoning 과정을 콘솔에 보여줄 수 있습니다.- 에이전트가 동작하면서 ReAct 패턴에 따라, 먼저 질문을 이해하고, 필요한 경우 “생각(Thought)” 단계에서 tool 사용을 결정합니다. 그 다음 “행동(Action)” 단계에서
math나weatherMCP 툴을 호출해 결과를 얻고, 다시 “Observation”으로 받아온 결과를 해석합니다. 이러한 일련의 과정이 react_agent_demo.py에 구현되어 있습니다. - 예를 들어, react_agent_demo.py를 실행한 후 “오늘 서울 날씨 알려줘. 내일은 비 올까?” 라는 질문을 넣으면, 에이전트는
weather.current("Seoul","KR")툴을 호출하여 현재 날씨를 알아내고, 이어서weather.forecast("Seoul","KR", days=2)를 호출해 오늘과 내일의 예보를 살펴본 뒤, 최종 답변으로 서울의 현재 날씨와 내일 비 예보 유무를 알려줄 것입니다. - 또 다른 예로 “5일 후 뉴욕의 예상 최고 기온은?” 이라는 질문을 하면, 에이전트는
weather.forecast("New York","US", days=5)를 호출하고 그 결과 중 5일째 항목의temp_max를 추출하여 답변할 수 있습니다. 수학 계산이 섞인 질문이라면math.eval도 함께 활용할 수 있습니다.
- 에이전트가 동작하면서 ReAct 패턴에 따라, 먼저 질문을 이해하고, 필요한 경우 “생각(Thought)” 단계에서 tool 사용을 결정합니다. 그 다음 “행동(Action)” 단계에서
- Copilot Chat 활용: VS Code 내에서 굳이 직접 에이전트를 실행하지 않더라도, Copilot Chat 창에 질문을 던져서 MCP 툴을 활용한 답을 얻을 수 있습니다. 예를 들어 에디터에서 Copilot Chat에게 “지금 뉴욕 기온 알려줘”라고 물으면, Copilot이
weatherMCP 서버의current("New York")를 호출하여 얻은 기온을 답변으로 줄 것입니다. 복잡한 수식 계산을 부탁하면mathMCP 서버를 이용해 정확한 결과를 얻을 수도 있습니다. 이렇게 IDE 안에서 AI 비서가 실제 API와 연동되므로, 개발 중에 필요한 정보 조회나 계산을 모델이 직접 수행하게 할 수 있습니다.
마무리: 전체 흐름 요약
정리하면, 이 프로젝트는 VS Code + Python 환경에서 AI 에이전트와 외부 도구(MCP 서버)의 통합 예제입니다. Miniconda로 격리된 Python 환경에서 MCP 서버들을 실행하고, VS Code의 GitHub Copilot 에이전트 모드를 통해 AI가 이러한 서버들을 호출하도록 구성했습니다. Math 서버는 계산기, Weather 서버는 날씨 정보원으로 동작하여, AI가 답변을 생성할 때 필요한 실시간 계산이나 데이터 조회를 도와줍니다.
이러한 구조를 통해 개발자는 LangGraph ReAct 에이전트의 사고 과정을 관찰하고, 필요에 따라 새로운 MCP 툴을 추가함으로써 AI의 능력을 확장할 수 있습니다. 예를 들어 더 복잡한 수학 계산, 데이터베이스 조회, 파일 시스템 접근 등의 MCP 서버를 추가하면, AI가 코딩 도우미를 넘어서 일반적인 작업 도우미로서 훨씬 강력해질 것입니다.
끝으로, GitHub Copilot과 MCP 통합의 힘을 활용하면 AI와 개발 환경이 긴밀히 상호작용할 수 있음을 기억하세요. 이 프로젝트를 실행하고 실험해보면서, AI가 어떻게 툴을 선택하고 사용하는지 그 내부 과정을 학습 자료로 삼을 수 있을 것입니다. 앞으로 질문을 던져보거나 새로운 툴을 만들어보며 MCP 생태계를 확장해 보는 것도 추천합니다.
이상 VSCode, Miniconda, Python, GitHub Copilot 환경에서 MCP 프로젝트의 구조와 실행 방법에 대한 설명입니다. 질문이 있으시면 Copilot에게 바로 물어보거나, 각 구성 요소의 문서를 참조하여 더 깊이 탐구해보시기 바랍니다.