Skip to content

Management API reference for tools, forwards and policies ​

The management API lets operators inspect and change Wanaku at runtime. It listens on port 8080 by default. Set WANAKU_MGMT_LISTEN to use a different address.

The server uses Pingora's ServeHttp trait. The A2A agent routes run first. The other core routes run next. Feature routes run after core routes. Core routes match complete path segments. For example, /api/v1/tools-export does not match the /api/v1/tools route, so a feature can own that path. If no route matches, the server returns 404.

Access and Response Format ​

Wanaku does not apply built-in authentication or rate limits to the management API. Restrict access to port 8080. In production, put the API behind an authenticated reverse proxy and apply a rate limit there.

Most JSON responses use this envelope:

json
{
  "data": {
    "name": "example"
  },
  "error": null
}

For an error, data is null and error contains a message:

json
{
  "data": null,
  "error": "Tool 'unknown-tool' not found"
}

The data value can be an object, an array, or null. This envelope keeps the API compatible with the classic Wanaku CLI.

Service and Core Routes ​

MethodPathPurpose
GET/healthGet the server health.
GET/healthzGet the server health.
GET/openapi.jsonGet the OpenAPI document.
GET/api/v1/management/infoGet the server name and version.
GET/api/v1/management/statisticsGet registry counts.
GET/api/v1/toolsList tools.
GET/api/v1/tools/{name}Get a tool.
DELETE/api/v1/tools/{name}Delete a tool.
PUT/api/v1/tools/{name}/enableEnable a tool.
PUT/api/v1/tools/{name}/disableDisable a tool.
GET/api/v1/resourcesList resources.
GET/api/v1/resources/{name}Get a resource.
DELETE/api/v1/resources/{name}Delete a resource.
PUT/api/v1/resources/{name}/enableEnable a resource.
PUT/api/v1/resources/{name}/disableDisable a resource.
GET/api/v1/promptsList prompts.
GET/api/v1/prompts/{name}Get a prompt.
DELETE/api/v1/prompts/{name}Delete a prompt.
PUT/api/v1/prompts/{name}/enableEnable a prompt.
PUT/api/v1/prompts/{name}/disableDisable a prompt.
GET/api/v1/namespacesList namespaces.
GET/api/v1/namespaces/{name}Get a namespace.
POST/api/v1/namespacesCreate a namespace from the JSON request body.
PUT/api/v1/namespaces/{name}Replace a namespace entry with the JSON request body.
DELETE/api/v1/namespaces/{name}Delete a namespace.
GET/api/v1/forwardsList forwards.
GET/api/v1/forwards/{name}Get a forward.
POST/api/v1/forwardsCreate a forward and run upstream discovery.
DELETE/api/v1/forwards/{name}Delete a forward and its discovered entries. Use optional label.<key>=<value> query parameters to delete only when the labels match.
POST/api/v1/forwards/{name}/refreshesRun upstream discovery again.
GET/api/v1/agentsList A2A agents. Use the optional namespace query parameter to select one namespace.
GET/api/v1/agents/{namespace}/{name}Get a registered A2A agent and its proxy endpoint.
POST/api/v1/agentsRegister an A2A agent.
PUT/api/v1/agents/{namespace}/{name}Replace an A2A agent's editable configuration.
DELETE/api/v1/agents/{namespace}/{name}Delete an A2A agent and remove its proxy route.
GET/api/v1/bindingsList credential bindings.
GET/api/v1/bindings/{id}Get a credential binding.

Wanaku discovers tools, resources, and prompts when you create or refresh a forward. The API does not have create routes for these entries. Tools and resources are read-only. You cannot edit them through the API.

Enable and Disable Tools, Resources, and Prompts ​

Each tool, resource, and prompt has an enabled field. The default value is true.

A disabled entry stays in the management API. GET /api/v1/tools and the other list routes return it with "enabled": false. MCP clients cannot see or use a disabled entry. tools/list, resources/list, and prompts/list do not include it. tools/call, resources/read, and prompts/get reject it.

Wanaku keeps the state when it discovers the entries of a forward again. A forward refresh or a reconnect does not enable a disabled entry.

