Skip to content

plugin.json hardcoded DATABASE_URL overrides user's shell environment #9

@darval

Description

@darval

Summary
The plugin-bundled MCP server config in [.claude-plugin/plugin.json] hardcodes DATABASE_URL=postgresql://localhost:5432/cortex in the mcpServers.cortex.env block. Claude Code merges this over the user's shell environment when launching the MCP server, so users running Postgres on any non-localhost host (remote DB, separate LXC, Docker network hostname, non-default port, or requiring credentials) hit a silent connection failure — regardless of what they set in ~/.claude/settings.json or their shell.

Reproduction
Run Postgres somewhere other than localhost:5432 (e.g., postgresql:5432 on a local network).
Set DATABASE_URL=postgresql://user:pass@postgresql:5432/cortex in ~/.claude/settings.json env block (or shell profile).
Restart Claude Code and call any Cortex MCP tool.
Observe:

RuntimeError: PostgreSQL connection failed. Cortex requires PostgreSQL in CLI mode.
Run: bash setup.sh to configure PostgreSQL.
Or set CORTEX_RUNTIME=cowork to allow SQLite fallback.
The hooks (which run via scripts/launcher.py and inherit the shell env) connect fine, but the MCP server — launched directly by Claude Code from plugin.json — gets the hardcoded localhost value.

Root cause
In .claude-plugin/plugin.json:

"mcpServers": {
"cortex": {
"command": “uvx”,
"args": ["--python", "3.13", "--from", "neuro-cortex-memory[postgresql]", "neuro-cortex-memory”],
"env": {
"DATABASE_URL": "postgresql://localhost:5432/cortex”
}
}
}
Claude Code's MCP server launch merges this env block over the user's shell env, so the hardcoded value always wins.

The generic error message also masks the real problem — mcp_server/infrastructure/memory_store.py::_try_pg catches the OperationalError: connection refused and logs it at WARNING level, but the caller only raises a generic "PostgreSQL connection failed" — so users don't see the actual host/port the server tried.

Proposed fixes
Any of these would work:

Drop the env block entirely. Let the user's shell DATABASE_URL pass through. The plugin already defaults to postgresql://localhost:5432/cortex in memory_config.py if nothing is set.
Use a shell-expansion default. If Claude Code supports ${DATABASE_URL:-postgresql://localhost:5432/cortex} substitution in plugin.json env values, that preserves the sensible default while letting users override.
Surface the real exception. In _try_pg, include the str(exc) (at minimum host/port) in the RuntimeError message so users can diagnose network/credential problems without reading plugin source. The hint could also mention: "If DATABASE_URL is set, verify it points to a reachable Postgres instance.”
Workaround
Edit ~/.claude/plugins/cache/cortex-plugins/cortex//.claude-plugin/plugin.json directly and replace the DATABASE_URL value. Note this gets wiped on plugin updates.

Environment
Cortex 3.5.1
macOS 15.4 (Darwin 25.4.0)
Claude Code VSCode extension
Postgres 17 on separate LXC (postgresql:5432), pgvector installed, cortex database exists and is reachable via direct psycopg.connect() from the same Python env that uvx resolves for the MCP server.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions