> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Server: Unified

> Deploy a unified server with all PraisonAI providers

Deploy a unified server that combines all PraisonAI provider types in a single endpoint.

## CLI

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
pip install "praisonai[serve]"
export OPENAI_API_KEY="your-key"

# Start unified server
praisonai serve unified --port 8765
```

**Expected Output:**

```
🚀 Starting Unified PraisonAI Server...
   Host: 127.0.0.1
   Port: 8765
   Providers: agents-api, recipe, mcp, a2a, a2u
📡 Discovery: http://127.0.0.1:8765/__praisonai__/discovery
✅ Server started at http://127.0.0.1:8765
```

## Python

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from fastapi import FastAPI
import uvicorn
from praisonaiagents import Agent

app = FastAPI(title="PraisonAI Unified Server")

# Create agents
assistant = Agent(
    name="Assistant",
    role="Helpful AI Assistant",
    goal="Help users with their questions",
    llm="gpt-4o-mini"
)

# Discovery endpoint
@app.get("/__praisonai__/discovery")
async def discovery():
    return {
        "schema_version": "1.0.0",
        "server_name": "praisonai-unified",
        "providers": [
            {"type": "agents-api", "name": "Agents API"},
            {"type": "recipe", "name": "Recipe Runner"},
            {"type": "mcp", "name": "MCP Server"},
            {"type": "a2a", "name": "A2A Protocol"},
            {"type": "a2u", "name": "A2U Event Stream"},
        ],
        "endpoints": [
            {"name": "agents", "provider_type": "agents-api"},
            {"name": "agent", "provider_type": "agents-api"},
            {"name": "mcp/tools", "provider_type": "mcp"},
            {"name": "a2a", "provider_type": "a2a"},
            {"name": "a2u/events", "provider_type": "a2u"},
        ]
    }

# Health endpoint
@app.get("/health")
async def health():
    return {"status": "healthy", "providers": 5}

# Agent endpoint
@app.post("/agent")
async def query_agent(request: dict):
    query = request.get("query", "")
    response = assistant.chat(query)
    return {"response": response}

uvicorn.run(app, host="0.0.0.0", port=8765)
```

<Note>
  `create_unified_app(..., api_key=...)` now installs the `_api_auth` middleware on every mounted route except `/health`. Existing callers that were passing `api_key=` but not sending `Authorization: Bearer` / `X-API-Key` from clients will start getting `401` — this closes a silent auth-bypass on the tool-driving routes.
</Note>

## Security

`praisonai serve unified` mounts tool-driving routes (notably `POST /v1/tools/invoke` via `mount_provider_routes`), so binding it to a non-localhost interface without authentication is refused.

<Warning>
  Binding to any host other than `127.0.0.1` / `localhost` / `::1` **requires** an API key. The server exits immediately (`SystemExit`) if neither `--api-key` nor `PRAISONAI_SERVE_API_KEY` is set.
</Warning>

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Localhost — no key required
praisonai serve unified --port 8765

# Remote — key required (via env var)
export PRAISONAI_SERVE_API_KEY="your-secret"
praisonai serve unified --port 8765 --host 0.0.0.0

# Or via flag
praisonai serve unified --port 8765 --host 0.0.0.0 --api-key "your-secret"
```

Clients send the key in `Authorization: Bearer …` or `X-API-Key: …`. The `/health` route is public.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Start[praisonai serve unified] --> Host{Host is<br/>localhost?}
    Host -->|Yes| Run[Start — no key needed]
    Host -->|No| Key{--api-key or<br/>PRAISONAI_SERVE_API_KEY?}
    Key -->|Set| Auth[Start — Bearer / X-API-Key enforced]
    Key -->|Missing| Exit[SystemExit — refuse to bind]

    classDef decision fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef ok fill:#10B981,stroke:#7C90A0,color:#fff
    classDef stop fill:#8B0000,stroke:#7C90A0,color:#fff

    class Host,Key decision
    class Run,Auth ok
    class Exit stop
```

