main

MCP 서버 자체는 단순히, 외부에서 호출할 수 있는 함수와 해당 함수에 대한 정보의 모음집. 제공하는 정보는 큰 틀에서 아래의 3개. (MCP의 3대 요소)

  • 도구 (Tools): 실행 가능한 함수. 외부 API 호출, 혹은 사이드 이펙트가 있는 작업을 수행한다.
  • 리소스 (Resources): 연산을 수행하는 함수가 아니라, LLM이 상황을 파악하기 위해 읽어들일 수 있는 ‘데이터 원본’
    • ex: 로컬 파일, 데이터베이스 내용, 시스템 로그 등
    • file:// 이나 postgres:// 같은 특정 URI 패턴으로 데이터를 요청하면 서버가 컨텍스트를 반환한다.
  • 프롬프트 (Prompts): 재사용 가능한 프롬프트 템플릿과 워크플로우를 서버 측에서 미리 정의하여 LLM 클라이언트에 제공
구성요소역할FastMCP 작성 방식감각적 이해
ToolsLLM이 실행할 수 있는 함수/행동@mcp.tool“이 작업을 실행해라”
ResourcesLLM/클라이언트가 읽을 수 있는 데이터/파일/상태@mcp.resource“이 데이터를 참고해라”
Prompts재사용 가능한 프롬프트 템플릿@mcp.prompt“이 형식으로 질문/작업을 시작해라”

비동기 요청-응답(RPC, Remote Procedure Call) 으로 동작하면서, 호출이 왔을때 인풋에 대해 정해진 연산을 진행한 후, 인풋값에 연산을 가한 결과값을 아웃풋으로 반환함.

굳이 MCP 서버로 따로 지칭되는 것은, 함수에 정의된 description 을, 함수를 호출하는 LLM 이 해석하고 함수의 역할을 인식할 수 있기 때문.

  • description 을 주입하는 개념 자체는 langchain 등에서 이미 시도되었으나, 표준 JSON-RPC로 완전히 통일된 것은 MCP 가 규약을 잡은 후

따라서 재사용성이 낮은 함수들을 굳이 MCP 서버로 따로 띄우는 것은 사실상 실익이 없다. MCP 를 띄울 것이라면

  • 외부 API 호출, 외부 DB 조회를 포함
    • 해당 함수가 단순 파이썬 내부 함수를 위주로 하는 도구일 경우, 실익이 없음
  • 해당 함수가 특정 솔루션 종속적이지 않음
    • 다른 AI 플랫폼 / IDE 와 도구를 공유할 일이 없을 경우, 실익이 낮음
  • 솔루션에서 정의되어 있는 파이프라인이 다소 느슨함
    • 엄격하게 하드코딩된 규칙이나 FSM 일 경우, MCP 를 올리는 실익이 낮음
    • MCP의 진가는 LLM이 런타임에 동적으로 서버의 스키마를 읽어오고, 어떤 도구를 쓸지 ‘자율적으로’ 결정하는 에이전틱(Agentic) 환경에서 발휘
  • Monolithic 하지 않음
    • 1인 개발 / 단일 repo 일 경우, 아키텍처 분리 실익이 낮음
    • ‘AI 모델링 팀’ 과 ‘DB/인프라 백엔드 팀’이 별도로 있는 환경일 경우에만, MCP 가 훌륭한 인터페이스 경계선으로 기능
    • 아니라면 분산 시스템이 주는 이점 < 인프라 관리 복잡도 단점
      • 컨테이너 관리, 포트 바인딩, 네트워크 에러 핸들링 등

MCP는 모든 LLM 도구 연동을 대체하는 만능 해결책이 아니다.

  • 다양한 AI 클라이언트와 다양한 데이터/도구 제공자 간의 N:M 결합 복잡도를 낮추기 위한 인터페이스 표준일 뿐

핵심 실익

