authenticate
Authenticate with the Relay Control Plane to enable access to shared Obsidian vaults, real-time sync, and collaborative note management.
Instructions
Authenticate with the Relay Control Plane.
Uses RELAY_EMAIL and RELAY_PASSWORD env vars. Returns a status message. The token is managed internally — subsequent tool calls use it automatically.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- relay_mcp.py:108-117 (handler)The main authenticate tool handler decorated with @mcp.tool(). Calls _ensure_token() to get or refresh the JWT token and returns a success message with token length.@mcp.tool() def authenticate() -> str: """Authenticate with the Relay Control Plane. Uses RELAY_EMAIL and RELAY_PASSWORD env vars. Returns a status message. The token is managed internally — subsequent tool calls use it automatically. """ token = _ensure_token() return f"Authenticated successfully. Token length: {len(token)}"
- relay_mcp.py:57-98 (helper)Core authentication logic that manages JWT tokens. Handles token refresh if available, otherwise performs full login using RELAY_EMAIL and RELAY_PASSWORD environment variables. Stores token, refresh_token, and expiry globally.def _ensure_token() -> str: """Return a valid JWT token, refreshing if needed.""" global _token, _token_expires, _refresh_token if _token and time.time() < _token_expires - 60: return _token # Try refresh first if _refresh_token: try: with _get_client() as client: r = client.post( f"{_get_base_url()}/v1/auth/refresh", json={"refresh_token": _refresh_token}, ) if r.status_code == 200: data = r.json() _token = data["access_token"] _refresh_token = data.get("refresh_token", _refresh_token) _token_expires = time.time() + data.get("expires_in", 3600) return _token except Exception: pass # Full login email = os.environ.get("RELAY_EMAIL", "") password = os.environ.get("RELAY_PASSWORD", "") if not email or not password: raise ValueError("RELAY_EMAIL and RELAY_PASSWORD must be set") with _get_client() as client: r = client.post( f"{_get_base_url()}/v1/auth/login", json={"email": email, "password": password}, ) r.raise_for_status() data = r.json() _token = data["access_token"] _refresh_token = data.get("refresh_token") _token_expires = time.time() + data.get("expires_in", 3600) return _token
- relay_mcp.py:108-108 (registration)The @mcp.tool() decorator that registers the authenticate function as an available MCP tool.@mcp.tool()
- relay_mcp.py:43-47 (helper)Helper function that retrieves the Relay Control Plane base URL from the RELAY_CP_URL environment variable.def _get_base_url() -> str: url = os.environ.get("RELAY_CP_URL", "") if not url: raise ValueError("RELAY_CP_URL environment variable not set") return url.rstrip("/")
- relay_mcp.py:50-54 (helper)Helper function that creates an httpx client with keep-alive disabled to prevent hanging on stale connections from the Caddy server.def _get_client() -> httpx.Client: # Disable keep-alive: Caddy sends GOAWAY on idle connections, # httpx tries to reuse the stale socket and hangs. limits = httpx.Limits(max_keepalive_connections=0) return httpx.Client(timeout=30.0, limits=limits)