Do not delete a tool, resource, or prompt. The next discovery adds it again. Disable the entry instead. The examples use the tool name get_weather. Use a name from GET /api/v1/tools:

bash
curl -X PUT http://localhost:8080/api/v1/tools/get_weather/disable

To enable the entry again:

bash
curl -X PUT http://localhost:8080/api/v1/tools/get_weather/enable

The response contains the updated entry. If the entry does not exist, the server returns 404.

The Admin UI shows an Enable/Disable toggle for each tool, resource, and prompt. The Admin UI does not show a Delete button for these entries.

Register an A2A agent ​

Register an upstream agent with its JSON-RPC address:

bash
curl -X POST http://localhost:8080/api/v1/agents \
  -H 'Content-Type: application/json' \
  -d '{"name":"assistant","namespace":"default","description":"Team assistant","address":"http://localhost:9000/"}'

The name and namespace identify the agent. Both values must use valid identifiers. Wanaku registers a missing namespace when you create an agent. The address must be an HTTP or HTTPS URL. URL credentials and fragments are not permitted. Set cardAddress when the Agent Card uses a different discovery URL.

Agent responses contain name, namespace, description, address, optional cardAddress, and proxyUrl. The proxy URL comes from the configured public A2A origin. It is not an editable agent field.

Creating an existing agent returns 409. Getting, updating, or deleting an unknown agent returns 404. Invalid configuration returns 400. An invalid update does not change the existing entry. An update does not change the namespace and name in the route.

An update sends the complete agent entry. The body must contain name and namespace, and both must be equal to the values in the route. A missing namespace defaults to default. If the route has a different namespace, the server returns 400. The body accepts only name, namespace, description, address, and cardAddress. Unknown keys return 400. Thus, do not send a GET response without changes: remove proxyUrl first.

bash
curl -X PUT http://localhost:8080/api/v1/agents/default/assistant \
  -H 'Content-Type: application/json' \
  -d '{"name":"assistant","namespace":"default","description":"Team assistant","address":"http://localhost:9000/"}'

Agent changes use the configured registry persistence backend. They affect subsequent proxy requests without a restart. See A2A Proxy for the admin UI, listener configuration, policy, and supported protocol operations.

Create a Namespace ​

Use the Wanaku CLI:

bash
wanaku namespaces create finance --no-auth

The CLI sends this request to the management API:

bash
curl -X POST http://localhost:8080/api/v1/namespaces \
  -H 'Content-Type: application/json' \
  -d '{"name":"finance"}'

Namespace names can contain lowercase letters, numbers, and hyphens. They cannot start or end with a hyphen. The maximum length is 63 characters.

Update a Namespace ​

Send the complete namespace entry to the namespace path:

bash
curl -X PUT http://localhost:8080/api/v1/namespaces/finance \
  -H 'Content-Type: application/json' \
  -d '{"name":"finance","labels":{"team":"payments"}}'

The name in the path identifies the namespace. Wanaku ignores the name value in the body. An update cannot rename a namespace. An update does not remove the tools, forwards, or A2A agents in the namespace. A malformed body, a missing body, or an invalid path name returns 400 and does not change the stored entry. The admin UI uses this operation to save namespace edits.

Create a Forward ​

Use the Wanaku CLI:

bash
wanaku forwards add --service="http://upstream-server:8080/mcp" --name upstream-mcp --namespace finance --no-auth

The CLI sends this request to the management API. Include the namespace in the request:

bash
curl -X POST http://localhost:8080/api/v1/forwards \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "upstream-mcp",
    "address": "http://upstream-server:8080/mcp",
    "namespace": "finance"
  }'

A successful request returns 200 with the forward and the discovered entry counts:

json
{
  "data": {
    "forward": {"name": "upstream-mcp", "address": "http://upstream-server:8080/mcp", "namespace": "finance", "available": true},
    "tools_discovered": 3,
    "resources_discovered": 0,
    "prompts_discovered": 1
  },
  "error": null
}

