API와 MCP 차이, 날씨 데이터 하나로 직접 확인하기: curl 한 줄에서 AI가 쓰는 도구까지 5단계
이 글과 연결된 글 보기
드래그로 이동 · 휠/두 손가락으로 확대 · 방향키로 글 선택 · 0으로 맞춤. 실선: 본문 링크, 점선: 시리즈·주제의 대표 연결.표시된 글 18편 목록
API는 사람이 정확한 주소와 값을 알고 직접 부르는 창구이고, MCP는 그 창구에 AI가 읽을 수 있는 설명서를 붙여 AI가 스스로 골라 부르게 하는 규격입니다. 이 글에서는 같은 날씨 데이터를 한 번은 API로, 한 번은 MCP 서버로 불러 보면서 그 차이를 직접 확인합니다. 글에 나온 명령과 코드는 모두 2026년 10월 7일에 실제로 실행해 결과까지 확인했습니다.
이 글은 이런 분께 필요합니다
- "API 쓰면 되는데 MCP는 왜 쓰나요?"라는 질문에 아직 자신 있게 답하지 못하는 분
- AI 에이전트를 만들려는데, 이미 쓰던 API를 그대로 부를지 MCP 서버로 감쌀지 고민되는 분
- MCP 서버를 설치만 해봤고, 안에서 무슨 일이 일어나는지 직접 본 적은 없는 분
준비물은 네 가지입니다.
| 준비물 | 확인 방법 |
|---|---|
| Mac 또는 Linux 터미널 | 터미널 앱을 열면 됩니다 |
curl | 대부분 기본으로 들어 있습니다. curl --version으로 확인합니다 |
uv (파이썬 실행 도구) | uv --version이 안 되면 아래 명령으로 설치합니다 |
| Codex CLI (Step 4에서만) | ChatGPT 계정으로 로그인해 씁니다. 설치는 Step 4에서 안내합니다 |
curl -LsSf https://astral.sh/uv/install.sh | sh
uv 설치 명령은 uv 공식 설치 문서에 있는 그대로입니다. 설치 후 터미널을 한 번 닫았다 열어야 uv 명령이 잡힙니다.
이 글에서 쓰는 날씨 데이터는 Open-Meteo의 공개 API입니다. 회원가입도 API 키도 필요 없어서 복사해서 바로 따라 할 수 있습니다.
Step 1. 날씨 API를 curl로 직접 호출합니다
먼저 "API를 쓴다"는 게 정확히 무엇인지 확인합니다. 터미널에 아래 한 줄을 붙여넣습니다. 서울(위도 37.5665, 경도 126.978)의 현재 기온과 풍속을 묻는 요청입니다.
curl "https://api.open-meteo.com/v1/forecast?latitude=37.5665&longitude=126.978¤t=temperature_2m,wind_speed_10m&timezone=Asia%2FSeoul"
이런 JSON이 돌아오면 성공입니다. 숫자는 실행하는 시각에 따라 다릅니다.
{"timezone":"Asia/Seoul", ... ,"current":{"time":"2026-10-07T09:00","interval":900,"temperature_2m":14.7,"wind_speed_10m":1.3}}
여기서 눈여겨볼 점은 모든 걸 내가 정했다는 것입니다.
- 어느 주소(
/v1/forecast)로 보낼지 - 서울의 위도·경도가 몇인지
- 어떤 값(
temperature_2m,wind_speed_10m)을 달라고 할지 - 언제 이 요청을 보낼지
API는 "이 형식으로 요청하면 이 데이터를 준다"는 약속입니다. 그 약속을 읽고, 값을 채우고, 부를 시점을 정하는 일은 전부 사람(또는 사람이 짠 코드)의 몫입니다.
Step 2. 같은 기능을 MCP 서버로 감쌉니다
이제 같은 날씨 API를 AI가 쓸 수 있는 도구(Tool) 로 바꿔 봅니다. 빈 폴더를 하나 만들고 그 안에 weather_server.py 파일을 만들어 아래 코드를 그대로 붙여넣습니다.
mkdir weather-mcp && cd weather-mcp
import json
import urllib.parse
import urllib.request
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("korea-weather")
CITIES = {
"서울": (37.5665, 126.9780),
"부산": (35.1796, 129.0756),
"제주": (33.4996, 126.5312),
}
@mcp.tool()
def get_current_weather(city: str) -> str:
"""도시의 현재 기온(°C)과 풍속(km/h)을 조회합니다. city는 서울, 부산, 제주 중 하나입니다."""
if city not in CITIES:
return f"지원하지 않는 도시입니다: {city}. 서울, 부산, 제주 중 하나를 넣어 주세요."
lat, lon = CITIES[city]
query = urllib.parse.urlencode({
"latitude": lat,
"longitude": lon,
"current": "temperature_2m,wind_speed_10m",
"timezone": "Asia/Seoul",
})
url = f"https://api.open-meteo.com/v1/forecast?{query}"
with urllib.request.urlopen(url, timeout=10) as res:
now = json.load(res)["current"]
return f"{city} {now['time']} 기준 기온 {now['temperature_2m']}°C, 풍속 {now['wind_speed_10m']}km/h"
if __name__ == "__main__":
mcp.run()
코드를 잘 보면 안쪽은 Step 1과 똑같은 API 호출입니다. MCP는 API를 없애거나 대체하지 않습니다. 달라진 건 바깥에 붙은 두 가지입니다.
@mcp.tool(): 이 함수를 AI가 부를 수 있는 도구로 등록합니다.- 함수 바로 아래 큰따옴표 세 개로 쓴 설명 문장: AI가 "이 도구는 언제, 어떤 값을 넣어 쓰는가"를 판단할 때 읽는 설명서가 됩니다.
위도·경도도 사람이 외울 필요가 없어졌습니다. AI는 city에 "부산"만 넣으면 됩니다.
Step 3. AI가 보는 '도구 설명서'를 직접 열어봅니다
MCP 서버는 AI 앱(클라이언트)과 JSON-RPC라는 형식의 메시지를 주고받습니다. 한 줄에 메시지 하나씩, 정해진 모양의 JSON을 보내고 받는 방식입니다. AI 앱이 MCP 서버에 처음 연결하면 하는 일을 우리가 손으로 똑같이 해보겠습니다.
같은 폴더에 ask.jsonl 파일을 만들고 아래 네 줄을 붙여넣습니다.
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"me","version":"1.0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_current_weather","arguments":{"city":"부산"}}}
각 줄의 뜻은 이렇습니다.
| 줄 | 하는 일 |
|---|---|
initialize | "연결할게요"라고 인사하고 서로 지원하는 기능을 맞춥니다 |
notifications/initialized | 준비가 끝났다고 알립니다 |
tools/list | "쓸 수 있는 도구 목록과 설명서를 주세요" |
tools/call | "get_current_weather에 부산을 넣어 실행해 주세요" |
이제 이 메시지를 서버에 흘려 넣습니다.
(cat ask.jsonl; sleep 3) | uv run --with "mcp<2" weather_server.py 2>/dev/null
처음 실행하면 uv가 MCP 파이썬 패키지를 내려받느라 몇 초 걸립니다. 응답 세 줄 중 두 번째 줄이 바로 AI가 보는 도구 설명서입니다. 보기 좋게 줄을 나누면 이렇습니다.
{
"tools": [{
"name": "get_current_weather",
"description": "도시의 현재 기온(°C)과 풍속(km/h)을 조회합니다. city는 서울, 부산, 제주 중 하나입니다.",
"inputSchema": {
"properties": {"city": {"title": "City", "type": "string"}},
"required": ["city"],
"type": "object"
}
}]
}
Step 2에서 쓴 함수 이름과 설명 문장이 그대로 name과 description이 됐고, city: str은 "city라는 글자 값이 반드시 필요하다"는 inputSchema가 됐습니다. 마지막 줄에는 실제 실행 결과가 들어 있습니다.
{"content":[{"type":"text","text":"부산 2026-10-07T09:00 기준 기온 17.5°C, 풍속 6.2km/h"}],"isError":false}
여기까지 오면 차이가 보입니다. Step 1에서는 내가 주소와 위도·경도를 알고 불렀습니다. Step 3에서는 서버가 먼저 "나는 이런 도구가 있고 이런 값이 필요해"라고 스스로 설명합니다. AI 앱은 이 설명서를 읽고, 사용자가 "부산 날씨 어때?"라고 물으면 get_current_weather에 "부산"을 넣어야겠다고 스스로 판단합니다.
Step 4. AI 앱에 연결하고, AI가 도구를 고르는지 확인합니다
이제 이 서버를 실제 AI 앱에 붙입니다. MCP는 공통 규격이라 MCP를 지원하는 앱이면 같은 서버를 그대로 연결할 수 있습니다. 여기서는 ChatGPT 계정으로 쓰는 터미널 앱 Codex CLI로 확인합니다. Codex CLI가 없다면 Codex CLI 공식 페이지의 설치 명령으로 설치하고, codex를 한 번 실행해 ChatGPT 계정으로 로그인합니다.
① 서버를 등록합니다. weather-mcp 폴더 안에서 아래 명령을 실행합니다. /절대/경로/ 부분은 pwd로 확인한 이 폴더의 실제 경로로 바꿉니다.
codex mcp add korea-weather -- uv run --with "mcp<2" /절대/경로/weather-mcp/weather_server.py
Added global MCP server 'korea-weather'.가 나오면 등록된 것입니다. codex mcp list를 실행하면 korea-weather가 enabled로 보입니다.
② 이 서버의 도구는 묻지 않고 쓰도록 허용합니다. Codex는 MCP 도구를 부르기 전에 승인을 받습니다. 날씨 조회는 읽기만 하는 도구라서, 설정 파일 ~/.codex/config.toml을 열어 방금 생긴 [mcp_servers.korea-weather] 칸 맨 아래에 한 줄을 추가합니다.
[mcp_servers.korea-weather]
command = "uv"
args = ["run", "--with", "mcp<2", "/절대/경로/weather-mcp/weather_server.py"]
default_tools_approval_mode = "approve"
default_tools_approval_mode는 Codex MCP 공식 문서에 나오는 설정입니다. 파일을 고치거나 메시지를 보내는 도구에는 이 줄을 넣지 않는 편이 안전합니다.
③ 질문만 던집니다. 도구 이름도, 위도·경도도 말하지 않습니다. 웹 검색은 끄고 실행합니다(이유는 바로 아래에서 설명합니다).
codex exec --skip-git-repo-check -c web_search='"disabled"' "부산이랑 제주 중 지금 어디가 더 따뜻해?"
2026년 10월 7일 오전에 실제로 실행한 결과입니다.
codex
지금 날씨는 실시간성이 커서 바로 확인해볼게요. 부산과 제주 현재 기온을 같은 기준으로 비교하겠습니다.
mcp: korea-weather/get_current_weather started
mcp: korea-weather/get_current_weather (completed)
mcp: korea-weather/get_current_weather started
mcp: korea-weather/get_current_weather (completed)
codex
지금은 **제주가 더 따뜻해요.**
- 부산: **19.4°C**
- 제주: **20.5°C**
get_current_weather를 두 번 불렀습니다. 한 번은 부산, 한 번은 제주를 넣어서입니다. 질문 어디에도 "get_current_weather를 두 번 불러라"라는 말은 없습니다. AI가 Step 3에서 본 설명서 한 줄("city는 서울, 부산, 제주 중 하나입니다")을 읽고, 도구를 몇 번, 어떤 값으로 부를지 스스로 정한 것입니다. Step 1에서 사람이 주소와 위도·경도를 직접 넣던 것과 가장 크게 달라지는 지점이 바로 여기입니다.
AI가 고른다는 건, 내 도구를 안 고를 수도 있다는 뜻입니다. 같은 질문을 웹 검색을 켠 채로 실행했더니, Codex는 이번에는 korea-weather 대신 웹 검색으로 기상청 페이지를 찾아 답했습니다. 쓸 수 있는 도구가 여러 개면 AI는 그중 하나를 고릅니다. 내 도구를 확실히 쓰게 하려면 위처럼 다른 도구를 끄거나, 질문에 "korea-weather 도구로 ~ 알려줘"처럼 도구 이름을 넣으면 됩니다. 도구 이름을 넣은 질문은 웹 검색을 켠 상태에서도 korea-weather를 두 번 불러 같은 답을 냈습니다.
Step 5. 내 상황에 API와 MCP 중 무엇이 맞는지 정합니다
직접 해본 걸 바탕으로 정리하면, 두 방식의 차이는 "누가 언제 부를지 정하는가" 입니다.
| 구분 | API | MCP |
|---|---|---|
| 누가 부르나 | 사람이 짠 코드가 정해진 순서대로 | AI가 대화 내용을 보고 골라서 |
| 무엇을 보고 부르나 | 사람이 읽는 API 문서 | 서버가 직접 내보내는 도구 설명서(tools/list) |
| 주고받는 형식 | REST, GraphQL 등 서비스마다 다름 | JSON-RPC 2.0으로 통일 |
| 연결 방식 | 앱마다 따로 연동 코드 작성 | 서버 하나를 MCP 지원 앱 여러 곳에서 재사용 |
아래 기준으로 고르면 됩니다.
API를 직접 쓰는 게 맞는 경우
- 결제 승인, 회원가입, 매일 정해진 시각의 데이터 수집처럼 언제나 같은 순서로 실행돼야 하는 일
- AI의 판단 없이 서버끼리 빠르게 데이터를 주고받아야 하는 일
MCP로 감싸는 게 맞는 경우
- AI가 대화 중에 필요할 때 알아서 꺼내 쓰게 하고 싶은 사내 데이터나 도구
- 같은 도구를 여러 AI 앱에서 코드 수정 없이 쓰고 싶을 때. AI 앱이 3개, 연결할 서비스가 4개라면 따로 연동하면 3×4=12번 만들어야 하지만, 서비스마다 MCP 서버를 하나씩 만들면 4개로 끝납니다
- AI에게 전체 권한을 주기 싫을 때. Step 2의 서버는 서울·부산·제주 날씨 조회 하나만 열어 둡니다. 이렇게 AI가 할 수 있는 일을 서버 코드에서 좁힐 수 있습니다
정리하면 "API냐 MCP냐"가 아니라 "MCP 안에서 API를 부른다" 가 정답에 가깝습니다. 이미 쓰고 있는 API가 있다면 버릴 필요 없이, Step 2처럼 설명서를 붙여 감싸기만 하면 AI가 쓰는 도구가 됩니다.
오류가 나면 여기부터 확인하세요
| 증상·메시지 | 원인 | 해결 |
|---|---|---|
command not found: uv | uv가 설치되지 않았거나 터미널이 설치 전 상태 | 준비물의 설치 명령을 실행하고 터미널을 새로 엽니다 |
No module named 'mcp.server.fastmcp'. This is mcp 2.x ... | MCP 파이썬 SDK 2.x가 설치됨. 2.x에서는 FastMCP가 MCPServer로 이름이 바뀌었습니다 | 이 글처럼 --with "mcp<2"로 1.x를 씁니다. 2.x로 옮기려면 공식 마이그레이션 가이드를 따릅니다 |
| Step 3에서 응답이 두 줄만 나오고 날씨 결과가 없음 | 날씨를 받아오기 전에 입력이 끝나 서버가 종료됨 | 명령의 sleep 3을 빼지 않았는지 확인하고, 인터넷이 느리면 sleep 5로 늘립니다 |
지원하지 않는 도시입니다 | CITIES에 없는 도시 이름을 넣음 | CITIES에 "대구": (35.8714, 128.6014)처럼 위도·경도를 추가합니다 |
MCP tool call requires approval, but approval policy is never | codex exec는 실행 중에 승인을 물을 수 없는데, 도구 승인 설정이 없음 | Step 4 ②처럼 default_tools_approval_mode = "approve" 줄을 넣거나, codex를 대화형으로 실행합니다 |
답은 나오는데 mcp: korea-weather/... 줄이 없음 | AI가 내 도구 대신 웹 검색 같은 다른 도구를 고름 | -c web_search='"disabled"'로 웹 검색을 끄거나, 질문에 "korea-weather 도구로"를 넣습니다 |
정리
curl로 API 직접 호출 → 같은 호출을 파이썬 파일 하나로 MCP 도구로 감싸기 → tools/list로 AI가 보는 설명서 확인 → AI 앱에 연결 → 내 상황에 맞는 방식 고르기, 이 다섯 단계면 API와 MCP의 차이를 말로 외우지 않고 직접 확인할 수 있습니다. 다음에는 Open-Meteo 대신 평소 쓰던 공공데이터 API 하나를 골라 Step 2의 함수 안쪽만 바꿔 보세요. 설명 문장을 어떻게 쓰느냐에 따라 AI가 도구를 얼마나 잘 골라 쓰는지도 직접 비교해볼 수 있습니다.
참고 자료
- Model Context Protocol 공식 문서: MCP 구조와 규격
- Anthropic 공식 소개 영상: Introducing the Model Context Protocol
- Open-Meteo: 이 글에서 쓴 무료 날씨 API
- MCP 파이썬 SDK 2.x 마이그레이션 가이드