핵심 실익세부 내용 및 아키텍처적 가치
관심사의 분리 및 팀 협업
(Separation of Concerns)
백엔드 엔지니어와 AI 엔지니어의 영역을 완벽히 분리할 수 있다. 백엔드 팀은 DB 커넥션, 보안, 인프라를 신경 쓰며 MCP 서버 형태로 도구를 노출하고, AI 개발자는 LangGraph에서 이 MCP 서버를 클라이언트로 연결하기만 하면 로컬 파이썬 래퍼 코드 없이 즉시 도구를 사용할 수 있다.
도구의 재사용성 및 상호운용성
(Interoperability)
LangGraph 전용으로 작성한 도구는 LangGraph 내에서만 쓸 수 있다. 반면 MCP 서버로 작성한 도구는 향후 에이전트를 확장하거나, 개발 과정에서 Cursor, Claude Desktop, 혹은 다른 AI 프레임워크로 테스트할 때 별도의 코드 수정 없이 그대로 꽂아서(Plug-and-Play) 사용할 수 있다.
동적 도구 검색 및 결합도 완화
(Dynamic Discovery)
기존 방식은 LangGraph 코드 내에 tools = [my_tool_a, my_tool_b] 처럼 도구를 직접 임포트하고 하드코딩해야 한다. MCP를 사용하면 서버가 가진 도구 스키마를 런타임에 동적으로 로드하므로, 도구를 수정하거나 추가할 때 LangGraph 서비스를 재배포할 필요 없이 MCP 서버만 업데이트하면 된다.
보안 및 실행 환경 격리
(Sandboxing & Security)
특정 도구가 민감한 데이터베이스에 접근하거나 무거운 연산(예: 보안 셸 실행, 파일 시스템 제어)을 해야 할 때, LangGraph 앱과 도구 실행 엔진(MCP 서버)을 도커(Docker) 컨테이너 등으로 물리적으로 격리하여 보안 리스크를 최소화할 수 있다.
  • 시스템 외부의 기능 / 서비스 (API, DB, 외부 툴 등) 를 연동하는 도구가 늘어날 것 같다 MCP 도입의 실익이 큼
  • langgraph FSM 안에서 내부 데이터 포맷 정제 / 계산 보조 함수가 늘어난다 일반 LangGraph @tool로 처리. MCP 를 띄우고 거치면 직렬화/역직렬화, IPC(프로세스 간 통신) 오버헤드, 내부 상태 접근이 번거로움
    • 내부 메모리에 밀접하게 엮인 도구일 경우, MCP 도입 실익이 적음

API 서버 vs MCP 서버

구분일반 API 서버MCP 서버
주요 목적소프트웨어 및 시스템 간의 범용적인 데이터 교환 및 비즈니스 로직 처리AI 모델 및 에이전트에게 상황적 컨텍스트(데이터)와 도구(기능)를 표준화하여 제공
타겟 클라이언트프론트엔드 웹/앱, 브라우저, 외부 연동 서버 등 (인간 및 범용 시스템)LLM 기반 프레임워크(LangGraph 등), AI IDE(Cursor), AI 에이전트(Claude Desktop)
통신 프로토콜REST, GraphQL, gRPC 등 개발자가 비즈니스 요구에 맞춰 자유롭게 설계Anthropic이 정의한 엄격한 단일 표준 JSON-RPC 프로토콜 강제
동적 탐색 (Discovery)없음. 개발자가 Swagger, OpenAPI 명세서를 별도 작성하여 클라이언트에 제공해야 함내장됨. 클라이언트 연결 시 서버가 보유한 도구 목록, 파라미터 스키마를 런타임에 자동 반환
제공 요소개발자가 정의한 엔드포인트에 따른 데이터 조회(GET) 및 상태 변경(POST/PUT 등)Tools(사이드 이펙트가 있는 함수), Resources(읽기 전용 데이터 원본), Prompts(사전 정의 템플릿)
클라이언트 연동 비용높음. 프레임워크나 환경에 맞춰 API 응답을 파싱하고 래핑하는 접착 코드(Glue Code) 필수낮음(Plug-and-Play). 프로토콜이 표준화되어 있어 엔드포인트 주소만 입력하면 즉시 인식 및 사용 가능
주요 활용처일반적인 웹/모바일 서비스 백엔드, 마이크로서비스 아키텍처(MSA) 내부 통신다중 AI 클라이언트 환경의 공용 도구 제공, RAG 데이터 소스 통합, 자율형 에이전트 워크플로우
  • 크게 보면, MCP 서버는 결국 API 서버의 일종
    • 통신할 대상을 크게 좁히고, 규격을 엄격하게 제한한 API 서버가 MCP 서버
  • 개발자(사람)가 직접 통제하는 아키텍처 관점에서는 그냥 API 서버(REST, gRPC 등)로 만드는 것이 훨씬 낫다
    • MCP 서버가 강점을 가지는 상황은, LLM에게 도구 선택의 자유를 주는 상황 단 하나 (자율적, Agentic)
      • 이외에는 다중 클라이언트 생태계 파편화 방지(Plug-and-Play) 목적
        • cursor, langgraph 등에서 코드를 각자 작성하는게 아니라, MCP 한번으로 모두 해결
    • 솔루션의 전반적인 흐름이 결정론적이면, MCP 도입을 고려할 이유 거의 없음

