본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 26. 19:55

우리는 MCP 서버를 구축했습니다. 왜 CLI가 더 중요한지에 대하여

요약

MCP(Model Context Protocol)가 제공하는 추상화 계층의 비용과 한계를 분석하고, 왜 CLI가 AI 에이전트 통합에 더 효과적인지 설명합니다. MCP의 프로토콜 방식이 가진 정보 손실 문제를 지적하며, 잘 설계된 CLI가 제공하는 발견성(Discovery)과 구조화된 데이터의 이점을 강조합니다.

핵심 포인트

  • MCP는 멀티 벤더 환경에 유용하지만 추상화 비용(Abstraction Tax)을 발생시킴
  • MCP 프로토콜 사용 시 스트리밍이나 복잡한 에러 구조 등 정보 손실(Fidelity loss) 발생 가능
  • 잘 설계된 CLI는 --help, JSON 응답 등을 통해 에이전트에게 높은 충실도 제공
  • 단일 파이프라인 환경에서는 MCP보다 CLI가 더 효율적인 통합 접점이 될 수 있음

ThoughtWorks Technology Radar Volume 32는 "MCP 기본 적용(MCP by default)"을 Caution(주의) 영역에 배치했습니다. 그들의 논거는 명확합니다. MCP는 구조화된 도구 계약(tool contracts), OAuth 기반의 인증 경계(authentication boundaries), 그리고 관리되는 멀티 테넌트 액세스(governed multi-tenant access)에 실질적인 가치를 더합니다. 하지만 또한 Justin Poehnelt가 말하는 "추상화 비용(abstraction tax)"을 발생시킵니다. 에이전트(agent)와 API 사이의 모든 프로토콜 계층은 충실도(fidelity)를 잃게 되며, 복잡한 API의 경우 이러한 손실은 복리로 쌓입니다.

Simon Willison은 이를 더욱 날카롭게 지적합니다: "MCP로 달성할 수 있는 거의 모든 것은 대신 CLI 도구로 처리할 수 있습니다."

우리는 Stave라고 불리는 오픈 소스 클라우드 보안 추론 엔진(cloud security reasoning engine)을 구축하고 있습니다. 우리에게는 MCP 서버가 있습니다. 또한 CLI도 있습니다. 그리고 실제로 중요한 통합 접점(integration surface)은 바로 CLI입니다. 그 이유와, 이 결정을 쉽게 만들어준 아키텍처 패턴에 대해 설명하겠습니다.

실전에서의 추상화 비용 (The abstraction tax in practice)

MCP는 프로토콜(protocol)입니다. 이는 탐색(discovery, 어떤 도구가 존재하는지), 호출(invocation, 특정 파라미터로 이 도구를 호출), 그리고 전송(transport, stdio, SSE, HTTP)을 처리합니다. 서로 다른 팀이 관리하는 여러 서버에 걸쳐 도구를 동적으로 찾아 사용해야 하는 AI 에이전트에게 이는 진정한 가치를 제공합니다. 탐색 문제 하나만으로도 멀티 벤더(multi-vendor) 환경에서 이 프로토콜의 정당성은 충분합니다.

하지만 대부분의 도구는 멀티 벤더 환경에 있지 않습니다. 대부분의 도구는 하나의 파이프라인(pipeline) 내에서 하나의 에이전트에 의해 호출되며, 하나의 작업만을 수행합니다. 그런 경우 MCP는 직접 통신할 수 있었던 두 시스템 사이의 번역 계층(translation layer)에 불과합니다.

충실도 손실(fidelity loss)은 실재합니다. MCP 도구 스키마는 JSON Schema를 사용하는데, 이는 파라미터 타입을 표현하기에는 충분히 풍부하지만 스트리밍 출력(streaming output), 진행 상태 표시기(progress indicators), 구조화된 에러 계층(structured error hierarchies)과 같은 요소들을 다루기에는 정보 손실이 발생합니다. 반면 CLI는 status 필드가 포함된 JSON 객체, 구조화된 에러 코드가 담긴 errors 배열, 그리고 타입화된 도메인 객체가 담긴 findings 배열을 하나의 예측 가능한 출력으로 내보낼 수 있습니다. MCP 도구는 텍스트 블록으로 구성된 content 배열을 반환합니다. 에이전트는 구조를 추출하기 위해 해당 텍스트를 파싱(parse)해야만 합니다. 모든 파싱 과정은 충실도의 경계가 됩니다.

잘 설계된 CLI가 에이전트에게 무료로 제공하는 것들

