opa-mcp-server
OPA MCP Server
A Model Context Protocol (MCP) server that turns any MCP-compatible client (Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Zed, and others) into a first-class Open Policy Agent and Rego authoring environment.
┌────────────────────┐ MCP / stdio ┌─────────────────┐ spawn / HTTP ┌──────────────────┐
│ Claude · Cursor · │ ────────────▶ │ @orygn/opa-mcp │ ─────────────▶ │ opa · regal · │
│ VS Code · ... │ ◀──────────── │ │ ◀───────────── │ OPA REST API │
└────────────────────┘ 32 tools └─────────────────┘ └──────────────────┘Status: v0.1.0. First stable release. Tool surface, error codes, and environment variables follow SemVer from this version forward.
Table of contents
Related MCP server: kubernetes-mcp
What you can do with it
Once an MCP client is connected, an agent can:
Author Rego. Generate, format, and refactor policies. The server runs the real
opa fmtandopa parseso output is byte-identical to what you'd get on the command line, andregal(optional) surfaces idiomatic suggestions.Evaluate against data. Run a query against a policy and an input document. Optional
--explain,--profile, and--coverageflags surface execution traces, hot rules, and per-line coverage.Debug a deny.
rego_explain_decisionwalks the agent through every rule that fired (and every one that didn't), so it can answer "why was this rejected" without you reading the trace by hand.Manage policies on a running OPA. List, get, put, delete policies on an OPA server through its REST API. Works against a local
opa run --serveror a production deployment with bearer-token auth.Build & sign bundles. Package a directory of policies into a deployable bundle, optionally signing it. Output is a regular
.tar.gzthe agent can hand to your delivery system.Lint.
rego_lintruns Regal across a directory or a single file and returns categorized findings (style, bugs, performance, idioms).
A walk-through of a typical session lives in Cookbook.
Why this MCP
OPA already has a perfectly good CLI and REST API. So why an MCP wrapper?
Schema-shaped tool surface. An agent calling
rego_evalgets a validated input schema, a structured output envelope, and stable error codes, instead of parsing free-form CLI text and inventing its own failure taxonomy. That alone makes Rego usable to an agent the way a language server makes a language usable to an IDE.Higher-level helpers.
rego_explain_decision,rego_generate_test_skeleton,rego_describe_policy, andrego_suggest_fixcompose the lower-level primitives into the tasks agents are actually asked to do. They don't exist in the OPA CLI.Curated knowledge. The bundled MCP resources expose the OPA built-in function catalog, the official Rego style guide (formatted for LLMs), and a curated pattern library covering RBAC, ABAC, Kubernetes admission, IaC gates, API authz, and rate limiting, so the agent has authoritative context without needing to scrape it.
Safety boundaries the agent can rely on. Path allow-list, subprocess timeouts, response-size caps, and an explicit
HTTP_SEND_BLOCKEDerror for the dangerous OPA built-ins. Defaults are conservative; running the server doesn't quietly grant the agent more reach than the operator intended.
If you've ever watched an agent fight opa eval's argument order, you'll
recognize the gap this fills.
Install
The server runs locally over stdio. Pick the install path that matches your client.
Claude Desktop / Claude Code
The fastest path is the Smithery one-liner:
npx -y @smithery/cli install @orygn/opa-mcp --client claudeOr download opa-mcp.mcpb from the
latest release
and double-click it.
If you prefer to edit claude_desktop_config.json by hand, the snippet
lives in examples/claude-desktop.json:
{
"mcpServers": {
"opa": {
"command": "npx",
"args": ["-y", "@orygn/opa-mcp"],
"env": {
"OPA_BINARY": "/usr/local/bin/opa",
"REGAL_BINARY": "/usr/local/bin/regal",
"OPA_URL": "http://localhost:8181",
"OPA_MCP_ALLOWED_PATHS": "/path/to/your/policies"
}
}
}
}Replace the
/usr/local/bin/...paths with your real ones. See the first-time install gotcha below. Windows users substituteC:\\path\\to\\opa.exe.
Cursor
Drop examples/cursor.json into either
.cursor/mcp.json (project-scoped) or ~/.cursor/mcp.json (user-scoped).
VS Code (GitHub Copilot Chat)
Drop examples/vscode.json into
.vscode/mcp.json, or paste the servers block into your user
settings.json under mcp.servers.
Windsurf, Zed, and others
See examples/ for a full set of drop-in configs.
Manual install (any MCP client)
npm install -g @orygn/opa-mcp
opa-mcp --versionthen point your client at the opa-mcp binary.
Docker
docker pull orygn/opa-mcp:latest
docker run --rm -i \
-v /path/to/your/policies:/policies:ro \
-e OPA_MCP_ALLOWED_PATHS=/policies \
orygn/opa-mcpThe image is multi-arch (linux/amd64, linux/arm64), bundles pinned
versions of opa and regal, and runs as a non-root user. No host
install of OPA or Regal is required.
⚠ First-time install gotcha (read this if you used npx or the global install)
If your client's PATH doesn't include the directory where opa lives
(this happens with Claude Desktop on Windows and macOS by default), the
server boots fine but every tool call returns OPA_BINARY_NOT_FOUND.
Fix: add OPA_BINARY and REGAL_BINARY env entries to your client
config with the absolute path to each binary. The example configs under
examples/ ship with placeholder paths you replace.
Find the real paths with:
which opa && which regal # macOS / LinuxGet-Command opa, regal | Select-Object Source # WindowsThis does not affect the Docker or MCPB install paths; those
ship opa and regal inside the bundle and bypass PATH entirely.
See Troubleshooting for full detail.
Configuration
The server reads its configuration from environment variables. Every
variable is optional; defaults are sensible for a local OPA on
http://localhost:8181.
Variable | Default | Purpose |
|
| Base URL of an OPA REST endpoint, used by |
| (unset) | Bearer token for OPA, if your instance requires auth. Treated as a secret. Never echoed in logs or tool responses. |
|
| Path to the |
|
| Path to the |
| (unset) | Comma- or semicolon-separated list of directories the server is allowed to read policies from. When unset, file-based tools refuse to read from disk. |
|
| Path the server appends logs to. The server never writes to stdout; that channel is reserved for the MCP protocol. |
|
| One of |
|
| Hard cap on a single tool response. Larger payloads are truncated with a |
|
| Hard timeout for any spawned subprocess ( |
|
| Timeout for HTTP requests to the OPA REST API. |
Paths in OPA_MCP_ALLOWED_PATHS and the *_BINARY variables must be
absolute. Relative paths and missing binaries are rejected with structured
errors.
Tool reference
Every tool returns a JSON envelope:
{ "ok": true, "data": { ... }, "warnings": [ ... ] }
{ "ok": false, "error": { "code": "INVALID_REGO", "message": "...", "hint": "...", "details": { ... } } }Stable error codes: INVALID_INPUT, INVALID_REGO, INVALID_BUNDLE,
EVAL_ERROR, OPA_BINARY_NOT_FOUND, REGAL_NOT_FOUND,
REGAL_VERSION_TOO_OLD, OPA_UNREACHABLE, OPA_AUTH_FAILED,
POLICY_NOT_FOUND, PATH_NOT_ALLOWED, PATH_NOT_FOUND,
DEPENDENCY_CONFLICT, NO_TESTS_FOUND, HTTP_SEND_BLOCKED, TIMEOUT,
UNKNOWN_ERROR.
Category A: Authoring & static analysis
Operate on Rego source code without needing a running OPA server. Wrap
opa fmt, opa parse, opa check, opa inspect, opa capabilities,
opa deps, and regal.
Tool | What it does |
| Format Rego source. Wraps |
| Type-check and validate Rego. Wraps |
| Run Regal across a file or directory. Returns findings grouped by category. Requires |
| Parse Rego to AST JSON. Wraps |
| Inspect a bundle or directory: packages, rules, annotations. Wraps |
| Return the capabilities (built-ins, future keywords) understood by the bundled OPA. |
| Static dependency analysis: rule-level data references and cross-package calls. |
Featured: rego_format
// Input
{
"source": "package x\nallow{input.user==\"admin\"}"
}
// Output (ok)
{
"ok": true,
"data": {
"formatted": "package x\n\nallow if input.user == \"admin\"\n",
"changed": true
}
}Featured: rego_check
// Input
{
"source": "package x\nallow if y",
"strict": true
}
// Output (error path; the JSON diagnostics arrive on stderr from opa)
{
"ok": true,
"data": {
"valid": false,
"errors": [
{
"code": "rego_unsafe_var_error",
"message": "var y is unsafe",
"location": { "row": 2, "col": 11 }
}
]
}
}Category B: Evaluation & testing
Run a query against a policy and input. Wrap opa eval, opa test, and
opa bench.
Tool | What it does |
| Evaluate a query against a policy and input. The bread-and-butter tool. |
| Evaluate with |
| Evaluate with |
| Evaluate with |
| Run |
| Run |
| Partially evaluate a query against a policy. |
Featured: rego_eval
// Input
{
"query": "data.rbac.allow",
"source": "package rbac\nimport rego.v1\nallow if input.role == \"admin\"",
"input": { "role": "admin" }
}
// Output
{
"ok": true,
"data": {
"result": [{ "expressions": [{ "value": true, "text": "data.rbac.allow", "location": { "row": 1, "col": 1 } }] }]
}
}Category C: Bundle operations
Package and sign deployable bundles. Wrap opa build and opa sign.
Tool | What it does |
| Build a |
| Sign a bundle with a private key. Returns |
Category D: OPA server management
Talk to a running OPA server over its REST API. Require OPA_URL to
point at a reachable server.
Tool | What it does |
| List policies registered on the server. |
| Get a single policy by ID. |
| Upload or replace a policy. |
| Delete a policy by ID. |
| Read a path from the data hierarchy. |
| Write to a path in the data hierarchy. |
| Apply a JSON Patch to the data hierarchy. |
| POST to a |
| Partially evaluate a query against the running server. |
| Liveness / readiness check. |
| Bundle / decision-log status. |
| Server configuration (without secrets). |
Category E: Higher-level helpers
The differentiation surface. These compose lower-level primitives into the tasks agents are actually asked to do.
Tool | What it does |
| Walk through every rule that fired (and didn't) for a given query. Wraps |
| Given a policy, generate a |
| Summarize what a policy does, its inputs, decisions, and assumptions. |
| For a failed |
Prompts
Three MCP prompts ship with the server. Clients surface them as slash commands or workflow templates.
Prompt | Purpose |
| Walks the agent through writing a new policy: ask about the decision surface, draft, review, format, lint, test. |
| Review checklist for an existing policy: completeness, edge cases, performance, security pitfalls. |
| Diagnostic flow when a decision is unexpected: gather input, run with explain, isolate the rule, propose a fix. |
Resources
Three MCP resources expose curated reference data the agent can read at any time.
Resource URI | What's there |
| Categorized OPA built-in function reference, derived at read time from |
| Condensed Rego style guide, formatted for LLM consumption. |
| Curated common-pattern library: RBAC, ABAC, Kubernetes admission, IaC gates, API authz, rate limiting. Each pattern includes when-to-use, full Rego, a test, and common pitfalls. |
Cookbook
A few session shapes that the tool set was designed for.
"Help me write a policy"
You: I need an authz policy: editors can read/write, viewers can only read,
admins can do anything.
Agent: I'll draft it. (calls rego_format on a draft, then rego_check, then
rego_lint)
Agent: Here's the policy. I've also generated a test file with cases for
each role. (calls rego_generate_test_skeleton, then rego_test)
Agent: All 9 tests pass. Want me to save it to <path>?"Why was this denied?"
You: This API call is being denied and I don't know why.
[pastes input.json]
Agent: (calls rego_explain_decision against your local policy with that input)
Agent: The deny comes from rule `forbid_anonymous_writes` at line 17.
Specifically, `input.user` is null and the request method is "POST".
The rule fires, which causes the default deny. To allow this, you'd
need either an authenticated user or a policy exception for this
endpoint."Push this policy to staging OPA"
You: Push policies/rbac.rego to the staging OPA server, but first lint and
test it.
Agent: (rego_lint → 2 style warnings, no errors)
(rego_test on policies/ → all pass)
(opa_put_policy with id="rbac" against $OPA_URL)
(opa_get_policy to verify)
Agent: Done. Policy `rbac` is live on staging at $OPA_URL.Architecture
┌──────────────────────────────────── @orygn/opa-mcp ───────────────────────────────────┐
│ │
│ src/server.ts ──── McpServer (stdio) ─── tool / prompt / resource registries │
│ │ │
│ ├── tools/authoring/ ─┐ │
│ ├── tools/evaluation/ ─┤ │
│ ├── tools/bundles/ ─┼─── lib/opa-cli.ts ──┐ │
│ ├── tools/server-management/ ─┤ │ │
│ ├── tools/helpers/ ─┘ │ │
│ │ ▼ │
│ │ lib/subprocess.ts ──┴── opa │
│ │ lib/regal-cli.ts ───── regal│
│ │ lib/opa-client.ts ───── HTTP │
│ │ │
│ └── lib/output.ts (envelope + truncation) │
│ lib/security.ts (path allow-list) │
│ lib/errors.ts (structured failures) │
│ lib/logger.ts (file-only, never stdout) │
└───────────────────────────────────────────────────────────────────────────────────────┘Three things worth knowing if you're going to operate this:
stdout is the protocol channel. The server logs to a file via
lib/logger.tsand never writes to stdout. If you see stray stdout bytes, the client disconnects; the MCP transport layer is strict.No tool throws. Every tool catches its own exceptions and returns a structured
{ ok: false, error: ... }envelope. The agent sees a stable error vocabulary, not a stack trace.Subprocesses are tightly bounded.
lib/subprocess.tsrunsopaandregalwithshell: false, a hard timeout, andSIGTERM-then-SIGKILLescalation. There is no path through the server where an agent can construct a shell command.
Security
This server is designed to run locally, started by an MCP client on the user's own machine, communicating over stdio. It is not designed to be exposed on the network.
File-based tools refuse to read anything outside
OPA_MCP_ALLOWED_PATHS. When that variable is unset, file tools returnPATH_NOT_ALLOWED.Subprocesses run with
shell: falseand a hard timeout.OPA_TOKENis never echoed in tool responses or log entries.Releases are published with npm provenance; the Docker image is built reproducibly from the committed
Dockerfile.
To report a vulnerability, follow SECURITY.md. Please do not open a public issue for security problems.
Troubleshooting
Common issues, fast fixes.
OPA_BINARY_NOT_FOUND even though opa is installed. (most common
first-day issue, read this first)
MCP clients (notably Claude Desktop on Windows and macOS) launch the
server with a deliberately reduced PATH that omits user-local bin
directories, even ones that work fine in your interactive shell. The
binary is on your machine; the spawned MCP server just can't see it.
Find the absolute path to opa:
# macOS / Linux
which opa
# → /usr/local/bin/opa (or /opt/homebrew/bin/opa, or ~/.local/bin/opa)# Windows
Get-Command opa | Select-Object -ExpandProperty Source
# → C:\Users\you\bin\opa.exe (or wherever)Then set OPA_BINARY to that absolute path in your client's MCP env
block. Same for REGAL_BINARY if you use the rego_lint tool. The
examples/ configs already include both env vars; just
edit the placeholder paths.
This issue does not affect the Docker or MCPB install paths. Those
bundle opa and regal and bypass PATH entirely.
The server starts, then the client says "disconnected."
The most likely cause is something in the process writing to stdout
besides MCP frames. If you've added a custom tool, check that no library
it calls prints to stdout. The fixed-position safety net is
lib/logger.ts. Use it, not console.log.
PATH_NOT_ALLOWED on a file under my project.
OPA_MCP_ALLOWED_PATHS is empty by default. Set it to the absolute
path(s) you want the server to read from, comma-separated.
OPA_UNREACHABLE when calling opa_* tools.
OPA_URL (default http://localhost:8181) must point at a running OPA
server (opa run --server ...). Check with curl $OPA_URL/health.
Regal "version too old."
We track the current Regal release. If REGAL_VERSION_TOO_OLD fires,
upgrade Regal: brew upgrade regal or download from the
Regal releases page.
directory-package-mismatch violation when linting inline source.
When you pass source rather than paths to rego_lint, Regal sees a
randomized temp-file path that can't possibly match your declared package
path. The diagnostic is an artifact of inline linting, not a real issue.
Disable the rule for inline workflows or lint via paths against the
real on-disk file when you want canonical signal.
Where are the logs?
Default location is <OS-tmpdir>/orygn-opa-mcp.log. That's typically
/tmp/orygn-opa-mcp.log on Linux/macOS or %TEMP%\orygn-opa-mcp.log
on Windows. Set OPA_MCP_LOG_FILE to override, and
OPA_MCP_LOG_LEVEL=debug to widen the firehose.
Development
git clone https://github.com/OrygnsCode/opa-mcp-server.git
cd opa-mcp-server
npm install
npm run devCommon commands:
npm run lint # ESLint
npm run typecheck # tsc --noEmit
npm test # unit tests (Vitest)
npm run test:coverage # unit + coverage report
npm run test:integration # against real opa + regal binaries
npm run build # compile to dist/CI runs lint, typecheck, build, and unit tests on every push and PR
across Ubuntu, macOS, and Windows on Node 20 and 22. Integration tests
run on Linux against pinned opa and regal releases.
For the full contributor workflow (adding tools, naming conventions, logging discipline, release process), see CONTRIBUTING.md.
Versioning & support
This project follows Semantic Versioning. The public surface for SemVer purposes is the set of registered tools, prompts, and resources, their input/output schemas, the recognized environment variables, and the CLI entry point.
Breaking changes will be:
announced in CHANGELOG.md under a new major version,
preceded by at least one minor release with a deprecation warning,
accompanied by a migration note in the release announcement.
Pinned versions of the upstream toolchain (opa and regal) are treated
as part of the build, not as a dependency the operator manages. The
Dockerfile, MCPB bundle, and CI all use the same pin; bumps go through
Dependabot or a manual PR.
License
MIT © Orygn LLC
@orygn/opa-mcp is an independent project. It is not affiliated with,
endorsed by, or sponsored by the Open Policy Agent project, the Cloud
Native Computing Foundation, Styra, or Anthropic. "Open Policy Agent"
and "Rego" are trademarks of their respective owners. "Model Context
Protocol" is a trademark of Anthropic, PBC.
Available Tools
52 toolsconftest_pullConftest pullADestructiveIdempotent
Download Rego policies from an OCI registry or Git repository into a local directory using conftest pull. Use this to hydrate a local policy/ directory before running conftest_test. Requires conftest on PATH or CONFTEST_BINARY set. The policy directory must be inside OPA_MCP_ALLOWED_PATHS. SECURITY: pulled policies are arbitrary Rego source that will be executed by conftest_test. Only pull from registries or repositories you own or explicitly trust -- malicious policy code can use OPA built-ins (http.send, opa.runtime) to exfiltrate data or make outbound network requests when the tests run.
Inputs: url (required), policy.
conftest_pushConftest pushADestructive
Package the local Rego policy directory as an OCI artifact and push it to a registry using conftest push. Registry credentials must be pre-configured in the host environment (docker login, ORAS keychain, etc.) -- this tool never handles credentials. The policy directory must be inside OPA_MCP_ALLOWED_PATHS. Requires conftest on PATH or CONFTEST_BINARY set.
Inputs: repository (required), policy, v0Compatible.
conftest_testConftest testA
Evaluate configuration files (Kubernetes manifests, Terraform plans, Dockerfiles, Helm charts, or any YAML/JSON/HCL/TOML/INI) against Rego policies using conftest test. Returns per-file, per-namespace pass/fail/warn results so you can pinpoint exactly which policy rules fired. Requires conftest on PATH or CONFTEST_BINARY set; returns CONFTEST_NOT_FOUND otherwise. Provide config via files (disk paths) or inlineConfig (inline string). Provide policy via policy (disk path) or inlinePolicy (inline Rego source). Omit policy and inlinePolicy to use conftest's default ./policy directory. Policies are executed by conftest and can call OPA built-ins such as http.send. A run in which no rule was evaluated (wrong namespace, or no deny/violation/warn rules) is reported as passed: false with nothingEvaluated: true and the namespaces that do hold rules, where conftest itself would exit 0.
Inputs: data, files, parser, policy, +8 more.
conftest_verifyConftest verifyA
Run the test_* rules inside *_test.rego files within a conftest policy directory, verifying that the policies themselves are correct. Equivalent to opa test but using conftest's policy-loading machinery. Returns per-file pass/fail results, and NO_TESTS_FOUND when the directory holds no test rules. Requires conftest on PATH or CONFTEST_BINARY set; returns CONFTEST_NOT_FOUND otherwise.
Inputs: data, policy, namespace, v0Compatible.
mcp_server_infoMCP server infoARead-onlyIdempotent
Return the name, version, and runtime details of this opa-mcp server instance. Use this when you need to confirm which version of opa-mcp is running, or to verify that the OPA, Regal, and Conftest binaries are reachable.
Inputs: no named parameters.
opa_bundle_buildBuild OPA bundleADestructiveIdempotent
Build a deployable bundle from policy / data paths using opa build. Output is a .tar.gz archive with optional inline signing. Supports optimization, custom revision strings, and the WASM target.
Inputs: paths (required), output (required), bundle, ignore, +13 more.
opa_bundle_signSign OPA bundleADestructiveIdempotent
Sign a bundle directory with opa sign. A directory is signed in place: .signatures.json is written into it and files are recorded as <directory name>/<file>, so the signed directory verifies wherever it is placed as long as its name is unchanged, with opa_bundle_verify or with opa build or opa run --bundle <name> from its parent. An archive is refused: OPA reads the signature from inside it, so a signed archive comes from opa_bundle_build with signingKey. The key is a PEM private key (RSA or ECDSA); for HMAC algorithms pass a file holding the secret. Extra claims such as keyid and scope come from claimsFile. Returns the path written, the algorithm, and the number of files covered.
Inputs: bundle (required), signingKey (required), claimsFile, signingAlg.
opa_bundle_verifyVerify OPA bundle signatureARead-onlyIdempotent
Verify the signature of a signed bundle directory or .tar.gz archive with the public key. OPA has no standalone verify command, so this runs opa build --verification-key into a private temp file that is discarded. A directory is verified by name from its parent, matching how opa_bundle_sign signs it. OPA reads the key, checks the JWT in .signatures.json, compares the scope claim, then checks every file: Rego files by digest before parsing, data files and .manifest by parsed value, so an unparseable data file fails before its digest is compared. Failures return INVALID_BUNDLE with details.reason set to one of signature_invalid, scope_mismatch, file_modified, file_added, file_missing, file_unparseable, unsigned, signatures_malformed, not_a_bundle, bundle_load_error, or unknown when the message is not recognised; the raw output is in details. A key or algorithm OPA cannot use returns INVALID_INPUT. Pass scope exactly as the bundle was signed with. With a single key OPA does not check verificationKeyId against the signature keyid claim. verified: true is returned only when OPA loaded the bundle with its signature intact.
Inputs: bundle (required), verificationKey (required), scope, signingAlg, +2 more.
opa_compile_queryCompile (partially evaluate) a query on OPAARead-onlyIdempotent
Send a query to the OPA server's /v1/compile endpoint for partial evaluation. Returns the residual query -- what remains after substituting in everything that's known.
Inputs: query (required), input, unknowns.
opa_configOPA configurationARead-onlyIdempotent
Return the running OPA server configuration from GET /v1/config. OPA drops the credentials block but returns services.*.headers verbatim, which is the ordinary place to put an API key or a bearer token, so those values are redacted here and the header names kept.
Inputs: no named parameters.
opa_delete_dataDelete a data document from OPAADestructive
Remove a document from OPA's data store at the given path. A path is read as dotted (users.alice) unless it contains a slash, in which case slash is the only separator (users/alice), so a key such as example.com is addressable as hosts/example.com. Pass segments instead when a key contains both. OPA responds with 204 No Content on success; if no document exists at the path, OPA returns 404 which is mapped to DATA_NOT_FOUND. Root-path deletion (/v1/data/ itself) is intentionally excluded -- supply at least one path segment.
Inputs: path, segments.
opa_delete_policyDelete OPA policyADestructive
Delete a policy by ID from the running OPA server.
Inputs: id (required).
opa_execBatch-evaluate OPA policy against input filesA
Evaluate a policy decision against one or more input files using opa exec --format=json. Unlike rego_eval (single input), opa exec processes every file independently and returns a per-file result -- ideal for CI pipelines that check many config files against a policy in one call. Supply bundle for a bundle, or dataPaths for plain .rego, JSON and YAML files and directories, which are loaded as opa eval --data loads them; the two are mutually exclusive. Each file that fails evaluation appears in results with an error field rather than a result field. Set one of fail/failDefined/failNonEmpty to turn the call into a CI gate: the result then reports failed: true (instead of erroring) when the gate condition is met.
Inputs: decision (required), inputPaths (required), fail, bundle, +6 more.
opa_get_dataRead data from OPAARead-onlyIdempotent
Read a path from OPA's data hierarchy. A path is read as dotted (users.alice) unless it contains a slash, in which case slash is the only separator (users/alice), so a key such as example.com is addressable as hosts/example.com. Pass segments instead when a key contains both.
Inputs: path, segments.
opa_get_policyGet OPA policy by IDARead-onlyIdempotent
Fetch a single policy by ID from the running OPA server. Returns the Rego source; the parsed AST is omitted unless asked for, since it is roughly forty times the size of the source it came from. Use rego_parse_ast on the source when an AST is what's wanted.
Inputs: id (required), includeAst.
opa_healthOPA health checkARead-onlyIdempotent
Hit the OPA /health endpoint. A server that answers reports { healthy: true } on 200 and { healthy: false } with OPA's own reason otherwise, so an unactivated bundle is a health result rather than a tool error. OPA_UNREACHABLE means the server could not be reached at all. Supports bundles and plugins query flags to require those subsystems to also be healthy.
Inputs: bundles, plugins.
opa_list_policiesList OPA policiesARead-onlyIdempotent
List policies registered on the running OPA server. Returns the policy IDs and a count. Set includeSource for the Rego text of every policy, or includeAst for the parsed AST of every policy; both are off by default because either one pushes a list of any real size past the response cap.
Inputs: includeAst, includeSource.
opa_patch_dataPatch data on OPAADestructive
Apply a JSON Patch (RFC 6902) to the data document. Each operation is { op, path, value? }. Omit both path and segments to patch the root of the data hierarchy, which is how a whole new top-level document is added.
Inputs: operations (required), path, segments.
opa_put_dataWrite data to OPAADestructiveIdempotent
Write or replace a value at the given data path. Body is sent as JSON. A path is read as dotted (users.alice) unless it contains a slash, in which case slash is the only separator (users/alice), so a key such as example.com is addressable as hosts/example.com. Pass segments instead when a key contains both.
Inputs: path, value, segments.
opa_put_policyUpload or replace OPA policyADestructiveIdempotent
Upload a Rego policy under the given ID. Replaces any existing policy with that ID; replaced says whether one existed. The policy is uploaded as raw text/plain and OPA compiles it on the server, so a policy that does not compile comes back as INVALID_REGO with OPA's errors, and nothing is stored.
Inputs: id (required), source (required).
opa_query_decisionQuery OPA decisionARead-onlyIdempotent
Evaluate a decision against the running OPA server. POSTs to the data path with {input} and returns whatever the rule produces, plus defined: false when the path produced no value, which OPA reports by leaving result out. Undefined is not false; a caller that treats it as false or as allow decides on something the policy never said. Use this to ask the server "given this input, what does data.X.allow say?"
Inputs: path, input, explain, metrics, +1 more.
opa_statusOPA statusARead-onlyIdempotent
Return the running OPA server configuration via GET /v1/config. Returns the same underlying document as opa_config but presented under a status key as a convenience for agents that want to check "what is running" rather than "what was the server configured with". The response includes bundle settings, decision-log settings, and plugin configuration as OPA reported them at startup. Service header values are redacted, since OPA returns them verbatim and a header is the ordinary place to put an API key.
Inputs: no named parameters.
rego_benchBenchmark Rego queryA
Benchmark a Rego query against a policy + input with opa bench. Returns statistical timing data: iterations, ns/op, and allocation counts. Use this to spot slow rules.
Inputs: query (required), count, input, paths, +2 more.
rego_capabilitiesOPA capabilitiesARead-onlyIdempotent
Return OPA capabilities -- the available builtins, future keywords, features, and WASM ABI versions. With current: true, returns the running OPA's capabilities. With version: "v1.19.0", returns those of a specific version. With neither, lists available named versions. By default (names_only: true), returns only builtin names and count to stay within response size limits. Pass builtins: [...] for the full type signatures and documentation of a few named builtins; names_only: false returns every full record, which needs OPA_MCP_MAX_RESPONSE_BYTES raised above its default.
Inputs: current, version, builtins, names_only.
rego_checkCheck RegoARead-onlyIdempotent
Type-check Rego with opa check. Returns { valid: true, errors: [] } on success, or a list of structured diagnostics with file/line locations on failure. Provide either source for inline checking or paths for file/directory checking.
Inputs: paths, bundle, source, strict, +4 more.
rego_check_schemaCheck Rego against a JSON SchemaARead-onlyIdempotent
Validate that a Rego policy's input.* field references are consistent with a JSON Schema using opa check --schema. Every field the policy reads from input must exist in the schema; mismatches surface as rego_type_error diagnostics with file/line locations. Returns { valid: true, errors: [] } when all references match the schema, or { valid: false, errors: [...] } with structured diagnostics when they do not. Accepts the schema inline (pass the schema output of rego_infer_input_schema directly as inlineSchema) or as a path to a JSON Schema file on disk, or to a schema directory when the policy declares schemas: annotations (schemaPath). Provide source for inline Rego or paths for file/directory checking.
Inputs: paths, source, strict, schemaPath, +2 more.
rego_compile_queryPartially evaluate a Rego queryA
Run partial evaluation on a query -- substitute known values and return the residual policy. Defaults unknowns to ["input"] (treat input as unknown), so the residual encodes "given input X, this is what would have to be true." Use this for offline policy slicing or pre-computing decision sets.
Inputs: query (required), input, paths, source, +5 more.
rego_coverage_gapsRego test coverage gapsA
Run opa test --coverage and return a per-file breakdown of uncovered line ranges. Identifies which rules or branches are not yet exercised by tests. Files are sorted by coverage ascending so the worst-covered files appear first. Use threshold to limit the report to files below a target coverage percentage.
Inputs: paths (required), threshold, runPattern, v0Compatible.
rego_depsRego dependency analysisARead-onlyIdempotent
Static dependency analysis for a Rego reference. Given a target ref like "data.example.allow", returns the base document references (input/data leaves) and virtual document references (rules) it depends on, transitively.
Inputs: ref (required), paths (required).
rego_describe_policyDescribe Rego policyARead-onlyIdempotent
Parse a Rego policy and return a structured summary: package, imports, and rules. Each rule reports clauseCount (how many definitions share the name), isDefault (true if any clause is a default), hasArgs, bodyLength (total body expressions across all clauses), and inline annotations. Useful as the first step in any "what does this policy do" workflow.
Inputs: source (required), v0Compatible.
rego_evalEvaluate Rego queryA
Evaluate a Rego query against a policy and an input document using opa eval. Returns the standard {result: [...]} shape plus defined, which is false when the query produced no value (undefined is not false), and printed, the lines the policy wrote with print(). The bread-and-butter authoring tool. The policy is optional, so a query alone tries out a built-in or an expression. Pass inputs to evaluate one query against many input documents in one call, and v0Compatible for a policy still written in pre-1.0 Rego.
Inputs: query (required), input, paths, inputs, +6 more.
rego_eval_with_coverageEvaluate Rego with coverageA
Evaluate with --coverage and return per-line coverage data. Useful for verifying that tests actually exercise the rules they're meant to.
Inputs: query (required), input, paths, source, +5 more.
rego_eval_with_explainEvaluate Rego with execution traceA
Evaluate with --explain=full and return OPA's raw trace events (with their AST nodes) alongside the result. For a readable trace use rego_explain_decision, which renders the same events as lines. Raw events are large: over the response cap the bound-variable values are dropped first, then trailing events (explanationTruncated), and the result is kept.
Inputs: query (required), input, paths, source, +5 more.
rego_eval_with_profileEvaluate Rego with profilingA
Evaluate with --profile and return per-rule timing and evaluation counts. Use this to find hot rules in slow policies.
Inputs: query (required), input, paths, source, +5 more.
rego_explain_decisionExplain Rego decisionA
Evaluate a Rego query with full tracing and return the result, the rules entered (rulesEvaluated) and those that produced a value (rulesFired), and the trace as readable lines: location, nesting, operation, the expression in Rego syntax, and the values of the variables it names. Backtracking (Redo) events are left out. Use it to answer "why was this denied?" or "why did this rule not match?": the Fail lines name the condition that stopped a rule. A trace too long for the response cap is cut from the end (traceTruncated); narrow the query or the input to see the rest.
Inputs: query (required), input, paths, source, +5 more.
rego_explain_undefinedExplain why a Rego query is undefinedA
Diagnose why a fully-qualified Rego query (e.g. "data.authz.allow") produces no value, or falls back to its default. Combines a plain eval, a full-trace eval, and per-condition AST analysis to identify the exact body expression blocking each rule. Handles both runtime failures (trace-based) and indexer elimination (standalone condition eval). A rule written with default allow := false always has a value, so queryResult reports default for it and the same per-rule breakdown follows: the question "why is allow false" is the question this answers. A multi-value rule such as deny contains msg if ... that holds no element reports empty with the same breakdown, which answers "why was this not denied". Returns a structured breakdown of which conditions blocked each rule plus a human-readable summary. paths may name directories, which are searched for the modules that declare the queried package.
Inputs: query (required), input, paths, source, +2 more.
rego_fixAuto-fix Rego violationsADestructive
Run regal fix to automatically apply mechanical fixes. Regal 0.42 fixes opa-fmt, use-rego-v1, use-assignment-operator, no-whitespace-comment, directory-package-mismatch, non-raw-regex-pattern, prefer-equals-comparison, redundant-existence-check and constant-condition; older releases fix a subset. Use dryRun: true to preview changes before modifying files. NOTE: directory-package-mismatch moves files to match their package path -- use disable: ["directory-package-mismatch"] to skip it. Regal before 0.41 refuses files with uncommitted git changes unless force: true. Requires regal.
Inputs: paths (required), force, dryRun, enable, +5 more.
rego_formatFormat RegoARead-onlyIdempotent
Format Rego source code using opa fmt. Returns the formatted source and a changed flag indicating whether the input was already canonical. When the source uses string interpolation ($"..." or $... syntax) and OPA v1.12.0 or v1.12.1 is detected, the tool warns about or blocks formatting due to a known OPA bug that corrupts { escape sequences (fixed in OPA v1.12.2).
Inputs: source (required), v0Compatible.
rego_format_writeFormat Rego files in placeADestructiveIdempotent
Run opa fmt --write to canonically format one or more Rego files or directories in place. Use dryRun: true to preview which files would change without modifying them. Returns a list of files that were (or would be) reformatted. Unlike rego_format which returns formatted source as a string, this tool writes directly to disk. Supports regoV1, v0Compatible, and v1Compatible flags for version-specific formatting. If any file cannot be parsed, the operation is aborted and no files are written.
Inputs: paths (required), dryRun, regoV1, v0Compatible, +1 more.
rego_generate_test_skeletonGenerate Rego test skeletonARead-onlyIdempotent
Generate a *_test.rego skeleton from a policy. Parses the AST, finds each non-test rule, and emits one stub test per rule. Existing test_* and todo_test_* rules are skipped automatically -- only production rules get stubs. Every stub is a todo_test_ rule, which opa test reports as skipped (and exits non-zero for) until a realistic input and the expected value are filled in and it is renamed test_: a placeholder input against a placeholder expectation would otherwise pass while testing nothing. The AST is walked to infer which input.* fields the policy accesses; the inferred shape is used as the placeholder with input as {...} in each stub, so the developer only needs to fill in realistic values rather than guess the structure. With tableStyle: true, each stub uses an every tc in cases { ... } loop so you can add multiple input/expected pairs without duplicating assertion code. The inferredInputShape field in the response shows the detected shape for reference.
Inputs: source (required), tableStyle, v0Compatible.
rego_infer_input_schemaInfer input schemaARead-onlyIdempotent
Statically analyse one or more Rego policies and return a JSON Schema (draft-07) object describing every input.* field the policies read. It follows the ways a policy reads input: loop variables (some c in input.containers then c.image), rules whose value is an input path (pod_spec := input.request.object.spec), function parameters (trusted(c)) and object.get keys. A key the policy computes is left open, and a scalar type is set only where a comparison with a literal, an is_* check or a string built-in shows it. Uses opa parse -- no running OPA server required. A starting point for test inputs and for a schema to give rego_check_schema; review it first, since types the policy never shows are left out. Accepts inline source, individual files, or directories (walked recursively for *.rego files).
Inputs: paths, source, v0Compatible.
rego_inspectInspect bundle or policyARead-onlyIdempotent
Inspect an OPA bundle, policy directory, or single Rego file with opa inspect. Returns manifest data, namespaces, rule annotations, and (if signed) signature metadata.
Inputs: target (required), v0Compatible.
rego_lintLint RegoA
Lint Rego source with the Regal linter. Returns categorized violations (style, bugs, idiomatic, performance) with file/line locations. Requires regal on PATH or REGAL_BINARY set; returns REGAL_NOT_FOUND otherwise. When called with inline source, location-bound rules whose verdict depends on the on-disk path (directory-package-mismatch) are auto-disabled to avoid temp-file false positives, and location.file is reported as <inline> instead of the randomized temp path. Re-enable those rules via enable if your workflow actually needs them.
Inputs: paths, enable, source, disable, +5 more.
rego_migrate_v1Migrate Rego to v1 syntaxA
Migrate Rego v0 source to Rego v1. First renames what v1 reserves (a rule called contains, every, if or in, and every reference to it in the module) and replaces built-ins v1 removed: re_match and net.cidr_overlap by their v1 names, and all, any, set_diff and the cast_* family by a helper function appended to the module that returns exactly what the built-in did, so behaviour does not change. re_match and net.cidr_overlap get such a helper too where the rename would change behaviour: the module mocks one spelling with with while calling both, or binds regex or net itself. Then opa fmt --rego-v1 converts the syntax (if, contains, import rego.v1) and opa check validates the result. rewrites lists each change by line and notes says why; a renamed rule must also be renamed in any other module that uses it. Pass inputs to evaluate the original as v0 and the result as v1 against each and compare every rule of the package, and queries to compare expressions too, such as calls to its functions; equivalence reports any difference. Evaluating runs the policy, http.send included. Returns the migrated source even when check finds remaining errors. A source that parses only as Rego v1 is returned unchanged; one that parses as both, such as v1 that imports rego.v1, is reformatted like any other. If the source parses as neither, returns INVALID_REGO with opa's own message.
Inputs: source (required), inputs, queries, dataPaths.
rego_parse_astParse Rego to ASTARead-onlyIdempotent
Parse Rego source to a JSON AST using opa parse. Returns the AST as a tree of nodes (package, imports, rules, expressions, terms). Use this when you need to introspect policy structure programmatically.
Inputs: source (required), v0Compatible.
rego_policy_diffDiff two Rego policiesA
Evaluate the same query against two policies (or two versions of the same policy) and compare the results. Both evaluations run in parallel. Returns equal: true/false, the raw result from each side, and changedPaths -- the dot/bracket paths that differ. Useful for verifying that a refactor preserves behavior, or understanding exactly where two policies diverge. Each side takes either inline source (sourceA/sourceB) or a file/directory path (pathA/pathB). The same input and query are used for both evaluations; pass inputs to compare on many input documents in one call, and dataPaths to load the data the policies read.
Inputs: query (required), input, pathA, pathB, +7 more.
rego_security_auditRego security auditA
Run regal lint restricted to its bugs category plus any custom rules placed in a security category, across one or more policy directories, and return the findings grouped by severity (high/medium) with remediation guidance and a link to each rule. Use it for a periodic fleet-wide sweep rather than per-file style review. Modules that do not parse are listed in unparseable and the rest are audited. These are lint findings: a policy with none can still let a request through, so probe it with rego_eval inputs (absent, null and wrong-typed fields) for that. Requires regal.
Inputs: paths (required), configFile, ignoreFiles.
rego_suggest_fixSuggest fix for Rego diagnosticsARead-onlyIdempotent
Map common Rego compile errors and Regal lint findings to fix suggestions. Pass errors from rego_check or violations from rego_lint unchanged. Returns one suggestion per diagnostic; confidence is high for well-known patterns, medium where the answer is the rule's documentation (docs), low for everything else.
Inputs: diagnostics (required).
rego_testRun Rego testsA
Run Rego unit tests with opa test. Returns aggregate pass/fail/skip/error counts plus per-test records. errored counts tests OPA could not evaluate (a rule conflict, a raising built-in); such a test is neither a pass nor a failure, and a suite with any is not passing. Tests live in *_test.rego files; rule names beginning with test_ are picked up automatically. Use runPattern to filter by name regex; when no tests match, the error hint includes the pattern you supplied. Use threshold to gate on minimum coverage (returns COVERAGE_BELOW_THRESHOLD on failure). Use varValues: true with verbose: true to include local variable bindings in the trace -- essential for debugging table-driven tests written with every tc in cases { ... } to identify which case caused a failure. When tests use the test_x[case] parameterized form, OPA reports the rule as a single test whatever the number of cases; parameterizedGroups maps the rule name to a record per case and caseCounts totals them, so a failing rule says which case failed. Use ignorePatterns to exclude generated or fixture files. Use bundle: true when testing bundle-structured policy directories. Use timeout to raise the per-test limit beyond OPA's default 5s. With coverage or threshold the suite runs a second time for the coverage report, which is added to the results; it is left out when a test fails or errors, since opa reports no coverage for such a run.
Inputs: paths (required), count, bundle, explain, +9 more.
rego_test_multirootRun Rego tests across multiple rootsA
Run opa test once per root and aggregate results. Solves the package-conflict problem that occurs when opa test . is run on a repo with multiple independent package namespaces (OPA issue #4724). Two modes: explicit (supply root list with optional per-root include paths for shared libraries) and scan (auto-discover leaf test roots using the leaf rule -- a directory is a root only if it directly contains *_test.rego files and none of its eligible subdirectories do, preventing OPA's automatic recursion from double-running tests). Use sharedPaths in scan mode to add shared library directories to every root's invocation without including them in discovery. Coverage and threshold work per-root; overallCoveragePct is the mean across roots that have coverage data.
Inputs: roots, scanDir, verbose, coverage, +8 more.
rego_verifyFormally verify a Rego policy ruleARead-onlyIdempotent
Formally verify a property about a Rego rule using SMT solving (Microsoft Z3). Unlike testing, this checks ALL possible inputs and either proves the property holds or returns a concrete counterexample input that falsifies it. Supports equality, comparison, startswith, endswith, contains, and simple regex.match patterns (prefix: ^lit.*, suffix: .lit$, exact: ^lit$, contains: .lit., wildcard: .). Complex regex patterns (character classes, quantifiers, alternation) return INCONCLUSIVE. Also reports INCONCLUSIVE for negation-as-failure (not), comprehensions, partial set and object rules (deny contains msg), functions, else chains, and any operand it cannot encode. A body that reads an absent field is undefined rather than true, so always_true holds only if the rule is also true for an empty input: a rule requiring input.x will be answered with the counterexample {}.
Inputs: kind (required), rule (required), source (required), v0Compatible.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 52 tools
Several clusters have blurred boundaries: rego_eval, rego_eval_with_profile, rego_eval_with_explain, rego_eval_with_coverage, rego_explain_decision, rego_explain_undefined, opa_exec, and opa_query_decision all answer overlapping evaluation/debug questions. opa_status and opa_config explicitly return the same underlying document, and rego_test/rego_test_multiroot/conftest_verify plus rego_format/rego_format_write are easy to misselect. Descriptions are detailed, but with 52 tools the risk of choosing the wrong variant remains high.
Names are consistently snake_case and use clear domain prefixes (rego_, opa_, conftest_), with bundle operations grouped under opa_bundle_. The pattern is not a uniform verb_noun scheme—some names are action+object and some use long variant suffixes—but it is predictable overall.
At 52 tools, the set is far beyond a well-scoped 3-15 tool surface and creates substantial context and selection burden. Many specialized variants, such as the eval-with-* tools and status/config duplication, could be consolidated into fewer tools with flags.
The surface covers the Rego policy lifecycle unusually thoroughly: authoring, evaluation, tracing, testing, coverage, linting, formatting, schema inference/checking, migration, verification, bundles, policy/data CRUD, and Conftest workflows. There are essentially no dead ends for the stated domain.
Maintenance
Related MCP Connectors
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Authenticated MCP server for ClearPolicy policy and compliance workflows.
MCP Server for Slima - AI Writing IDE for Novel Authors with AI Beta Reader.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP Server that enables natural language interaction with the Open Policy Agent REST API, allowing users to manage policies, decisions, and data through conversational interfaces.1-
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server that provides safe, read-only access to Kubernetes resources for debugging and inspection. Built with security in mind, it offers comprehensive cluster visibility without modification capabilities.45MIT
- AlicenseNot gradedqualityCmaintenanceMCP server to lint and validate Kubernetes-related manifests(Helm, FluxCD, ArgoCD, Kustomize, etc.)46 PyPIMIT
- AlicenseNot gradedqualityBmaintenanceAn MCP server that enforces authorization by evaluating Rego policies or querying an OpenID AuthZEN-compliant PDP, providing accurate access decisions for AI agents. It includes tools for policy evaluation, AuthZEN evaluation, batch evaluation, and PDP discovery.1MIT