Skip to main content
Summary

이 장에서 배울 것

앞 장에서는 LLM이 외부 함수를 호출하는 방식, 즉 function calling을 배웠다. function calling은 "이 함수는 이런 이름을 갖고, 이런 입력을 받으며, 이런 결과를 돌려준다"는 계약이다. 작은 서비스에서는 이 정도로 충분하다. 날씨 조회 함수 하나, 주문 상태 조회 함수 하나, 사내 FAQ 검색 함수 하나를 붙이는 정도라면 모델 요청 안에 함수 정의를 넣고 결과를 받아 처리하면 된다.

하지만 에이전트가 다루는 도구가 늘어나면 문제가 달라진다. 파일 시스템, 문서 저장소, 데이터베이스, GitHub, Slack, 사내 승인 API, CRM, 결제 시스템이 모두 연결되기 시작한다. 이때마다 각 도구를 모델별 function calling 형식에 맞춰 새로 감싸면 유지보수가 어려워진다.

이 장에서는 MCP, 즉 Model Context Protocol을 배운다. MCP는 에이전트가 외부 도구와 컨텍스트를 표준 방식으로 발견하고 호출하게 해주는 프로토콜이다. 쉽게 말해, 에이전트와 외부 세계 사이에 놓는 공통 연결 규칙이다.

이 장을 마치면 다음을 설명할 수 있어야 한다.

  • MCP가 왜 등장했는지 설명한다.

  • MCP와 function calling, 플러그인, 커스텀 API 래퍼의 차이를 구분한다.

  • MCP server, client, tool, resource, prompt의 역할을 이해한다.

  • 파일, 문서 저장소, DB, 사내 API를 MCP 계층으로 연결하는 구조를 설계한다.

  • 인증, 권한, 감사 로그를 포함한 운영 보안 경계를 설정한다.

  • 간단한 FAQ agent가 MCP 도구를 통해 로컬 문서를 검색하도록 구성한다.

MCP와 외부 도구 연결

왜 이 주제가 중요한가

에이전트는 말만 잘하는 시스템이 아니다. 실제 배포 환경에서는 파일을 읽고, 검색하고, 티켓을 만들고, 데이터베이스를 조회하고, 문서를 수정하고, 승인 요청을 보낸다. 즉 에이전트의 품질은 모델 성능만으로 결정되지 않는다. 어떤 도구를 어떤 방식으로 연결했는지가 더 중요해지는 순간이 많다.

초기에는 대부분 직접 연결한다. 예를 들어 다음과 같은 코드를 작성한다.

def search_faq(query: str) -> list[dict]:
    ...

def create_ticket(title: str, body: str) -> dict:
    ...

그리고 이 함수들을 모델의 function calling 스키마로 넘긴다. 이 방식은 빠르다. 프로토타입에는 좋다. 그러나 다음 상황이 오면 한계가 드러난다.

  • 같은 도구를 여러 에이전트가 함께 써야 한다.

  • Claude, OpenAI, 로컬 LLM 등 여러 모델을 바꿔가며 써야 한다.

  • 도구 목록이 자주 바뀐다.

  • 도구별 권한과 감사 로그가 필요하다.

  • 외부 서비스 연결 코드를 제품 코드와 분리하고 싶다.

  • 사내 API를 안전하게 노출해야 한다.

이때 필요한 것이 표준화된 도구 연결 계층이다. MCP는 이 문제를 해결하기 위해 등장했다. 공식 문서는 MCP를 AI 애플리케이션을 위한 USB-C 포트에 비유한다. USB-C가 노트북과 다양한 주변기기를 같은 방식으로 연결하듯, MCP는 AI 애플리케이션과 다양한 데이터·도구를 같은 규칙으로 연결한다1.

중요한 점은 MCP가 모델을 똑똑하게 만드는 마법이 아니라는 것이다. MCP는 연결 방식을 표준화한다. 좋은 에이전트는 여전히 좋은 도구 설명, 적절한 권한, 검증 가능한 출력, 실패 처리, 로그 설계를 필요로 한다.

핵심 개념 설명

MCP는 무엇인가

MCP는 Model Context Protocol의 약자다. 이름 그대로 모델에 필요한 컨텍스트와 도구를 제공하는 방법을 표준화한 프로토콜이다. 여기서 프로토콜은 "서로 통신할 때 따르는 약속"을 뜻한다.

MCP가 하는 일은 크게 세 가지다.

  1. 에이전트가 사용할 수 있는 도구 목록을 발견한다.

  2. 각 도구의 이름, 설명, 입력 스키마를 확인한다.

  3. 필요한 도구를 호출하고 결과를 받는다.

앞 장의 function calling과 비교하면 차이가 더 분명해진다.

