Add DML_ONLY access mode #124
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Add DML_ONLY Access Mode
Overview
Adds a new
DML_ONLYaccess mode to postgres-mcp that allows data manipulation (INSERT, UPDATE, DELETE, SELECT) while blocking schema changes and other DDL operations. This provides a middle ground betweenUNRESTRICTED(allows everything) andRESTRICTED(read-only) modes.Motivation
Users often need to perform data modifications without having the ability to alter database schema. The existing access modes didn't support this use case:
UNRESTRICTED: Too permissive, allows DDL operationsRESTRICTED: Too restrictive, blocks all writes including DMLDML_ONLYmode enables safe data manipulation for use cases like:Implementation Details
New Components:
DmlOnlySqlDriverclass insrc/postgres_mcp/sql/dml_only_sql.pySafeSqlDriver.ALLOWED_FUNCTIONSand extendsALLOWED_NODE_TYPESAllowed Operations:
SELECT- Read queriesINSERT- Including UPSERT withON CONFLICTUPDATE- With all standard clauses (WHERE, RETURNING, etc.)DELETE- With all standard clausesEXPLAIN- Query planning (but notEXPLAIN ANALYZE)SHOW- View configuration variablesBlocked Operations:
CREATE/ALTER/DROP TABLECREATE/DROP INDEXCREATE/DROP VIEW/FUNCTION/SCHEMA/DATABASETRUNCATEVACUUMCREATE/DROP EXTENSIONSET(configuration changes)BEGIN/COMMIT/ROLLBACK(transaction control)EXPLAIN ANALYZE(can impact performance)Usage:
Testing
Design Decisions
RawStmt Validation: Validates inner statement (
stmt.stmt) to properly check the actual SQL command, not just the wrapper nodeFunction Allow-list: Reuses
SafeSqlDriver.ALLOWED_FUNCTIONSto maintain consistency with read-only mode's security modelError Messages: Provides specific, actionable error messages (e.g., "Statement type CreateStmt not allowed in DML_ONLY mode") rather than generic failures
Timeout Handling: Returns
TimeoutError(notValueError) for query timeouts, enabling callers to distinguish timeout from validation failuresDELETE/UPDATE without WHERE: Required for safety. UPDATE and DELETE statements must include a WHERE clause to prevent accidental modification or deletion of all rows. This is a critical safety feature that helps prevent data loss from mistaken queries
Files Changed
src/postgres_mcp/server.py- Add DML_ONLY to AccessMode enum, update driver selectionsrc/postgres_mcp/sql/dml_only_sql.py- New DmlOnlySqlDriver implementationsrc/postgres_mcp/sql/__init__.py- Export DmlOnlySqlDrivertests/unit/sql/test_dml_only_sql.py- New comprehensive test suitetests/unit/test_access_mode.py- Add DML_ONLY test casesREADME.md- Document new access mode and usageRelated Documentation
Implementation follows the plan outlined in
DML_ONLY_MODE_IMPLEMENTATION.mdBreaking Changes
None. This is a purely additive feature that doesn't modify existing behavior.