ThoughtWorks는 "훌륭한 --help 출력, 구조화된 JSON 응답, 그리고 예측 가능한 에러 핸들링 (error handling)"을 언급합니다. 이는 자세히 살펴볼 가치가 있는데, 이러한 각 속성들은 MCP가 프로토콜 (protocol)을 통해 제공하려고 노력하는 요소들과 대응되지만, CLI는 관습 (convention)을 통해 제공하기 때문입니다.

발견 (Discovery). MCP에는 tools/list가 있습니다. CLI에는 --helpman 페이지가 있습니다. AI 에이전트 (AI agent)에게 stave --help는 모든 서브커맨드 (subcommand), 플래그 (flag), 그리고 출력 형식에 대한 구조화된 설명을 생성합니다. 에이전트는 이를 한 번 읽으면 됩니다. 핸드셰이크 (handshake), 전송 협상 (transport negotiation), 기능 교환 (capability exchange)이 필요 없습니다.

호출 (Invocation). MCP에는 JSON 파라미터 (parameters)를 사용하는 tools/call이 있습니다. CLI에는 플래그와 인자 (arguments)가 있습니다. stave evaluate --snapshot ./snapshot.json --format json은 하나의 셸 (shell) 명령입니다. 에이전트는 도움말 출력을 바탕으로 이를 구성합니다. 직렬화 계층 (serialization layer)이나 전송 인코딩 (transport encoding)이 필요 없습니다.

출력 (Output). MCP는 content 블록을 반환합니다. CLI는 표준 출력 (stdout)에 기록합니다. stave evaluate는 문서화되고, 버전이 관리되며, JSON 스키마 (JSON Schema)로 검증된 구조를 가진 JSON 파일인 out.v0.1.json을 생성합니다. 에이전트는 이 파일을 읽습니다. MCP 콘텐츠 블록을 파싱 (parsing)하거나 프로토콜 래퍼 (protocol wrappers)에서 텍스트를 추출할 필요가 없습니다.

에러 핸들링 (Error handling). MCP는 JSON-RPC 엔벨로프 (envelope) 내에 에러 코드 (error codes)를 가집니다. CLI에는 종료 코드 (exit codes)와 표준 에러 (stderr)가 있습니다. 종료 코드 0은 성공을 의미하고, 종료 코드 1은 평가 실패를, 종료 코드 2는 잘못된 입력을 의미합니다. 표준 에러 (stderr)는 사람이 읽을 수 있는 메시지를 전달하고, 표준 출력 (stdout)은 기계가 읽을 수 있는 출력을 전달합니다. 명확한 분리가 이루어지며 프로토콜 오버헤드 (protocol overhead)가 없습니다.

계약 우선 패턴 (The contract-first pattern)

우리의 결정을 쉽게 만들어준 아키텍처적 통찰 (architectural insight)은 다음과 같습니다.

Stave의 통합 접점 (integration surface)은 CLI도 아니고 MCP 서버도 아닙니다. 그것은 바로 계약 (contract)인 out.v0.1.json입니다. 이것은 문서화된 스키마 (JSON Schema Draft 2020-12)를 가진 JSON 파일로, SchemaOutput 상수에 의해 버전이 관리되며, 런타임 (runtime)에 검증되고, 릴리스 (release) 전반에 걸쳐 안정적으로 유지됩니다. 모든 발견 사항, 모든 통제 판정 (control verdict), 모든 복합 위험 체인 (compound risk chain)은 이 파일에 존재합니다.

CLI가 계약(contract)을 생성합니다. MCP 서버 또한 계약을 생성합니다. Steampipe 플러그인이 계약을 읽습니다. Powerpipe 모듈이 계약을 읽습니다. Flowpipe 파이프라인이 계약을 읽습니다. 계약은 통합 표면(integration surface)입니다. 그 외의 모든 것 — CLI, MCP, SQL, HCL — 은 이를 감싸는 전송 계층(transport)일 뿐입니다.

이것이 ThoughtWorks가 암묵적으로 권장하는 패턴입니다:

                    ┌── CLI (직접적)
                    │
Contract (JSON) ────┼── MCP server (프로토콜)
...

계약이 먼저였습니다. 전송 계층은 그다음이었습니다. 만약 계약을 잘 설계한다면 — 안정적인 스키마(schema), 버전 관리, 검증, 문서화 — MCP를 추가하는 것은 얇은 래퍼(wrapper)를 씌우는 작업일 뿐, 재설계(re-architecture)가 아닙니다. 또한 MCP를 제거하더라도 시스템의 통합 능력에는 아무런 변화가 없습니다. 계약은 살아남습니다.

만약 MCP를 중심으로 먼저 설계한다면, 프로토콜이 곧 계약이 되어버리며, 모든 소비자(consumer)를 그들이 필요로 하지 않을 수도 있는 전송 계층에 결합(coupling)시키게 됩니다.

