Self-hosting

Run sremcp's API and console in your own cloud or cluster, next to your MCP servers.

sremcp is two Next.js services and a Postgres database:

ServiceRoleHolds
API (api.sremcp.com)Every rule and every outbound call: access checks, MCP connections, the agent, reportsThe database, MCP credentials, the model key
Console (app.sremcp.com)The UI. Reaches data only through the APINo database, no credentials

Sign-in uses Clerk. Both services use the same Clerk instance.

Self-hosting is the way to reach MCP servers on private addresses without exposing them. See Expose a self-hosted server.

API environment

VariableWhat it's for
DATABASE_URLPostgres 14+.
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEYYour Clerk instance.
CLERK_WEBHOOK_SIGNING_SECRETClerk webhook <api>/webhooks/clerk, events user.created, user.updated, user.deleted.
CLERK_AUTHORIZED_PARTIESThe console's origin(s), for example https://sremcp.acme.internal. Required.
APP_URLThe console's public URL: invitation links and sremcp's OAuth identity (<APP_URL>/oauth/client.json).
SECRETS_ENCRYPTION_KEYEncrypts MCP secrets. openssl rand -base64 32. Changing it makes stored secrets unreadable.
CRON_SECRETProtects /cron/tick. openssl rand -hex 32.
GOOGLE_GENERATIVE_AI_API_KEY, ANTHROPIC_API_KEY or AI_GATEWAY_API_KEYAt least one model provider.
AGENT_MODELOptional: <provider>:<model>, for example anthropic:claude-opus-5-5. Default: the first provider with a key.
MCP_ALLOW_PRIVATE_NETWORKStrue lets sremcp call private addresses and plain http://. Metadata addresses stay blocked.
MCP_ALLOWED_HOSTSOptional allowlist of host suffixes, for example mcp.acme.com,svc.cluster.local.
ORG_CREATORSOptional: who may start an organization, for example @acme.com.
AGENT_MAX_TOOLSOptional: tools offered to the agent at once. Default 64.
RESEND_API_KEY, EMAIL_FROMOptional: email invitations. Without them, the console shows invitation links to copy.

Console environment

VariableWhat it's for
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEYThe same Clerk instance as the API.
API_BASE_URLThe API's URL.
APP_URLOptional: the console's public URL, when a proxy changes the host. Must match the API's APP_URL.

Scheduler

Reports and health checks run when something calls the API's /cron/tick with Authorization: Bearer <CRON_SECRET>. Call it every minute: a Kubernetes CronJob, Vercel Cron, or any scheduler.

apiVersion: batch/v1
kind: CronJob
metadata: { name: sremcp-tick }
spec:
  schedule: "* * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: tick
              image: curlimages/curl
              args: ["-fsS", "-H", "Authorization: Bearer $(CRON_SECRET)", "https://sremcp-api.acme.internal/cron/tick"]
              env:
                - name: CRON_SECRET
                  valueFrom: { secretKeyRef: { name: sremcp, key: cron-secret } }

Database migrations

Run the API's migrations against the database before each release that adds one: bun run db:migrate.

On this page