Newer
Older
gnexus-creds / docs / deployment-and-mcp.md

Deployment and MCP Connection Guide

This document describes how to deploy gnexus-creds and connect the MCP server to an AI agent.

Runtime Components

gnexus-creds is one FastAPI application that serves:

  • Vue UI from the built frontend bundle.
  • REST API under /api/v1.
  • OAuth session routes under /auth.
  • gnexus-auth profile webhook under /webhooks/gnexus-auth.
  • Legacy HTTP/SSE MCP adapter under /mcp.
  • Official MCP Streamable HTTP endpoint under /mcp-protocol/.

PostgreSQL is required. SQLite is not supported for production.

Required Environment

Create .env from .env.example and set real values:

GNEXUS_CREDS_ENV=production
GNEXUS_CREDS_DATABASE_URL=postgresql+psycopg://gnexus_creds:change-me@postgres:5432/gnexus_creds
GNEXUS_CREDS_MASTER_KEY=replace-with-a-long-random-master-key
GNEXUS_CREDS_SESSION_SECRET=replace-with-a-long-random-session-secret
GNEXUS_CREDS_SESSION_COOKIE_NAME=gnexus_creds_session

GNEXUS_AUTH_BASE_URL=https://auth.gnexus.space
GNEXUS_AUTH_CLIENT_ID=replace-with-client-id
GNEXUS_AUTH_CLIENT_SECRET=replace-with-client-secret
GNEXUS_AUTH_REDIRECT_URI=https://creds.gnexus.space/auth/callback
GNEXUS_AUTH_WEBHOOK_SECRET=replace-with-webhook-secret

GNEXUS_CREDS_MCP_RESOURCE_URL=https://creds.gnexus.space/mcp-protocol/

GNEXUS_CREDS_RATE_LIMIT_WINDOW_SECONDS=60
GNEXUS_CREDS_RATE_LIMIT_MAX_SENSITIVE_REQUESTS=120

For local development on port 8018, use HTTP values:

GNEXUS_CREDS_ENV=development
GNEXUS_CREDS_DATABASE_URL=postgresql+psycopg://gnexus_creds:gnexus_creds@127.0.0.1:5432/gnexus_creds
GNEXUS_CREDS_MASTER_KEY=local-long-random-master-key
GNEXUS_CREDS_SESSION_SECRET=local-long-random-session-secret

GNEXUS_AUTH_BASE_URL=http://gnexus-auth.local
GNEXUS_AUTH_CLIENT_ID=gnexus-creds
GNEXUS_AUTH_CLIENT_SECRET=replace-with-local-client-secret
GNEXUS_AUTH_REDIRECT_URI=http://localhost:8018/auth/callback
GNEXUS_AUTH_WEBHOOK_SECRET=replace-with-local-webhook-secret

GNEXUS_CREDS_MCP_RESOURCE_URL=http://localhost:8018/mcp-protocol/

Production mode fails fast if default secrets are used or if public auth/MCP URLs do not use HTTPS.

gnexus-auth Integration

Register gnexus-creds as an OAuth client in gnexus-auth.

Local development values:

  • Client ID: gnexus-creds, or the value from GNEXUS_AUTH_CLIENT_ID.
  • Client secret: the value from GNEXUS_AUTH_CLIENT_SECRET.
  • Redirect URI: http://localhost:8018/auth/callback.
  • Requested scopes: openid, email, profile.
  • Webhook URL: http://localhost:8018/webhooks/gnexus-auth.
  • Webhook secret: the same value as GNEXUS_AUTH_WEBHOOK_SECRET.

Production values:

  • Redirect URI: https://creds.gnexus.space/auth/callback.
  • Webhook URL: https://creds.gnexus.space/webhooks/gnexus-auth.
  • Auth base URL: https://auth.gnexus.space.

User profile data and user status come from gnexus-auth. The supported system roles are:

  • user
  • admin

If gnexus-auth sends a disabled, blocked, or deleted status, gnexus-creds keeps the local user data but blocks login.