function calling은 보통 모델 요청 안에 함수 정의를 함께 넣는다. 애플리케이션은 모델이 반환한 함수 호출 요청을 해석해 직접 함수를 실행한다. 반면 MCP는 도구 제공자를 별도의 서버로 분리한다. 에이전트는 MCP client를 통해 MCP server에 연결하고, 서버가 노출한 도구와 리소스를 표준 메시지로 사용한다.

즉 function calling이 "모델이 어떤 함수를 호출할지 표현하는 방식"에 가깝다면, MCP는 "그 함수와 데이터 소스를 여러 클라이언트가 재사용할 수 있게 노출하는 연결 계층"에 가깝다.

둘은 경쟁 관계가 아니다. 실제 구현에서는 MCP 서버가 도구 목록을 제공하고, 에이전트 SDK가 그 도구들을 모델의 function calling 형식으로 변환해 전달하는 경우가 많다.

기존 방식과 무엇이 다른가

MCP를 이해하려면 기존 방식과 비교해야 한다.

방식핵심 역할장점한계
커스텀 API 래퍼특정 API를 직접 코드로 감싼다빠르고 단순하다재사용과 표준화가 어렵다
function calling모델이 호출할 함수 형식을 정의한다모델과 도구 호출을 쉽게 연결한다모델·SDK별 구현 차이가 있다
플러그인특정 플랫폼에 외부 서비스를 연결한다사용자 경험이 단순하다플랫폼 종속성이 크다
RAG문서를 검색해 컨텍스트로 넣는다문서 Q&A에 강하다실행·수정 작업에는 약하다
MCP도구·리소스·프롬프트를 표준 서버로 노출한다재사용, 분리, 확장에 유리하다초기 구조와 운영 설계가 필요하다

여기서 RAG는 Retrieval-Augmented Generation의 약자다. 질문과 관련된 문서를 검색해 모델 입력에 넣는 방식이다. RAG는 "읽기"에 강하다. MCP는 읽기뿐 아니라 실행 도구도 다룬다. 예를 들어 사내 문서를 검색하는 것은 RAG에 가깝고, 검색 결과를 바탕으로 승인 문서를 생성해 저장하고 담당자에게 알림을 보내는 것은 MCP 기반 도구 연결이 어울린다.

MCP의 기본 구성 요소

MCP 구조는 보통 host, client, server로 나눈다.

Host는 사용자가 만나는 AI 애플리케이션이다. 예를 들어 IDE, 데스크톱 앱, 사내 챗봇, 에이전트 실행 서비스가 host가 될 수 있다. Host는 사용자의 입력을 받고, LLM 호출과 MCP 연결을 조율한다.

Client는 MCP server와 연결되는 프로토콜 클라이언트다. 하나의 client는 보통 하나의 server와 연결된다. Client는 서버 초기화, 도구 목록 조회, 도구 호출, 리소스 요청, 알림 수신을 담당한다.

Server는 외부 기능을 MCP 방식으로 노출하는 프로그램이다. 파일 시스템 서버, GitHub 서버, DB 서버, 사내 문서 서버, 캘린더 서버처럼 특정 기능 묶음을 제공한다.

MCP server는 주로 다음 요소를 제공한다.

Tool은 모델이 호출할 수 있는 실행 기능이다. 예를 들어 search_documents, read_file, create_issue, query_customer, send_approval_request가 tool이다. MCP 명세에서 tool은 이름, 설명, 입력 스키마를 가진다. 클라이언트는 tools/list로 도구 목록을 확인하고, tools/call로 특정 도구를 실행한다2.

Resource는 모델이 참고할 수 있는 외부 데이터다. 파일 내용, 문서 페이지, DB 스키마, 로그, 프로젝트 설정 등이 resource가 될 수 있다. Tool이 "무언가를 실행하는 버튼"이라면, resource는 "읽을 수 있는 자료"에 가깝다.

Prompt는 서버가 제공하는 재사용 가능한 프롬프트 템플릿이다. 예를 들어 사내 문서 요약 방식, 이슈 생성 규칙, 고객 응대 톤을 prompt로 제공할 수 있다. 모델에게 매번 긴 지시문을 직접 쓰지 않고, 서버가 검증된 템플릿을 제공하게 할 수 있다.

이 구조를 간단히 그리면 다음과 같다.

사용자
  ↓
AI 애플리케이션 Host
  ↓
LLM + MCP Client들
  ↓
MCP Server A ─ 파일 시스템
MCP Server B ─ 문서 저장소
MCP Server C ─ 데이터베이스
MCP Server D ─ 사내 승인 API

핵심은 도구 로직이 에이전트 본체와 분리된다는 점이다. 에이전트는 "어떤 서버가 어떤 도구를 제공하는지"를 표준 방식으로 알 수 있다. 서버는 내부적으로 REST API, GraphQL, SQL, 파일 입출력, 사내 SDK를 자유롭게 사용할 수 있다. 바깥으로는 MCP 규격만 지키면 된다.

MCP의 동작 흐름