fastmcp 에서 tool 정의 방법

from typing import Annotated
from fastmcp import FastMCP
 
mcp = FastMCP("CompanyOperations")
 
@mcp.tool
def create_jira_issue(
    summary: Annotated[str, "지라 티켓의 제목. 핵심 요약 위주로 작성"],
    project_key: str,
    priority: str = "Medium"
) -> str:
    """새로운 Jira 개발 이슈 티켓을 생성합니다. 
    사용자가 버그를 보고하거나, 새로운 기능 개발 요건을 요청했을 때 이 도구를 호출해야 합니다.
 
    Args:
        project_key: 지라 프로젝트의 키 값 (예: 'PLAT', 'GAME', 'WEB')
        priority: 티켓의 우선순위. 'High', 'Medium', 'Low' 중 하나만 허용됨.
    """
    # 실제 API 호출 로직...
    return "JIRA-1234 티켓이 성공적으로 생성되었습니다."
파악 목적 (구분)코드 참조 요소개발자 작성 예시매핑 목적지 (MCP Tool Schema)FastMCP 변환 및 LLM 인식 원리
도구의 목적 파악Docstring
(함수 설명문)
"""새로운 Jira 개발 이슈 티켓을 생성합니다…"""description (최상위 레벨)FastMCP가 Docstring 전체를 해당 필드에 매핑. LLM은 대화 맥락과 이 설명을 대조해 호출할 도구를 동적으로 선택
매개변수(Args)의
의미 파악
(방법 A) Annotatedsummary: Annotated[str, “지라 티켓 제목…”]inputSchema.properties.[인자명].descriptionAnnotated 설명이나 Docstring을 파싱해 개별 인자의 설명 필드로 자동 주입. LLM은 이를 참조해 알맞은 값을 추론 및 할당
(방법 B) Docstring ArgsArgs: project_key: 지라 프로젝트 키…
입력 포맷과
제약 조건 파악
Type Hinting
(타입 힌트)
project_key: str, priority: str = “Medium”inputSchema.properties.[인자명].type
inputSchema.required
타입 힌트 기반으로 데이터 타입(type) 지정 및 디폴트값 유무에 따라 필수 입력 여부(required 배열) 매핑. 제약 조건에 맞는 인자를 강제함 (Pydantic 모델 사용 시 중첩 구조 객체 스키마까지 변환 가능)
  • 3대 요소인 tool, resources, prompt 에서 tool 에만 해당함

mcp 통신 흐름

LangGraph 혹은 클라이언트가 MCP 서버에 연결하면, 다음과 같이 통신 발생

단계통신 방향동작 내용
1. Discovery (도구 목록 조회)CLI → MCP 서버”네가 가진 도구 목록과 스펙을 줘”
2. Schema 전송CLI ← MCP 서버FastMCP 서버는 위 파이썬 함수를 해석하여 JSON 스키마 규격 반환
3. LLM 추론 및 결정CLI (LLM 내부)LLM은 사용자 메시지를 분석 후, 위 JSON 스펙을 보고 할 일을 자율적으로 결정
4. Tool Calling (도구 실행)CLI → MCP 서버LLM의 추론 결과를 바탕으로, 클라이언트가 알맞은 인자값을 담아 MCP 서버에 실제 도구 실행을 요청
  1. json 스키마 예시
  2. 사용자 프롬프트 ex) “웹서버가 죽었는데 WEB 프로젝트에 우선순위 높음으로 티켓 좀 생성해줘”
    • json 확인 후 LLM 판단: “아, create_jira_issue 도구를 쓰고, summary에는 ‘웹서버 다운 장애’, project_key에는 ‘WEB’, priority에는 ‘High’를 넣어서 호출해야겠다”
{
  "name": "create_jira_issue",
  "description": "새로운 Jira 개발 이슈 티켓을 생성합니다. 사용자가 버그를 보고하거나...",
  "inputSchema": {
    "type": "object",
    "properties": {
      "summary": {
        "type": "string",
        "description": "지라 티켓의 제목. 핵심 요약 위주로 작성"
      },
      "project_key": {
        "type": "string",
        "description": "지라 프로젝트의 키 값 (예: 'PLAT', 'GAME', 'WEB')"
      },
      "priority": {
        "type": "string",
        "description": "티켓의 우선순위. 'High', 'Medium', 'Low' 중 하나만 허용됨.",
        "default": "Medium"
      }
    },
    "required": ["summary", "project_key"]
  }
}