Remote MCP server with GitHub OAuth authentication for PostgreSQL database access, supporting read-only queries and write operations with role-based access control
This PostgreSQL MCP server has three well-structured tools with good naming (all action verbs: list, query, execute) and solid descriptions (194-260 chars each). However, there are critical gaps: (1) input schemas are present but incomplete, the `listTables` tool has an empty input schema `{}` which violates the requirement that every parameter be described, and the other two tools have minimal parameter documentation; (2) tool annotations (readOnlyHint, destructiveHint, idempotentHint) are declared in metadata but NOT visible in the source code as part of the tool registration, suggesting they may not be wired into the MCP response; (3) output schemas are not formally documented, the tools return markdown-formatted text rather than structured JSON objects that downstream tools can parse; (4) error handling returns markdown text with Sentry event IDs rather than actionable recovery guidance ('please report to support' tells the LLM nothing about what to do). The security model is reasonable (permission gates via ALLOWED_USERNAMES, input validation via validateSqlQuery), but the lack of structured output and formal schema documentation limits composability.
Execute any SQL statement against the PostgreSQL database, including INSERT, UPDATE, DELETE, and DDL operations. This tool is restricted to specific GitHub users and can perform write transactions. **USE WITH CAUTION** - this can modify or delete data.
Get a list of all tables in the database along with their column information. Use this first to understand the database structure before querying.
Execute a read-only SQL query against the PostgreSQL database. This tool only allows SELECT statements and other read operations. All authenticated users can use this tool.
listTables has empty input schema {}, no parameters are documented, violating the requirement that all parameters have types and descriptions. This prevents LLMs from understanding what inputs (if any) the tool accepts.
Output schemas are not formally documented. Tools return markdown-formatted text wrapped in MCP content blocks rather than structured JSON objects. This breaks tool chaining, downstream tools cannot extract typed fields (table names, row counts, column types) from markdown strings without expensive LLM parsing. Every response is a single flat text block.
Tool annotations (readOnlyHint, destructiveHint) are mentioned in the Risk field but NOT visible in the actual tool registration code. The server.tool() calls in database-tools-sentry.ts do not include a fourth argument (options/metadata) that would declare these annotations to the MCP client. The hints are metadata-only, not part of the wire protocol.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 58 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 49 | - | v1 |
Error responses lack actionable recovery guidance. When validation fails or the user lacks permissions, the response is generic markdown ('Error', 'Event ID: <id>', 'Please report to support') rather than telling the LLM what to do next. Example: 'This operation requires write access. Ask the administrator to add your GitHub username to the allowlist, or use queryDatabase for read-only queries instead.'
Parameter descriptions are sparse. The 'sql' parameter in queryDatabase and executeDatabase is described as 'SQL query to execute' / 'SQL command to execute', but lacks detail on length limits, forbidden statements (e.g. PRAGMA, system calls), or format expectations. queryDatabase mentions 'SELECT queries only' in the tool description but should also enforce this at the parameter level.
No pagination or result limits documented. The listTables response includes all tables and columns without mention of upper bounds. Large schemas could return thousands of columns, exhausting context windows. The queryDatabase tool accepts arbitrary SQL with no documented limit on result rows returned.