The forward object also contains other forward fields. Wanaku stores the forward even if discovery fails. In that case, the response is also 200. The counts are zero, forward.available is false, and forward.statusMessage contains the error. Thus, curl --fail does not detect a discovery failure. Check forward.available:

bash
curl -sS -X POST http://localhost:8080/api/v1/forwards \
  -H 'Content-Type: application/json' \
  -d '{"name":"upstream-mcp","address":"http://upstream-server:8080/mcp","namespace":"finance"}' \
  | jq -e '.data.forward.available' >/dev/null || echo "discovery failed"

POST /api/v1/forwards/{name}/refreshes returns a different shape: refreshed (the forward name) and the three counts. It does not return the forward. After a refresh, use GET /api/v1/forwards/{name} to check available and statusMessage.

The request body can also contain credentialBindings, a map from purpose (discovery, invocation) to binding id. The bindings themselves must exist in wanaku.yaml, because the management API cannot create bindings. See Credential Brokerage.

Delete a Forward Conditionally ​

A runtime that registers its own forward can mark the forward with a label, such as cic.instance. A replacement instance can register the same forward name before the old instance stops. To prevent the old instance from deleting the new forward, send the label as a precondition:

bash
curl -X DELETE 'http://localhost:8080/api/v1/forwards/upstream-mcp?label.cic.instance=pod-a'

Each label.<key>=<value> query parameter adds one precondition. You can send more than one. Wanaku ignores query parameters that do not start with label.. Encode keys and values as URL query components.

CaseResponse
No label.* parameters200. Wanaku deletes the forward without a check.
The forward has all the given labels with the given values200. Wanaku deletes the forward.
A given label is absent or has a different value409 Conflict with {"data": null, "error": "forward {name} label precondition failed"}. Wanaku keeps the forward.
The forward does not exist404.

Wanaku checks the labels and removes the forward in one registry operation. A concurrent POST /api/v1/forwards for the same name cannot occur between the check and the removal. When Wanaku deletes a forward, it also removes the cached credentials and the discovered tools, resources, and prompts of the forward. A 409 response does not change these entries.

Inspect a Credential Binding ​

The binding routes are read-only. They return only non-secret binding metadata — secretRefs lists opaque references such as env:API_TOKEN, never a resolved value.

bash
curl http://localhost:8080/api/v1/bindings/b1

Replace b1 with a binding ID from GET /api/v1/bindings.

There is no create, update, or delete route for bindings in this release. Bindings are part of the registry snapshot. See Credential Brokerage for the binding schema and the brokerage flow.

Feature Routes ​

Audit ​

MethodPathPurpose
GET/api/v1/audit/eventsList audit events with pagination and filters.
GET/api/v1/audit/events/{id}Get one audit event.
GET/api/v1/audit/schemaGet the audit schema version.
GET/api/v1/audit/healthGet audit-store health and the dropped-event count.
POST/api/v1/audit/semanticAccept one semantic audit event from an external producer, such as WSR.

POST /api/v1/audit/semantic returns 404 unless WANAKU_AUDIT_INGESTION_ENABLED=true. See Ingest Camel semantic audit records.

Metrics ​

MethodPathPurpose
GET/api/v1/metricsGet filter, evaluator, LLM, WASM, and pipeline metrics.

Evaluators ​

MethodPathPurpose
GET/api/v1/evaluatorsList evaluator definitions.
GET/api/v1/evaluators/statusGet runtime readiness, revision, safe reason code, and effective posture. The optional namespace query parameter defaults to default.
PUT/api/v1/evaluatorsReplace evaluator definitions. The body uses the evaluators configuration schema.
GET/api/v1/evaluators/llm-connectionsList configured LLM connection names only, never the model, URL, or credential. Connections are config-only. Set them in wanaku.yaml, not through this API.
GET/api/v1/evaluators/namespacesList namespace-to-conversation bindings.
PUT/api/v1/evaluators/namespaces/{namespace}Bind a namespace to a conversation.
DELETE/api/v1/evaluators/namespaces/{namespace}Remove a namespace binding.
GET/api/v1/evaluators/revisionsList evaluator revision metadata.
GET/api/v1/evaluators/revisions/activeGet the active evaluator revision.
GET/api/v1/evaluators/revisions/{id}Get one evaluator revision.
POST/api/v1/evaluators/revisions/{id}/activateActivate a prior evaluator configuration as a new revision.

