Query OPA decision
opa_query_decisionEvaluate a policy decision by posting input to an OPA server at a specified data path and returning the rule result.
Instructions
Evaluate a decision against the running OPA server. POSTs to the data path with {input} and returns whatever the rule produces. Use this to ask the server "given this input, what does data.X.allow say?"
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Decision path under `data.`, e.g. "rbac/allow" or "rbac.allow". | |
| input | No | Input document to evaluate against. | |
| explain | No | Include a trace at the requested level. | |
| metrics | No | Include metrics in the response. |
Implementation Reference
- The handler that executes the 'opa_query_decision' tool logic: registers the tool with MCP server, defines input schema (path, input, explain, metrics), and on invocation POSTs to OPA's /v1/data/{path} endpoint with the input document and optional explain/metrics query params, returning the result envelope.
server.registerTool( 'opa_query_decision', { title: 'Query OPA decision', description: 'Evaluate a decision against the running OPA server. POSTs to the data path with `{input}` and returns whatever the rule produces. Use this to ask the server "given this input, what does data.X.allow say?"', inputSchema: { path: z .string() .min(1) .describe('Decision path under `data.`, e.g. "rbac/allow" or "rbac.allow".'), input: z.unknown().optional().describe('Input document to evaluate against.'), explain: z .enum(['notes', 'fails', 'full', 'debug']) .optional() .describe('Include a trace at the requested level.'), metrics: z.boolean().optional().describe('Include metrics in the response.'), }, }, async ({ path, input, explain, metrics }) => { return withToolEnvelope<{ result?: unknown; explanation?: unknown; metrics?: unknown }>( config, async () => { try { const query: Record<string, string | boolean> = {}; if (explain) query['explain'] = explain; if (metrics) query['metrics'] = true; const data = await opa.request<{ result?: unknown; explanation?: unknown; metrics?: unknown; }>({ method: 'POST', path: dataPath(path), body: input !== undefined ? { input } : {}, query, }); return ok({ result: data.result, explanation: data.explanation, metrics: data.metrics, }); } catch (e) { return mapOpaClientError(e); } }, ); }, ); - Input schema definition for opa_query_decision using Zod: path (required string), input (optional unknown), explain (optional enum: notes/fails/full/debug), metrics (optional boolean).
inputSchema: { path: z .string() .min(1) .describe('Decision path under `data.`, e.g. "rbac/allow" or "rbac.allow".'), input: z.unknown().optional().describe('Input document to evaluate against.'), explain: z .enum(['notes', 'fails', 'full', 'debug']) .optional() .describe('Include a trace at the requested level.'), metrics: z.boolean().optional().describe('Include metrics in the response.'), }, - src/tools/index.ts:37-43 (registration)Top-level tool registration entry point that calls registerServerManagementTools, which in turn calls registerDecisionTools that registers opa_query_decision.
export function registerTools(server: McpServer, config: Config): void { registerAuthoringTools(server, config); registerEvaluationTools(server, config); registerBundleTools(server, config); registerServerManagementTools(server, config); registerHelperTools(server, config); } - src/tools/server-management/index.ts:16-21 (registration)Category-D registration entry point that invokes registerDecisionTools to register the opa_query_decision tool.
export function registerServerManagementTools(server: McpServer, config: Config): void { registerPolicyTools(server, config); registerDataTools(server, config); registerDecisionTools(server, config); registerStatusTools(server, config); } - Helper that converts a dotted or slashed decision path (e.g. 'rbac.allow' or 'data.rbac.allow') into a /v1/data/ URL path used in the OPA REST API call.
function dataPath(path: string): string { const stripped = path.replace(/^data\./, '').replace(/^\/+/, ''); return `/v1/data/${stripped.replace(/\./g, '/')}`; }