MCP 기반 에이전트의 전형적인 흐름은 다음과 같다.

  1. Host가 MCP server 설정을 읽는다.

  2. Host 내부의 MCP client가 server에 연결한다.

  3. Client가 서버에 도구 목록을 요청한다.

  4. Server가 도구 이름, 설명, 입력 스키마를 반환한다.

  5. Host는 이 도구 정보를 LLM이 이해할 수 있는 도구 정의로 전달한다.

  6. 사용자가 요청을 입력한다.

  7. LLM이 필요한 도구와 인자를 선택한다.

  8. Client가 MCP server에 도구 호출 요청을 보낸다.

  9. Server가 실제 외부 시스템을 호출한다.

  10. 결과가 client와 LLM으로 돌아온다.

  11. LLM이 결과를 해석해 사용자에게 최종 답변한다.

예를 들어 사용자가 이렇게 묻는다고 하자.

"지난주 장애 보고서에서 결제 오류 관련 항목만 찾아 요약해줘."

에이전트는 먼저 문서 검색 도구가 필요하다고 판단한다. MCP client는 문서 서버의 search_documents tool을 호출한다. 서버는 문서 저장소를 검색하고 결과를 반환한다. 에이전트는 필요한 문서를 다시 read_document로 읽고, LLM은 내용을 요약한다.

사용자가 이어서 말한다.

"이 내용을 운영팀 검토 요청 문서로 만들어줘."

이번에는 문서 생성 또는 승인 요청 도구가 필요하다. 에이전트는 create_review_doc 또는 send_approval_request 같은 도구를 호출한다. 이때 운영 환경에서는 바로 실행하지 않고 human approval을 요구해야 할 수도 있다. 이 주제는 Human approval과 guardrails에서 더 자세히 다룬다.

쉬운 비유 또는 사례

MCP는 멀티탭이 아니라 표준 콘센트다

에이전트에 도구를 붙이는 일을 멀티탭에 플러그를 꽂는 것으로 생각해보자. function calling만 사용할 때는 각 전자제품의 플러그 모양이 조금씩 다르다. 어떤 모델은 A 형식, 어떤 SDK는 B 형식, 어떤 프레임워크는 C 형식이다. 그래서 도구가 늘어날수록 변환 어댑터가 많아진다.

MCP는 "우리 조직에서는 외부 도구를 이 규격으로 노출한다"는 표준 콘센트에 가깝다. 에이전트 앱이 바뀌어도, 모델이 바뀌어도, 도구 서버는 같은 방식으로 발견되고 호출된다.

물론 콘센트가 표준이라고 해서 모든 전자제품을 무조건 꽂아도 되는 것은 아니다. 전압, 허용 전류, 접지, 차단기가 필요하다. MCP도 마찬가지다. 도구 목록을 표준화하는 것만으로는 충분하지 않다. 인증, 권한, 입력 검증, 로그, 승인 절차가 함께 있어야 운영 가능한 시스템이 된다.

사내 FAQ agent 사례

가장 단순한 사례로 FAQ agent를 생각해보자. 이 에이전트는 고객지원팀의 문서를 검색해 답변한다. 처음에는 다음처럼 만들 수 있다.

def search_faq(query: str) -> str:
    # 로컬 문서 폴더에서 검색
    ...

이 함수 하나를 function calling으로 붙이면 빠르게 동작한다. 그러나 곧 요구사항이 늘어난다.

  • 고객지원팀 문서뿐 아니라 제품팀 릴리스 노트도 검색해야 한다.

  • 운영팀 장애 보고서도 참고해야 한다.

  • 답변에 사용한 문서 출처를 남겨야 한다.

  • 일부 문서는 관리자만 볼 수 있어야 한다.

  • 검색 도구를 FAQ agent뿐 아니라 문서 작성 agent도 사용해야 한다.

이때 검색 기능을 MCP server로 분리하면 구조가 좋아진다.

FAQ Agent
문서 작성 Agent
운영 분석 Agent
       ↓
MCP Client
       ↓
Knowledge MCP Server
       ↓
로컬 문서 폴더 / 벡터 DB / 문서 저장소 / 권한 시스템

각 에이전트는 같은 MCP server를 사용한다. 문서 검색 로직이 바뀌어도 에이전트 코드를 모두 고칠 필요가 없다. 새 문서 저장소가 추가되어도 MCP server 내부만 수정하면 된다.

외부 도구 연결 구조 설계

파일 시스템 연결

파일 시스템 MCP server는 로컬 또는 서버의 특정 디렉터리를 읽고 쓰는 도구를 제공한다. 예를 들어 다음 도구가 있을 수 있다.

  • list_files(path)

  • read_file(path)

  • write_file(path, content)

  • search_files(query, root_path)