The PUT /api/v1/evaluators body is {"evaluators": [...], "expected_revision": N}. expected_revision is optional. Unknown keys return 400. A revision mismatch returns 409. A configuration that does not validate or compile returns 422, and the active revision does not change. See Update Evaluators for an example.

The activate body is optional. To prevent a lost update, send {"expected_revision": N}. A mismatch returns 409.

Bind a namespace to a conversation:

bash
curl -X PUT http://localhost:8080/api/v1/evaluators/namespaces/finance \
  -H 'Content-Type: application/json' \
  -d '{"conversation_id": "conversation-123"}'

See Evaluator Engine for the evaluator configuration schema.

The OpenAPI document contains all evaluator request and response schemas. Run yarn run generate-api in ui/admin after you change an evaluator route or schema.

Action Policies ​

MethodPathPurpose
GET/api/v1/action-policiesGet the effective policy.
PUT/api/v1/action-policiesValidate and activate a policy.
GET/api/v1/action-policies/revisionsList policy revision metadata.
GET/api/v1/action-policies/revisions/activeGet the active policy revision.
GET/api/v1/action-policies/revisions/{id}Get one policy revision.
POST/api/v1/action-policies/revisions/{id}/activateActivate a prior policy as a new revision.

The update and activation requests accept an optional expected_revision. Wanaku returns 409 Conflict if the value does not equal the active revision. See Action Policies for request examples and validation behavior.

The OpenAPI document contains all action-policy request and response schemas. Run yarn run generate-api in ui/admin after you change an action-policy route or schema.

Policy Simulation ​

MethodPathPurpose
POST/api/v1/policy-simulations/validateValidate a transient candidate.
POST/api/v1/policy-simulations/simulateEvaluate one synthetic MCP action.
POST/api/v1/policy-simulations/replaysStart a bounded asynchronous comparison job.
GET/api/v1/policy-simulations/replays/{id}Get job status and its impact report.
POST/api/v1/policy-simulations/replays/{id}/cancelRequest job cancellation.
DELETE/api/v1/policy-simulations/replays/{id}Delete a retained job.

These routes do not activate candidates. They do not forward actions or resolve credentials. External evaluator execution is not supported. Reports contain decision metadata instead of request payloads. See Policy Simulation for candidate selection, replay limits, audit input, and CI examples.

Inference Proxy (not part of this API) ​

Chat completions do not go through the management API. Wanaku exposes a separate, raw reverse-proxy listener on port 8083 that forwards requests as-is to whatever OpenAI-compatible backend WANAKU_INFERENCE_UPSTREAM points at — including the caller's own Authorization header. The LLM Chat page in the Wanaku Debugger plugin calls this port directly with a key you supply in the browser. Install the plugin from the Admin UI Plugin Catalog. Open Debugger from the Developer navigation section. Select the LLM Chat tab:

bash
curl -X POST http://localhost:8083/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-key>" \
  -d '{
    "model": "llama3.1:8b",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

See Configuration for how to set the upstream.

OAuth Metadata ​

When you set WANAKU_AUTH_ISSUER, the MCP metadata feature exposes OAuth Protected Resource Metadata:

text
GET /.well-known/oauth-protected-resource/{namespace}/mcp

The MCP listener (port 8081) serves this route, not the management API. For example:

bash
curl http://localhost:8081/.well-known/oauth-protected-resource/default/mcp

MCP clients use this document to find the authorization server. An external authentication proxy enforces access to the MCP endpoint. See Authentication.

Web UI Plugins ​

Open Plugin Catalog in the admin UI to browse available plugins. Select Info to view the metadata and required services. Select Install to download and install the archive. Set the service URLs in the configuration dialog when the plugin requires backend services. Reload the admin UI after installation to load the plugin. The server adds the plugin to the list without a restart. The UI shows Not specified or None when the source has no value for a field.

