mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
321 lines
9.3 KiB
Markdown
321 lines
9.3 KiB
Markdown
# Authentik MCP Bridge Specification
|
|
|
|
> **Purpose**: Define a Model Context Protocol (MCP) server surface so any LLM can safely manage Authentik identities through structured tools.
|
|
> **Status**: Draft — not yet implemented
|
|
> **Last updated**: 2026-05-20
|
|
|
|
---
|
|
|
|
## 1. What is MCP?
|
|
|
|
[Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for exposing tools, resources, and prompts to LLMs. An MCP server provides a JSON-RPC interface that a client (Claude Desktop, Cursor, a custom agent harness) can discover and invoke.
|
|
|
|
For Authentik, an MCP bridge means:
|
|
|
|
- **No raw curl** in the LLM prompt. The LLM calls `create_agent("openclaw-7", ...)` and the bridge handles the REST API.
|
|
- **Type safety**: input schemas are JSON Schema; the bridge validates before touching Authentik.
|
|
- **Auditability**: every tool call is logged with arguments and results.
|
|
- **Rate limiting / circuit breaking**: the bridge can throttle or deny dangerous operations.
|
|
|
|
---
|
|
|
|
## 2. Bridge Architecture
|
|
|
|
```
|
|
┌─────────────────┐ MCP (stdio/sse) ┌──────────────────┐ REST + Bearer ┌─────────────┐
|
|
│ LLM Client │ ───────────────────────▶ │ Authentik MCP │ ───────────────────▶ │ Authentik │
|
|
│ (Claude / │ JSON-RPC 2.0 │ Bridge Server │ Token │ API │
|
|
│ Cursor / etc) │ │ (Python/Node) │ │ :9000 │
|
|
└─────────────────┘ └──────────────────┘ └─────────────┘
|
|
│
|
|
│
|
|
┌────────▼─────────┐
|
|
│ Audit Log │
|
|
│ (JSONL + S3) │
|
|
└─────────────────┘
|
|
```
|
|
|
|
> **Authentication required**: The bridge itself must be authenticated by Authentik. It reads `AUTHENTIK_TOKEN` at startup (from env var or the credential server). The token must belong to an Authentik account with admin-level privileges (e.g., `llm-agent-controller` in the `authentik Admins` group). Without a valid token, every tool call returns an authentication error.
|
|
|
|
### Transport options
|
|
|
|
| Transport | Use case | Endpoint |
|
|
|-----------|----------|----------|
|
|
| `stdio` | Local CLI tools, Claude Desktop | `authentik-mcp-bridge stdio` |
|
|
| `sse` | Remote/web clients, persistent connection | `authentik-mcp-bridge sse --port 8080` |
|
|
|
|
---
|
|
|
|
## 3. Tool Surface
|
|
|
|
### 3.1 `create_agent`
|
|
|
|
Create a service-account user in Authentik.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"username": "openclaw-instance-7",
|
|
"name": "OpenClaw Instance 7",
|
|
"email": "openclaw-7@researchstack.info",
|
|
"group": "AgentManager"
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"pk": 42,
|
|
"username": "openclaw-instance-7",
|
|
"uuid": "...",
|
|
"group_assigned": true
|
|
}
|
|
```
|
|
|
|
**Implementation**: `POST /core/users/` then `POST /core/groups/{uuid}/add_user/`
|
|
|
|
---
|
|
|
|
### 3.2 `create_token`
|
|
|
|
Generate an API token for an existing agent.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"user_pk": 42,
|
|
"identifier": "openclaw-7-token"
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"identifier": "openclaw-7-token",
|
|
"key": "keJxas4I...",
|
|
"warning": "Store immediately — shown once"
|
|
}
|
|
```
|
|
|
|
**Implementation**: `POST /core/tokens/` then `GET /core/tokens/{identifier}/view_key/`
|
|
|
|
---
|
|
|
|
### 3.3 `list_agents`
|
|
|
|
List all service-account users.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"active_only": true
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"agents": [
|
|
{"pk": 7, "username": "llm-agent-controller", "is_active": true},
|
|
{"pk": 42, "username": "openclaw-instance-7", "is_active": true}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Implementation**: `GET /core/users/` with `?type=service_account` filter
|
|
|
|
---
|
|
|
|
### 3.4 `suspend_agent`
|
|
|
|
Soft-delete (deactivate) an agent.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"user_pk": 42
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"pk": 42,
|
|
"is_active": false
|
|
}
|
|
```
|
|
|
|
**Implementation**: `PATCH /core/users/{pk}/` with `{"is_active": false}`
|
|
|
|
---
|
|
|
|
### 3.5 `revoke_agent`
|
|
|
|
Hard-delete an agent and all its tokens.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"user_pk": 42
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"pk": 42,
|
|
"status": "deleted"
|
|
}
|
|
```
|
|
|
|
**Implementation**: `DELETE /core/users/{pk}/`
|
|
|
|
---
|
|
|
|
### 3.6 `rotate_token`
|
|
|
|
Regenerate the key for an existing token.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"identifier": "openclaw-7-token"
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"identifier": "openclaw-7-token",
|
|
"key": "newKey...",
|
|
"warning": "Old key invalidated immediately"
|
|
}
|
|
```
|
|
|
|
**Implementation**: `POST /core/tokens/{identifier}/set_key/`
|
|
|
|
---
|
|
|
|
### 3.7 `create_application`
|
|
|
|
Create an application that agents can be granted access to.
|
|
|
|
**Input schema**:
|
|
```json
|
|
{
|
|
"name": "OpenClaw Data Sink",
|
|
"slug": "openclaw-data-sink"
|
|
}
|
|
```
|
|
|
|
**Output**:
|
|
```json
|
|
{
|
|
"slug": "openclaw-data-sink",
|
|
"name": "OpenClaw Data Sink",
|
|
"meta_launch_url": ""
|
|
}
|
|
```
|
|
|
|
**Implementation**: `POST /core/applications/`
|
|
|
|
---
|
|
|
|
## 4. Safety Boundaries
|
|
|
|
| Boundary | MCP Bridge Rule |
|
|
|----------|-----------------|
|
|
| **Token exposure** | `create_token` returns the key exactly once. The bridge does not log the key. The LLM client must store it in SOPS/RDS. |
|
|
| **Scope** | The bridge authenticates with the `llm-controller-token`. It cannot escalate beyond what that token permits. |
|
|
| **Rate limit** | Configurable: max 10 `create_agent` calls per minute, max 3 `revoke_agent` calls per minute. |
|
|
| **Deny list** | The bridge refuses to operate on `akadmin` (pk=6) and `llm-agent-controller` (pk=7). |
|
|
| **Audit** | Every call writes a JSON line to `~/.cache/authentik-mcp-bridge.jsonl` and optionally to `s3://research-stack/agent-receipts/`. |
|
|
|
|
---
|
|
|
|
## 5. Reference Implementation (Python, stdio)
|
|
|
|
A minimal skeleton using the official `mcp` Python SDK:
|
|
|
|
```python
|
|
# /// script
|
|
# requires-python = ">=3.10"
|
|
# dependencies = [
|
|
# "mcp>=1.0.0",
|
|
# "httpx",
|
|
# ]
|
|
# ///
|
|
|
|
import os
|
|
import httpx
|
|
from mcp.server import Server
|
|
from mcp.server.stdio import stdio_server
|
|
from mcp.types import TextContent, Tool
|
|
|
|
AUTHENTIK_TOKEN = os.environ["AUTHENTIK_TOKEN"]
|
|
BASE_URL = "https://researchstack.info"
|
|
|
|
app = Server("authentik-mcp-bridge")
|
|
|
|
@app.list_tools()
|
|
async def list_tools():
|
|
return [
|
|
Tool(name="create_agent", description="Create a service account", inputSchema={...}),
|
|
Tool(name="create_token", description="Create an API token", inputSchema={...}),
|
|
Tool(name="list_agents", description="List agents", inputSchema={...}),
|
|
Tool(name="suspend_agent", description="Deactivate an agent", inputSchema={...}),
|
|
Tool(name="revoke_agent", description="Hard-delete an agent", inputSchema={...}),
|
|
Tool(name="rotate_token", description="Rotate a token key", inputSchema={...}),
|
|
]
|
|
|
|
@app.call_tool()
|
|
async def call_tool(name: str, arguments: dict):
|
|
async with httpx.AsyncClient(timeout=30) as client:
|
|
headers = {"Authorization": f"Bearer {AUTHENTIK_TOKEN}"}
|
|
if name == "create_agent":
|
|
r = await client.post(f"{BASE_URL}/api/v3/core/users/", headers=headers, json={...})
|
|
return [TextContent(type="text", text=r.text)]
|
|
# ... etc
|
|
|
|
async def main():
|
|
async with stdio_server() as (read, write):
|
|
await app.run(read, write, app.create_initialization_options())
|
|
|
|
if __name__ == "__main__":
|
|
import asyncio
|
|
asyncio.run(main())
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Deployment Plan
|
|
|
|
| Step | Action | Owner |
|
|
|------|--------|-------|
|
|
| 1 | Implement the 7 tools in Python using `mcp` SDK | Future agent |
|
|
| 2 | Add JSONL audit log + optional S3 sink | Future agent |
|
|
| 3 | Add rate limiting + deny-list for protected accounts | Future agent |
|
|
| 4 | Deploy as systemd service on qfox-1 or nixos-laptop | Future agent |
|
|
| 5 | Register with Claude Desktop / Cursor / OpenClaw harness | User |
|
|
| 6 | Document per-LLM configuration (env vars, transport mode) | Future agent |
|
|
|
|
---
|
|
|
|
## 7. Relationship to Existing Components
|
|
|
|
| Component | How MCP Bridge Uses It |
|
|
|-----------|----------------------|
|
|
| `authentik_agent_manager` (Rust) | The bridge is a higher-level wrapper around the same REST calls. The Rust shim supports both individual CLI commands and full DAG execution. The bridge is for LLM tool use. |
|
|
| Credential Server (RDS) | The bridge reads `AUTHENTIK_TOKEN` from the credential server at runtime: `curl http://100.101.247.127:8444/credentials/authentik` |
|
|
| SOPS secrets | Source of truth for the token. The bridge can optionally load from `sops -d` if the credential server is down. |
|
|
| `Authentik-Agent-Management.md` | Operational docs — the bridge implements the API patterns documented there. |
|
|
|
|
---
|
|
|
|
## 8. Open Questions
|
|
|
|
- Should the bridge support **application entitlement management** (granting an agent access to a specific app)? This requires `POST /core/application_entitlements/` which is more complex.
|
|
- Should the bridge support **group creation** so LLMs can define new scopes dynamically?
|
|
- Should the bridge support **impersonation** (`POST /core/users/{pk}/impersonate/`) for testing agent permissions?
|