파일 시스템 도구는 편리하지만 위험하다. 운영 환경에서는 반드시 루트 경계를 제한해야 한다. 예를 들어 /home/app/docs 아래만 접근하게 해야지, 서버 전체 파일 시스템을 열어두면 안 된다. 또한 쓰기 도구는 읽기 도구보다 훨씬 엄격하게 다뤄야 한다.

권장 구조는 다음과 같다.

MCP Filesystem Server
  - 허용 루트: /workspace/faq_docs
  - 읽기 도구: 허용
  - 쓰기 도구: 초안 폴더에만 허용
  - 삭제 도구: 기본 비활성화
  - 모든 호출 로그 기록

문서 저장소 연결

문서 저장소는 Notion, Confluence, Google Drive, SharePoint, 사내 위키처럼 문서가 모이는 곳이다. 문서 저장소 MCP server는 보통 다음 도구를 제공한다.

  • search_documents(query, filters)

  • read_document(document_id)

  • list_recent_documents(space_id)

  • create_document(title, content, folder_id)

  • update_document(document_id, patch)

검색과 읽기는 비교적 안전하지만, 생성과 수정은 승인 절차가 필요할 수 있다. 특히 사내 지식 베이스에 직접 반영되는 문서는 잘못된 내용이 퍼질 위험이 있다. 따라서 운영 환경에서는 "초안 생성"과 "최종 게시"를 분리하는 편이 좋다.

create_document_draft: 에이전트가 호출 가능
publish_document: 사람 승인 필요
update_official_policy: 관리자 승인 필요

데이터베이스 연결

DB 연결은 강력하지만 가장 조심해야 한다. 에이전트에게 SQL 실행 권한을 직접 주는 것은 위험하다. 모델이 잘못된 쿼리를 만들 수도 있고, 사용자 프롬프트에 의해 민감한 데이터 조회가 유도될 수도 있다.

DB용 MCP server를 설계할 때는 자유 SQL보다 제한된 도구를 먼저 고려한다.

나쁜 예:

run_sql(query: string)

더 나은 예:

get_order_status(order_id: string)
search_customer_by_email(email: string)
list_failed_payments(start_date: string, end_date: string)
get_daily_signup_count(date: string)

이렇게 업무 단위 도구로 감싸면 입력 검증과 권한 제어가 쉬워진다. 꼭 SQL이 필요하다면 읽기 전용 계정, 허용 테이블 목록, 쿼리 타임아웃, 결과 행 수 제한, 개인정보 마스킹을 적용해야 한다.

사내 API 연결

사내 API는 MCP server로 감싸기 좋은 대상이다. 이미 운영 중인 API를 에이전트가 직접 호출하게 하지 말고, MCP server가 중간에서 다음 역할을 하게 한다.

  • API 인증 정보를 보관한다.

  • 사용자 권한을 확인한다.

  • 입력값을 검증한다.

  • 위험 작업은 승인 대기 상태로 만든다.

  • 응답에서 불필요한 민감 정보를 제거한다.

  • 호출 내역을 감사 로그로 남긴다.

예를 들어 승인형 문서 에이전트에서는 다음 구조를 사용할 수 있다.

Document Approval Agent
  ↓
MCP Client
  ↓
Approval MCP Server
  ↓
사내 결재 API / 문서 저장소 / 알림 시스템

도구는 다음처럼 나눌 수 있다.

  • create_approval_draft(title, body, reviewers)

  • get_approval_status(request_id)

  • send_approval_request(request_id)

  • cancel_approval_request(request_id)

여기서 send_approval_request는 실제 업무 프로세스를 시작한다. 따라서 사용자 확인 또는 관리자 승인 정책을 붙이는 것이 좋다.

보안 경계 설계

MCP는 연결을 표준화하지만 보안을 자동으로 해결하지는 않는다. 실제 운영에서는 MCP server 하나가 민감한 시스템의 관문이 될 수 있다. 따라서 "모델이 호출할 수 있는 도구"가 아니라 "외부 사용자가 간접적으로 실행할 수 있는 API"로 보고 설계해야 한다.

도구 노출 범위 최소화

가장 기본 원칙은 필요한 도구만 노출하는 것이다. 에이전트가 FAQ 답변만 하면 된다면 파일 삭제, 문서 수정, DB 업데이트 도구는 노출하지 않는다.

도구 이름도 중요하다. execute_action처럼 모호한 이름보다 search_faq_documents처럼 구체적인 이름이 안전하다. 설명도 과장하지 않는다. 모델이 도구를 잘못 선택하지 않도록 입력 조건과 한계를 명확히 적는다.

예:

도구명: search_faq_documents
설명: 고객지원 FAQ 문서에서 관련 문단을 검색한다. 제품 정책의 최종 판단에는 사용하지 않는다.
입력: query, max_results
출력: 문서 제목, 문단, 문서 경로, 수정일

인증과 서비스 계정

