LLM 엔지니어링10장 · MCP 와 Prompt·Context Engineering5 / 22← 이전목차다음 →MetaContents

10장. MCP 와 Prompt·Context Engineering

MCP 서버와 클라이언트의 대화

전화를 걸면 먼저 "여보세요, 누구시죠?"로 서로를 확인하고, "무엇을 도와드릴까요?"를 들은 뒤 용건을 말합니다. MCP 클라이언트와 서버도 인사(initialize), 할 수 있는 일 묻기(tools/list), 일 시키기(tools/call)의 순서로 대화합니다.

연결과 인사, 도구 목록 받기, 도구 부르기, 결과 받기의 네 걸음 흐름도

1번 클라이언트가 서버 프로그램을 띄우고 initialize 로 서로의 판과 능력을 확인합니다. 2번 tools/list 로 도구 이름, 설명, 인자 스키마를 받습니다. 3번 tools/call 로 도구를 이름과 인자로 부릅니다. 4번 결과(글 묶음, 오류 여부)를 받습니다. 여기서 "여보세요"가 initialize, 용건이 tools/call 입니다.

메시지의 꼴: JSON-RPC

메서드하는 일돌려받는 것
initialize판과 능력을 맞춘다서버의 이름, 판, 지원하는 기능
tools/list도구 목록을 받는다도구마다 이름, 설명, 입력 스키마
tools/call도구를 부른다결과 내용(content), 오류인지(isError)
resources/read리소스를 읽는다자료의 글
Python
import json

# 클라이언트가 서버에 보내는 tools/call 요청의 꼴(JSON-RPC 2.0)
request = {"jsonrpc": "2.0", "id": 3, "method": "tools/call",
           "params": {"name": "get_stock", "arguments": {"code": "P-101"}}}
print(json.dumps(request, ensure_ascii=False))

{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {...}} 한 줄이 나옵니다. id 는 요청과 응답을 짝짓는 번호입니다. 파이썬 mcp 패키지의 ClientSession 이 이 메시지를 대신 만들고 읽어 주므로, 우리는 session.call_tool("get_stock", {...}) 만 부릅니다.

주고받는 통로

통로생김새쓰는 곳
stdio클라이언트가 서버를 하위 프로그램으로 띄우고 표준 입출력으로 대화내 PC 안의 서버. 이 장의 실습
HTTP(Streamable HTTP)서버가 웹 주소에서 기다리고 클라이언트가 접속여러 사람이 함께 쓰는 원격 서버(13장)

코드에 나오는 함수

코드쉬운 뜻
"jsonrpc": "2.0"이 메시지가 JSON-RPC 2.0 판의 약속을 따른다는 표시다
"id": 3요청 번호다. 서버는 같은 번호를 붙여 답한다
"method": "tools/call"서버에게 시킬 일의 이름이다. 여기서는 "도구 부르기"
"params": {"name": …, "arguments": …}일에 필요한 값이다. 부를 도구의 이름과 그 도구에 넘길 인자
json.dumps(request, …)dump string(글로 쏟아 내기)의 줄임으로 본다. 파이썬 사전을 JSON 글 한 줄로 바꾼다
ensure_ascii=False한글을 \uXXXX 꼴로 바꾸지 말고 그대로 적으라는 옵션이다. ASCII(American Standard Code for Information Interchange)는 영어 글자 중심의 기본 문자표다

이 코드가 뜻하는 것

카페의 주문 번호표로 읽어 봅니다. 손님은 "아메리카노, 샷 추가"를 주문하고 번호표 3번을 받습니다. 음료가 나오면 직원이 "3번 손님"을 부릅니다. 손님이 여럿이어도 번호로 자기 음료를 찾습니다. 여기서 번호표가 id, 메뉴 이름이 method 와 name, "샷 추가" 같은 옵션이 arguments 입니다.

줄하는 일쉽게 말하면
request = {...}요청 하나를 사전으로 짠다주문서를 쓴다
"id": 3요청에 번호를 붙인다번호표 3번
"params": {"name": "get_stock", "arguments": {"code": "P-101"}}부를 도구와 인자를 적는다"재고 찾기, 품목은 P-101"
json.dumps(..., ensure_ascii=False)사전을 글 한 줄로 바꾼다주문서를 주방에 넘기는 꼴로 옮겨 적기

결과는 사전과 생김새가 거의 같은 JSON 글 한 줄입니다. 파이썬 사전은 프로그램 안에서만 쓰이고, 다른 프로그램(서버)에 보낼 때는 이렇게 글로 바꿔야 합니다.

작게 줄여서 눈으로 보기

응답이 보낸 순서와 다르게 와도 id 로 짝을 찾는 모습을 봅니다. 두 응답은 설명을 위해 지어낸 것입니다.

Python
import json

# 보낸 요청 두 개. id 로 구분한다
sent = {7: "tools/list", 8: "tools/call"}
# 서버가 돌려준 응답. 순서가 바뀌어 와도 id 로 짝을 찾는다
replies = ['{"jsonrpc": "2.0", "id": 8, "result": {"isError": false}}',
           '{"jsonrpc": "2.0", "id": 7, "result": {"tools": []}}']
for line in replies:
    msg = json.loads(line)
    print(msg["id"], "번 응답 →", sent[msg["id"]], "의 답:", msg["result"])
출력
8 번 응답 → tools/call 의 답: {'isError': False}
7 번 응답 → tools/list 의 답: {'tools': []}
결과읽는 법
8 번 응답 → tools/call먼저 온 응답은 나중에 보낸 8번 요청의 답이었다. 번호로 짝을 찾았다
7 번 응답 → tools/list7번 요청(도구 목록)의 답은 뒤에 왔다
{'isError': False}JSON 의 false 가 파이썬의 False 로 읽혔다

json.loads 는 load string(글에서 읽어 오기)의 줄임으로 보며, json.dumps 의 반대로 JSON 글을 파이썬 사전으로 바꿉니다. 실제로는 ClientSession 이 이 짝 맞추기를 대신해 줍니다.

주의할 점

  • stdio 서버는 표준 출력이 대화 통로라서, 서버 코드에서 print() 로 아무 글이나 찍으면 메시지가 깨집니다. 기록은 표준 오류나 파일로 남깁니다.
  • 교안을 만든 PC 의 mcp 2.3.0 에서는 도구 함수가 예외를 내면 클라이언트에 "Error executing tool …"만 가고 예외의 내용은 가지 않았습니다. 모델에게 알려야 할 오류는 예외 대신 {"오류": "…"} 같은 결과로 돌려줍니다.
← 이전 절10장 · MCP 의 구조다음 절 →10장 · MCP 를 쓸 때의 보안