GET /api/v1/plugins/catalog returns available plugins in the standard data response field. Each entry contains id, name, version, description, publisher, license, dependencies, requires, metadata, and url. The url field identifies the installation archive. The requires.services field lists the backend services that the plugin needs.

The default source is the embedded features/plugins/plugin-catalog.json file. The server uses the plugin description and publisher from each catalog entry. It does not read GitHub release notes or plugin archives during catalog requests.

WANAKU_PLUGIN_CATALOG_PATH selects a local JSON file. WANAKU_PLUGIN_CATALOG_URL selects a remote JSON file. A local path takes precedence. A custom source replaces the complete default catalog. See Plugin Catalog for the source format and publication instructions.

The endpoint returns HTTP 502 if the selected source is unavailable or invalid. It does not use a fallback source. A request has a 30-second limit. A remote download has a 15-second limit. Catalog JSON has a 1 MiB size limit.

MethodPathPurpose
GET/api/v1/pluginsList discovered UI plugin manifests.
GET/api/v1/plugins/catalogList the plugins in the selected catalog.
POST/api/v1/plugins/installDownload a ZIP archive and install a plugin. The body is {"id": "...", "version": "...", "url": "..."}.
PUT/api/v1/plugins/{pluginId}/configReplace the backend service mappings of a plugin. The body is {"services": {"<serviceId>": {"target": "<url>"}}}.
GET/plugins/{pluginId}/{path}Get a static plugin file.
Any HTTP method/api/plugins/{pluginId}/{serviceId}/{path}Send a request through a configured plugin service mapping.

The plugin proxy accepts only plugin and service IDs that Wanaku loaded from configuration. It forwards the request method, body, query, and selected headers to the configured service. See Backend configuration.

Persistence ​

Wanaku enables file persistence by default. It stores registry snapshots in $HOME/.wanaku/server. After each registry change, Wanaku queues a snapshot and writes it in the background. On an orderly shutdown, Wanaku waits up to 10 seconds for the last write to finish.

Set WANAKU_PERSIST_BACKEND=none to disable persistence. Set WANAKU_PERSIST_PATH to use a different directory.

File persistence supports one writer. Do not run multiple replicas against the same persistence directory.

Status Codes ​

The API uses these status codes:

  • 200 OK: The request succeeded. Core delete routes return a JSON confirmation in the standard envelope.
  • 202 Accepted: The server started an asynchronous job, for example a policy simulation replay.
  • 400 Bad Request: The request body is missing or invalid.
  • 404 Not Found: The route or requested entry does not exist.
  • 408 Request Timeout: A policy simulation exceeded its time limit.
  • 409 Conflict: An expected_revision does not match the active revision, an entry already exists, or a label precondition failed.
  • 413 Payload Too Large: The request body is larger than 1 MiB, or a simulation exceeded a size limit.
  • 422 Unprocessable Entity: The configuration or candidate is well-formed but does not validate, or a plugin archive is not valid.
  • 429 Too Many Requests: All simulation permits are in use, or the external audit capacity is full.
  • 500 Internal Server Error: The server could not complete the request.
  • 502 Bad Gateway: A plugin catalog, a plugin archive download, or a plugin service request failed.
  • 503 Service Unavailable: The audit store or the simulation store is not available.

Plugin file and proxy routes can return other status codes from file handling or the upstream service.

CORS ​

The management API sets Access-Control-Allow-Origin from WANAKU_CORS_ORIGIN. The default value is *.

Set a specific origin in production:

bash
export WANAKU_CORS_ORIGIN=https://app.example.com

The management API sets only the Access-Control-Allow-Origin header. It does not answer OPTIONS preflight requests. Thus, a browser on another origin can send simple GET requests, but a cross-origin JSON POST or PUT request fails the preflight. Serve browser clients from the same origin as the management API, or put a reverse proxy in front of it that handles preflight requests.

The MCP endpoint (port 8081) and the inference proxy (port 8083) each use their own pipeline CORS filter, set from the same WANAKU_CORS_ORIGIN value.

Next steps ​