MCP server가 외부 시스템을 호출하려면 인증 정보가 필요하다. 이때 인증 정보를 에이전트 프롬프트나 사용자 입력에 넣으면 안 된다. API 키, OAuth 토큰, DB 비밀번호는 서버 환경 변수나 비밀 관리 시스템에 둔다.

서비스 계정은 사람이 아닌 시스템용 계정이다. 예를 들어 faq-agent-reader라는 계정을 만들고 문서 읽기 권한만 부여한다. 문서 생성이 필요하면 doc-agent-draft-writer처럼 별도 계정을 둔다.

하나의 강력한 계정으로 모든 MCP server를 운영하면 편하지만 위험하다. 서버가 침해되거나 도구 설명이 잘못 구성되면 피해 범위가 커진다.

RBAC

RBAC는 Role-Based Access Control의 약자다. 역할 기반 접근 제어라는 뜻이다. 사용자나 서비스 계정에 역할을 부여하고, 역할에 따라 가능한 작업을 제한한다.

예를 들어 문서 에이전트에는 다음 역할을 둘 수 있다.

역할가능 작업
viewer문서 검색, 문서 읽기
drafter초안 생성, 초안 수정
approver승인 요청 검토, 승인 또는 반려
admin권한 설정, 서버 설정 변경

MCP server는 도구 호출 시 현재 사용자의 역할을 확인해야 한다. 사용자가 viewer라면 publish_document를 호출할 수 없어야 한다. 모델이 "게시해도 됩니다"라고 판단해도 권한 시스템이 막아야 한다.

감사 로그

감사 로그는 누가, 언제, 어떤 도구를, 어떤 입력으로 호출했고, 결과가 무엇이었는지 남기는 기록이다. 에이전트 운영에서 감사 로그는 선택이 아니라 필수에 가깝다.

최소한 다음 항목을 남긴다.

  • 요청 ID

  • 사용자 ID 또는 세션 ID

  • MCP server 이름

  • tool 이름

  • 입력 인자

  • 실행 결과 상태

  • 외부 API 응답 코드

  • 실행 시간

  • 승인 여부

  • 에러 메시지

다만 로그에 개인정보와 비밀값을 그대로 남기면 안 된다. 이메일, 전화번호, 토큰, 비밀번호, 주민등록번호 같은 값은 마스킹하거나 저장하지 않는다.

입력 검증과 출력 정리

MCP tool은 모든 입력을 검증해야 한다. 모델이 항상 올바른 인자를 만든다고 가정하면 안 된다. 날짜 형식, ID 형식, 숫자 범위, 허용 경로, 최대 검색 개수 등을 서버에서 확인한다.

출력도 정리해야 한다. 외부 API 응답 전체를 모델에 넘기면 불필요한 민감 정보가 포함될 수 있다. 에이전트가 필요한 필드만 추려서 반환한다.

예를 들어 고객 조회 도구는 내부 고객 ID, 이름, 등급 정도만 반환하고, 결제 토큰이나 내부 메모는 제거해야 한다.

위험 작업에는 승인 절차를 둔다

읽기 작업과 쓰기 작업은 위험도가 다르다. 다음 작업은 기본적으로 human approval 대상으로 보는 것이 안전하다.

  • 이메일 발송

  • 문서 게시

  • 파일 삭제

  • DB 수정

  • 결제, 환불, 주문 취소

  • 권한 변경

  • 외부 고객에게 보이는 메시지 발송

일부 SDK는 MCP 도구 호출 전 승인 정책을 설정할 수 있다. 예를 들어 특정 도구는 항상 승인받고, 읽기 도구는 자동 실행하게 구성할 수 있다3. 구체적인 구현은 프레임워크마다 다르지만 원칙은 같다. 위험한 작업은 모델 판단만으로 실행하지 않는다.

직접 해보는 실습

이번 실습에서는 로컬 FAQ 문서 폴더를 MCP 형태의 도구 계층으로 감싸고, FAQ agent가 이 도구를 통해 검색하도록 구성한다. 제품 UI나 특정 클라우드 설정은 빠르게 바뀌므로 여기서는 구조와 최소 코드 중심으로 다룬다.

실습 목표

  • 로컬 문서 폴더를 만든다.

  • 문서 검색 MCP server를 만든다.

  • 에이전트가 MCP server의 도구 목록을 가져오게 한다.

  • 사용자의 질문에 맞는 문서를 검색해 답변하게 한다.

1단계: 문서 폴더 만들기

프로젝트 폴더를 다음처럼 만든다.

faq-mcp-agent/
  docs/
    refund.md
    login.md
    plan.md
  server.py
  client.py

docs/refund.md:

# 환불 정책

월간 요금제는 결제 후 7일 이내 사용량이 없으면 전액 환불할 수 있다.
연간 요금제는 결제 후 14일 이내에 환불 요청을 접수해야 한다.
프로모션 쿠폰으로 결제한 금액은 현금 환불 대상이 아니다.

