feat: Update .env.example and server.py to clarify Frappe credentials handling for different deployment modes
This commit is contained in:
parent
c051804170
commit
7289a91b66
36
.env.example
36
.env.example
@ -1,25 +1,37 @@
|
|||||||
# ══════════════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════════════
|
||||||
# DEPLOYMENT MODE
|
# THREE SUPPORTED MODES
|
||||||
# ══════════════════════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════════════════════
|
||||||
#
|
#
|
||||||
# SSE / VPS mode (hosted server — recommended):
|
# MODE 1 — Local / stdio (single user, your machine)
|
||||||
# Frappe credentials are NOT stored here. Each user passes their own
|
# Run: frappe-mcp
|
||||||
# X-Frappe-URL, X-Frappe-API-Key, X-Frappe-API-Secret headers when connecting.
|
# Config: Set FRAPPE_URL + credentials below.
|
||||||
# Only set MCP_HOST, MCP_PORT, MCP_BEARER_TOKEN below.
|
# Claude Desktop spawns the process directly via stdio.
|
||||||
#
|
#
|
||||||
# Local / stdio mode:
|
# MODE 2 — VPS / SSE, multi-tenant (public hosted server)
|
||||||
# Credentials are read from this file. Run: frappe-mcp (no --sse flag).
|
# Run: frappe-mcp --sse
|
||||||
# Uncomment the Frappe Connection block below.
|
# Config: Set only MCP_HOST, MCP_PORT, MCP_BEARER_TOKEN here.
|
||||||
|
# Each connecting user supplies their own Frappe credentials as
|
||||||
|
# request headers: X-Frappe-URL, X-Frappe-API-Key, X-Frappe-API-Secret
|
||||||
|
# No Frappe credentials are stored on the server.
|
||||||
#
|
#
|
||||||
# ── SSE Server Settings (VPS hosting) ────────────────────────────────────────
|
# MODE 3 — VPS / SSE, single-tenant (you host it for yourself)
|
||||||
|
# Run: frappe-mcp --sse
|
||||||
|
# Config: Set BOTH the MCP server settings AND Frappe credentials here.
|
||||||
|
# Users connect without sending credential headers — the server's
|
||||||
|
# .env credentials are used for everyone.
|
||||||
|
#
|
||||||
|
# ── SSE Server Settings (modes 2 & 3) ────────────────────────────────────────
|
||||||
MCP_HOST=0.0.0.0
|
MCP_HOST=0.0.0.0
|
||||||
MCP_PORT=8001
|
MCP_PORT=8001
|
||||||
|
|
||||||
# Shared access token — all users must send this as: Authorization: Bearer <token>
|
# Shared access token — clients must send: Authorization: Bearer <token>
|
||||||
# Generate with: python -c "import secrets; print(secrets.token_hex(32))"
|
# Generate: python -c "import secrets; print(secrets.token_hex(32))"
|
||||||
MCP_BEARER_TOKEN=change_this_to_a_strong_random_token
|
MCP_BEARER_TOKEN=change_this_to_a_strong_random_token
|
||||||
|
|
||||||
# ── Frappe Connection (local/stdio mode only) ─────────────────────────────────
|
# ── Frappe Connection (modes 1 & 3) ──────────────────────────────────────────
|
||||||
|
# Required for local stdio mode (mode 1).
|
||||||
|
# Optional for SSE mode — set these only if you want a single fixed Frappe
|
||||||
|
# instance for all connections (mode 3). Leave commented for multi-tenant (mode 2).
|
||||||
# FRAPPE_URL=http://YOUR_VPS_IP:8000
|
# FRAPPE_URL=http://YOUR_VPS_IP:8000
|
||||||
# FRAPPE_API_KEY=your_api_key_here
|
# FRAPPE_API_KEY=your_api_key_here
|
||||||
# FRAPPE_API_SECRET=your_api_secret_here
|
# FRAPPE_API_SECRET=your_api_secret_here
|
||||||
|
|||||||
@ -83,18 +83,22 @@ def _run_sse():
|
|||||||
if auth != f"Bearer {bearer_token}":
|
if auth != f"Bearer {bearer_token}":
|
||||||
return Response("Unauthorized", status_code=401)
|
return Response("Unauthorized", status_code=401)
|
||||||
|
|
||||||
# Extract per-user Frappe credentials from request headers
|
# Per-user Frappe credentials via request headers (optional).
|
||||||
|
# If omitted, FrappeClient falls back to .env values — useful when the
|
||||||
|
# server owner is the only user, or for a single-tenant VPS deployment.
|
||||||
frappe_url = request.headers.get("X-Frappe-URL", "")
|
frappe_url = request.headers.get("X-Frappe-URL", "")
|
||||||
api_key = request.headers.get("X-Frappe-API-Key", "")
|
api_key = request.headers.get("X-Frappe-API-Key", "")
|
||||||
api_secret = request.headers.get("X-Frappe-API-Secret", "")
|
api_secret = request.headers.get("X-Frappe-API-Secret", "")
|
||||||
site_name = request.headers.get("X-Frappe-Site-Name", "")
|
site_name = request.headers.get("X-Frappe-Site-Name", "")
|
||||||
|
|
||||||
if not frappe_url or not api_key or not api_secret:
|
if frappe_url or api_key or api_secret:
|
||||||
|
# At least one header present — require all three to be explicit
|
||||||
|
if not (frappe_url and api_key and api_secret):
|
||||||
return Response(
|
return Response(
|
||||||
"Missing required headers: X-Frappe-URL, X-Frappe-API-Key, X-Frappe-API-Secret",
|
"Partial credentials: supply all three headers together — "
|
||||||
|
"X-Frappe-URL, X-Frappe-API-Key, X-Frappe-API-Secret",
|
||||||
status_code=400,
|
status_code=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
from frappe_mcp.session import SessionConfig, set_session
|
from frappe_mcp.session import SessionConfig, set_session
|
||||||
set_session(SessionConfig(
|
set_session(SessionConfig(
|
||||||
frappe_url=frappe_url,
|
frappe_url=frappe_url,
|
||||||
@ -102,6 +106,7 @@ def _run_sse():
|
|||||||
api_secret=api_secret,
|
api_secret=api_secret,
|
||||||
site_name=site_name,
|
site_name=site_name,
|
||||||
))
|
))
|
||||||
|
# else: no headers — FrappeClient will use .env credentials
|
||||||
|
|
||||||
async with sse.connect_sse(
|
async with sse.connect_sse(
|
||||||
request.scope, request.receive, request._send
|
request.scope, request.receive, request._send
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user