블로그 • AI / Agent

Claude Managed Agents 2026 새 기능 해설: AI Agent는 Tool Call 허용 여부를 어떻게 자동 판단하는가? JSON permission policy와 MCP Security 완전 튜토리얼

2026년 9월 10일 Anthropic은 Claude Managed Agents의 권한 정책에 새 유형을 더했다:auto. 같은 날 agent.tool_use와 agent.mcp_tool_use 이벤트는 evaluation 필드를 갖기 시작했고, 기존 evaluated_permission과 나란히 둔다.

모델이 Tool Call을 냈다고 해서 이번 호출이 실행되는 것은 아니다. 실제로 결정하는 것은 서버의 정책 평가다. Agent 설정에 넣은 JSON policy를 읽고, 이번 호출의 도구 이름, 입력, 세션 내용으로 allow, deny 또는 ask를 낸다.

이 글에서는:

이것만 기억하라: auto는 「전부 열림」도, 사람 승인도 아니다. 서버가 안전하다고 보면 당신이 보기 전에 호출이 끝난다. 고위험이면 클라이언트는 deny를 뒤집을 기회조차 없다. 아래는 「세 정책 → 호출마다 평가 → 이벤트 JSON → MCP → 승인 흐름」으로 가른다.

세 정책: always_allow, always_ask, auto

Permission policy는 서버가 대신 실행하는 도구만 본다: 내장 agent_toolset_20260401, 그리고 당신이 붙인 MCP toolset. 커스텀 도구는 앱이 실행하며 이 정책을 타지 않는다. 요청에는 beta 헤더 managed-agents-2026-04-01가 필요하다. 공식 설명은

Claude Managed Agents Permission policies.

정책이 정하는 것은 「이번 호출을 언제 돌릴지」이지, 「이 도구가 목록에 있는지」가 아니다. Agent에서 도구를 빼려면 disable을 쓴다. 정책이 도구를 숨겨 주길 기대하지 마라.

정책 서버가 하는 일 클라이언트가 더 할 일
always_allow 바로 실행하고, 사람을 기다리지 않는다 이벤트를 읽으면 된다. 확인 단계는 없다
always_ask tool_use 이벤트를 낸 뒤 멈춘다 막힌 이벤트마다 user.tool_confirmation
auto 이번 호출을 평가한다: 돌리거나, 거절하거나, 멈추고 묻는다 결과가 ask인 이벤트만 처리한다. deny는 뒤집지 못한다

기본값은 양쪽이 다르다. Agent toolset 기본은 always_allow. MCP toolset 기본은 always_ask. 어떤 toolset도 기본으로 auto를 켜지 않는다. JSON에 직접 써야 한다.

이미 도는 session은 만들 때 받은 그 toolset 설정을 쓴다. Agent를 바꾼 뒤, 새 session부터 새 정책이 적용된다. 릴리스 노트는

Claude Platform release notes(2026-09-10).

auto가 실제로 보는 것

이전에는 「이 도구는 항상 통과」 또는 「이 도구는 항상 사람에게 묻기」만 있었다. auto는 판단을 도구 단위에서 호출 단위로 옮긴다.

공식 문장은 구체적이다. 평가는 도구 자체, 이번 input, 지금까지의 세션을 본다. 그래서 같은 bash라도 서로 다른 command이면 하나는 allow, 하나는 deny일 수 있다.

  1. 1
    호출이 통과한다

    서버가 이번은 안전하다고 보고, 도구는 always_allow처럼 실행된다. 일시 정지도, 사람 창도 없다.

  2. 2
    호출이 거절된다

    서버가 고위험으로 보고, 도구는 돌지 않는다. Agent는 오류 tool result를 받는다: Permission to use {tool_name} has been denied., 그리고 is_error: true. 세션은 이어진다. 클라이언트는 이 deny를 바꿀 수 없다.

  3. 3
    호출이 멈추고 당신을 기다린다

    서버가 확정 결론을 내지 못하면, 세션은 always_ask처럼 일시 정지한다. 확인 이벤트로 통과시키거나 거절한다.

의도는 당신이 보낸 user.message에서만 읽는다. 도구 결과, 가져온 웹 페이지, MCP Server 반환, 스레드 사이 메시지는 서버가 내용을 평가하지만 지시로 쓰지 않는다. 어떤 호출은 누가 말해도 고위험이다.

