-
Notifications
You must be signed in to change notification settings - Fork 77
Expand file tree
/
Copy path.env.example
More file actions
257 lines (231 loc) · 15.4 KB
/
Copy path.env.example
File metadata and controls
257 lines (231 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# =============================================================================
# AnythingMCP — Environment Variables
# =============================================================================
# The recommended way to generate this file is `./setup.sh`, which writes a
# fully-populated `.env` to the project root (where docker-compose.yml lives).
#
# For manual setup: copy this file to `.env` in the project root, replace the
# `change-me-…` values with secure secrets, then run `docker compose up -d`.
# For local development without Docker, copy it to `packages/backend/.env`.
# =============================================================================
# ── General ──────────────────────────────────────────────────────────────────
NODE_ENV=production
# Internal backend port inside the container. The host-published port is set
# separately via BACKEND_PORT (see the Ports section) — leave this at 4000.
PORT=4000
# Compose project name — also the prefix for the network, volumes and container
# names (amcp-app, amcp-postgres, …). Override it to run more than one
# AnythingMCP stack on the same host without name collisions.
# COMPOSE_PROJECT_NAME=amcp
# ── Database ─────────────────────────────────────────────────────────────────
POSTGRES_PASSWORD=change-me-in-production
DATABASE_URL=postgresql://amcp:${POSTGRES_PASSWORD}@postgres:5432/anythingmcp
# ── Redis (optional) ─────────────────────────────────────────────────────────
# Redis enables response caching and rate limiting. The app works without it.
# REDIS_URL=redis://redis:6379
# ── Security ─────────────────────────────────────────────────────────────────
# JWT secret for API authentication (min 32 characters)
JWT_SECRET=change-me-in-production-min-32-chars
# AES-256-GCM encryption key for stored credentials (exactly 32 characters)
ENCRYPTION_KEY=change-me-in-production-exactly-32
# HMAC secret for signed cookies (OAuth callback flow). Optional — falls back
# to JWT_SECRET if unset. Set it separately for defense in depth (rotate it
# independently from JWT_SECRET).
# COOKIE_SECRET=change-me-in-production-min-32-chars
# Postgres Row-Level Security — database-enforced tenant isolation on top of the
# app-layer checks. OFF by default; this is a staged rollout, not a flip switch:
# the DATABASE_URL role must be NON-superuser, query call sites must run through
# tenantTx, and the policies must be applied. See
# docs/operations/row-level-security.md before enabling.
# ENABLE_RLS=false
# ── Frontend ─────────────────────────────────────────────────────────────────
FRONTEND_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:4000
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=change-me-in-production
# ── CORS ─────────────────────────────────────────────────────────────────────
CORS_ORIGIN=http://localhost:3000
# ── Registration ──────────────────────────────────────────────────────────────
# When false (default), only the first user can self-register via the UI.
# All other users must be invited by an admin. Set to true to allow open registration.
ALLOW_OPEN_REGISTRATION=false
# ── Catalog auto-sync ─────────────────────────────────────────────────────────
# On startup, automatically applies "safe" catalog updates (tool
# description/parameter fixes — no endpoint or tool add/remove changes) to
# connectors installed from the catalog, so adapter improvements reach existing
# connectors without manual action. Structural updates are left for explicit
# review. Set to false to disable and pin installed connectors to their tools.
# CATALOG_AUTOSYNC=true
# ── MCP Server Auth (for external MCP clients like Claude Desktop) ───────────
# Auth mode: none | legacy | oauth2 | both
# none — No authentication (not recommended for production)
# legacy — Static Bearer Token or API Key (set MCP_BEARER_TOKEN / MCP_API_KEY)
# oauth2 — OAuth 2.0 Authorization Code (PKCE) + Client Credentials
# both — OAuth 2.0 + Legacy (accepts either)
MCP_AUTH_MODE=oauth2
# Legacy auth tokens (used when MCP_AUTH_MODE=legacy or both)
# MCP_BEARER_TOKEN=your-secret-token
# MCP_API_KEY=your-api-key
# Server URL for OAuth2 redirects and metadata endpoints
SERVER_URL=http://localhost:4000
# ── Public demo endpoint (operators only) ────────────────────────────────────
# /mcp/demo is always reachable without authentication and always serves the
# static anythingmcp_* tools that describe the product. Setting this to the id
# of one MCP server on this instance ALSO serves that server's READ-ONLY tools
# there — anonymously, to anyone. Only tools whose derived annotations say
# readOnlyHint=true are exposed; write tools of that server stay invisible.
#
# Leave it unset unless you are deliberately running a public playground. The
# right server for it is one whose connectors need no credentials of yours
# (Deutsche Bahn, OpenPLZ, Bundesbank, VIES, Nominatim, Hacker News…), because
# every anonymous caller uses whatever credentials that server's connectors
# hold. See docs/demo-endpoint.md.
# MCP_DEMO_SERVER_ID=
# ── MCP Rate Limiting ──────────────────────────────────────────────────────
# Max requests per minute per client (by API key or IP). Only enforced when Redis is available.
MCP_RATE_LIMIT_PER_MINUTE=60
# ── MCP Stateful Sessions (optional) ─────────────────────────────────────────
# When true, the per-server MCP endpoint keeps a live session (with an SSE
# channel) per connected client and PUSHES notifications/tools/list_changed when
# a connector or its tool surface changes — so clients like ChatGPT/Claude pick
# up new tools without a manual refresh. Default (false) is stateless: each
# request is independent and clients only see tool changes on reconnect.
# MCP_STATEFUL_SESSIONS=false
# Streamable-HTTP response framing. Default (unset/false) = SSE-framed
# responses (text/event-stream), the spec-standard required by some clients
# (e.g. Microsoft Copilot Studio). Set true to force application/json responses.
# MCP_STREAMABLE_JSON_RESPONSE=false
# What the shared /mcp endpoint lists. "direct" (self-hosted default) lists
# the caller's own tools; "fixed" (cloud default) lists one fixed set of tools
# for every user (search, describe, run read / run write, workspace guide…)
# through which the caller's tools are reached. /mcp/<serverId> always lists a
# server's tools directly.
# MCP_SHARED_ENDPOINT_TOOLS=direct
# Idle session eviction (minutes) and a global cap on concurrent sessions.
# MCP_SESSION_IDLE_MIN=30
# MCP_MAX_SESSIONS=500
# ── Knowledge Graph — AI features (optional) ─────────────────────────────────
# Global switch + API key for LLM graph enrichment / skill generation. Without
# these, all AI features stay off regardless of per-workspace toggles.
# KG_LLM_ENABLED=false
# KG_LLM_MODEL=gpt-4o-mini
# OPENAI_API_KEY= # or OPENROUTER_API_KEY / ANTHROPIC_API_KEY
#
# Scheduled AI extension (cloud cron): periodically extends the graph + skills
# from captured user intents. Off unless ALL of: this flag is true, the cron
# runs (POST /api/cron/kg-discovery with CRON_SECRET), and the workspace turned
# on "Scheduled AI extension". Cost controls: per-org cooldown + per-run cap, and
# it only spends when the graph changed / new intents arrived.
# KG_LLM_CRON_ENABLED=false
# KG_LLM_MIN_INTERVAL_HOURS=24 # per-workspace cooldown between AI passes
# KG_LLM_CRON_MAX_ORGS=20 # max workspaces given an AI pass per cron run
# Batch mode (Anthropic only): the cron submits the AI passes as a Message Batch
# (~50% cheaper, processed asynchronously) and applies the results on a later
# run. Off by default = synchronous. Requires KG_LLM_PROVIDER=anthropic.
# KG_LLM_BATCH=false
#
# Provider/model: KG_LLM_PROVIDER = openai (default) | openrouter | anthropic.
# For GDPR/EU, prefer an EU-resident, no-training, zero-retention provider (e.g.
# Azure OpenAI EU, or Claude via AWS Bedrock EU). Anthropic default model is now
# claude-haiku-4-5. OpenAI default is gpt-4o-mini.
#
# PII minimization: captured intents are scrubbed (emails, phones, ids, IBAN,
# cards) before being sent to the LLM for skill generation. Set to false to send
# raw intents (not recommended when personal data may appear in requests).
# KG_LLM_REDACT_INTENTS=true
# ── Proxy / Web-Unblocker (optional) ─────────────────────────────────────────
# When set, tools whose `use_proxy` flag is on route their outbound HTTP
# request through this proxy. Use a plain rotating proxy for IP/geo/rate-limit
# cases, or a "web unblocker" (e.g. Zyte API proxy mode) for anti-bot targets
# like Akamai / Cloudflare / DataDome.
#
# Zyte API proxy mode: http://<ZYTE_API_KEY>:@api.zyte.com:8011
# Generic proxy: http://user:pass@host:port
#
# If unset, the feature is off everywhere: tools that opted in simply make a
# direct request. Per-tool opt-in is a UI checkbox (shown only when this is
# set) plus the adapter spec's `useProxy` field.
# CONNECTOR_PROXY_URL=
# Cloud only: default hourly cap on proxy-routed tool calls PER WORKSPACE.
# Override per workspace by setting organizations.proxy_rate_limit in the DB
# (admin-only; there is no API to change it). Defaults to 100 when unset.
# PROXY_RATE_LIMIT_DEFAULT=100
# ── Usage cost estimate (Analytics) ──────────────────────────────────────────
# The Analytics page shows a volume-based cost estimate (there are no LLM
# tokens): est = tool_calls × COST_PER_CALL_MICROS + proxy_calls ×
# COST_PER_PROXY_CALL_MICROS. Values are in micros (millionths of a currency
# unit). Both default to 0, so the estimate shows 0 until an operator sets rates.
# COST_PER_CALL_MICROS=0
# COST_PER_PROXY_CALL_MICROS=0
# ── Operator Analytics (cloud build only — leave empty on self-hosted) ──────
# Loads Google Tag Manager + a Consent Mode v2 cookie banner. Self-hosted
# builds must leave both empty so no tracking is shipped to community users.
#
# GTM_ID — Google Tag Manager container ID (e.g. GTM-XXXXXXX).
# COOKIE_DOMAIN — Domain attribute for the consent cookie. Set to a parent
# domain (e.g. .anythingmcp.com) to share consent with the
# marketing site running on the same parent domain. Leave
# unset for host-only scope.
# GTM_ID=
# COOKIE_DOMAIN=
# ── Reverse Proxy (Caddy) ────────────────────────────────────────────────────
# Uncomment to enable Caddy reverse proxy with automatic HTTPS (Let's Encrypt).
# Requires a Caddyfile in the project root (setup.sh generates it automatically).
# COMPOSE_PROFILES=proxy
# DOMAIN=example.com
# ACME_EMAIL=admin@example.com
# APP_BIND_IP=127.0.0.1
# ── Process vitals & heap guard ──────────────────────────────────────────────
# The backend logs one structured `vitals` line per interval (rss, heap, event
# loop delay, live MCP request/handler/tool-call gauges) and guards its own
# heap. Added after the cloud backend ran out of heap four times in one
# afternoon while /health kept answering 200 — it checked Postgres and Redis,
# never the process. All percentages are of V8's heap limit (see
# NODE_MAX_OLD_SPACE_MB in docker-compose.cloud.yml).
#
# VITALS_INTERVAL_SEC seconds between vitals lines; 0 disables. Default 30.
# HEAP_WARN_PERCENT log a warning when the heap first crosses this. Default 75.
# HEAP_SNAPSHOT_PERCENT write ONE heap snapshot per process when crossing this.
# OFF by default (0), and not lightly: V8 builds the
# snapshot in memory before writing a byte, roughly
# another heap's worth. At 60 % of a 4 GB heap in a
# 5 GB container that is what got the process killed
# nineteen times on 2026-09-21. The guard refuses the
# snapshot unless rss + heap fits in 85 % of the cgroup
# limit; set it low (30-40) and give the container room.
# HEAP_SNAPSHOT_DIR where the snapshot goes. Mount a volume here on cloud.
# Default /tmp/anythingmcp-diagnostics.
# HEAP_EXIT_PERCENT exit gracefully after HEAP_EXIT_CONSECUTIVE ticks at or
# above this, before the GC death spiral makes the
# process unresponsive; the supervisor restarts it.
# 0 disables. Default 90.
# HEAP_RSS_EXIT_PERCENT same, for RSS against the container's cgroup memory
# limit — the number the kernel actually kills on, which
# it can reach with the V8 heap well under its own cap.
# Ignored when there is no cgroup limit. Default 90.
# HEAP_EXIT_CONSECUTIVE ticks in a row over either line before exiting.
# Default 3 (= 90 s at the default interval).
# HEALTH_HEAP_PERCENT /health reports the process down at or above this, so
# a probe sees the decline before the crash. 0 disables.
# Default 90.
# VITALS_INTERVAL_SEC=30
# HEAP_WARN_PERCENT=75
# HEAP_SNAPSHOT_PERCENT=0
# HEAP_SNAPSHOT_DIR=/tmp/anythingmcp-diagnostics
# HEAP_EXIT_PERCENT=90
# HEAP_RSS_EXIT_PERCENT=90
# HEAP_EXIT_CONSECUTIVE=3
# HEALTH_HEAP_PERCENT=90
# ── Cloud host jobs (AnythingMCP Cloud droplet only — ignore when self-hosting) ─
# Read from the host's .env by the systemd timers installed by
# .github/workflows/deploy-cloud.yml, not by the app. They mail through the
# SMTP_* settings above. See docs/operations/observability.md, section 4.
#
# UPTIME_ALERT_TO where the minute-by-minute uptime probe mails DOWN and
# RECOVERED (deploy/cloud/uptime-probe.sh).
# REPORT_TO where the Monday stuck-users report goes
# (deploy/cloud/stuck-users-report.sh); comma-separated.
# Falls back to UPTIME_ALERT_TO; with neither, journal only.
# The report contains customer e-mail addresses.
# UPTIME_ALERT_TO=
# REPORT_TO=