Govern an MCP server
This tutorial puts one upstream MCP server behind Wanaku. It uses a complete wanaku.yaml that combines the sections of a governed deployment: a forward, a credential binding, an LLM connection, an evaluator, action-policy rules, and governance. Each section in examples/governed-mcp/wanaku.yaml has comments that explain how it depends on the other sections.
The processor is actions/dist/safety_review_action.wasm. Its source is in actions/safety-review.
Before you begin
- An MCP server at
http://127.0.0.1:3000/mcpthat accepts a bearer token. - An OpenAI-compatible LLM endpoint. The example uses Ollama at
http://localhost:11434/v1with thellama3.2model. cargo-componentand thewasm32-wasip1target to build the processor.
What the configuration does
Agents connect to http://localhost:8081/tickets/mcp. For a tools/call request in the tickets namespace:
- The action-policy filter denies tools whose names start with
delete-. It allows all other tool calls with an explicit allow. - The evaluator filter runs
tickets-safety-gate. The LLM classifies the call, and the processor blocksredcalls. - Wanaku injects the bearer token from
TICKETS_TOKENand forwards the call to the upstream server.
The governance posture keeps the fail-safe defaults: no_match: deny and on_failure: deny. The action-policy filter and the evaluator filter apply no_match independently. A governed request must pass both filters:
Request in tickets | Action policy | Evaluator | Result |
|---|---|---|---|
tools/call for list-tickets | Explicit allow | tickets-safety-gate runs | Allowed if the processor passes it |
tools/call for delete-ticket | Explicit deny | Does not run | Denied with -32003 |
resources/read or prompts/get | No match, denied | Does not run | Denied with -32003 |
If the LLM is not reachable, the evaluator fails. With on_failure: deny, Wanaku denies the call.
A namespace override with no_match: allow removes the baseline in both filters. It also opens resources/read and prompts/get in that namespace, because no rule or evaluator governs them. Prefer explicit rules and evaluators for each method that agents use.
The sandbox namespace uses mode: audit. Wanaku records the governance decisions there and lets every request continue.
Run the example
Build the processor:
bashmkdir -p actions/dist (cd actions/safety-review && cargo component build --release) cp actions/safety-review/target/wasm32-wasip1/release/safety_review_action.wasm actions/dist/Set the upstream token in the server environment:
bashexport TICKETS_TOKEN=<token>Start Wanaku from the repository root with the example configuration:
bashcargo run -- --wanaku-config examples/governed-mcp/wanaku.yamlList the tools:
bashcurl -s -X POST http://localhost:8081/tickets/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Adapt the example
- Change the forward
address, the bindingorigin, and the namespace for your server. The origin keeps only the scheme, host, and port. - Replace the evaluator with an OPA evaluator or a passthrough evaluator. See Evaluator engines and Gate tool calls with OPA.
- Remove the
llm_connectionsentry if no evaluator uses it. Wanaku resolves every connection at startup.
Next steps
- Governance Posture: learn the
no_matchandon_failuredefaults that this example keeps. - Action Policies: write more rules for the namespace.
- Credential Brokerage: configure other credential mechanisms.
- Wanaku configuration file: find every section of
wanaku.yaml.