신뢰할 수 없는 최종 사용자 원문을 그대로 user.message에 넣으면, 서버도 그것을 당신 의도로 보고 호출을 통과시킬 수 있다. 이런 입구의 도구는 따로 always_ask를 둔다.

정책이 들어가는 JSON 구간

정책은 두 곳에 있다. toolset의 default_config.permission_policy, 그리고 configs에서 한 도구의 덮어쓰기. 아래 설정은 Agent toolset과 GitHub MCP를 모두 auto로 두고, bash만 always_ask로 고정한다.

Agent를 만들 때의 tools 설정(공식 문서에서 발췌)
{
  "name": "Ops Agent",
  "model": "claude-opus-5",
  "mcp_servers": [
    {
      "type": "url",
      "name": "github",
      "url": "https://mcp.example.com/github"
    }
  ],
  "tools": [
    {
      "type": "agent_toolset_20260401",
      "default_config": {
        "permission_policy": { "type": "auto" }
      },
      "configs": [
        {
          "name": "bash",
          "permission_policy": { "type": "always_ask" }
        }
      ]
    },
    {
      "type": "mcp_toolset",
      "mcp_server_name": "github",
      "default_config": {
        "permission_policy": { "type": "auto" }
      }
    }
  ]
}

mcp_server_name는 mcp_servers의 해당 항목 name와 맞아야 한다. MCP 쪽에서 도구 이름으로 덮을 때 name는 Server가 보고한 도구 이름이지, 당신이 붙인 별명이 아니다.

default_config를 생략하면 Agent toolset은 always_allow로 켜진다. 편한 기본값이지, 안전한 기본값이 아니다.

호출마다 남는 evaluation

정책이 무엇이든 agent.tool_use와 agent.mcp_tool_use는 최상위 필드 evaluated_permission를 가지며, 값은 allow, ask 또는 deny이다. 대부분의 이벤트는 evaluation 객체를 더 두고, type로 어느 정책이 결론을 냈는지 표시한다.

auto에서는 객체에 서버 판정도 쓴다. 결과가 ask 또는 deny면 reason_code도 붙는다. 공식 예: bash가 auto를 타고, 고위험 호출이 거절된다.

auto가 거절한 agent.tool_use 이벤트
{
  "type": "agent.tool_use",
  "id": "sevt_01pqr...",
  "name": "bash",
  "input": {
    "command": "rm -rf /workspace/reports"
  },
  "evaluated_permission": "deny",
  "evaluation": {
    "type": "auto",
    "evaluated_permission": {
      "type": "deny",
      "reason_code": "high_risk"
    }
  },
  "processed_at": "2026-03-25T14:05:12Z"
}
evaluation 최상위 결과 의미
{"type":"always_allow"} allow 해석된 정책이 always_allow이고, 호출은 이미 실행됐다
{"type":"always_ask"} ask 해석된 정책이 always_ask이고, 세션이 당신을 기다린다
{"type":"auto","evaluated_permission":{"type":"allow"}} allow auto가 이번은 안전하다고 보고, 이미 돌렸다
{"type":"auto","evaluated_permission":{"type":"ask","reason_code":"indeterminate"}} ask auto가 결론을 내지 못해, 멈추고 묻는다
{"type":"auto","evaluated_permission":{"type":"deny","reason_code":"high_risk"}} deny auto가 고위험으로 보고, 이미 거절했다

reason_code는 클라이언트 분기와 감사 로그용이지, 사람용 문장이 아니다. 공식이 지금 밝힌 값은 indeterminate와 high_risk이다. 클라이언트는 나중에 더해질 type나 reason_code를 견뎌야 한다.

다음 두 경우에는 evaluation가 없다. Agent가 세션에 켜지지 않은 도구를 고르면 이벤트에는 evaluated_permission: "deny"만 있다. 필드가 생기기 전에 기록된 옛 이벤트에도 없다. 그때 allow는 always_allow로, ask는 always_ask로 읽는다.

이것은 「JSON이 보안 경계」와 같은 층이지만 절개면이 다르다. 그쪽은 모델이 낸 arguments를 먼저 검증해야 한다고 말한다. 이쪽은 플랫폼이 평가 결과를 다시 쓰고, 그 결과는 당신이 뒤집지 못한다고 말한다. 앞 글은

AI Agent와 JSON 보안 경계.

MCP Tool Call과 기본 always_ask

MCP는 도구 목록을 당신 저장소에서 바깥 Server로 옮긴다. Server는 JSON-RPC로 tool을 노출하고, 각 tool은 inputSchema를 가진다. Host는 목록을 모델에 넣고, 모델의 호출을 tools/call로 바꾼다. 규격은

