sql-forge-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Sql Forge MCP Server
2
+
3
+ MCP server for SQL — query builder, syntax validator, schema generator, query formatter, common patterns.
4
+
5
+ ## Tools
6
+
7
+ | Tool | Description |
8
+ |------|-------------|
9
+ | `format_sql` | Format and prettify SQL queries with proper indentation and keyword capitalization. |
10
+ | `validate_sql` | Check SQL syntax for common issues (unbalanced parens, missing clauses, quote errors). |
11
+ | `build_select` | Build a SELECT query from table, columns, conditions, ordering. |
12
+ | `build_create_table` | Generate CREATE TABLE SQL from column definitions. |
13
+ | `sql_patterns` | Get common SQL patterns/snippets (pagination, upsert, pivot, CTE, window functions). |
14
+
15
+
16
+ ## Installation
17
+
18
+ ### Claude Desktop / Claude Code
19
+
20
+ Add to your MCP config:
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "sql-forge": {
26
+ "command": "node",
27
+ "args": ["/path/to/sql-forge/dist/index.js"]
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Build
34
+
35
+ ```bash
36
+ npm install
37
+ npm run build
38
+ npm start
39
+ ```
40
+
41
+ ## License
42
+
43
+ MIT — Built by [Sovereign](https://github.com/ryudi84/sovereign-tools) (Taylor, autonomous AI agent)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ export declare function createSandboxServer(): McpServer;
package/dist/index.js ADDED
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createSandboxServer = createSandboxServer;
5
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
6
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
7
+ const zod_1 = require("zod");
8
+ // SQL formatting helper
9
+ function formatSql(sql) {
10
+ const keywords = ['SELECT', 'FROM', 'WHERE', 'JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'INNER JOIN',
11
+ 'ON', 'AND', 'OR', 'ORDER BY', 'GROUP BY', 'HAVING', 'LIMIT', 'OFFSET', 'INSERT INTO',
12
+ 'VALUES', 'UPDATE', 'SET', 'DELETE FROM', 'CREATE TABLE', 'ALTER TABLE', 'DROP TABLE',
13
+ 'CREATE INDEX', 'UNION', 'UNION ALL', 'AS', 'IN', 'NOT IN', 'EXISTS', 'BETWEEN', 'LIKE',
14
+ 'IS NULL', 'IS NOT NULL', 'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'DISTINCT', 'COUNT',
15
+ 'SUM', 'AVG', 'MIN', 'MAX'];
16
+ let formatted = sql.trim();
17
+ // Uppercase keywords
18
+ for (const kw of keywords) {
19
+ formatted = formatted.replace(new RegExp('\\b' + kw.replace(' ', '\\s+') + '\\b', 'gi'), kw);
20
+ }
21
+ // Add newlines before major clauses
22
+ const breakBefore = ['SELECT', 'FROM', 'WHERE', 'JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'INNER JOIN',
23
+ 'ORDER BY', 'GROUP BY', 'HAVING', 'LIMIT', 'UNION', 'INSERT INTO', 'UPDATE', 'SET', 'DELETE FROM',
24
+ 'VALUES', 'CREATE TABLE', 'ALTER TABLE'];
25
+ for (const kw of breakBefore) {
26
+ formatted = formatted.replace(new RegExp('\\s+(' + kw.replace(' ', '\\s+') + ')\\b', 'gi'), '\n$1');
27
+ }
28
+ return formatted.trim();
29
+ }
30
+ // Simple SQL syntax checker
31
+ function checkSqlSyntax(sql) {
32
+ const issues = [];
33
+ const upper = sql.toUpperCase().trim();
34
+ if (upper.startsWith('SELECT') && !upper.includes('FROM'))
35
+ issues.push('SELECT without FROM clause');
36
+ if (upper.includes('WHERE') && !upper.includes('SELECT') && !upper.includes('UPDATE') && !upper.includes('DELETE')) {
37
+ issues.push('WHERE clause without SELECT/UPDATE/DELETE');
38
+ }
39
+ const opens = (sql.match(/\(/g) || []).length;
40
+ const closes = (sql.match(/\)/g) || []).length;
41
+ if (opens !== closes)
42
+ issues.push(`Unbalanced parentheses: ${opens} open, ${closes} close`);
43
+ if (sql.includes("'") && (sql.match(/'/g) || []).length % 2 !== 0) {
44
+ issues.push('Unbalanced single quotes');
45
+ }
46
+ return { valid: issues.length === 0, issues };
47
+ }
48
+ // === MCP Server Setup ===
49
+ const server = new mcp_js_1.McpServer({ name: "sql-forge", version: "1.0.0" }, {
50
+ capabilities: { tools: {} },
51
+ instructions: "MCP server for SQL — query builder, syntax validator, schema generator, query formatter, common patterns.",
52
+ });
53
+ // Tool: format_sql
54
+ server.tool("format_sql", "Format and prettify SQL queries with proper indentation and keyword capitalization.", {
55
+ sql: zod_1.z.string().describe("SQL query to format")
56
+ }, async ({ sql }) => {
57
+ try {
58
+ const formatted = formatSql(sql);
59
+ return { content: [{ type: "text", text: `\`\`\`sql\n${formatted}\n\`\`\`` }] };
60
+ }
61
+ catch (e) {
62
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
63
+ }
64
+ });
65
+ // Tool: validate_sql
66
+ server.tool("validate_sql", "Check SQL syntax for common issues (unbalanced parens, missing clauses, quote errors).", {
67
+ sql: zod_1.z.string().describe("SQL query to validate")
68
+ }, async ({ sql }) => {
69
+ try {
70
+ const result = checkSqlSyntax(sql);
71
+ if (result.valid) {
72
+ return { content: [{ type: "text", text: "PASS: No syntax issues found." }] };
73
+ }
74
+ return { content: [{ type: "text", text: `FAIL: ${result.issues.length} issue(s) found:\n\n${result.issues.map((i, n) => `${n + 1}. ${i}`).join("\n")}` }] };
75
+ }
76
+ catch (e) {
77
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
78
+ }
79
+ });
80
+ // Tool: build_select
81
+ server.tool("build_select", "Build a SELECT query from table, columns, conditions, ordering.", {
82
+ table: zod_1.z.string().describe("Table name"),
83
+ columns: zod_1.z.array(zod_1.z.string()).default(['*']).describe("Columns to select"),
84
+ where: zod_1.z.string().optional().describe("WHERE condition"),
85
+ order_by: zod_1.z.string().optional().describe("ORDER BY clause"),
86
+ limit: zod_1.z.number().optional().describe("LIMIT value")
87
+ }, async ({ table, columns, where, order_by, limit }) => {
88
+ try {
89
+ let q = `SELECT ${columns.join(", ")}\nFROM ${table}`;
90
+ if (where)
91
+ q += `\nWHERE ${where}`;
92
+ if (order_by)
93
+ q += `\nORDER BY ${order_by}`;
94
+ if (limit)
95
+ q += `\nLIMIT ${limit}`;
96
+ return { content: [{ type: "text", text: `\`\`\`sql\n${q}\n\`\`\`` }] };
97
+ }
98
+ catch (e) {
99
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
100
+ }
101
+ });
102
+ // Tool: build_create_table
103
+ server.tool("build_create_table", "Generate CREATE TABLE SQL from column definitions.", {
104
+ table: zod_1.z.string().describe("Table name"),
105
+ columns: zod_1.z.array(zod_1.z.object({ name: zod_1.z.string(), type: zod_1.z.string(), nullable: zod_1.z.boolean().default(true), primary: zod_1.z.boolean().default(false) })).describe("Column definitions")
106
+ }, async ({ table, columns }) => {
107
+ try {
108
+ const colDefs = columns.map(c => {
109
+ let def = ` ${c.name} ${c.type.toUpperCase()}`;
110
+ if (c.primary)
111
+ def += " PRIMARY KEY";
112
+ if (!c.nullable && !c.primary)
113
+ def += " NOT NULL";
114
+ return def;
115
+ });
116
+ const sql = `CREATE TABLE ${table} (\n${colDefs.join(",\n")}\n);`;
117
+ return { content: [{ type: "text", text: `\`\`\`sql\n${sql}\n\`\`\`` }] };
118
+ }
119
+ catch (e) {
120
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
121
+ }
122
+ });
123
+ // Tool: sql_patterns
124
+ server.tool("sql_patterns", "Get common SQL patterns/snippets (pagination, upsert, pivot, CTE, window functions).", {
125
+ pattern: zod_1.z.enum(["pagination", "upsert", "cte", "window", "pivot", "soft_delete", "audit"]).describe("Pattern name")
126
+ }, async ({ pattern }) => {
127
+ try {
128
+ const patterns = {
129
+ pagination: "SELECT * FROM table_name\nORDER BY id\nLIMIT :page_size OFFSET (:page - 1) * :page_size;",
130
+ upsert: "INSERT INTO table_name (id, col1, col2)\nVALUES (:id, :val1, :val2)\nON CONFLICT (id) DO UPDATE SET\n col1 = EXCLUDED.col1,\n col2 = EXCLUDED.col2;",
131
+ cte: "WITH ranked AS (\n SELECT *, ROW_NUMBER() OVER (PARTITION BY category ORDER BY score DESC) as rn\n FROM items\n)\nSELECT * FROM ranked WHERE rn <= 3;",
132
+ window: "SELECT name, department, salary,\n AVG(salary) OVER (PARTITION BY department) as dept_avg,\n RANK() OVER (ORDER BY salary DESC) as salary_rank\nFROM employees;",
133
+ pivot: "SELECT\n category,\n SUM(CASE WHEN month = 'Jan' THEN amount ELSE 0 END) as jan,\n SUM(CASE WHEN month = 'Feb' THEN amount ELSE 0 END) as feb,\n SUM(CASE WHEN month = 'Mar' THEN amount ELSE 0 END) as mar\nFROM sales GROUP BY category;",
134
+ soft_delete: "-- Add soft delete column\nALTER TABLE table_name ADD COLUMN deleted_at TIMESTAMP NULL;\n\n-- Query only active records\nSELECT * FROM table_name WHERE deleted_at IS NULL;\n\n-- Soft delete\nUPDATE table_name SET deleted_at = NOW() WHERE id = :id;",
135
+ audit: "CREATE TABLE audit_log (\n id SERIAL PRIMARY KEY,\n table_name VARCHAR(100),\n record_id INTEGER,\n action VARCHAR(10),\n old_data JSONB,\n new_data JSONB,\n changed_by VARCHAR(100),\n changed_at TIMESTAMP DEFAULT NOW()\n);"
136
+ };
137
+ const p = patterns[pattern] || "Unknown pattern";
138
+ return { content: [{ type: "text", text: `# SQL Pattern: ${pattern}\n\n\`\`\`sql\n${p}\n\`\`\`` }] };
139
+ }
140
+ catch (e) {
141
+ return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true };
142
+ }
143
+ });
144
+ // === Smithery sandbox support ===
145
+ function createSandboxServer() {
146
+ return server;
147
+ }
148
+ // === Start Server ===
149
+ async function main() {
150
+ const transport = new stdio_js_1.StdioServerTransport();
151
+ await server.connect(transport);
152
+ }
153
+ // Only auto-start when run directly
154
+ const isDirectRun = !process.env.SMITHERY_SCAN;
155
+ if (isDirectRun) {
156
+ main().catch((error) => {
157
+ console.error("Fatal error:", error);
158
+ process.exit(1);
159
+ });
160
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "sql-forge-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for SQL \u2014 query builder, syntax validator, schema generator, query formatter, common patterns.",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "sql-forge-mcp": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "tsc && node dist/index.js"
13
+ },
14
+ "keywords": [
15
+ "mcp",
16
+ "mcp-server",
17
+ "model-context-protocol",
18
+ "sql forge",
19
+ "ai-tools",
20
+ "claude",
21
+ "cursor",
22
+ "windsurf"
23
+ ],
24
+ "author": "Sovereign (Taylor) <ricardo.yudi@gmail.com>",
25
+ "license": "MIT",
26
+ "type": "commonjs",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/ryudi84/sovereign-mcp-servers"
30
+ },
31
+ "homepage": "https://github.com/ryudi84/sovereign-mcp-servers#readme",
32
+ "mcpName": "io.github.ryudi84/sql-forge",
33
+ "files": [
34
+ "dist/",
35
+ "README.md",
36
+ "LICENSE",
37
+ "smithery.yaml"
38
+ ],
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "^1.26.0",
41
+ "zod": "^4.3.6"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^25.3.0",
45
+ "typescript": "^5.9.3"
46
+ }
47
+ }
package/smithery.yaml ADDED
@@ -0,0 +1,8 @@
1
+ startCommand:
2
+ type: stdio
3
+ configSchema:
4
+ type: object
5
+ properties: {}
6
+ commandFunction: |
7
+ (config) => ({ command: 'npx', args: ['-y', 'sql-forge-mcp'] })
8
+ exampleConfig: {}