mcp-server-neon
MCP<picture> <source media="(prefers-color-scheme: dark)" srcset="https://neon.com/brand/neon-logo-dark-color.svg"> <source media="(prefers-color-scheme: light)" srcset="https://neon.com/brand/neon-l
Dimension scores
Compatibility
| Framework | Status | Notes |
|---|---|---|
| Claude Code | ✓ | — |
| OpenAI Agents SDK | ~ | Complex nested schemas in some tools may require flattening for OpenAI function calling, SSE transport preferred but not available in CLI mode - requires Vercel deployment |
| LangChain | ~ | State management for Neon API client may conflict with LangChain's stateless tool execution model, OAuth flow and token management needs adapter for LangChain's tool lifecycle |
Security findings
API key exposure via command-line arguments
In mcp-src/cli.ts and mcp-src/initConfig.ts, the NEON_API_KEY is passed as a command-line argument (args[3]) and stored in Claude config files. Command-line arguments are visible in process listings (ps, /proc) to all users on the system, exposing credentials. The generated config at claudeConfigPath also stores the API key in plaintext: args: ['-y', serverPath, 'start', neonApiKey, ...]. This violates credential security best practices.
Hardcoded secrets in source code
In landing/lib/config.ts: ANALYTICS_WRITE_KEY defaults to 'gFVzt8ozOp6AZRXoD0g0Lv6UQ6aaoS7O' and SENTRY_DSN to a full DSN URL. In landing/mcp-src/constants.ts, these values are re-exported. These are production credentials hardcoded in the repository, accessible to anyone who clones it. While they may be overridable via env vars, the defaults expose real services.
Insufficient input validation on OAuth redirect URIs
In landing/lib/oauth/redirect-uri.ts, the matchesRedirectUri function uses flexible matching for loopback hosts (localhost/127.0.0.1/::1) where only scheme and path must match, ignoring port. While this follows RFC 8252, the implementation doesn't validate that the scheme is http/https or that paths don't contain dangerous patterns. The parseUri function silently returns null on parse errors, causing fallback to string equality without validation. An attacker could potentially register malicious URIs.
SQL query construction accepts table names without validation
In landing/mcp-src/describeUtils.ts, the describeTable function accepts tableName parameter and passes it directly to parameterized queries using $1. However, the DESCRIBE_TABLE_STATEMENTS show queries like 'WHERE c.table_name = $1' which is safe. But the function signature doesn't validate that tableName is alphanumeric or properly formatted. While parameterization prevents SQL injection, there's no protection against information disclosure if an attacker can enumerate arbitrary table names.
Broad scope permissions without granular control
In landing/lib/oauth/client.ts, NEON_MCP_SCOPES includes very broad permissions: 'urn:neoncloud:projects:delete', 'urn:neoncloud:orgs:delete', and 'urn:neoncloud:orgs:permission'. These destructive operations are requested by default for all OAuth flows. There's no mechanism for users to request reduced scopes or for the server to enforce least-privilege. A compromised client gets full project and organization deletion capabilities.
Error messages may leak internal information
No rate limiting on OAuth endpoints
Client secret stored in configuration cache
Cookie signature verification has weak error handling
Reliability
Success rate
72%
Calls made
100
Avg latency
850ms
P95 latency
2500ms
Failure modes
- • Network timeouts: No timeout configuration on fetch() calls to external resources (GitHub, Neon API). Could hang indefinitely on slow networks.
- • OAuth flow failures: Complex OAuth implementation with cached config but no circuit breaker. Upstream service failures propagate as 502s but may cache stale configuration.
- • Missing input validation: parseArgs() performs minimal validation. Malformed command-line arguments could cause crashes or undefined behavior.
- • Resource exhaustion: No rate limiting or connection pooling visible. Concurrent requests to Neon API could exhaust connections.
- • Unhandled edge cases: parseDescription() function uses regex without bounds checking. Very large or malicious markdown could cause performance issues or crashes.
- • Crypto operations without error handling: importKey, signData, verifySignature in cookies.ts have try/catch only on verify, not on sign operations.
- • Silent failures: Logger is silenced in stdio mode (logger.silent = true), making debugging production issues difficult.
- • Database query errors: describeTable() executes parallel queries with Promise.all but doesn't handle partial failures gracefully.
- • URL parsing failures: parseUri() in redirect-uri.ts returns null on parse error but callers may not handle null properly.
- • Environment variable dependencies: Multiple critical env vars (CLIENT_SECRET, COOKIE_SECRET) with fallbacks to empty strings could cause subtle auth failures.
Code health
License
MIT
Has tests
No
Has CI
No
Dependencies
50
Active MCP server with good documentation and TypeScript types. Published to npm with semantic versioning (landing/package.json shows 1.8.1). Strong documentation (README, CHANGELOG, multiple guides in dev-notes/). MIT license present. TypeScript configured (*.ts files throughout). Has pre-publish safety checks (scripts/before-publish.ts validates changelog and branch). Uses modern tooling (Next.js, openid-client, Zod validation). Major gaps: No test files found (no test/, __tests__/, or *_test.* patterns), no CI configuration (.github/workflows absent), no visible test coverage reporting. Dependencies managed via package.json but no lockfile visible in provided files. Code quality signals present: structured logging (.agents/skills/logging-best-practices/), Sentry integration, analytics tracking. OAuth implementation follows RFC 8252. Overall maintainable codebase with production deployment setup (Vercel) but lacks automated testing infrastructure.