MCP Tools.

Managed Agents는 이 일에 보수적이다. MCP toolset 기본은 always_ask. 이미 이은 Server에 새 도구가 더해져도 앱에서 몰래 실행되지 않는다. 이것이 플랫폼 쪽에 내려앉는 MCP Security의 첫 문이며, 「Server의 description을 믿는다」보다 낫다.

바꿀 수는 있다. 어떤 GitHub MCP를 신뢰하고 덜 끊고 싶다면, 그 toolset의 default_config.permission_policy를 always_allow 또는 auto로 바꾼다. 바꾸는 것은 「언제 실행할지」이지, 「Schema를 더 검증할지」가 아니다.

층 답하는 것 답하지 않는 것
JSON Schema 인자 필드, 타입, 필수, 열거가 맞는가 이번 호출이 일어나야 하는가
Tool Calling 모델이 고른 도구와 채운 arguments Host가 실행할 것인가
permission policy 이번 호출의 allow / ask / deny payload가 schema에 맞는지, description이 모델을 끌어당겼는지

세 층을 겹쳐야 문처럼 보인다. auto만 켜고 Schema가 여전히 {"sql":{"type":"string"}}이면, 평가기가 보는 입력 면이 너무 넓어 판단하지 못하고, 더 많은 호출이 indeterminate, 곧 ask로 떨어진다. schema를 조이는 것은 auto가 로그에 쓸 결론을 내도록 돕는 일이다. 누가 어느 층을 맡는지는

MCP 보안: Schema, Tool Calling, 권한은 왜 서로를 대신하지 못하는가.

ask 이후의 JSON 승인 흐름

호출이 ask가 되는 길은 두 가지뿐이다. always_ask, 또는 auto의 indeterminate. 이후 이벤트 순서는 고정이다.

  1. 1
    먼저 tool_use 이벤트

    세션이 agent.tool_use 또는 agent.mcp_tool_use를 내고, 이미 evaluated_permission: "ask"가 들어 있다.

  2. 2
    이어서 idle

    세션이 멈추고, session.status_idle의 stop_reason.type는 requires_action이다. 막힌 이벤트 id는 stop_reason.event_ids에 있다. 계속 기다린다.

  3. 3
    확인 이벤트를 보낸다

    막힌 id마다 user.tool_confirmation를 보내고, tool_use_id에는 그 이벤트 id, result에는 allow 또는 deny를 넣는다. 거절할 때는 deny_message로 설명할 수 있다. 한 요청에 확인을 여러 개 담을 수 있다.

  4. 4
    세션이 running으로 돌아온다

    막힌 것이 모두 풀리면 허용된 도구는 실행되고, 거절된 것은 돌지 않는다. Agent는 당신의 deny_message가 붙은 tool result를 받는다.

대기 중인 호출을 허용하거나 거절하기
{
  "events": [
    {
      "type": "user.tool_confirmation",
      "tool_use_id": "sevt_01ask...",
      "result": "allow"
    },
    {
      "type": "user.tool_confirmation",
      "tool_use_id": "sevt_01mcp...",
      "result": "deny",
      "deny_message": "Do not push to main from this session."
    }
  ]
}

이벤트의 evaluated_permission가 ask가 아닌데 확인을 내면 API는 400을 돌려준다. auto가 이미 deny한 호출도 여기 들어간다. 클라이언트에 재심 통로는 없다. 대화형 처리는 ant beta:sessions connect로 할 수 있다. 터미널에서 대기 중인 호출을 보고 허용하거나 거절한다.

승인 큐를 직접 만들고, deny를 Agent에 되돌리고, Host에 재생 가능한 정책을 남기는 일은 다음 구현 편으로 미룬다. 이 글은 플랫폼이 이미 평가해 둔 그 JSON만 분명히 한다.

auto는 검문점이 아니다

공식 문서에 건너뛰면 안 되는 문장이 있다. auto는 사람 검문점이 아니다. 서버가 안전하다고 보면 누구든 보기 전에 호출이 실행되고, 효과는 되돌리지 못할 수 있다. 사람이 봐야 하는 도구에는 always_ask를 둔다.

커스텀 도구도 이 문 밖에 있다. agent.custom_tool_use에는 evaluated_permission도, evaluation도 없다. 앱이 이벤트를 받고 실행 또는 거절을 정한 뒤 user.custom_tool_result를 돌려준다. 플랫폼은 이 홉을 대신 평가하지 않는다.

