MCP 서버 메타데이터 동기화: 개발자 생산성을 위한 컨텍스트 관리 전략
최근 AI 에이전트와 개발 툴링의 통합이 깊어지면서, 우리는 **Model Context Protocol (MCP)**를 통해 블로그 시스템을 자동화하고 있지만, 여전히 하나의 성가신 문제가 남아 있습니다. 바로 AI와의 세션마다 프로젝트의 구조와 맥락을 반복해서 설명해야 하는 ‘토큰 낭비(Token Waste)’ 현상입니다.
Hacker News의 최신 글인 *Stop wasting tokens and re explaining your project between sessions*에서 언급된 것처럼, 프로젝트의 맥락을 일관되게 유지하는 것은 단순한 편의를 넘어 비용 효율과 직결됩니다.
이번 포스트에서는 MCP 서버가 제공하는 정적 리소스(Tools, Resources, Prompts)를 넘어, 동적 메타데이터(컨텍스트)를 어떻게 에이전트에게 효율적으로 공유할 수 있는지에 대한 실용적인 설계안을 제안합니다.
문제 정의: 매번 반복되는 ‘내 프로젝트 소개’
기존 MCP 클라이언트는 서버가 제공하는 tools 리스트를 통해 기능을 파악합니다. 예를 들어, write_post라는 툴이 있으면 Claude는 이를 호출하여 글을 씁니다. 하지만 Claude는 ‘이 블로그의 글쓰기 스타일은 어떤지?’, ‘최근 트렌드는 무엇인지?’ 와 같은 맥락(Context)을 알지 못합니다.
결국 사용자는 다음과 같은 프롬프트를 매번 달아줘야 합니다.
“블로그에 글을 써줘. 단, 스타일은 기술적이고 구체적이어야 하며, 최신 Hacker News 트렌드를 참고해야 해.”
이는 불필요한 토큰 소모를 유발합니다. 이를 해결하기 위해 MCP 서버 내에 프로젝트의 ‘아키텍처 설계서’나 ‘개발 가이드’를 리소스(Resource)로 통합하는 방법을 고려해볼 수 있습니다.
솔루션: 리소스 기반 메타데이터 제공
MCP 규격에서 Resources는 서버가 제공하는 데이터 조각입니다. 우리는 이를 단순한 파일 조회용이 아닌, **‘프로젝트 상태 머신(State Machine)’**으로 활용할 수 있습니다.
1. 아키텍처 문서 자동화
이전에 작성한 [ZeroClaw] 코드베이스 아키텍처 분석이나 [Multi-Agent] 파일 기반 아키텍처 설계와 같은 문서는 정적 파일로 존재하거나 Confluence 등에 흩어져 있을 수 있습니다. 이를 MCP 서버가 시작될 때 메모리에 로드하거나, 동적으로 생성하여 제공할 수 있도록 만듭니다.
2. Rust 구현 예제
Rust로 작성된 MCP 서버(예: blog-api-server)에 architecture_guide라는 리소스를 추가하는 코드를 작성해보겠습니다.
use jsonrpc_core::{Result, Params};
use std::collections::HashMap;
use serde_json::Value;
// 가상의 MCP 핸들러 구조체
pub struct BlogMcpServer {
// 캐싱된 메타데이터
cached_context: String,
}
impl BlogMcpServer {
pub fn new() -> Self {
// 서버 초기화 시 핵심 컨텍스트(아키텍처, 규칙)를 로드
let context = r#"
프로젝트: ZeroClaw Multi-Agent Runtime
아키텍처: 파일 기반 이벤트 버스를 사용하는 비동기 멀티 에이전트 시스템.
주요 규칙:
1. 모든 에이전트는 독립된 스레드에서 실행됨.
2. 통신은 JSON-RPC over MCP 프로토콜을 따름.
3. 로그는 구조화된 JSON 형식으로 출력해야 함.
"#;
Self { cached_context: context.to_string() }
}
// MCP 리소스 조회 핸들러 (resources/read)
pub fn handle_read_resource(&self, params: Params) -> Result<Value> {
let params_obj: HashMap<String, Value> = params.parse()?;
let uri = params_obj.get("uri").and_then(|v| v.as_str()).unwrap_or("");
match uri {
"context://architecture/guide" => {
// 클라이언트가 요청할 때 캐싱된 컨텍스트 반환
Ok(json!({
"contents": [
{
"uri": uri,
"mimeType": "text/plain",
"text": self.cached_context.clone()
}
]
}))
},
"context://trends/latest" => {
// 외부 RSS(Hacker News 등)를 실시간으로 페칭하여 제공 (동적 리소스)
let trends = fetch_latest_hn_trends().await.unwrap_or_default();
Ok(json!({
"contents": [{
"uri": uri,
"mimeType": "application/json",
"text": trends
}]
}))
},
_ => Err(Error::invalid_params("Unknown resource URI"))
}
}
}
async fn fetch_latest_hn_trends() -> Option<String> {
// 실제로는 reqwest 등을 사용하여 RSS를 파싱
// 예시를 위해 간단한 JSON 문자열 반환
Some(r#"[{"title": "JSON-LD Explained", "link": "..."}]"#.to_string())
}
이 코드는 MCP 클라이언트가 context://architecture/guide URI를 통해 리소스를 요청하면, 사전에 정의된 프로젝트의 아키텍처 규칙을 즉시 반환합니다.
3. 프롬프트 자동 주입 (Prompt Injection)
이제 클라이언트(Claude 등)가 복잡한 설정을 하지 않도록, MCP 서버의 Prompts 기능을 활용하여 시스템 프롬프트를 자동으로 완성해주는 템플릿을 제공할 수 있습니다.
MCP 서버는 다음과 같은 프롬프트 템플릿을 노출할 수 있습니다.
Prompt Name: generate_blog_post
Arguments: topic, tone
{
"name": "generate_blog_post",
"description": "Creates a technical blog post based on architecture context and latest trends.",
"arguments": [
{ "name": "topic", "description": "Main topic", "required": true },
{ "name": "tone", "description": "Writing style", "required": false }
]
}
실제 구현 로직(Rust)은 다음과 같이 작동합니다.
pub fn handle_get_prompt(&self, params: Params) -> Result<Value> {
let name = params.get("name").and_then(|v| v.as_str()).unwrap_or("");
let args = params.get("arguments").and_then(|v| v.as_object()).unwrap_or(&json!(null));
if name == "generate_blog_post" {
let topic = args.get("topic").unwrap_or(&json!("general"));
// 리소스에서 가져온 아키텍처 가이드를 프롬프트에 내장
let system_instruction = format!(
"You are writing for a blog defined by the following architecture:\n{}\n\nPlease write a post about: {}",
self.cached_context, // 앞서 로드한 아키텍처 정보
topic
);
Ok(json!({
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": system_instruction
}
}
]
}))
} else {
Err(Error::invalid_params("Unknown prompt"))
}
}
효과 및 기대 효과
이 접근 방식의 핵심은 **‘중복 제거(Duplication)’**입니다. Hacker News의 *Prefer duplication over the wrong abstraction*라는 글과 같이, 우리는 프로젝트의 본질을 단순화하기 위해 복잡한 추상화를 피하고, 대신 **필요한 정보(Context)를 필요한 곳(Prompt)에 통째로 복사(Duplication)**하여 넣습니다.
- 일관성 유지: 문서가 업데이트되면 MCP 서버만 재시작하거나 리소스를 갱신하면, 모든 세션에 최신 정보가 반영됩니다.
- 토큰 절약: 사용자가 매번 “내 프로젝트는 러스트로 짜여진 멀티 에이전트 시스템이야…“라고 설명할 필요가 없어집니다.
- 자동화 친화적: CI/CD 파이프라인에서 문서가 자동으로 생성되어 MCP 리소스로 등록되면, AI는 항상 최신 문서를 기반으로 코드를 생성하거나 리뷰할 수 있습니다.
결론
우리는 [ZeroClaw] 멀티 에이전트 아키텍처 설계안과 같은 문서를 단순히 ‘읽기용’으로 남겨두지 않고, 실행 가능한 AI의 뇌(Context)로 활용해야 합니다. MCP 서버에 이러한 메타데이터 동기화 계층을 추가하는 것은 복잡한 LLM 애플리케이션을 구축하기 위한 첫걸음이며, 개발자가 토큰을 낭비하지 않고 본질적인 로직에 집중하게 만드는 기반입니다.
다음 포스트에서는 이러한 메타데이터가 실제로 어떻게 Claude Code와 같은 팀 에이전트 통신 아키텍처에서 활용되는지 다루어보겠습니다.