Skip to content

Policer

primalmotion edited this page May 15, 2025 · 5 revisions

While Minibridge already offers advanced features such as strong client authentication and SBOM validation, it can be further enhanced through integration with a Policer. A Policer is responsible for:

  • Authentication
  • Authorization
  • Input analysis and logging
  • Full request tracing
  • And more advanced policy-based controls

There are various available policers in Minibridge:

  • HTTP policer: sends a request to a remote HTTP service to delegate decision
  • Rego policer: runs a rego policy file on the request

Note

More policers will be added!

The Policer, if set, will be called and passed various information so it can make a decision on what to do with the request, based on the user who initiated the request and the content of the request.

You can then start Minibridge, using either the aio or backend subcommand, with the following arguments to start an HTTP policer:

minibridge aio --policer-type http \
  --policer-http-url https://policer.acme.com/police \
  --policer-http-bearer-token $PTOKEN

Or using with the following command to start Minibridge with a Rego policer:

minibridge aio --policer-type rego \
  --policer-rego-policy ./example/policer-rego/policy.rego

Once integrated, any command from the user or response from the MCP Server received by the backend is first passed to the Policer for authentication and/or analysis.

Policer API

Police Request

The Policer will receives the following information:

{
  "type": "request|response"
  "agent": {
    "user": "user",
    "password": "password",
    "userAgent": "curl/7.54.1",
    "remoteAddr": "10.0.1.265:44536",
  },
  "mcp": {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
  }
}

The Policer can use this information to decide if the request should be denied.

The agent contains the information about the caller which are useful to handle the Authentication:

  • user/password the username/password when using a Basic Authentication. Password contains the token if you are using a Bearer Authentication.
  • userAgent the user agent of the caller
  • remoteAddr the caller address as seen by the minibridge frontend. The address is passed to the minibridge backend.

Police Response

The policer must return a response with the following information:

{
  "allow": false,
  "reasons": ["reason 1", "reason 2"],
  "mcp": null
}
  • If allow is true, the request or response is allowed and will be forwarded.

  • If allowed is false, then the request or response is considered as blocked and Minibridge will not forward it to the MCP server or to the Agent. Instead, it will return a descriptive MCP error containing the reasons (if any), to the caller. If no reasons are set (empty or null), a generic reason will be used.

  • In addition, if allow is true, and mcp is non null, Minibridge will swap the original MCP call with the one provided in the response, allowing Policers to mutate the call. For instance this can be used to hide some tools based on the agent identity. You cannot change the MCP call ID. If you do, it will be overwritten with the original ID anyway.

Available Policers

Rego Policer

The Rego Policer allows to run the Police Request through a rego policy to decide if the request should be allowed or not. The Police Request is passed an input, and the rego policy must either return and allow := true or allow := false and optionally a list of reasons containing strings explaining what's wrong with the request.

Note

The rego package must be named main.

For instance, to allow the request:

package main

import rego.v1

allow := true

To deny the request:

package main

import rego.v1

allow if {
  count(reasons) == 0
}

reasons contains "authentication required" if {
  input.agent.password == ""
}
Example
package main

import rego.v1

allowed_urls := {"https://acuvity.ai"}

# Look for tool/calls, fetch method and url argument parameter
reasons contains msg if {
	input.mcp.method == "tools/call"
	input.mcp.params.name == "fetch"
	url := input.mcp.params.arguments.url
	not url in allowed_urls
	msg := sprintf("fetch to URL '%s' is not allowed", [url])
}

allow if {
	count(reasons) == 0
}

HTTP Policer

The HTTP Policer will receive the Police Request as POST on the url provided by --policer-http-url.

To allow the request or response, the HTTP Policer must respond with:

  • An HTTP status 204 No Content, or
  • An HTTP status 200 OK with allow property set true.

To disallow the request or response:

  • An HTTP status 200 OK with allow set to false and optional reasons.
  • Any other HTTP code will also deny the request, but is considered as an error.

For example, a policy result that allows the request:

HTTP/1.1 204 No Content

Or

HTTP/1.1 200 OK


{ "allow": true }

And a policy result that denies the request:

HTTP/1.1 200 OK


{ "allow": false, "reasons": ["You are not allowed to list the tools"] }

The HTTP Policer can also decide to mutate the MCP call. To do so, it must allow the request, and pass back a modified MCP call:

HTTP/1.1 200 OK


{
  "allow": true,
  "mcp": {
    "id": 2,
    "jsonrpc": "2.0",
    "result": {
    "tools": [{
      "description": "POLICER HAS MODIFIED THIS DESCRIPTION",
      "name": "echo"
    }]
  }
}

Tip

Check out the Policer HTTP examples

Clone this wiki locally