docs/login.md:

# 로그인 문제

비밀번호를 5회 이상 틀리면 계정이 10분 동안 잠긴다.
소셜 로그인 계정은 비밀번호 재설정 메일이 발송되지 않는다.
관리자 계정의 2단계 인증 해제는 보안 담당자의 승인이 필요하다.

docs/plan.md:

# 요금제 변경

무료 요금제에서 팀 요금제로 변경하면 즉시 새 기능을 사용할 수 있다.
팀 요금제에서 엔터프라이즈 요금제로 변경하려면 영업팀 상담이 필요하다.
다운그레이드는 다음 결제 주기부터 적용된다.

2단계: MCP server 설계하기

이번 서버는 하나의 도구만 제공한다.

search_faq(query: string, max_results: integer)

이 도구는 docs 폴더의 마크다운 파일을 읽고, 질문 단어가 포함된 문단을 찾아 반환한다. 실제 서비스에서는 벡터 검색이나 전문 검색 엔진을 쓸 수 있지만, 실습에서는 재현 가능한 단순 검색을 사용한다.

예시 코드:

from pathlib import Path
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("faq-knowledge-server")
DOCS_DIR = Path("./docs").resolve()

@mcp.tool()
def search_faq(query: str, max_results: int = 3) -> list[dict]:
    """
    Search local FAQ markdown documents.

    Args:
        query: User question or search keyword.
        max_results: Maximum number of matched passages to return.

    Returns:
        A list of matched passages with title, path, and text.
    """
    if max_results < 1 or max_results > 10:
        max_results = 3

    keywords = [w.strip().lower() for w in query.split() if w.strip()]
    results = []

    for file_path in DOCS_DIR.glob("*.md"):
        text = file_path.read_text(encoding="utf-8")
        blocks = [b.strip() for b in text.split("nn") if b.strip()]
        title = blocks[0].replace("#", "").strip() if blocks else file_path.name

        for block in blocks[1:]:
            block_lower = block.lower()
            score = sum(1 for k in keywords if k in block_lower)
            if score > 0:
                results.append({
                    "title": title,
                    "path": str(file_path),
                    "text": block,
                    "score": score,
                })

    results.sort(key=lambda x: x["score"], reverse=True)
    return results[:max_results]

if __name__ == "__main__":
    mcp.run(transport="stdio")

이 코드에서 중요한 부분은 @mcp.tool()이다. 이 표시가 붙은 함수는 MCP server가 제공하는 tool로 노출된다. 함수 이름, docstring, 인자 타입은 도구 설명과 입력 스키마를 만드는 데 사용된다. 설명이 부정확하면 모델이 도구를 잘못 사용할 수 있으므로 실제 프로젝트에서는 docstring을 신중하게 작성해야 한다.

3단계: 도구 목록 확인하기

에이전트는 먼저 MCP server에 연결해 도구 목록을 확인한다. MCP 명세에서는 도구 목록 조회와 도구 호출이 별도 메시지로 정의된다. 개념적으로는 다음 흐름이다.

client → server: tools/list
server → client: search_faq 도구 정보 반환
client → server: tools/call search_faq { query: "환불 기간" }
server → client: 검색 결과 반환

실제 코드에서는 사용하는 SDK에 따라 문법이 달라진다. 중요한 것은 에이전트 코드가 search_faq의 내부 구현을 몰라도 된다는 점이다. 에이전트는 MCP server가 알려준 도구 스키마를 보고 호출한다.

4단계: FAQ agent 지시문 작성하기

FAQ agent의 시스템 지시문은 간단하고 명확해야 한다.

너는 고객지원 FAQ agent다.
답변하기 전에 필요한 경우 search_faq 도구를 사용한다.
문서에 근거가 없으면 추측하지 말고 "문서에서 확인할 수 없습니다"라고 말한다.
답변에는 근거 문서 제목을 함께 표시한다.
환불, 계정 보안, 요금제 변경 외의 질문은 담당자 문의를 안내한다.

이 지시문에는 네 가지 안전장치가 있다.

  • 필요한 경우 검색 도구를 사용하게 한다.

  • 문서에 없는 내용을 지어내지 않게 한다.

  • 근거 문서를 표시하게 한다.

  • 범위 밖 질문을 제한한다.

5단계: 테스트 질문

다음 질문으로 테스트한다.

Q1. 연간 요금제는 언제까지 환불할 수 있어?
Q2. 비밀번호를 여러 번 틀리면 어떻게 돼?
Q3. 팀 요금제에서 엔터프라이즈로 바로 바꿀 수 있어?
Q4. 세금계산서는 어떻게 발급해?

기대 결과는 다음과 같다.

  • Q1: refund.md를 검색하고 14일 이내 접수 조건을 답한다.

  • Q2: login.md를 검색하고 10분 잠금 내용을 답한다.

  • Q3: plan.md를 검색하고 영업팀 상담이 필요하다고 답한다.

  • Q4: 문서에 근거가 없으므로 확인할 수 없다고 답한다.

