
MCP 란 Model Context Protocol 의 약어로, 애플리케이션이 LLM에 컨텍스트(정보)를 제공하는 방식을 표준화하는 개방형 프로토콜입니다. AI모델 Claude를 만든 회사인 Anthropic 에서 처음 발의한 개념으로, AI 시스템과 데이터 소스를 연결하기 위한 표준 규격을 뜻합니다. MCP를 사용하면 결과적으로 LLM 시스템이 필요한 데이터에 액세스할 수 있는 더 간단하고 안정적인 방법을 제공합니다.

Claude, ChatGPT, Cursor, Perplexity 등 최근에 다양한 LLM host 들이 등장하고 있습니다. 초창기에는 각 host 마다 연결하는 통신 규격이 정해져 있지 않아서, 외부 시스템과 연동을 위해서는 데이터 원천/외부 시스템(M개)와 host(N개)의 곱(M * N) 만큼의 연결 서버를 만들어야 하는 번거로움이 있었습니다.

MCP는 이 과정을 표준화해서 각 외부 시스템마다 MCP 서버만 만들고, 각 애플리케이션마다 MCP 클라이언트만 만들면 되도록 구조를 단순화합니다. LLM host 개발자들은 MCP 규격에 맞게 MCP Client 를 개발/제공하고 LLM 사용자들은 MCP Server 만 만들게 되어 통합 난이도가 M+N 문제로 줄어들었으며 여러 MCP Client 와 한 번에 연결할 수 있게 되었습니다.
양방향 통신: 단순 API 호출이 아니라, AI와 외부 시스템이 지속적으로 정보를 주고받음.
보안과 권한 관리: OAuth2.0, JWT 등 기존 인증 체계와 연동. 각 연결마다 명확한 권한과 보안 경계 설정.
확장성: 오픈소스, 커뮤니티 기반. 누구나 새로운 MCP 서버(도구) 개발 가능.
표준화: 하나의 MCP 인터페이스로 다양한 데이터 소스/도구 연결, 코드 재사용성 극대화

GPT는 stateless, 즉 상태를 저장하지 않는 모델입니다. 서버나 모델 자체가 과거 대화를 기억하지 않기 때문에, 우리가 봤을 때 자연스럽고 일관된 대화를 만들기 위해서는 모든 대화 내역을 매번 요청에 함께 보내야 합니다.
이로 인해 아래의 문제가 발생합니다.
요청에 포함되는 메시지가 많아질수록 전체 입력 토큰 수가 늘어나게 되고, 이에 따라 응답 속도가 느려지고 비용도 증가하게 됩니다. 특히 GPT-4 같이 고성능 모델의 경우 입력 토큰에 따라 요금이 달라지므로, 대화가 길어질수록 부담이 커집니다.
사용자가 민감한 정보를 다루는 경우, 매번 전체 메시지를 포함해서 전송한다는 점이 보안상 취약점이 될 수 있습니다. 이를 해결하려면 프론트엔드 또는 백엔드에서 컨텍스트를 잘 관리하고, 필요 시 민감한 내용을 요약하거나 마스킹하는 등의 처리가 필요합니다.
초보자 입장에서 보면 단순히 질문만 보내는 것이 아니라, 시스템 프롬프트부터 이전 대화까지 포함해서 메시지 배열을 구성해야 하므로, 구조화된 프로토콜 설계가 필요합니다. 특히 멀티턴(Multi-turn) 챗봇을 만들 경우, 대화 기록을 요약하거나 압축하는 로직도 함께 고려해야 합니다.
/src
├── models/gpt.ts ← Model: GPT 호출
├── contexts/ChatContext.tsx ← Context: 메시지 관리
├── protocols/message.ts ← Protocol: 메시지 타입 정의
└── App.tsx ← View: UI 구성
export type Role = "user" | "assistant" | "system";
export interface ChatMessage {
role: Role;
content: string;
}
import { ChatMessage } from "../protocols/message";
export async function callGPT(messages: ChatMessage[]) {
const res = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "gpt-4",
messages: messages
})
});
const data = await res.json();
return data.choices[0].message as ChatMessage;
}
import { createContext, useContext, useState } from "react";
import { ChatMessage } from "../protocols/message";
import { callGPT } from "../models/gpt";
const ChatContext = createContext(null);
export const ChatProvider = ({ children }) => {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const sendMessage = async (content: string) => {
const userMessage: ChatMessage = { role: "user", content };
const newMessages = [...messages, userMessage];
setMessages(newMessages);
const assistantMessage = await callGPT(newMessages);
setMessages([...newMessages, assistantMessage]);
};
return (
<ChatContext.Provider value={{ messages, sendMessage }}>
{children}
</ChatContext.Provider>
);
};
export const useChat = () => useContext(ChatContext);