Skip to main content

Policies

Policies are the core of Igris governance. Each policy contains an ordered list of rules evaluated against incoming tool calls and LLM requests. The first matching rule determines the action.

Concepts

A policy is attached to one or more connections and contains:
  • Name — human-readable label
  • Connection — which connection(s) this policy applies to
  • Rules — ordered list of target/action/condition tuples
  • Enabled — whether the policy is active
A rule specifies:
  • Target — what to match (MCP tool name, LLM model, or LLM endpoint)
  • Action — what to do when the target matches: allow, deny, alert, or redact
  • Conditions (optional) — attribute-based gates on user identity or metadata
  • Rate limit (optional) — cap calls, tokens, or dollars per time period
  • Token guard (optional, LLM rules) — cap input tokens or max_tokens per request
  • Content guard (optional) — run detectors on request or response content

Rule Targets

The target.kind field is the discriminator. Three variants are supported:
type PolicyRuleTarget =
  // Match an MCP tool call by name or glob
  | { kind: "mcp_tool"; tool: string }

  // Match a specific LLM model name or glob (e.g. "gpt-4*", "claude-*")
  | { kind: "llm_model"; model: string }

  // Match a specific LLM endpoint type
  | { kind: "llm_endpoint"; endpoint:
      | "chat.completions"
      | "embeddings"
      | "images.generate"
      | "audio.transcriptions"
      | "audio.speech"
      | "passthrough"
    }

MCP tool glob matching

MCP tool targets use glob-style patterns with * as a wildcard:
PatternMatches
*Everything (catch-all)
delete_*delete_user, delete_record, delete_all
*_sensitiveread_sensitive, export_sensitive
db_*db_query, db_insert, db_delete
read_userExact match: only read_user

LLM model glob matching

The model field also supports * as a wildcard:
{ "kind": "llm_model", "model": "gpt-4*" }       // matches gpt-4o, gpt-4-turbo, gpt-4o-mini
{ "kind": "llm_model", "model": "*" }              // catch-all — matches any model
{ "kind": "llm_model", "model": "claude-3-5-*" }  // matches claude-3-5-sonnet, claude-3-5-haiku

Rule Evaluation: First Match Wins

Rules are evaluated top to bottom. The first rule whose target matches (and whose conditions pass) determines the action. Remaining rules are skipped.
{
  "rules": [
    { "target": { "kind": "mcp_tool", "tool": "delete_*" }, "action": "deny" },
    { "target": { "kind": "mcp_tool", "tool": "drop_*" }, "action": "deny" },
    { "target": { "kind": "mcp_tool", "tool": "write_*" }, "action": "alert" },
    { "target": { "kind": "mcp_tool", "tool": "*" }, "action": "allow" }
  ]
}
In this example:
  • delete_usersdenied (matches rule 1)
  • drop_tabledenied (matches rule 2)
  • write_recordallowed + alert sent (matches rule 3)
  • read_dataallowed (matches catch-all rule 4)
If no rule matches, the tool call is denied by default. Always include a catch-all * rule at the end if you want a default-allow posture.

Actions

Allow

The tool call is forwarded to the upstream server. An audit event is logged.

Deny

The tool call is blocked. The client receives an error response. An audit event is logged with the denial reason.

Alert

The tool call is forwarded (same as allow), but an additional anomaly event is emitted via SSE and logged. Use this for tool calls you want to monitor without blocking.

Redact

The tool call arguments are inspected by the configured content-guard detectors. Any matched sensitive content (PII, secrets, etc.) is masked in-place before the request is forwarded. The upstream call still proceeds — redact is not a blocking action. An audit event records what was redacted.

Conditions (Attribute-Based Access Control)

Rules can include conditions that match against user identity and request metadata. A rule with conditions only applies when all conditions are met.

Example: Block destructive ops for interns

{
  "rules": [
    { "target": { "kind": "mcp_tool", "tool": "delete_*" }, "action": "deny", "conditions": { "metadata.role": "intern" } },
    { "target": { "kind": "mcp_tool", "tool": "drop_*" }, "action": "deny", "conditions": { "metadata.role": "intern" } },
    { "target": { "kind": "mcp_tool", "tool": "*" }, "action": "allow" }
  ]
}
This blocks delete_* and drop_* calls only when metadata.role is "intern". Admins and developers can still use these tools.

Condition Fields

FieldSourceExample
userX-Igris-User header"user": "alice@company.com"
traceIdX-Igris-Trace-Id header"traceId": "trace-abc"
metadata.*X-Igris-Metadata header"metadata.role": "admin"
connectionSlugThe connection slug being used"connectionSlug": "openai-prod"

Condition Operators

OperatorExampleMeaning
String (shorthand)"metadata.role": "intern"Equals “intern”
eq"metadata.role": { "eq": "intern" }Equals “intern”
neq"metadata.role": { "neq": "admin" }Not equals “admin”
in"metadata.role": { "in": ["dev", "admin"] }Value in list
nin"metadata.role": { "nin": ["intern"] }Value not in list

Missing Fields

If a condition references a field that isn’t present in the request, the rule is skipped — it does not deny or allow. Evaluation continues to the next rule.
Pass user identity and metadata via the SDK’s connectHttp() options. See Identity & Metadata for details.

Rate Limits

Add a limit to any rule to restrict usage frequency. You can cap by requests, tokens, or dollars over a minute, hour, or day period:
{
  "target": { "kind": "mcp_tool", "tool": "query_*" },
  "action": "allow",
  "limit": {
    "requests": 100,
    "per": "minute"
  }
}
All three dimensions are optional — set any combination:
FieldTypeDescription
requestsnumberMaximum tool calls in the period
tokensnumberMaximum tokens consumed (LLM rules)
dollarsnumberMaximum cost in USD (LLM rules)
per"minute" | "hour" | "day"The rolling window duration
When any configured limit is exceeded, the tool call is denied regardless of the rule’s action. Rate counters are tracked per organization in Redis using sliding windows. Example: cap GPT-4o calls for contractors at 10 requests/hour:
{
  "target": { "kind": "llm_model", "model": "gpt-4o" },
  "action": "allow",
  "conditions": { "metadata.role": "contractor" },
  "limit": { "requests": 10, "per": "hour" }
}

Token Guards and Content Guards

Token guards cap the size of LLM requests before they are forwarded. Content guards run detectors on request and response content. Both are documented on the Guards page.

Creating Policies

  1. Go to Govern → Policies in the dashboard
  2. Click Create Policy
  3. Select the target connection
  4. Add rules in priority order (with optional conditions)
  5. Save

Policy Caching

Active policies are cached in Redis with a TTL. When you update a policy, the cache is invalidated immediately. On cache miss, policies are loaded from the database and re-cached. This ensures low-latency policy evaluation on the proxy path while keeping changes responsive.

Best Practices

  1. Start restrictive — begin with deny-all, then add specific allows as needed.
  2. Use alert for new tools — when a new MCP tool appears, set it to alert before deciding on allow/deny.
  3. Group by risk — create separate policies for different risk levels (e.g., read-only vs. write operations).
  4. Use rate limits on expensive operations — protect against runaway agents with rate limits on write and delete operations.
  5. Review audit events — regularly check denied and alerted calls to refine your policies.