6단계: 실습 결과 기록

실습 후 다음 항목을 기록한다.

항목기록
검색 도구가 호출되었는가예/아니오
올바른 문서를 찾았는가예/아니오
문서에 없는 내용을 지어냈는가예/아니오
근거 문서 제목을 표시했는가예/아니오
실패한 질문질문과 원인

이 기록은 Tracing과 evals에서 다룰 eval의 기초 자료가 된다. 에이전트는 한 번 만들고 끝나는 시스템이 아니다. 도구 호출 로그와 실패 사례를 모아 계속 개선해야 한다.

흔한 실수와 오류 분석

실수 1: MCP를 붙이면 에이전트가 자동으로 좋아진다고 믿는다

MCP는 연결 규칙이다. 도구 설명이 모호하거나 검색 결과 품질이 낮으면 답변도 나빠진다. search라는 이름의 도구 하나에 모든 기능을 몰아넣으면 모델은 언제 어떻게 써야 할지 헷갈린다.

해결책은 도구를 업무 단위로 작게 나누고, 설명을 구체적으로 쓰는 것이다.

나쁜 도구 설명:

search: Search things.

좋은 도구 설명:

search_faq_documents: 고객지원 FAQ 문서에서 질문과 관련된 문단을 검색한다. 제품 정책의 법적 해석이나 계약 조건 판단에는 사용하지 않는다.

실수 2: 너무 많은 도구를 한 번에 노출한다

도구가 많을수록 모델이 항상 더 잘하는 것은 아니다. 비슷한 이름의 도구가 많으면 잘못 선택할 수 있다. 도구 목록이 길어지면 컨텍스트 비용도 늘고, 판단도 어려워진다.

해결책은 에이전트 역할별로 도구를 제한하는 것이다. FAQ agent에는 FAQ 검색 도구만, 문서 작성 agent에는 초안 생성 도구만, 운영 agent에는 장애 로그 조회 도구만 우선 노출한다. 더 복잡한 도구 선택 문제는 Planner, router, multi-agent에서 다룬다.

실수 3: 서버에 너무 강한 권한을 준다

MCP server가 관리자 권한으로 DB와 문서 저장소에 접근하면, 모델의 작은 실수가 큰 사고로 이어질 수 있다.

해결책은 서비스 계정을 나누고 최소 권한을 부여하는 것이다. 읽기 전용 서버와 쓰기 서버를 분리하는 것도 좋다. 삭제, 게시, 결제, 권한 변경 도구는 기본적으로 비활성화하거나 승인 절차를 둔다.

실수 4: 로컬 파일 시스템 전체를 열어둔다

파일 시스템 서버를 사용할 때 / 또는 홈 디렉터리 전체를 허용하면 위험하다. 에이전트가 의도치 않게 SSH 키, 환경 변수 파일, 내부 설정 파일을 읽을 수 있다.

해결책은 허용 루트를 명확히 제한하는 것이다.

허용: /workspace/faq_docs
금지: /, /home, ~/.ssh, .env, secrets

또한 경로 이동 공격을 막아야 한다. 예를 들어 ../../secrets.env 같은 입력이 들어와도 허용 루트 밖으로 나가지 못하게 서버에서 검증한다.

실수 5: 도구 결과를 검증하지 않고 모델에 넘긴다

외부 API 응답에는 불필요한 필드, 오류 메시지, 내부 식별자, 민감 정보가 포함될 수 있다. 이를 그대로 모델에 넘기면 정보 유출 위험이 생긴다.

해결책은 MCP server에서 결과를 정리해 반환하는 것이다. 모델이 답변에 사용할 필드만 남기고 나머지는 제거한다. 오류 메시지도 사용자에게 보여도 되는 수준으로 바꾼다.

실수 6: 로그를 남기지 않는다

에이전트가 어떤 도구를 왜 호출했는지 모르면 장애 분석이 불가능하다. 사용자가 "왜 이 문서를 수정했느냐"고 물었을 때 답할 수 없다.

해결책은 모든 도구 호출을 요청 ID와 함께 기록하는 것이다. 단, 비밀번호와 토큰 같은 비밀값은 로그에 남기지 않는다.

실수 7: MCP server를 외부에서 그대로 신뢰한다

공개 MCP server나 제3자 서버를 사용할 때는 그 서버가 어떤 데이터를 받는지 확인해야 한다. 원격 서버에는 사용자 프롬프트, 문서 내용, 검색어, 인증 헤더가 전달될 수 있다. Microsoft Agent Framework 문서도 제3자 MCP 서버를 사용할 때 데이터 공유, 책임 범위, 감사 로깅, 데이터 보관 위치를 검토하라고 권고한다4.

