정책
영어 원문 -- 번역은 기술 검토 대기 중입니다
Supported modes: Hosted Hybrid Local Available in: Free Solo Teams (audit retention is a configured window by tier: Free 7 days, Solo 90 days, Teams 365 days, see Feature Availability)
정책은 AI 에이전트가 할 수 있는 일과 할 수 없는 일을 정하는 규칙입니다. 이 페이지에서는 정책을 구성하는 방법, SDK 호출과의 연결 방식, 평가 순서, 와일드카드, 조건, 암호화, 캐싱까지 모든 것을 다룹니다.
핵심 개념
정책은 이름이 붙은 규칙의 모음입니다. 각 규칙은 “에이전트가 리소스 Y에 대해 액션 X를 시도하면, 답은 허용 또는 거부다”라고 말합니다.
{
"name": "my-policy",
"rules": [
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-4"
}
]
}
SDK 코드가 cz.guard("llm", method="generate", args={"model": "gpt-5.4"})를 호출하면, SDK는 이 규칙을 찾아 효과가 allow임을 확인하고 액션을 진행시킵니다.
액션 문자열 형식: 정책 규칙의 액션 문자열은 콜론 구분 형식(
tool:method)을 사용합니다. SDK 호출은tool과method를 별도의 매개변수로 전달하며, 두 값은tool:method로 매칭됩니다. 예:llm:generate,tool:call,data:read,api:request.
SDK 호출이 정책 규칙에 매핑되는 방식
이것이 이해해야 할 가장 중요한 내용입니다. guard() 호출은 도구 이름과 메서드를 정책 액션에, args를 정책 조건에 매핑합니다.
SDK call: Policy rule:
cz.guard( {
"llm", "action": "llm:generate",
method="generate", --> "resource": "model/gpt-5.4",
args={ --> "conditions": {
"model": "gpt-5.4", "agent_id": "agent-*"
"agent_id": "agent-001", },
}, "effect": "allow"
) }
- 도구 이름과 메서드가 정책 액션 문자열을 이룹니다(예:
"llm"+"generate"="llm:generate"). - args 딕셔너리는 규칙의
conditions객체(있는 경우)와 매칭됩니다. - 모든 필드가 일치하면 규칙의
effect가 결과를 결정합니다.
정책 구성: 단계별 안내
1단계: 액션 선택
액션은 에이전트가 하려는 일을 설명합니다. 이름 규칙은 직접 정합니다. 일반적인 패턴은 다음과 같습니다.
| 액션 | 의미 | 사용 시점 |
|---|---|---|
llm:generate | 텍스트 생성을 위해 LLM 호출 | chat.completions.create() 또는 messages.create() 호출 전 |
llm:embed | 임베딩 생성 | embeddings.create() 호출 전 |
tool:call | 도구 또는 함수 호출 | LLM이 요청한 도구를 실행하기 전 |
mcp.tool:call | MCP 도구 호출 | MCP 프로토콜을 통해 도구를 호출하기 전 |
mcp.resource:read | MCP 리소스 읽기 | MCP를 통해 데이터를 읽기 전 |
data:read | 데이터 소스에서 읽기 | 데이터베이스나 벡터 저장소를 쿼리하기 전 |
data:write | 데이터 소스에 쓰기 | 데이터를 삽입하거나 업데이트하기 전 |
file:read | 파일 읽기 | 디스크의 파일에 접근하기 전 |
file:write | 파일 쓰기 | 파일을 쓰거나 수정하기 전 |
api:request | 아웃바운드 HTTP 요청 보내기 | 외부 API를 호출하기 전 |
* | 모든 액션 | 전체 포괄(catch-all) 규칙 |
직접 액션 이름을 만들어 써도 됩니다. 액션 이름은 그저 문자열입니다. SDK와 정책 규칙이 같은 문자열을 사용하며, 이것이 둘을 연결하는 방식입니다.
2단계: 리소스 선택
리소스는 액션의 대상을 설명합니다. 이름 규칙은 직접 정합니다.
| 리소스 패턴 | 대상 | SDK 호출 예시 |
|---|---|---|
model/gpt-5.4 | 특정 LLM 모델 | guard("llm", method="generate", context={"resource": "model/gpt-5.4"}) |
model/claude-* | 모든 Claude 모델(와일드카드) | guard("llm", method="generate", context={"resource": "model/claude-sonnet-4-6"}) |
tool/search_web | 특정 도구 | guard("tool", method="call", context={"resource": "tool/search_web"}) |
mcp://filesystem/read_file | 특정 MCP 도구 | guard("mcp.tool", method="call", context={"resource": "mcp://filesystem/read_file"}) |
mcp://filesystem/* | MCP 서버의 모든 도구 | filesystem 서버의 모든 도구와 일치 |
vectorstore/documents | 데이터 컬렉션 | guard("data", method="read", context={"resource": "vectorstore/documents"}) |
https://api.example.com/* | API 엔드포인트 | guard("api", method="request", context={"resource": "https://api.example.com/v1/users"}) |
* | 모든 리소스 | 전체 포괄(catch-all) |
3단계: 효과 설정
각 규칙에는 allow 또는 deny 중 하나인 effect가 있습니다.
[
{ "effect": "allow", "action": "llm:generate", "resource": "model/gpt-5.4" },
{ "effect": "deny", "action": "llm:generate", "resource": "model/gpt-4*" }
]
4단계: 조건 추가(선택 사항)
조건을 사용하면 SDK에서 전달한 런타임 값에 따라 규칙을 제한할 수 있습니다. 조건은 로컬 정책 적용기(Python, Node, Go)에 구현되어 있으므로 Hosted 모드와 로컬 전용 모드 모두에서 동작합니다.
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-4",
"conditions": {
"agent_id": "support-*",
"environment": "production"
}
}
전체 매칭 의미는 아래의 별도 조건 섹션을 참고하세요.
검증
정책 버전을 게시하거나 저장하면, 플랫폼은 모든 규칙의 actions[*] 항목을 표준 액션 집합과 별칭 표에 대해 검증합니다(표준 도구 이름 참고). 알 수 없는 액션(오타, 임의로 만든 이름)을 대상으로 하는 규칙은 did_you_mean 제안 목록이 담긴 422 validation_failed 응답으로 거부됩니다. 이렇게 하면 “규칙은 등록되었지만 절대 작동하지 않는” 조용한 유형의 버그를, 규칙이 프로덕션에 배포된 뒤가 아니라 작성 시점에 잡아낼 수 있습니다.
규칙이 database:queryy(오타)를 대상으로 할 때의 응답 예시:
{
"error": "validation_failed",
"unknown_actions": ["database:queryy"],
"suggestions": {
"database:queryy": ["database:query (legacy)"]
}
}
대시보드 규칙 편집기는 문제가 있는 규칙을 빨간 테두리로 표시하고, 제안마다 “database:query 사용” 버튼을 한 번의 클릭으로 제공합니다. (legacy) 태그가 붙은 제안은 표준화 이전 규칙을 위한 별칭 심(shim)에서 온 것이고, 태그가 없는 제안은 최신 표준 클래스입니다(새 규칙에는 이쪽을 권장합니다).
SDK는 정책을 로드할 때 같은 검증기를 경고로 실행하므로, 로컬 정책 모드 사용자(플랫폼 백엔드 없음)도 오타를 확인할 수 있습니다. SDK 경고는 차단하지 않으며 정책은 그대로 로드됩니다. 따라서 SDK가 아직 알지 못하는 사용자 정의 도구를 쓰는 고객도 계속 진행하면서, 실제 오타에 대한 did-you-mean 제안은 여전히 볼 수 있습니다.
검증기가 알고 있는 액션 집합은 표준 SDK 추출기 도구, 호스트 도구 별칭(예: Read는 file_read로 해석), 네 가지 표준 SQL 의미 클래스(database:read|write|admin|exec), 모든 레거시 SQL 별칭(database:query, database:SELECT, database:DROP, ...), 그리고 와일드카드(*, tool:*, *:method)의 합집합입니다. SDK 별칭 표를 업데이트하면 검증기가 허용하는 범위가 자동으로 넓어집니다.
규칙 필드 레퍼런스
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
effect | "allow" 또는 "deny" | 예 | 규칙이 액션을 허용하는지 차단하는지 |
action | string | 예 | 매칭할 액션. 와일드카드(*) 지원 |
resource | string | 예 | 매칭할 리소스. 와일드카드(*) 지원 |
conditions | object | 아니요 | 요청 컨텍스트와 모두 일치해야 하는 키-값 쌍. 값은 glob 패턴을 지원합니다 |
clients | list of strings | 아니요 | 규칙을 특정 AI 클라이언트(cursor, claude-code, gemini-cli, codex-cli, windsurf, python-sdk 등)로 제한합니다. 비어 있거나 없으면 모든 클라이언트와 일치합니다. glob 패턴을 지원합니다. #175에서 추가됨. |
projects | list of strings | 아니요 | 규칙을 특정 프로젝트 ID로 제한합니다. 비어 있거나 없으면 모든 프로젝트와 일치합니다. glob 패턴을 지원합니다. #175에서 추가됨. |
셀렉터 의미(clients / projects)
clients 목록이 비어 있지 않은 규칙은 요청에서 감지된 클라이언트 이름이 항목 중 하나와 일치하지 않으면 건너뜁니다. projects도 마찬가지입니다. 두 셀렉터 모두 요청을 명시적으로 선택해야 합니다. 빈 client_name은 clients: ["cursor"]와 일치하지 않습니다. 첫 번째 일치가 우선한다는 원칙은 여전히 적용되며, “가장 구체적인 규칙이 우선” 하도록 암묵적으로 재정렬되지 않습니다. 우선순위는 더 구체적인 규칙을 더 일반적인 규칙 앞에 작성하는 방식으로 표현하세요.
rules:
- allow: delete_* # cursor-only override fires first
clients: ['cursor']
- deny: delete_* # global default applies to everything else
Glob 문법 참고: clients / projects의 glob 지원은 action / resource와 같은 규칙으로 매칭됩니다. Rust와 Go에서는 *, prefix*, *suffix, Python에서는 여기에 ?와 [seq]가 추가됩니다(fnmatch.fnmatchcase 사용). 이는 액션과 리소스에도 적용되는 기존의 SDK 간 동작 특성이므로, 이식성을 위해 공통분모 문법(정확히 일치, prefix*, *suffix)만 사용하기를 권장합니다.
와일드카드
action과 resource 필드는 모두 glob 방식의 와일드카드를 지원합니다.
[
{ "action": "llm:*", "resource": "*" },
{ "action": "mcp.tool:call", "resource": "mcp://filesystem/*" },
{ "action": "*", "resource": "*" }
]
| 패턴 | 일치하는 대상 | 일치하지 않는 대상 |
|---|---|---|
model/gpt-5.4 | model/gpt-5.4만 | model/gpt-5.4-mini |
model/gpt-5.4* | model/gpt-5.4, model/gpt-5.4-mini | model/gpt-4-turbo |
model/* | 모든 모델 | tool/search_web |
mcp://filesystem/* | mcp://filesystem/read_file, mcp://filesystem/write_file | mcp://github/create_issue |
* | 모든 것 | (모두 일치) |
조건
조건은 런타임에 모두 일치해야 하는 키-값 glob 패턴으로 규칙을 세분화합니다. 조건은 모든 SDK(Python과 Node)의 로컬 적용기에서, Hosted와 로컬 전용 모드 모두에서 평가되며 서버 왕복이 없습니다.
각 조건이 매칭되는 대상
규칙에 conditions: { key: pattern, ... }가 있으면, 적용기는 guard 호출의 병합된 뷰를 만들고 각 key를 이 뷰에 대해 검사합니다. 병합 규칙은 다음과 같습니다.
- 호출의
args딕셔너리에서 시작합니다. - 그 위에
context를 덮어씁니다(키가 충돌하면 context가 우선). context["tags"]가 매핑이면,context와 같은 우선순위로 최상위 수준에 펼칩니다.- 각 조건 값은 glob(
*와일드카드)입니다.key의 값이 glob과 일치하면 조건이 통과합니다. 모든 조건이 통과해야 합니다.
실질적인 결과: args, 최상위 context, 중첩된 context["tags"] 중 어느 것으로든 조건을 구동할 수 있습니다. 호출하는 쪽에서 가장 자연스러운 것을 고르세요.
예시: provider 태그(단순화된 래퍼 패턴)
- effect: allow
action: 'llm:generate'
conditions:
provider: 'openai'
이 규칙은 다음 호출 중 어느 것이든 수행되면 일치합니다.
# via top-level context (direct guard)
cz.guard("llm", method="generate", context={"provider": "openai"})
# via nested tags (simplified wrapper populates tags)
cz.guard("llm", method="generate", context={"tags": {"provider": "openai"}})
# via args (some integrations put it there)
cz.guard("llm", method="generate", args={"provider": "openai"})
예시: 에이전트 + 환경
{
"effect": "allow",
"action": "llm:generate",
"conditions": {
"agent_id": "support-*",
"environment": "production"
}
}
cz.guard(
"llm",
method="generate",
context={
"agent_id": "support-agent-1", # matches "support-*"
"environment": "production", # matches "production"
},
)
예시: 중첩된 태그
래퍼가 호출을 태그(provider, 모델 계열, 비용 등급)로 분류하면, 조건은 그 태그를 최상위 값처럼 매칭할 수 있습니다.
{ "effect": "deny", "action": "llm:generate", "conditions": { "cost_tier": "premium" } }
cz.guard(
"llm",
method="generate",
context={"tags": {"cost_tier": "premium", "provider": "openai"}},
)
# Denied: conditions.cost_tier matches tags.cost_tier after flattening.
정책 평가 순서
여러 규칙이 같은 guard() 호출에 일치할 수 있을 때, Control Zero는 다음 우선순위를 적용합니다.
세 가지 규칙:
-
명시적 거부가 항상 우선합니다. 거부 규칙이 하나라 도 일치하면, 허용 규칙도 일치하더라도 액션은 차단됩니다.
-
더 구체적인 규칙이 더 넓은 규칙보다 우선합니다.
model/gpt-4에 대한 규칙은model/*에 대한 규칙보다 우선합니다. -
일치 없음 = 거부(기본). 액션과 리소스에 일치하는 규칙이 없으면 액션은 거부됩니다.
영어 원문 -- 번역은 기술 검토 대기 중입니다
This is the secure-by-default allow-list posture, and it is the default. It is also a knob: the
settings.default_actionfield controls the no-match path and can be set todeny(allow-list, the default),warn(log-and-proceed, for discovery rollouts), orallow(deny-list -- allow unmatched calls and block only the tools you explicitlydeny:).일치 없음 경로의 전체 계약은 적용 동작을, 복사해서 쓸 수 있는
default_action: allow정책은 거부 목록 레시피를 참고하세요.
예시: 실제 평가
다음 정책이 주어졌다면:
{
"rules": [
{ "effect": "allow", "action": "llm:generate", "resource": "model/*" },
{ "effect": "deny", "action": "llm:generate", "resource": "model/gpt-4*" }
]
}
| SDK 호출 | 규칙 1 일치? | 규칙 2 일치? | 결과 |
|---|---|---|---|
guard("llm:generate", "model/gpt-4") | 예 (allow) | 아니요 | 허용됨 |
guard("llm:generate", "model/gpt-3.5-turbo") | 예 (allow) | 아니요 | 허용됨 |
guard("llm:generate", "model/gpt-4-turbo") | 예 (allow) | 예 (deny) | 거부됨 (거부가 우선) |
guard("tool:call", "tool/search") | 아니요 | 아니요 | 거부됨 (일치 없음 = 거부) |
전체 정책 예시
예시 1: 모델 거버넌스
특정 모델은 허용하고 나머지는 모두 거부합니다.
{
"name": "model-governance",
"description": "Only approved models can be used",
"rules": [
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-5.4"
},
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/claude-sonnet-4-6"
},
{
"effect": "deny",
"action": "llm:generate",
"resource": "model/*"
}
]
}
마지막 규칙은 전체 포괄(catch-all) 역할을 합니다. 명시적으로 허용되지 않은 모델은 모두 거부됩니다.
코드에서:
cz.guard("llm", method="generate", context={"resource": "model/gpt-5.4"}) # ALLOWED
cz.guard("llm", method="generate", context={"resource": "model/claude-sonnet-4-6"}) # ALLOWED
cz.guard("llm", method="generate", context={"resource": "model/gpt-4o"}) # DENIED (catch-all)
예시 2: MCP 도구 제어
에이전트가 호출할 수 있는 MCP 도구를 제어합니다.
{
"name": "mcp-tool-control",
"description": "Restrict MCP tool access per agent",
"rules": [
{
"effect": "allow",
"action": "mcp.tool:call",
"resource": "mcp://filesystem/read_file",
"conditions": { "agent_id": "analyst-*" }
},
{
"effect": "deny",
"action": "mcp.tool:call",
"resource": "mcp://filesystem/write_file"
},
{
"effect": "allow",
"action": "mcp.tool:call",
"resource": "mcp://github/*",
"conditions": { "agent_id": "dev-agent" }
},
{
"effect": "deny",
"action": "mcp.tool:call",
"resource": "mcp://*"
}
]
}
코드에서:
# Analyst agent reading a file: ALLOWED (rule 1 matches)
cz.guard(
"mcp.tool",
method="call",
context={"resource": "mcp://filesystem/read_file", "agent_id": "analyst-42"},
)
# Any agent writing a file: DENIED (rule 2 matches)
cz.guard(
"mcp.tool",
method="call",
context={"resource": "mcp://filesystem/write_file", "agent_id": "analyst-42"},
)
# Dev agent using GitHub: ALLOWED (rule 3 matches)
cz.guard(
"mcp.tool",
method="call",
context={"resource": "mcp://github/create_issue", "agent_id": "dev-agent"},
)
# Unknown MCP tool: DENIED (rule 4 catch-all)
cz.guard(
"mcp.tool",
method="call",
context={"resource": "mcp://slack/send_message", "agent_id": "analyst-42"},
)
예시 3: 다층 프로덕션 정책
모델 거버넌스, 도구 제어, 데이터 접근, API 제한을 결합한 정책입니다.
{
"name": "production-agent-policy",
"description": "Full governance for production AI agents",
"rules": [
{
"effect": "allow",
"action": "llm:generate",
"resource": "model/gpt-4",
"conditions": { "environment": "production" }
},
{
"effect": "allow",
"action": "tool:call",
"resource": "tool/search_web"
},
{
"effect": "deny",
"action": "tool:call",
"resource": "tool/execute_code"
},
{
"effect": "allow",
"action": "data:read",
"resource": "vectorstore/public-docs"
},
{
"effect": "deny",
"action": "data:read",
"resource": "vectorstore/internal-*"
},
{
"effect": "allow",
"action": "api:request",
"resource": "https://api.internal.example.com/*"
},
{
"effect": "deny",
"action": "api:request",
"resource": "https://*.external.example.com/*"
},
{
"effect": "deny",
"action": "*",
"resource": "*"
}
]
}
마지막 규칙은 전역 전체 포괄(catch-all) 규칙입니다. 명시적으로 허용되지 않은 것은 모두 거부됩니다.
정책 번들
정책은 SDK에 개별적으로 전송되지 않습니다. 대신 프로젝트의 모든 활성 정책이 하나의 정책 번들로 컴파일됩니다.
번들이 동작하는 방식
대시보드에서 정책을 게시하면 Control Zero는 이를 하나의 번들로 SDK에 전달합니다. 새 정책은 약 1분 이내에, 또는 수동 새로 고침 시 즉시 에이전트에서 활성화됩니다.
번들 보안
영어 원문 -- 번역은 기술 검토 대기 중입니다
Every policy bundle is signed. The SDK verifies the signature before use, detects tampering, and rejects an invalid bundle. If this happens on a background refresh, it keeps enforcing the last known good policy; if it happens at startup, there is no verified policy to fall back to and calls are denied. A modified bundle cannot silently change enforcement either way.
로컬 캐싱
SDK는 현재 번들을 디스크에 캐시합니다. 이를 통해 다음을 얻을 수 있습니다.
영어 원문 -- 번역은 기술 검토 대기 중입니다
- Offline enforcement: If the SDK cannot reach the server, it enforces the last known good policy.
영어 원문 -- 번역은 기술 검토 대기 중입니다
- Zero-latency evaluation: Every
guard()call evaluates against local memory. No network round-trip.
영어 원문 -- 번역은 기술 검토 대기 중입니다
- Resilience: Network outages or server maintenance do not interrupt policy enforcement.
기본 캐시 위치:
- Python:
~/.controlzero/cache/ - Go:
~/.controlzero/cache/ - Node.js:
~/.controlzero/cache/
정책 새로 고침
SDK는 기본적으로 60초마다 새 번들이 있는지 확인합니다(각 확인은 ETag 조건부 요청이므로 정책이 바뀌지 않았다면 다시 다운로드하지 않습니다). 이 주기를 늘리거나 줄이려면 CONTROLZERO_POLICY_STALENESS_S를 설정하세요. 새로 고침을 강제할 수도 있습니다.
# Python: policies refresh automatically; close the client when done
client.close()
// Go
err := client.RefreshPolicies(ctx)
// Node.js
await cz.refreshPolicies();
영어 원문 -- 번역은 기술 검토 대기 중입니다
Audit log retention is a configured window by tier: Free 7 days, Solo 90 days, Teams 365 days (see Feature Availability). Automatic deletion of audit records at the end of the window is not currently running on the production audit store, so audit records are kept longer than the window. Deletion will be switched on only after dated notice to affected organizations. When tiered audit retention takes effect, Free organizations created before then keep their existing 30-day window unless an owner changes it, and an owner can set a shorter window. Compliance exports are available in Solo and Teams. View pricing
MCP 도구 호출 통제
Model Context Protocol(MCP) 도구는 AI 에이전트에 파일 시스템 접근, 데이터베이스 쿼리, 셸 실행, API 호출 같은 폭넓은 기능을 제공합니다. Control Zero는 각 MCP 도구 호출을 (action, resource) 쌍으로 통제하며, 액션은 mcp.tool:call이고 리소스는 mcp://{server}/{tool} 규칙을 따릅니다.
이 섹션은 MCP 정책 매칭을 정의합니다. 실제 적용 여부는 각 클라이언트에 문서화된 훅 적용 범위에 따라 달라집니다.
일반적인 패턴
읽기 전용 에이전트 -- 읽기는 허용하고 쓰기와 셸은 거부합니다.
{
"name": "read-only-agent",
"rules": [
{ "effect": "allow", "action": "mcp.tool:call", "resource": "mcp://filesystem/read_file" },
{ "effect": "allow", "action": "mcp.tool:call", "resource": "mcp://filesystem/list_directory" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://filesystem/write_file" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://filesystem/delete_file" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://shell/execute" }
]
}
데이터베이스 리더 -- SELECT는 허용하고 쓰기는 거부합니다.
{
"name": "db-reader-agent",
"rules": [
{ "effect": "allow", "action": "mcp.tool:call", "resource": "mcp://database/read_query" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://database/write_query" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://database/execute_query" }
]
}
API 전용 에이전트 -- 아웃바운드 HTTP는 허용하고 로컬 접근은 거부합니다.
{
"name": "api-only-agent",
"rules": [
{ "effect": "allow", "action": "mcp.tool:call", "resource": "mcp://http/request" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://filesystem/*" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://shell/*" },
{ "effect": "deny", "action": "mcp.tool:call", "resource": "mcp://database/*" }
]
}
MCP 정책 게이트웨이 패턴
MCP 네이티브 클라이언트에서는 도구 호출을 작은 게이트웨이로 감싸, 실제 MCP 서버로 전달하기 전에 guard()를 호출하세요.
from controlzero import Client
from typing import Any
cz = Client(api_key="cz_live_your_api_key_here")
class PolicyGateway:
"""MCP gateway that enforces Control Zero policies on tool calls."""
def __init__(self, agent_id: str):
self.agent_id = agent_id
def call_tool(self, server: str, tool: str, arguments: dict) -> Any:
cz.guard(
"mcp.tool",
method="call",
context={"resource": f"mcp://{server}/{tool}", "agent_id": self.agent_id},
args=arguments,
)
return self._forward_to_server(server, tool, arguments)
def check_tool(self, server: str, tool: str) -> bool:
"""Check if a tool call would be allowed (without enforcing)."""
decision = cz.guard(
"mcp.tool",
method="call",
context={"resource": f"mcp://{server}/{tool}", "agent_id": self.agent_id},
)
return decision.effect == "allow"
def _forward_to_server(self, server, tool, arguments):
# Implementation depends on your MCP client library.
pass
표시 시점에 도구 목록 필터링
에이전트에 도구를 제시하기 전에 정책으로 카탈로그를 필터링하면, 모델이 호출할 수 없는 도구를 아예 보지 못하게 할 수 있습니다.
available_tools = [
("filesystem", "read_file"),
("filesystem", "write_file"),
("database", "read_query"),
("database", "write_query"),
("shell", "execute"),
("http", "request"),
]
allowed_tools = []
for server, tool in available_tools:
decision = cz.guard(
"mcp.tool",
method="call",
context={"resource": f"mcp://{server}/{tool}", "agent_id": "my-agent"},
)
if decision.effect == "allow":
allowed_tools.append((server, tool))
이렇게 하면 모델이 거부된 도구를 시도조차 하지 않으므로 낭비되는 토큰과 불필요한 감사 이벤트가 줄어듭니다.