{"id":47623353,"url":"https://github.com/radoslaw-sz/guardio","last_synced_at":"2026-04-01T22:28:44.546Z","repository":{"id":341000324,"uuid":"1150420837","full_name":"radoslaw-sz/guardio","owner":"radoslaw-sz","description":"The most flexible control plane for AI Agent systems","archived":false,"fork":false,"pushed_at":"2026-03-19T08:34:17.000Z","size":1154,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-20T01:50:23.997Z","etag":null,"topics":["ai","ai-agent","ai-agents","control-plane","framework","guard","mcp","security"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/radoslaw-sz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-05T09:01:12.000Z","updated_at":"2026-03-19T08:34:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/radoslaw-sz/guardio","commit_stats":null,"previous_names":["radoslaw-sz/guardio"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/radoslaw-sz/guardio","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radoslaw-sz%2Fguardio","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radoslaw-sz%2Fguardio/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radoslaw-sz%2Fguardio/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radoslaw-sz%2Fguardio/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/radoslaw-sz","download_url":"https://codeload.github.com/radoslaw-sz/guardio/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/radoslaw-sz%2Fguardio/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","ai-agent","ai-agents","control-plane","framework","guard","mcp","security"],"created_at":"2026-04-01T22:28:43.974Z","updated_at":"2026-04-01T22:28:44.535Z","avatar_url":"https://github.com/radoslaw-sz.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"packages/dashboard/public/favicon.svg\" alt=\"Guardio\" width=\"48\" height=\"48\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003e\n    Guardio\n  \u003c/h1\u003e\n\u003c/p\u003e\n\nGuardio is a **control plane** that sits between your **AI Agent system** and the external world. It catches and evaluates messages flowing to and from **MCP tools** and other APIs before they reach the real servers. You can enforce policies (allow, block, sanitize), require approval, simulate MCP responses and observe activity—all through a **plugin system**.\n\n\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003cimg alt=\"High view\" src=\"./docs/high-view-2.png\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n## Supported connections\n\n| Connection type             | Status     | Notes                                                 |\n| --------------------------- | ---------- | ----------------------------------------------------- |\n| **HTTP server**             | Supported  | Guardio runs as an HTTP server; clients connect here. |\n| **MCP tool (upstream)**     | Supported  | Proxying to MCP servers over HTTP/SSE.                |\n| **stdio**                   | On the way | Client transport.                                     |\n| **Other APIs / transports** | On the way | Extensible for more protocols.                        |\n\nToday you run one **Guardio instance** that fronts **all** your external MCP tools and APIs (one proxy, many upstreams).\n\n---\n\n## Quick start\n\n### Create a Guardio project\n\nScaffold a new project with config and optional plugins:\n\n```bash\nnpx create-guardio\n```\n\nYou will be prompted for:\n\n- **Guardio directory** – e.g. `guardio-project` (default)\n- **Guardio HTTP port** – e.g. `3939`\n- **Storage and events** – optional; needed for dashboard and policy state. Choose SQLite (in-memory by default, or file `guardio.sqlite`) or PostgreSQL.\n- **Example custom policy plugin?** – optional; scaffolds `plugins/example`\n- **Install dashboard?** – optional; adds `@guardiojs/dashboard` and a `dashboard` run script\n\nThe scaffold creates **empty `servers`** by default. A commented example in `guardio.config.ts` shows how to add an MCP server (e.g. `{ name: \"nuvei-docs\", type: \"url\", url: \"https://mcp.nuvei.com/sse\" }`). All built-in policy plugins (**deny-tool-access**, **deny-regex-parameter**) are included by default.\n\nThen:\n\n```bash\ncd \u003cguardio-directory\u003e\nnpm install   # or: pnpm install, yarn, bun install, etc.\nnpm run guardio\n```\n\nPoint your AI Agent or MCP client at `http://127.0.0.1:\u003cport\u003e`. If you installed the dashboard, run `pnpm run dashboard` (or `npm run dashboard`) and point it at the same Guardio base URL.\n\n### Run Guardio with Docker\n\nA minimal Docker image is provided for the core Guardio HTTP server (package `@guardiojs/guardio`). Build it from the `packages/guardio` directory:\n\n```bash\ncd packages/guardio\ndocker build -t guardio .\n```\n\nRun the container, mounting your `guardio.config.*` into the container and mapping the HTTP port (defaults to `3939` unless overridden in config or via env):\n\n```bash\ndocker run --rm \\\n  -p 3939:3939 \\\n  -v \"$(pwd)/guardio.config.ts:/config/guardio.config.ts:ro\" \\\n  guardio \\\n  --config /config/guardio.config.ts\n```\n\nThe container:\n\n- **Exposes** port `3939` by default (override with `GUARDIO_HTTP_PORT` / `GUARDIO_HTTP_HOST`).\n- **Starts** the Guardio CLI via `node bin/guardio.mjs` (you can pass any CLI args after the image name).\n\n---\n\n## Concepts\n\n### AI Agent connection\n\nAI Agents (MCP clients) connect to **Guardio's HTTP server**, not directly to the upstream MCP servers. Guardio is the single entry point.\n\n- **SSE (stream)** – Connect to `http://\u003chost\u003e:\u003cport\u003e/{serverName}/sse` for the MCP SSE stream. Use the **server name** from your config (e.g. `nuvei-docs` → `/nuvei-docs/sse`).\n- **Optional `x-agent-name`** – Send this header on the SSE connection to give the agent a human-readable name. If omitted, Guardio generates one. The connection is assigned an agent id used for policy scoping.\n- **POST messages** – Send JSON-RPC to `http://\u003chost\u003e:\u003cport\u003e/{serverName}/messages`. You can send **`x-agent-id`** (the id for the SSE connection) so policies can be applied per agent.\n\nSo: one Guardio URL base, multiple paths like `/{mcp-tool}/sse` and `/{mcp-tool}/messages` for each configured upstream.\n\n### MCP tool connection\n\nIn your config you define a **`servers`** array. Each entry has a **`name`** (unique, used in the URL path) and an **`url`** (the upstream MCP server's HTTP/SSE base URL). Guardio proxies:\n\n- **GET /{name}/sse** – to the upstream SSE endpoint (and manages the stream).\n- **POST /{name}/messages** – to the upstream after running policies (or returns a blocked result without forwarding).\n\nSo each \"MCP tool\" or upstream is one entry in `servers`; a single Guardio instance serves all of them.\n\n### Plugins\n\nPlugins extend Guardio's behavior. Types:\n\n| Type               | Role                                                                                                                   |\n| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |\n| **Policy**         | Evaluate `tools/call` requests: allow, block, or modify arguments. Optional; no policies means all calls pass through. |\n| **Storage**        | Persist state (e.g. policy assignments, agent list). Used by built-in policy config and dashboard.                     |\n| **EventSink**      | Receive events for each processed request (e.g. ALLOWED/BLOCKED, tool name, policy).                                   |\n| **EventSinkStore** | Store and query events; used by the dashboard for activity views.                                                      |\n\n**Built-in plugins:**\n\n- **Policy:** `deny-tool-access`, `deny-regex-parameter` (both are added by default when you scaffold with `create-guardio`)\n- **Storage / EventSink / EventSinkStore:** `sqlite` or `postgres`\n  - **sqlite:** `config: { inMemory: true }` (default) or `config: { database: \"guardio.sqlite\" }` for a file\n  - **postgres:** `config: { connectionString: \"postgresql://user:pass@host:5432/dbname\" }` or discrete `host`, `port`, `user`, `password`, `database`, `ssl`\n\nYou register plugins in **`guardio.config.ts`** in the **`plugins`** array. Policy config for built-ins is typically managed at runtime (e.g. via the dashboard), not in the config file.\n\n### Create a custom plugin\n\nUse a **path-based** plugin: in config add an entry with **`path`** pointing to a directory that contains **`index.js`** or **`index.mjs`** (build from `index.ts` if needed).\n\nExport a **`PolicyPluginDefinition`** with a factory function. This enables full dashboard integration: runtime configuration, multiple instances, config validation, and custom form widgets.\n\n```ts\n// plugins/my-policy/index.ts\nimport { z } from \"zod\";\nimport type {\n  PolicyPluginDefinition,\n  PolicyPluginInterface,\n  PolicyRequestContext,\n  PolicyResult,\n  PolicyPluginContext,\n} from \"@guardiojs/guardio\";\n\n// Config schema for dashboard validation\nconst configSchema = z.object({\n  maxLength: z.number().min(1).describe(\"Maximum argument length\"),\n  blockedPatterns: z.array(z.string()).optional(),\n});\n\ntype Config = z.infer\u003ctypeof configSchema\u003e;\n\nclass MyPolicyPlugin implements PolicyPluginInterface {\n  readonly name = \"my-policy\";\n  constructor(\n    private config: Config,\n    private context?: PolicyPluginContext,\n  ) {}\n\n  async evaluate(ctx: PolicyRequestContext): Promise\u003cPolicyResult\u003e {\n    // Access config: this.config.maxLength\n    // Access plugin storage: this.context?.pluginRepository\n    return { verdict: \"allow\" };\n  }\n}\n\nconst definition: PolicyPluginDefinition = {\n  name: \"my-policy\",\n  factory: (config, context) =\u003e new MyPolicyPlugin(config as Config, context),\n  configSchema,\n  uiSchema: {\n    maxLength: { \"ui:widget\": \"updown\" },\n  },\n};\n\nexport default definition;\n```\n\nIn config:\n\n```ts\n{ type: \"policy\", name: \"my-policy\", path: \"./plugins/my-policy\" }\n```\n\nCustom plugins work exactly like built-in plugins:\n- Create multiple instances with different configs via the dashboard\n- Configs are stored in the database and validated against your schema\n- Plugins receive a `PolicyPluginContext` with a scoped `PluginRepository` for persisting plugin-specific state\n\nIf you chose \"Add example custom policy plugin\" when running `npx create-guardio`, see the generated `plugins/example` folder.\n\n---\n\n## Processing\n\n### Evaluating policy\n\nWhen a **`tools/call`** request hits Guardio (POST `/{serverName}/messages`):\n\n1. Guardio resolves which **policy plugins** apply (from storage, optionally scoped by agent and tool).\n2. Each policy's **`evaluate`** is run with the tool name and arguments.\n3. If any policy returns **block**, the call is **not** forwarded. Guardio responds with a **success** JSON-RPC result that includes a human-readable message and **`_guardio`** metadata (so agent frameworks don't treat it as a fatal error).\n4. If all policies **allow**, the request (with any **modified arguments**) is forwarded to the upstream MCP server and the response is proxied back.\n\nNon–`tools/call` messages are forwarded without policy evaluation.\n\n### Emitting events\n\nIf **EventSink** plugins are configured, Guardio emits a **GuardioEvent** for each processed `tools/call` (both allowed and blocked). The event includes:\n\n- **decision** – `ALLOWED` or `BLOCKED`\n- **tool name**, **request id**, **agent id** (if present)\n- For blocks: **policy name**, **code**, **reason**\n\nEventSinkStore (e.g. sqlite or postgres) persists these for the dashboard and for your own auditing.\n\n---\n\n## Simulation Mode (Testing)\n\nGuardio supports **Simulation Mode**, which returns **mocked tool responses** instead of calling the real upstream MCP server. This is useful for testing and demos because **policies still run first**, but the upstream call is skipped.\n\n### How Simulation Mode is applied\n\n- **Global simulation**: when enabled, **all** `tools/call` requests are simulated (regardless of per-tool settings).\n- **Per-tool simulation**: when global simulation is off, you can mark specific tools as simulated **per MCP server + tool name**.\n- **Per-request header**: `X-Guardio-Mode: simulation` can simulate a single request when global simulation is off.\n\n### Dashboard controls\n\nIn the dashboard sidebar, open **Testing → Simulation** to:\n\n- Toggle **Global simulation** on/off\n- Configure **Per-tool simulation** per MCP server + tool\n\nThese settings are stored in the database (runtime settings) and can be changed **without restarting** Guardio.\n\n### API endpoints\n\n- **GET** `/api/testing/simulation` – returns current simulation settings\n- **PUT** `/api/testing/simulation` – updates simulation settings\n\nExample payload:\n\n```json\n{\n  \"globalSimulated\": false,\n  \"tools\": [\n    { \"serverName\": \"docs\", \"toolName\": \"search\", \"simulated\": true }\n  ]\n}\n```\n\n### Events\n\nWhen Simulation Mode is used for a `tools/call`, Guardio records simulation details in the event so the dashboard activity feed can render it (e.g. `simulation.enabled` and `simulation.source`).\n\n---\n\n## Configuration and running\n\n- **Config file:** `guardio.config.ts` (or pass `--config \u003cpath\u003e`). It must export a **`GuardioConfig`** with **`servers`** (array of `{ name, type: \"url\", url }`; can be empty) and **`plugins`**. The scaffold adds a commented example server in the config so you can uncomment and edit to add MCP upstreams.\n- **Client (HTTP server):** Optional **`client`** with **`port`** (default `3939`) and **`host`** (default `127.0.0.1`). Override with **`GUARDIO_HTTP_PORT`** and **`GUARDIO_HTTP_HOST`**.\n- **Debug:** `GUARDIO_DEBUG=1` to log request/response flow.\n\nBlocked tool calls return a **success** result with **`result.isError: true`** and **`result._guardio`** (version, requestId, timestamp, policyId, action). See the repo for the full response shape.\n\n---\n\n## Dashboard\n\n\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003cimg alt=\"High view\" src=\"./docs/topology-example.png\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\nThe **dashboard** is a Next.js web UI for Guardio. It lets you view activity (allowed/blocked tool calls), manage policies, and inspect agents and topology. You can add it when scaffolding with `npx create-guardio` (choose \"Install dashboard?\").\n\n---\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradoslaw-sz%2Fguardio","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fradoslaw-sz%2Fguardio","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fradoslaw-sz%2Fguardio/lists"}