Use the examples below as starting points, adapt them to your repo, and validate them with the Go-based CLI:
eunox-mcp validate ./eunox.policy.yaml
# reference the policy from a route's `policy:` in eunox.yaml, then:
eunox-mcp proxy --config ./eunox.yaml
| Policy | Upstream | What it enforces |
|---|---|---|
filesystem.policy.yaml
|
@modelcontextprotocol/server-filesystem |
Writes & deletes confined to /data/; executable
file types blocked.
|
postgres.policy.yaml
|
@modelcontextprotocol/server-postgres |
Non-SELECT SQL blocked; credential and audit tables
blocked.
|
github.policy.yaml
|
@modelcontextprotocol/server-github |
Write tools rate-limited to prevent runaway automation. |
slack.policy.yaml
|
@modelcontextprotocol/server-slack |
Direct messages restricted to your domain via
recipientDomain.
|
fetch.policy.yaml
|
mcp-server-fetch |
HTTP blocked; userinfo authority blocked; private RFC-1918 and metadata endpoints blocked (lexical SSRF guard). |
Filesystem
Stops the agent from reading sensitive file types and confines writes to
a sandbox directory. argumentSchema is a top-level field on
the constraint (not a condition); maxCalls uses
count.
schemaVersion: "0.1"
name: filesystem-agent
version: 0.1.0
capabilities:
- target: tool:read_file
actions: [call]
conditions:
- type: allowedExtensions
argument: path
extensions: [".csv", ".json", ".txt", ".md"]
- target: tool:write_file
actions: [call]
argumentSchema:
type: object
required: [path, content]
properties:
path: { type: string, pattern: "/data/.*" }
content: { type: string }
additionalProperties: false
conditions:
- type: allowedExtensions
argument: path
extensions: [".csv", ".json", ".txt", ".md"]
- type: maxCalls
count: 100
windowSeconds: 60
- target: tool:list_directory
actions: [call]
Postgres
SELECT-only, with a per-session call cap. Table-level
protection comes from running the upstream under a read-only database
role — the proxy can't reliably pull table names out of free-form SQL,
so it doesn't try.
schemaVersion: "0.1"
name: postgres-agent
version: 0.1.0
capabilities:
- target: tool:query
actions: [call]
conditions:
- type: allowedOperations
argument: sql
operations: [SELECT, EXPLAIN, SHOW]
- type: maxCalls
count: 100
windowSeconds: 60
GitHub
Read-heavy, write-rate-limited — protects against runaway issue or PR creation.
schemaVersion: "0.1"
name: github-agent
version: 0.1.0
capabilities:
- target: tool:search_repositories
actions: [call]
- target: tool:get_file_contents
actions: [call]
- target: tool:create_issue
actions: [call]
conditions:
- type: maxCalls
count: 10
windowSeconds: 3600
- target: tool:create_pull_request
actions: [call]
conditions:
- type: maxCalls
count: 5
windowSeconds: 3600
Slack
Restricts DMs to your own domain — a single
recipientDomain condition stops agents from leaking
conversations. Channel posting (post_message) addresses
Slack channel IDs (e.g. C12345), so a domain gate doesn't
apply there.
schemaVersion: "0.1"
name: slack-agent
version: 0.1.0
capabilities:
- target: tool:send_dm
actions: [call]
conditions:
- type: recipientDomain
argument: to
domains: [company.com]
- type: maxCalls
count: 20
windowSeconds: 3600
- target: tool:post_message
actions: [call]
conditions:
- type: maxCalls
count: 50
windowSeconds: 3600
Fetch — lexical SSRF guard
Blocks http://, userinfo authorities, and private RFC-1918
ranges including the cloud metadata endpoint
169.254.169.254. The guard is implemented purely with
argumentSchema + maxCalls — no custom
condition module required. Read it as a defense-in-depth guard
rather than a complete SSRF solution — pair with network-level controls
in production.
schemaVersion: "0.1"
name: fetch-agent
version: 0.1.0
capabilities:
- target: tool:fetch
actions: [call]
argumentSchema:
type: object
required: [url]
additionalProperties: false
properties:
url:
type: string
# https only; reject userinfo (user@host), loopback,
# RFC-1918 ranges, and the 169.254/16 metadata endpoint.
pattern: 'https://(?!(?:[^/]*@|localhost|127\.|10\.|192\.168\.|172\.(?:1[6-9]|2[0-9]|3[01])\.|169\.254\.)).*'
method:
type: string
enum: [GET, HEAD, OPTIONS]
conditions:
- type: maxCalls
count: 60
windowSeconds: 60
tools/call,
resources/read, prompts/get,
sampling/createMessage, and unrecognized methods. Only
capabilities explicitly listed in the manifest are permitted.