Published on

AutoGPT에 MCP 붙여 툴 권한 최소화·안전 강화

Authors

서버/클라이언트가 분리된 에이전트 구조에서 보안 사고의 대부분은 모델이 아니라 툴(도구) 권한 설계에서 터집니다. AutoGPT가 파일을 읽고, 셸을 실행하고, 네트워크로 데이터를 보내는 순간부터 에이전트는 사실상 “자동화된 운영자”가 됩니다. 여기에 MCP(Model Context Protocol)를 붙이면 툴 호출이 표준화되는 장점이 있지만, 반대로 MCP 서버가 단일 실패 지점(single point of failure) 이 되기도 합니다.

이 글은 AutoGPT에 MCP를 연결할 때, 툴 권한을 최소화하고(least privilege) 안전장치를 강화하는 방법을 MCP 서버를 권한 경계로 삼는 관점에서 정리합니다. 핵심은 간단합니다.

  • AutoGPT는 “요청만” 하고, 실제 실행은 MCP 서버가 “정책에 따라” 수행한다
  • MCP 서버는 툴을 직접 제공하는 동시에 정책 엔진 + 감사 로깅 + 샌드박스 역할을 한다
  • 툴은 넓게 제공하지 말고, 업무 단위로 쪼개서 좁은 인터페이스로 제공한다

이미 AutoGPT 계열 샌드박스 권한 모델을 다룬 글이 있다면, 이번 글은 그 연장선에서 MCP라는 표준 레이어에 정책을 어떻게 녹일지에 집중합니다. 참고로 기존 권한 샌드박스 접근은 아래 글과 함께 보면 연결이 잘 됩니다.

왜 MCP를 “권한 경계”로 봐야 하나

MCP는 에이전트가 외부 리소스(파일, DB, SaaS, 내부 API 등)에 접근할 때, 컨텍스트와 툴 호출을 표준화하는 프로토콜입니다. 문제는 표준화가 곧 통합을 의미한다는 점입니다.

  • 툴 호출이 한 채널로 모이면, 정책을 넣기 좋은 지점이 생긴다
  • 동시에 그 채널이 뚫리면, “모든 툴”이 뚫린다

따라서 MCP 도입 시 보안 목표는 다음으로 정리됩니다.

  1. 권한 최소화: 툴이 할 수 있는 일을 원자적으로 줄인다
  2. 격리: 파일/네트워크/프로세스/자격증명을 분리한다
  3. 검증: 입력 스키마, 경로, 쿼리, URL을 강하게 검증한다
  4. 감사: 누가(어떤 에이전트가) 무엇을 언제 왜 했는지 남긴다
  5. 차단/승인: 위험 작업은 자동 실행하지 않고 승인 흐름을 둔다

설계 원칙: “툴을 API로 만들지 말고, 작업을 툴로 만들어라”

권한이 커지는 가장 흔한 실수는 “편의상 범용 툴”을 주는 겁니다.

  • shell.exec 같은 범용 실행기
  • fs.read 에 임의 경로 허용
  • http.request 에 임의 도메인 허용

이런 툴은 생산성은 좋지만, 보안 측면에서는 사실상 root 권한을 준 것과 다르지 않습니다.

대신 업무 단위(task-level) 로 툴을 쪼개면 권한을 자연스럽게 줄일 수 있습니다.

  • repo.searchCode (허용된 리포만, 읽기 전용)
  • docs.getPage (사내 위키 중 특정 스페이스만)
  • deploy.preview (프로덕션 배포 금지, 프리뷰만)
  • db.queryReadOnly (읽기 전용, 테이블 화이트리스트)

즉, “API를 그대로 노출”하지 말고 “업무를 수행하는 좁은 툴”을 제공해야 합니다.

아키텍처: AutoGPT는 얇게, MCP 서버는 두껍게

권장 구조는 다음과 같습니다.

  • AutoGPT(에이전트): 플래닝/추론/툴 호출
  • MCP 서버: 툴 제공 + 정책 집행 + 로깅 + 격리 실행
  • 실제 리소스: GitHub, DB, S3, 내부 서비스 등

여기서 중요한 포인트는 정책이 에이전트 코드에 있으면 안 된다는 점입니다. 에이전트는 언제든 프롬프트 인젝션이나 정책 우회 시도를 할 수 있습니다. 정책은 반드시 MCP 서버에 둬야 합니다.

구현 패턴 1: 툴 스키마를 “권한 모델”로 사용하기

MCP 툴 정의에서 입력 스키마를 강하게 잡으면, 에이전트가 애초에 위험한 형태로 요청하기 어렵습니다.

예를 들어 “파일 읽기”를 제공하더라도, 임의 경로를 받지 말고 허용된 루트 아래의 상대 경로만 받게 합니다.

// TypeScript 예시: 툴 입력을 상대 경로로만 제한
import path from "path";
import fs from "fs/promises";

const ALLOW_ROOT = "/srv/workspace";