MCP가 제 역할을 하는 경우

이 모든 내용이 MCP가 틀렸다는 뜻은 아닙니다. ThoughtWorks의 말대로 MCP는 특정 사례에서 실질적인 가치를 더한다는 점은 맞습니다:

멀티 테넌트 액세스 거버넌스 (Multi-tenant access governance). MCP 서버가 사용자별 OAuth 스코프(scope)를 사용하여 공유 리소스에 대한 액세스를 중재할 때, 프로토콜 경계는 실질적인 역할을 수행합니다. 즉, 단순한 전송 계층이 아니라 인가(authorization) 계층으로서 작동합니다. CLI는 동일한 경계를 다시 구현하지 않고서는 이를 수행할 수 없습니다.

조직 간 동적 도구 발견 (Dynamic tool discovery across organizations). 에이전트가 이전에 본 적 없는 도구를 발견해야 하거나, 협업 관계가 없는 팀에서 발행한 도구를 찾아야 할 때, MCP의 tools/list + 스키마(schema) 메커니즘은 적절한 기본 요소(primitive)가 됩니다. CLI의 --help 출력은 이미 알고 있는 도구에는 작동하지만, MCP는 알지 못하는 도구에 대해서도 작동합니다.

호스팅된 상태 유지 서비스 (Hosted, stateful services). 도구가 호출자(caller)에 의해 관리되어서는 안 되는 서버 측 상태(세션, 캐시, 연결)를 유지해야 하는 경우, MCP의 서버 생명주기(lifecycle)가 유효합니다. CLI는 설계상 상태가 없는(stateless) 방식이지만, 만약 당신의 도구가 상태를 유지해야 한다면 MCP가 그 상태 유지(statefulness)를 관리합니다.

Stave의 경우, AI 에이전트 플랫폼(Claude Desktop, Cursor, Windsurf)이 MCP를 네이티브하게 지원하기 때문에 MCP 서버를 구축했습니다. 만약 에이전트가 쉘 명령(shell command)을 직접 구성하지 않고 "이 AWS 스냅샷의 보안 태세(security posture)는 어떠한가?"라고 묻고 싶다면, MCP 서버가 이를 처리합니다. 이것은 실제 사용 사례(use case)이지만, 이는 계약(contract) 위에 얹어진 편의 계층(convenience layer)일 뿐, 통합 아키텍처(integration architecture) 그 자체는 아닙니다.

올바른 질문 던지기

MCP를 사용하기 전에 세 가지 질문을 던져보십시오.

소비자(consumer)가 도구에 대해 미리 알고 있는가? 만약 그렇다면 — 즉, 특정 도구를 호출하는 파이프라인을 구축하고 있다면 — CLI 호출이 더 단순하고 빠르며 충실도(fidelity)의 손실도 없습니다. MCP의 발견 메커니즘(discovery mechanism)은 당신에게 존재하지 않는 문제를 해결하려 하는 것입니다.

상호작용에 서버 측 상태(state)나 권한 부여(authorization)가 필요한가? 만약 그렇다면 — OAuth 경계, 지속적인 세션(persistent session), 또는 사용자별 스코핑(per-user scoping)이 존재한다면 — MCP의 프로토콜 생명주기(protocol lifecycle)가 제 역할을 다할 것입니다. CLI는 이러한 경계를 직접 다시 구현해야 할 것입니다.

계약(contract)이 전송 계층(transport)과 독립적으로 문서화되고 버전 관리되고 있는가? 만약 그렇지 않다면 — 도구가 무엇을 생성하는지 알 수 있는 유일한 방법이 MCP 도구 스키마(tool schema)를 읽는 것뿐이라면 — 해당 도구는 프로토콜에 결합(coupled)된 것입니다. 계약을 먼저 문서화하십시오. 파일, 스키마, 또는 아티팩트(artifact)로 만드십시오. 그런 다음 이를 MCP로 감쌀지, CLI로 감쌀지, 둘 다 사용할지, 아니면 둘 다 사용하지 않을지 결정하십시오.

살아남는 설계는 다음과 같습니다: 계약 우선(contract-first), 프로토콜 차선(protocol-second).

Stave는 구성 스냅샷을 안전 불변량(safety invariants) — 즉, JSON Schema로 검증된 사실(facts)에 대한 CEL 술어(predicates) — 에 대해 평가하는 오픈 소스 클라우드 보안 추론 엔진입니다. 출력 계약(out.v0.1.json)은 CLI, MCP, Steampipe, Powerpipe, 그리고 Flowpipe에서 소비됩니다. GitHub에서 별(Star)을 눌러주세요.

ThoughtWorks Technology Radar Vol 32, "MCP by default" — 전체 항목

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0