Format SQL across 19 dialects (PostgreSQL, MySQL, BigQuery, Snowflake, etc.) with configurable indentation and keyword case via @mukundakatta/sqlfmt-mcp
@mukundakatta/sqlfmt-mcp v0.1.0 — dialect-aware SQL formatter
Install & run:
npm install @mukundakatta/sqlfmt-mcp
node node_modules/@mukundakatta/sqlfmt-mcp/src/index.js # stdio MCP serverTools (2):
| Tool | Params | Description |
|---|---|---|
format_sql | sql (required), dialect? (default "sql"), tab_width? (1-8, default 2), use_tabs? (default false), keyword_case? (preserve/upper/lower, default upper) | Format a SQL string |
list_dialects | (none) | Returns the 19 supported dialects |
19 dialects: sql, bigquery, db2, db2i, duckdb, hive, mariadb, mysql, n1ql, plsql, postgresql, redshift, singlestoredb, snowflake, spark, sqlite, tidb, transactsql, trino
Return shape: { formatted: string, dialect: string, line_count: number }
Verified trace (10 calls, 100% success)
1. list_dialects → 19 dialects returned (69ms)
2. Basic SELECT (generic sql):
IN: select id,name,email from users where status='active' and created_at > '2024-01-01' order by name asc limit 10
OUT: SELECT\n id,\n name,\n email\nFROM\n users\nWHERE\n status = 'active'\n AND created_at > '2024-01-01'\nORDER BY\n name ASC\nLIMIT\n 10
(77ms, 13 lines)3. Complex JOIN + subquery (postgresql):
IN: select u.id,u.name,o.total,p.name as product from users u inner join orders o on u.id=o.user_id left join order_items oi on o.id=oi.order_id left join products p on oi.product_id=p.id where o.total>(select avg(total) from orders) group by u.id,u.name,o.total,p.name having count(*)>1 order by o.total desc
OUT: properly indented with subquery nested, JOINs aligned (629ms — first dialect-specific call is slowest)4. INSERT + multiple VALUES (mysql): properly splits each value tuple onto its own line (174ms)
5. CTE / WITH clause (postgresql): each CTE indented as nested SELECT, final query separate (127ms)
6. CREATE TABLE with constraints (sqlite): columns, CHECK, REFERENCES, UNIQUE all properly formatted (98ms)
7. BigQuery-specific syntax: countif(), safe_divide(), backtick-quoted table refs preserved (101ms)
8. keyword_case: lower + tab_width: 4: select, from, where, order by all lowercase, 4-space indent (12ms)
9. Snowflake MERGE: WHEN MATCHED/NOT MATCHED clauses properly structured (103ms)
10. Window functions (transactsql): RANK() OVER (PARTITION BY ... ORDER BY ...) with nested indentation (32ms)
Key observations
- First call with a new dialect is slowest (~630ms for postgresql) — subsequent calls with same dialect are 10-100ms
- Generic `sql` dialect works for most ANSI SQL — only use specific dialects for dialect-only syntax (BigQuery backticks, Snowflake MERGE, etc.)
- `keyword_case: "lower"` works correctly — transforms all keywords to lowercase
- Subqueries and CTEs get proper nesting — not just line breaks
- `line_count` in response helps estimate output size before rendering
- No validation — it formats whatever you give it, even invalid SQL (may produce odd results)