function safeJoin(root: string, rel: string) {
  // rel에 절대경로, 상위 디렉터리 탈출이 섞이면 차단
  const resolved = path.resolve(root, rel);
  if (!resolved.startsWith(root + path.sep)) {
    throw new Error("path escape blocked");
  }
  return resolved;
}

export async function readWorkspaceFile(input: { relPath: string }) {
  const full = safeJoin(ALLOW_ROOT, input.relPath);
  return await fs.readFile(full, "utf-8");
}

이 패턴의 핵심은 fs.read 같은 범용 툴이 아니라 workspace.readFile 같이 “루트가 고정된” 툴로 만드는 겁니다.

체크리스트

  • 경로 입력은 절대경로 금지
  • .. 등 상위 이동 차단
  • 심볼릭 링크 우회 가능성 고려(필요하면 realpath 기반 검증)
  • 읽기/쓰기 툴 분리(읽기 전용을 기본값으로)

구현 패턴 2: 네트워크 이그레스(egress) 정책을 MCP에서 강제

에이전트 보안에서 가장 위험한 순간은 데이터가 외부로 나갈 때입니다. 따라서 http.request 같은 범용 네트워크 툴은 가능한 피하고, 불가피하다면 도메인 allowlist메서드 제한을 둬야 합니다.

# Python 예시: 허용 도메인만 호출하는 간단한 프록시
from urllib.parse import urlparse
import requests

ALLOW_HOSTS = {
    "api.github.com",
    "internal.example.com",
}

def safe_get(url: str, timeout_s: int = 10):
    u = urlparse(url)
    if u.scheme not in ("https",):
        raise ValueError("only https allowed")
    if u.hostname not in ALLOW_HOSTS:
        raise ValueError("host not allowed")

    # GET만 허용, 리다이렉트 제한
    r = requests.get(url, timeout=timeout_s, allow_redirects=False)
    r.raise_for_status()
    return r.text

여기서도 요지는 “범용 HTTP” 대신 “허용된 곳만 가는 HTTP”입니다.

추가로 넣으면 좋은 것

  • 응답 크기 제한(대용량 다운로드 차단)
  • 콘텐츠 타입 제한
  • DNS 리바인딩 방어(가능하면 고정 IP 또는 내부 프록시)
  • 요청/응답 전문 로깅 시 민감정보 마스킹

구현 패턴 3: 승인 게이트(approval gate)로 고위험 툴 분리

운영 환경에서 가장 현실적인 안전장치는 사람 승인입니다. 특히 다음은 자동 실행을 막는 게 좋습니다.

  • 금전/결제
  • 배포(프로덕션)
  • 데이터 삭제/스키마 변경
  • 외부로의 데이터 업로드

MCP 서버에서 툴을 두 종류로 나눕니다.

  • safe 툴: 자동 실행 가능
  • restricted 툴: 승인 토큰이 있어야 실행
// 승인 토큰이 없으면 실행 불가한 툴 게이트 예시

type ToolContext = {
  approvalToken?: string;
  actor: string;
};

function requireApproval(ctx: ToolContext) {
  if (!ctx.approvalToken) throw new Error("approval required");
  // 실제로는 토큰 서명 검증, 만료, 범위(scope) 확인
}

export async function prodDeploy(ctx: ToolContext, input: { version: string }) {
  requireApproval(ctx);
  // ... 배포 실행
  return { ok: True, version: input.version };
}

승인 흐름은 Slack 버튼, GitHub PR 코멘트, 내부 콘솔 등으로 붙일 수 있습니다. 중요한 건 “에이전트가 스스로 승인할 수 없게” 만드는 겁니다.

구현 패턴 4: 자격증명은 MCP 서버가 “짧고, 좁게” 발급

에이전트가 장기 토큰을 들고 있으면, 프롬프트 인젝션이나 로그 유출로 끝입니다. 권장 방식은 다음입니다.

  • 장기 자격증명은 MCP 서버(또는 Vault)에만 둔다
  • 에이전트 요청 시, MCP 서버가 짧은 TTL 의 임시 토큰을 발급하거나 프록시 호출을 수행한다
  • 토큰 스코프는 툴 단위로 최소화한다

AWS를 예로 들면, STS 기반 임시 자격증명과 잘 맞습니다. 운영에서 STS 만료/403 이슈를 겪는다면 아래 글이 진단에 도움됩니다.

구현 패턴 5: “감사 로그”는 관측이 아니라 억제 장치다

감사 로그는 사고 후 분석용이기도 하지만, 더 중요한 역할은 억제(deterrence) 입니다. 에이전트는 반복 실행을 쉽게 하므로, 작은 실수가 대규모 피해로 커집니다.

MCP 서버에서 최소한 아래를 구조화 로그로 남기세요.

  • tool name
  • input 요약(민감정보 마스킹)
  • 결과 요약(성공/실패, 영향 범위)
  • 실행 시간, 리트라이 횟수
  • actor(에이전트 인스턴스, 사용자 세션)
  • 정책 판정 결과(허용/차단/승인대기)