그래서 「AI Agent는 Tool Call 허용 여부를 어떻게 자동 판단하는가」의 범위는 좁다. 서버가 대신 실행하는 Agent 도구와 MCP 도구만 덮고, 당신이 policy를 명시적으로 auto로 쓴 뒤에만 해당한다. 나머지는 항상 통과이거나, 항상 사람에게 묻거나, 플랫폼 밖이다.

JSONNote로 정책과 이벤트를 대조하기

정책 JSON, tool_use 이벤트, 확인 요청은 생김새는 닮았지만 필드 층이 다르다. 디버그할 때 눈으로 훑지 마라.

  1. 1
    먼저 정책을 포맷한다

    Agent의 tools 설정을 JSON 포맷터에 넣고, default_config와 configs의 permission_policy.type가 틀리지 않았는지, 덮어쓰기에 먹히지 않았는지 확인한다.

  2. 2
    이어서 이벤트 모양을 검증한다

    JSON Schema로 evaluation의 최소 schema를 쓴다. type 열거는 always_allow / always_ask / auto. auto일 때는 중첩 evaluated_permission를 필수로 한다. 모르는 reason_code는 additionalProperties로 호환하고, 바로 거절하지 않는다.

  3. 3
    두 호출을 비교한다

    같은 도구가 하나는 허용, 하나는 거절이면 JSON Diff로 두 번의 input와 두 번의 evaluation를 맞춘다. 차이는 거의 항상 command, path, 또는 세션에서 방금 일어난 한 걸음이지, 도구 이름이 아니다.

  4. 4
    공유할 수 있는 회고를 남긴다

    정책과 마스킹한 이벤트는 Hash 공유로 동료에게 넘긴다. 데이터는 서버를 지나지 않는다. 키와 프로덕션 token은 넣지 마라.

자주 묻는 질문

auto는 모든 Tool Call을 통과시키는가?

아니다. auto는 호출마다 평가한다. 같은 도구라도 입력과 세션이 다르면 결과가 다를 수 있다. high_risk면 바로 deny이고, 클라이언트는 user.tool_confirmation으로 뒤집지 못한다.

JSON Schema가 합법이면 실행해도 되는가?

아니다. Schema는 인자 모양이 맞는지만 답한다. permission policy는 이번 호출을 돌려도 되는지를 답한다. 모양이 맞는 bash 명령도 auto가 deny로 쓸 수 있다.

MCP Tool Call은 기본으로 어느 정책을 타는가?

MCP toolset 기본값은 always_ask다. Server에 새 도구가 들어와도 앱에서 자동 실행되지 않는다. 그 Server를 신뢰한 뒤에 default_config.permission_policy를 always_allow 또는 auto로 바꾼다.

커스텀 도구도 permission policy의 대상인가?

아니다. Custom tools는 앱이 실행한다. 이벤트는 agent.custom_tool_use이고, evaluated_permission과 evaluation이 없다. 돌릴지 당신이 정한 뒤 user.custom_tool_result를 돌려준다.

auto가 사람 승인을 대신할 수 있는가?

없다. 공식 문서는 auto가 사람 검문점이 아니라고 쓴다. 서버가 안전하다고 보면, 누구든 보기 전에 호출이 실행되고 부작용은 되돌리지 못할 수 있다. 사람이 봐야 하는 도구는 always_ask를 따로 둔다.

요약

9월 10일에 더해진 auto는 「이 도구를 쓸 수 있는가」를 「이번 호출을 돌려도 되는가」로 바꿨다. 판단 근거는 Agent에 넣은 JSON policy와 이번 도구, 입력, 세션이다. 결과는 이벤트의 evaluated_permission와 evaluation에 다시 쓴다.

모델은 호출을 제안한다. 정책 엔진은 허용, 거절, 또는 멈추고 사람에게 묻기를 맡는다. MCP는 기본으로 먼저 묻는다. 커스텀 도구는 당신이 맡는다. 클라이언트는 deny를 뒤집지 못한다.

정책 JSON과 이벤트 JSON을 두 계약으로 읽어라. Schema가 합법하다고 이미 인가된 것으로 보지 마라. 사람이 지켜야 하는 도구는 계속 always_ask. 덜 끊기면서 감사 필드를 남기고 싶은 도구에만 auto를 연다.

← 블로그로