Skip to content

MCP Server

The Policy MCP server lets AI assistants evaluate, validate, and explain policy rules directly. It implements the Model Context Protocol and is built into the API — no additional installation required.

The MCP server is available at:

https://api.policy2.net/mcp

It uses Streamable HTTP transport — all communication happens on a single endpoint via POST /mcp.

All MCP connections require a valid API key with view scope. Pass the key as a query parameter:

https://api.policy2.net/mcp?api_key=YOUR_API_KEY

Or use the x-api-key header on requests.

Add the following to your Claude Desktop configuration file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"policy": {
"type": "streamable-http",
"url": "https://api.policy2.net/mcp?api_key=YOUR_API_KEY"
}
}
}

Add the MCP server to your project with the Claude Code CLI:

Terminal window
claude mcp add policy --transport http "https://api.policy2.net/mcp?api_key=YOUR_API_KEY"

Or add it manually to .claude/settings.json:

{
"mcpServers": {
"policy": {
"type": "http",
"url": "https://api.policy2.net/mcp?api_key=YOUR_API_KEY"
}
}
}

Add the MCP server to your codex configuration. In your project’s codex.json or via the CLI:

{
"mcpServers": {
"policy": {
"type": "http",
"url": "https://api.policy2.net/mcp?api_key=YOUR_API_KEY"
}
}
}

The MCP server exposes four tools that AI assistants can call.

Evaluate a policy rule against JSON data. Returns the overall result, per-outcome booleans, an execution trace, and any errors.

Parameters:

FieldTypeDescription
rulestringThe policy rule DSL string to evaluate
dataobjectThe JSON data to evaluate against

Example call:

{
"rule": "A **Person** gets senior_discount\n if the __age__ of the **Person** is greater than or equal to 65.",
"data": { "Person": { "age": 70 } }
}

Example response:

{
"result": true,
"outcomes": { "senior_discount": true },
"trace": { "..." },
"error": null
}

Check whether a policy rule is syntactically valid without evaluating it.

Parameters:

FieldTypeDescription
rulestringThe policy rule DSL string to validate

Example response:

{
"valid": true,
"error": null
}

Parse a policy rule and return a structured breakdown of its selectors, outcomes, and conditions.

Parameters:

FieldTypeDescription
rulestringThe policy rule DSL string to explain

Example call:

{
"rule": "A **Person** gets senior_discount\n if the __age__ of the **Person** is greater than or equal to 65."
}

Example response:

{
"rule_count": 1,
"rules": [
{
"label": null,
"selector": "Person",
"outcome": "senior_discount",
"conditions": [
{
"type": "comparison",
"selector": "Person",
"property": "age",
"operator": "is greater than or equal to",
"value": "65",
"logical_op": null,
"optional": false,
"negated": false
}
]
}
],
"error": null
}

List all comparison operators supported by the policy DSL, grouped by operator with all accepted string forms. Takes no parameters.

Example response (abbreviated):

[
{
"operator": "is greater than or equal to",
"forms": ["is greater than or equal to", "is at least", ">="]
},
{
"operator": "is equal to",
"forms": ["is equal to", "is", "equals", "=="]
},
{
"operator": "is a valid email",
"forms": ["is a valid email", "is a valid email address"]
}
]

Once configured, your AI assistant can:

  • Write policy rules — ask it to create rules for your business logic and validate them on the fly
  • Test rules against data — provide sample JSON and have the assistant evaluate whether a rule passes or fails
  • Debug rules — use explain_rule to break down a rule’s structure and evaluate_rules with trace output to see exactly which conditions pass or fail
  • Discover operators — the assistant can call list_operators to find the right comparison for your use case

You: Write a policy that gives free shipping to orders over $50 that weigh less than 5kg.

Assistant: (uses validate_rule to confirm syntax, then evaluate_rules to test it)

Here’s the policy:

A **Order** gets free_shipping
if the __total__ of the **Order** is greater than 50
and the __weight__ of the **Order** is less than 5.

I’ve validated the syntax and tested it against sample data — it works correctly.