## Unified Endpoints

| Endpoint | Method | Provider | Description |
| - | - | - | - |
| `/__praisonai__/discovery` | GET | - | Discovery document |
| `/health` | GET | - | Health check |
| `/agents` | POST | agents-api | Multi-agent router |
| `/agent` | POST | agents-api | Single agent |
| `/mcp/tools` | GET | mcp | List MCP tools |
| `/mcp/tools/call` | POST | mcp | Call MCP tool |
| `/.well-known/agent.json` | GET | a2a | A2A agent card |
| `/a2a` | POST | a2a | A2A messages |
| `/a2u/info` | GET | a2u | A2U info |
| `/a2u/events/<stream>` | GET | a2u | A2U event stream |

## Discovery Document

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
curl http://localhost:8765/__praisonai__/discovery
```

**Response:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "schema_version": "1.0.0",
  "server_name": "praisonai-unified",
  "providers": [
    {"type": "agents-api", "name": "Agents API", "capabilities": ["invoke", "health"]},
    {"type": "recipe", "name": "Recipe Runner", "capabilities": ["list", "describe", "invoke"]},
    {"type": "mcp", "name": "MCP Server", "capabilities": ["list-tools", "call-tool"]},
    {"type": "a2a", "name": "A2A Protocol", "capabilities": ["agent-card", "message-send"]},
    {"type": "a2u", "name": "A2U Event Stream", "capabilities": ["subscribe", "stream"]}
  ],
  "endpoints": [...]
}
```

## Client Usage

Use the unified endpoints CLI to interact with any provider:

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# List all endpoints
praisonai endpoints list --url http://localhost:8765

# Filter by provider type
praisonai endpoints list --url http://localhost:8765 --type agents-api

# Get discovery document
praisonai endpoints discovery --url http://localhost:8765

# Health check
praisonai endpoints health --url http://localhost:8765
```

## CLI Options

| Option | Default | Description |
| - | - | - |
| `--port` | 8765 | Server port |
| `--host` | 127.0.0.1 | Server host |
| `--api-key` | - | API key. **Required when `--host` is not `127.0.0.1` / `localhost` / `::1`.** Can also be set via `PRAISONAI_SERVE_API_KEY`. Enforces `Authorization: Bearer` / `X-API-Key` on every route except `/health`. |
| `--file` | agents.yaml | Agents configuration file |

## Environment Variables

| Variable | Default | Description |
| - | - | - |
| `PRAISONAI_SERVE_API_KEY` | - | API key required to bind `praisonai serve unified` on a non-localhost host. The server exits with `SystemExit` if this is unset and no `--api-key` is passed when `--host` is not localhost. Also drives the `_api_auth` middleware when the server is running. |

## Provider Types

| Type | Description |
| - | - |
| `recipe` | Recipe runner endpoints |
| `agents-api` | Single/multi-agent HTTP API |
| `mcp` | MCP server (stdio, http, sse) |
| `tools-mcp` | Tools exposed as MCP server |
| `a2a` | Agent-to-agent protocol |
| `a2u` | Agent-to-user event stream |

## Troubleshooting

| Issue | Fix |
| - | - |
| Port in use | `lsof -i :8765` |
| Missing deps | `pip install "praisonai[serve]"` |
| No API key | `export OPENAI_API_KEY="your-key"` |
| Provider not found | Check discovery document |
| `--api-key ... is required when binding to a non-localhost host` at startup | Set `PRAISONAI_SERVE_API_KEY=...` (or `--api-key ...`), or bind to `127.0.0.1` / `localhost` for a private-only server. |

## Related

* [Endpoints CLI](/docs/cli/endpoints) - Client for all server types
* [Serve CLI](/docs/cli/serve) - All serve commands
* [A2A Server](./a2a) - Agent-to-agent protocol
* [A2U Server](./a2u) - Agent-to-user events
* [Agents Server](./agents) - HTTP API server


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.