해결책은 신뢰할 수 있는 제공자의 서버를 사용하고, 가능하면 사내에서 직접 호스팅하는 것이다. 외부 서버를 붙일 때는 데이터 분류, 약관, 보관 위치, 로그 정책을 확인한다.

요약

MCP는 에이전트와 외부 도구 사이의 표준 연결 계층이다. function calling이 개별 함수 호출의 형식을 다룬다면, MCP는 여러 도구와 리소스를 서버로 노출하고 클라이언트가 이를 발견·호출하게 만든다.

MCP의 핵심 구성은 host, client, server다. Server는 tool, resource, prompt를 제공한다. Tool은 실행 기능이고, resource는 참고 데이터이며, prompt는 재사용 가능한 지시 템플릿이다.

MCP는 도구가 많아질수록 가치가 커진다. 같은 도구를 여러 에이전트가 재사용할 수 있고, 모델이나 프레임워크가 바뀌어도 연결 계층을 유지하기 쉽다. 그러나 MCP가 보안을 자동으로 해결하지는 않는다. 운영 환경에서는 도구 노출 범위, 인증, 서비스 계정, RBAC, 감사 로그, 입력 검증, 출력 정리, human approval을 함께 설계해야 한다.

실습에서는 로컬 FAQ 문서 폴더를 MCP server로 감싸고, FAQ agent가 search_faq 도구를 통해 문서를 검색하는 구조를 만들었다. 이 구조는 이후 문서 저장소, DB, 사내 API로 확장할 수 있다.

퀴즈

  1. MCP가 해결하려는 핵심 문제는 무엇인가?

  2. function calling과 MCP는 어떤 관계인가? 둘 중 하나가 다른 하나를 완전히 대체하는가?

  3. MCP server가 제공할 수 있는 세 가지 주요 요소는 무엇인가?

  4. Tool과 resource의 차이는 무엇인가?

  5. 파일 시스템 MCP server를 운영할 때 허용 루트를 제한해야 하는 이유는 무엇인가?

  6. DB 연결 도구에서 run_sql(query)가 위험한 이유는 무엇인가?

  7. 서비스 계정에 최소 권한을 부여해야 하는 이유는 무엇인가?

  8. 감사 로그에 반드시 남겨야 할 항목을 세 가지 이상 적어보라.

  9. 어떤 종류의 tool 호출에 human approval을 붙이는 것이 좋은가?

  10. FAQ agent가 문서에 없는 질문을 받았을 때 어떻게 답해야 하는가?

체크리스트

  • MCP를 "모델이 도구와 컨텍스트를 발견하고 호출하는 표준 인터페이스"로 설명할 수 있다.

  • function calling, RAG, 커스텀 API 래퍼, MCP의 차이를 구분할 수 있다.

  • host, client, server의 역할을 설명할 수 있다.

  • tool, resource, prompt의 차이를 설명할 수 있다.

  • 파일 시스템, 문서 저장소, DB, 사내 API를 MCP server로 감싸는 구조를 그릴 수 있다.

  • 도구 노출 범위를 최소화해야 하는 이유를 이해했다.

  • 인증 정보는 프롬프트가 아니라 서버 측 비밀 관리에 둬야 함을 이해했다.

  • RBAC와 서비스 계정으로 권한을 나누는 방법을 설명할 수 있다.

  • 감사 로그에 도구 호출 기록을 남겨야 함을 이해했다.

  • 위험 작업에는 승인 절차를 붙여야 함을 이해했다.

  • 로컬 FAQ 문서 폴더를 검색 도구로 노출하는 실습 구조를 재현할 수 있다.

다음 장 연결

이번 장에서는 에이전트가 외부 도구와 데이터에 접근하는 표준 연결 계층으로 MCP를 배웠다. 이제 에이전트는 파일, 문서, DB, 사내 API를 사용할 수 있다.

하지만 도구를 연결했다고 해서 에이전트가 긴 작업을 안정적으로 수행하는 것은 아니다. 에이전트는 대화 중 무엇을 기억해야 하는지, 작업 중간 상태를 어디에 저장해야 하는지, 다음 호출에서 어떤 정보를 다시 불러와야 하는지 알아야 한다.

다음 장에서는 memory와 state를 다룬다. memory는 에이전트가 과거 대화나 사용자 선호를 기억하는 방식이고, state는 현재 작업의 진행 상황을 구조화해 보관하는 방식이다. MCP가 외부 세계와 연결하는 문이라면, memory와 state는 에이전트 내부의 작업대다.

참고

1Model Context Protocol Introduction

2Model Context Protocol Tools Specification

3OpenAI Agents SDK: Model context protocol (MCP)

4Using MCP tools with Agents - Microsoft Learn

책 목록

AI 교육 6권 : 에이전트 설계·배포: 도구를 쓰는 LLM을 운영 가능한 시스템으로 만드는 법

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기