또한 “이상 징후” 기준을 정해 자동 차단을 걸 수 있습니다.

  • 동일 툴 초당 호출 수 제한
  • 동일 파일/테이블에 대한 과도한 접근
  • 외부 도메인 접근 시도 증가

구현 패턴 6: 샌드박스는 프로세스가 아니라 “행위”를 격리

컨테이너나 VM 샌드박스는 기본입니다. 하지만 에이전트 보안은 단순 격리로 끝나지 않습니다.

  • 파일 시스템 격리: 읽기 전용 마운트, 작업 디렉터리만 RW
  • 프로세스 격리: shell 자체를 없애거나, 허용 명령만 실행
  • 네트워크 격리: 기본 차단 후 필요한 목적지만 허용
  • 리소스 제한: CPU/메모리/디스크/실행 시간 제한

특히 “셸 실행”은 가능하면 제거하고, 꼭 필요하면 명령 화이트리스트 로 대체하세요.

# 예: 허용 명령만 실행하는 래퍼(개념 예시)
# 실제 운영에서는 인자 검증까지 포함해야 함

case "$1" in
  "git") exec /usr/bin/git "${@:2}" ;;
  "rg")  exec /usr/bin/rg "${@:2}" ;;
  *) echo "command not allowed"; exit 1;;
 esac

여기서도 핵심은 “범용 셸”이 아니라 “업무에 필요한 최소 커맨드”입니다.

운영 팁: 툴 경계는 DDD의 애그리게이트 경계처럼 다뤄라

툴 설계를 하다 보면, 결국 경계(boundary) 문제로 귀결됩니다. 범용 툴 하나가 여러 도메인을 가로지르면, 권한이 쉽게 비대해지고 정책이 복잡해집니다.

  • 하나의 툴이 너무 많은 리소스를 만지지 않게 쪼개기
  • 도메인별로 정책과 책임을 분리하기

이 관점은 DDD의 경계 설계와 유사합니다. 툴 경계가 자꾸 깨진다면 아래 글의 사고방식이 의외로 도움이 됩니다.

예시: AutoGPT + MCP에서 “리포지토리 읽기 전용 에이전트” 만들기

요구사항이 다음이라고 해보겠습니다.

  • 특정 GitHub 조직의 특정 리포만 읽기
  • 코드 검색과 파일 읽기만 허용
  • 외부 네트워크는 GitHub API만 허용
  • 쓰기(이슈 생성, PR 생성 등)는 금지

이때 툴은 아래처럼 설계합니다.

  • repo.listFiles(repo, path)
  • repo.readFile(repo, path)
  • repo.search(repo, query)

그리고 MCP 서버는 다음 정책을 강제합니다.

  • repo 값은 allowlist
  • path 는 상대 경로 + 탈출 차단
  • GitHub 토큰은 read-only scope
  • 호출량 제한(rate limit)
  • 모든 호출 감사 로그

이렇게 하면 AutoGPT는 “읽기 전용 분석가” 역할을 하며, 설령 프롬프트 인젝션으로 secrets 를 찾으려 해도

  • 허용된 리포 밖은 접근 불가
  • 허용된 경로 밖은 탈출 불가
  • 외부 업로드도 불가

로 피해를 크게 줄일 수 있습니다.

흔한 실패 사례

1) MCP 서버가 툴을 많이 제공하는데, 정책은 “나중에” 붙이려는 경우

처음엔 빨리 붙이려고 fs, shell, http 를 다 열어두고 시작합니다. 그리고 그 상태로 PoC가 운영에 들어갑니다. 이 순간부터 에이전트는 내부망에서 가장 위험한 자동화가 됩니다.

2) 정책을 프롬프트로 해결하려는 경우

“이 툴은 이런 용도로만 써” 같은 지시는 모델에게는 힌트일 뿐 강제력이 아닙니다. 강제는 MCP 서버에서 해야 합니다.

3) 감사 로그에 민감정보를 그대로 남기는 경우

로그는 또 다른 데이터 유출 경로입니다. 입력/출력 전문을 남기되, 토큰/키/개인정보는 마스킹 규칙을 먼저 만드세요.

결론: MCP는 생산성 레이어가 아니라 통제 레이어가 되어야 한다

AutoGPT에 MCP를 붙이면 툴 통합이 쉬워지고 에이전트가 강력해집니다. 하지만 그 강력함은 곧 위험이기도 합니다. 안전하게 쓰려면 다음 한 줄로 정리됩니다.

  • AutoGPT는 똑똑하게, MCP 서버는 엄격하게

툴을 범용으로 주지 말고 업무 단위로 좁히고, MCP 서버에서 스키마 검증, 이그레스 통제, 승인 게이트, 임시 자격증명, 감사 로그를 묶어 “권한 경계”를 세우면, 에이전트는 훨씬 안전한 자동화 동료가 됩니다.