본문으로 건너뛰기
← Blog

MCP 서버를 실무에 붙이면서 배운 것들

사내 데이터를 에이전트에 연결할 때 툴을 몇 개로 쪼갤지, 권한을 어디서 막을지, 실패를 어떻게 돌려줄지에 대한 실전 기록.

3분 분량연재: AI 개발 파이프라인

에이전트에 사내 데이터를 붙이는 방법은 여러 가지가 있지만, 도구 정의를 표준화해두면 나중에 모델이나 클라이언트를 바꿔도 그대로 씁니다. MCP(Model Context Protocol)를 실무에 넣으면서 겪은 것들을 정리합니다.

툴은 잘게 쪼개는 쪽이 낫다

처음에는 queryDatabase(sql) 하나로 시작했습니다. 유연하고 코드도 짧았습니다. 그리고 문제가 바로 나왔습니다.

  • 모델이 잘못된 SQL을 만들면 에러 메시지만 보고 고쳐야 하는데, 몇 번씩 왕복합니다
  • 권한 제어를 SQL 파싱으로 해야 합니다. 실질적으로 불가능합니다
  • 어떤 데이터에 접근했는지 로그로 남기기 어렵습니다

목적별로 쪼갠 뒤 전부 해결됐습니다.

ts
// 하나의 만능 툴 대신
server.tool("searchOrders", {
  description: "주문을 조건으로 검색합니다. 최대 100건 반환.",
  inputSchema: {
    customerId: z.string().optional(),
    status: z.enum(["pending", "paid", "shipped", "cancelled"]).optional(),
    from: z.string().describe("ISO 날짜"),
    to: z.string().describe("ISO 날짜"),
  },
}, handler);

권한은 MCP 서버 안에서 막는다

에이전트에게 "고객 개인정보는 조회하지 마"라고 프롬프트로 지시하는 건 보안이 아닙니다. 프롬프트는 요청이고, 코드는 보장입니다.

권한 체크는 툴 핸들러 안에서 합니다.

ts
async function handler(args, { session }) {
  if (!session.can("orders:read")) {
    return { isError: true, content: [{ type: "text",
      text: "권한이 없습니다. 관리자에게 orders:read 권한을 요청하세요." }] };
  }
  const rows = await db.orders.find(args);
  return { content: [{ type: "text", text: formatAsTable(rows) }] };
}

실패는 모델이 고칠 수 있게 돌려준다

에러 응답을 그냥 스택 트레이스로 던지면 모델이 같은 실수를 반복합니다. 다음 행동을 알려주는 문장으로 바꿔주면 대부분 한 번에 복구합니다.

diff
- Error: ER_BAD_FIELD_ERROR: Unknown column 'order_date'
+ 'order_date' 컬럼이 없습니다. 사용 가능한 날짜 컬럼: created_at, paid_at, shipped_at

이 한 줄 차이로 재시도 횟수가 눈에 띄게 줄었습니다.

반환량을 제한한다

컨텍스트 윈도우는 유한합니다. 3천 건을 그대로 돌려주면 토큰을 다 쓰고 정작 추론할 여유가 없습니다.

  • 기본 상한을 두고 (예: 100건), 초과 시 총 3,241건 중 100건 같은 안내를 붙입니다
  • 집계로 답할 수 있는 질문은 집계 툴을 따로 만듭니다 (countOrders)
  • 긴 텍스트는 요약본과 원문 조회 툴을 분리합니다

정리

  • 만능 툴 하나보다 목적별 툴 여러 개가 권한·로깅·정확도 모두에서 낫습니다
  • 권한은 프롬프트가 아니라 핸들러 코드에서 막습니다
  • 에러는 다음 행동을 알려주는 문장으로 돌려줍니다
  • 반환량 상한을 두고, 집계는 별도 툴로 뺍니다

MCP 자체는 얇은 규약입니다. 어려운 부분은 프로토콜이 아니라 무엇을 툴로 노출할지 정하는 설계에 있습니다.

댓글 & 토론

Powered by GitHub Discussions

GitHub Discussions 댓글 시스템 준비 중

GitHub 저장소에서 Discussions 기능을 활성화하고 Giscus를 연동하면 방문자가 GitHub 계정으로 댓글을 남길 수 있습니다.