Local Development Deploy

Install backend dependencies:

uv sync --extra dev

Start PostgreSQL through Docker Compose:

docker-compose up -d postgres

Run migrations:

uv run alembic upgrade head

Build the frontend bundle served by FastAPI:

cd frontend
npm install
npm run build
cd ..

Start the server on port 8018:

uv run uvicorn gnexus_creds.main:app --host 0.0.0.0 --port 8018 --reload

Open the UI:

http://localhost:8018/

Login starts through:

http://localhost:8018/auth/login

Docker Compose Deploy

Prepare .env, then build and start PostgreSQL:

docker-compose build app
docker-compose up -d postgres

Run migrations explicitly:

docker-compose run --rm app alembic upgrade head

Start the app:

docker-compose up -d app

The included docker-compose.yml maps the app to host port 8000:

ports:
  - "8000:8000"

For local testing on 8018, change it to:

ports:
  - "8018:8000"

The Docker image contains the built Vue UI. Migrations are not run automatically by the container.

Reverse Proxy

The reverse proxy must forward these paths to the FastAPI app:

  • /
  • /api/v1/*
  • /auth/*
  • /webhooks/*
  • /mcp/*
  • /mcp-protocol/*
  • /health
  • /ready

For MCP Streamable HTTP, do not buffer or rewrite request bodies. Keep the trailing slash in the MCP URL:

https://creds.gnexus.space/mcp-protocol/

Operational Checks

Liveness:

curl -fsS http://localhost:8018/health

Readiness, including database connectivity:

curl -fsS http://localhost:8018/ready

Apply migrations before every deploy:

uv run alembic upgrade head

or inside Docker:

docker-compose run --rm app alembic upgrade head

Preparing MCP Access

MCP uses gnexus-creds API tokens, not gnexus-auth access tokens.

  1. Log in to the UI.
  2. Open Tokens.
  3. Create a token for the AI agent.
  4. Select scopes based on the agent's required access:
mcp, read

Allows search and metadata reads.

mcp, read, reveal

Allows search, metadata reads, and decrypted reveal.

mcp, read, reveal, write

Allows full MCP access, including creating and updating secrets.

The admin scope is not required for normal MCP access.

Only secrets with allow_mcp=true are visible through MCP. Archived secrets are not visible through normal MCP access.

Use the official Streamable HTTP endpoint when the AI agent supports MCP over HTTP:

https://creds.gnexus.space/mcp-protocol/

Local development:

http://localhost:8018/mcp-protocol/

The agent must send:

Authorization: Bearer <gnexus-creds-api-token>

Generic agent configuration shape:

{
  "mcpServers": {
    "gnexus-creds": {
      "type": "streamable-http",
      "url": "https://creds.gnexus.space/mcp-protocol/",
      "headers": {
        "Authorization": "Bearer <gnexus-creds-api-token>"
      }
    }
  }
}

Some agents name the transport http, streamable_http, or mcp-http. Use the transport name expected by the concrete agent, but keep the URL and Authorization header unchanged.

stdio is not supported and should not be used: the AI agent and gnexus-creds server are expected to run on different hosts.

Legacy MCP HTTP/SSE Adapter

Use the legacy adapter only for clients that do not support MCP Streamable HTTP.

Discovery stream:

curl -N \
  -H "Authorization: Bearer $GNEXUS_CREDS_MCP_TOKEN" \
  http://localhost:8018/mcp/sse

Search secrets:

curl -sS \
  -H "Authorization: Bearer $GNEXUS_CREDS_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"arguments":{"q":"github","limit":5}}' \
  http://localhost:8018/mcp/tools/search_secrets

Reveal one secret:

curl -sS \
  -H "Authorization: Bearer $GNEXUS_CREDS_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"arguments":{"secret_id":"<secret-uuid>"}}' \
  http://localhost:8018/mcp/tools/reveal_secret

Create a secret:

curl -sS \
  -H "Authorization: Bearer $GNEXUS_CREDS_MCP_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "arguments": {
      "title": "Example",
      "purpose": "example.com",
      "category": "site",
      "tags": ["example"],
      "allow_ui": true,
      "allow_rest_api": true,
      "allow_mcp": true,
      "fields": [
        {"name": "username", "value": "user@example.com", "encrypted": false},
        {"name": "password", "value": "secret-password", "encrypted": true, "masked": true}
      ]
    }
  }' \
  http://localhost:8018/mcp/tools/create_secret

MCP Tools

Current tools:

  • search_secrets
  • get_secret
  • reveal_secret
  • create_secret
  • update_secret
  • set_secret_status
  • archive_secret

search_secrets supports pagination with offset and limit. The maximum limit is 50. If many secrets match, iterate with offset increments.

Search returns metadata and unencrypted fields only. Encrypted values are returned only by reveal_secret.

Reveal and write actions create audit events with channel=mcp.

Backup and Restore

Backups are managed from the admin panel (Admin tab → Backups).

Backup directory

By default, backups are written to ./backups. In Docker Compose, this is a persistent volume mounted at /app/backups.

Set a custom path via environment variable:

GNEXUS_CREDS_BACKUP_DIR=/var/backups/gnexus-creds

Create backup

From the UI:

  1. Open the Admin tab.
  2. Click Create backup.

From the command line (inside the container or on the host with pg_dump):

docker-compose exec app python -c "from gnexus_creds.backup import create_backup; print(create_backup())"

Or via the admin API (admin user required):

curl -fsS -X POST \
  -H "Cookie: gnexus_creds_session=..." \
  http://localhost:8000/api/v1/admin/backup

List backups

UI: Admin tab shows the backup table with size and creation time.

API:

curl -fsS \
  -H "Cookie: gnexus_creds_session=..." \
  http://localhost:8000/api/v1/admin/backups

Download backup

Click Download in the UI, or use the direct link:

curl -fsS \
  -H "Cookie: gnexus_creds_session=..." \
  -O \
  http://localhost:8000/api/v1/admin/backups/backup_20260520_120000.sql

Restore backup

Warning: restore overwrites the current database. All existing data is replaced.

From the UI:

  1. Open the Admin tab.
  2. Click Restore next to the desired backup.
  3. Confirm in the modal.

After restore, reload the page to refresh the UI state.

From the command line:

docker-compose exec app python -c "
from gnexus_creds.backup import restore_backup
restore_backup('/app/backups/backup_20260520_120000.sql')
"

Or via API:

curl -fsS -X POST \
  -H "Cookie: gnexus_creds_session=..." \
  -H "Content-Type: application/json" \
  -d '{"filename": "backup_20260520_120000.sql"}' \
  http://localhost:8000/api/v1/admin/restore

Supported engines

  • PostgreSQL — dumps with pg_dump, restores with psql. The pg_dump binary is included in the Docker image.
  • SQLite — file copy (not recommended for production).

Troubleshooting

401 Unauthorized:

  • Token is missing, revoked, or copied incorrectly.
  • The AI agent is not sending the Authorization header.

403 Forbidden:

  • Token does not have the mcp scope.
  • Tool-specific scope is missing: read, reveal, or write.
  • User is disabled by gnexus-auth.

Secret is missing from MCP search:

  • Secret has allow_mcp=false.
  • Secret is archived.
  • Search query targets an encrypted field value. Encrypted values are not searchable.

OAuth callback fails:

  • GNEXUS_AUTH_REDIRECT_URI does not exactly match the client redirect URI in gnexus-auth.
  • GNEXUS_AUTH_CLIENT_SECRET is wrong.
  • GNEXUS_AUTH_BASE_URL points to the wrong auth instance.

Production app refuses to start:

  • GNEXUS_CREDS_ENV=production requires HTTPS for auth redirect and MCP resource URLs.
  • Default secrets from .env.example must be replaced.