Deploy Aira's MCP server in your own cloud for enterprise environments where data must stay within your infrastructure.
Why self-host
- Data sovereignty — All project data, sources, and LLM calls stay within your cloud
- Compliance — Meet internal security and regulatory requirements
- Network isolation — Keep the backend on a private network, only the MCP endpoint is public
- Custom models — Use your own LLM deployments or private model endpoints
What you need
- A running aira-agent (backend) instance — see Self-Hosting
- A running aira-web (frontend) instance for the OAuth consent flow
- Public HTTPS endpoint for the MCP server
- DNS records for your domain
Architecture
MCP Clients ──→ mcp.your-domain.com ──→ aira-mcp (FastMCP)
│
▼
aira-backend (FastAPI)
│
▼
PostgreSQL
Browser ──→ app.your-domain.com ──→ aira-web (Next.js)
│
└──→ aira-backend
Two services are involved:
- aira-backend — Your FastAPI instance. Contains the OAuth authorization server endpoints and all business logic.
- aira-mcp — A FastMCP service that exposes the
/mcpendpoint. Routes tool calls to the backend API.
Configuration
aira-backend environment
AIRA_MCP_OAUTH_ISSUER_URL=https://mcp.your-domain.com
AIRA_MCP_OAUTH_RESOURCE_SERVER_URL=https://mcp.your-domain.com
AIRA_MCP_OAUTH_AUTHORIZE_UI_URL=https://app.your-domain.com/api/auth/mcp/authorize
aira-mcp environment
AIRA_MCP_AUTH_MODE=oauth
AIRA_MCP_REQUIRE_API_KEY=false
AIRA_MCP_API_BASE_URL=https://<internal-backend-url>/api/v1
AIRA_MCP_OAUTH_ISSUER_URL=https://mcp.your-domain.com
AIRA_MCP_OAUTH_RESOURCE_SERVER_URL=https://mcp.your-domain.com
AIRA_MCP_OAUTH_REQUIRED_SCOPES=mcp
JWT_SECRET=<same value as backend JWT secret>
The JWT_SECRET must match between the backend and MCP service — they share the same token verification.
Deployment steps
1. Deploy infrastructure
If using Terraform with GCP:
cd aira-infra
# Set tfvars: domain, frontend_domain, mcp_domain, secrets
terraform init
terraform plan
terraform apply
2. Deploy backend and MCP services
Build and deploy both services via your CI/CD pipeline. Both need access to the PostgreSQL database.
3. Configure DNS
mcp.your-domain.com→ aira-mcp service (public)app.your-domain.com→ aira-web service (public)- Backend can be internal-only (no public ingress needed if MCP calls go through the load balancer)
4. Verify OAuth discovery
curl https://mcp.your-domain.com/.well-known/oauth-authorization-server
Should return the OAuth metadata document with authorization, token, and revocation endpoints.
5. Verify MCP endpoint
curl https://mcp.your-domain.com/mcp
6. Connect Claude Code
claude mcp add --transport http aira https://mcp.your-domain.com/mcp
OAuth endpoints
The backend serves these OAuth endpoints (automatically registered):
| Endpoint | Purpose |
|---|---|
/.well-known/oauth-authorization-server | OAuth discovery metadata |
/api/v1/mcp/oauth/register | Dynamic client registration |
/api/v1/mcp/oauth/authorize | Authorization endpoint |
/api/v1/mcp/oauth/token | Token exchange |
/api/v1/mcp/oauth/revoke | Token revocation |
Differences from managed remote
| Aspect | Managed | Self-hosted |
|---|---|---|
| Data location | Aira's cloud | Your cloud |
| OAuth issuer | mcp.aira.pro | mcp.your-domain.com |
| Consent UI | app.aira.pro | app.your-domain.com |
| Maintenance | Aira handles updates | You handle updates |
| LLM provider | Aira's API keys | Your API keys |
Security notes
- Keep the JWT secret consistent between backend and MCP service
- OAuth issuer and resource URLs must be exact and stable — changing them invalidates existing tokens
- Use a secret manager (GCP Secret Manager, AWS Secrets Manager, etc.) for all sensitive values
- The MCP endpoint should be public (HTTPS), but the backend can remain on a private network