mcp-postgres 2.0.0

High-performance MCP server for PostgreSQL with CPU-aware connection pooling and optimized buffers
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
[
  {
    "name": "create_table",
    "description": "Create a new table with specified columns and constraints. Define each column with type and optional constraints (PRIMARY KEY, UNIQUE, NOT NULL, DEFAULT, etc.). Use for creating new tables with custom schemas.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name (required). Example: 'users', 'products'. Case-insensitive."
        },
        "columns": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Column definitions (required). Each string defines one column with type and constraints. Examples: ['id SERIAL PRIMARY KEY', 'email VARCHAR(255) UNIQUE NOT NULL', 'created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP', 'status VARCHAR(20) DEFAULT \\'active\\'']. Format: 'column_name TYPE [CONSTRAINT...]'"
        }
      },
      "required": [
        "table",
        "columns"
      ]
    }
  },
  {
    "name": "list_tables",
    "description": "List all user-defined tables in the database with schema, name, and table type. Use this to discover available tables, understand the database structure, and identify which tables are available for querying or modification. Returns a list of tables (BASE TABLE, TEMPORARY, etc.) excluding system tables. Useful for schema exploration and data modeling.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "describe_table",
    "description": "Get detailed column information for a specific table including column names, data types, nullability, default values, and column order. Essential for understanding table structure before querying or modifying data. Shows constraints, triggers, and column descriptions. Use this to explore unfamiliar tables or verify schema assumptions.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name to describe (required). Example: 'users', 'orders', 'products'. Case-insensitive. Use schema.table for non-public schemas."
        }
      },
      "required": [
        "table"
      ]
    }
  },
  {
    "name": "execute_query",
    "description": "Execute a SELECT query and retrieve data. Returns result rows as arrays with column values. Supports all SELECT operations: filtering, aggregation, joins, subqueries, window functions, CTEs. Use for data retrieval, analysis, and reporting. Maximum query execution time enforced to prevent runaway queries.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "SELECT SQL query to execute (required). Max 10,000 characters. Examples: 'SELECT * FROM users LIMIT 10', 'SELECT COUNT(*) as count FROM orders WHERE status = ''shipped''', 'SELECT u.name, COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id'. Must be a SELECT query only."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "execute_insert",
    "description": "Execute an INSERT statement to add new records to a table. Returns the number of rows affected and optionally inserted IDs if RETURNING clause is used. Supports single row, multi-row, and SELECT-based inserts. Useful for adding new data, bulk imports, and data migrations. Rows are returned in the order inserted.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "INSERT SQL statement (required). Max 10,000 characters. Examples: 'INSERT INTO users (email, name) VALUES (''user@example.com'', ''John'')', 'INSERT INTO users (email, name) VALUES (''a@test.com'', ''A''), (''b@test.com'', ''B'') RETURNING id', 'INSERT INTO archive SELECT * FROM temp_table'. Use RETURNING clause to get inserted IDs or values."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "execute_update",
    "description": "Execute an UPDATE statement to modify existing records. Returns the number of rows affected. Supports conditional updates with WHERE clause, computed values, and RETURNING clause for verification. Essential for data corrections, status changes, and bulk updates. Consider using RETURNING to verify the changes.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "UPDATE SQL statement with WHERE clause for safety (required). Max 10,000 characters. Examples: 'UPDATE users SET status = ''active'' WHERE created_at > now() - interval ''7 days''', 'UPDATE products SET price = price * 1.1 WHERE category_id = 5 RETURNING id, price', 'UPDATE orders SET shipped_at = now() WHERE status = ''ready'''. ALWAYS include WHERE clause to prevent accidental updates."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "execute_delete",
    "description": "Execute a DELETE statement to remove records from a table. Returns the number of rows deleted. Always requires careful WHERE clauses to prevent accidental data loss. Consider backing up or using soft-delete (UPDATE status) for critical data. RETURNING clause shows which rows were deleted.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "DELETE SQL statement with WHERE clause (required). Max 10,000 characters. Examples: 'DELETE FROM audit_logs WHERE created_at < now() - interval ''90 days''', 'DELETE FROM temp_uploads WHERE status = ''failed'' RETURNING id, filename'. ALWAYS include a WHERE clause - deleting without one removes all rows. Use RETURNING to verify what was deleted."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "async_batch_insert",
    "description": "High-performance multi-row insert optimized for speed with synchronous_commit temporarily disabled. Insert up to 1,000 rows in a single operation. Much faster than individual INSERT statements for bulk loads. Returns rows affected count and optionally inserted IDs via RETURNING. Perfect for importing CSV data, test data loading, and bulk operations.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Target table name (required). Example: 'users', 'products', 'orders'. Case-insensitive. Must exist and have INSERT permissions."
        },
        "columns": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Column names in order matching the row data (required). Example: ['email', 'name', 'created_at']. Column count must match row data length. Order matters - first column in array corresponds to first value in each row."
        },
        "rows": {
          "type": "array",
          "items": {
            "type": "array"
          },
          "description": "Array of rows to insert (required). Max 1,000 rows per call. Each row is an array of values matching columns order. Example: [['user1@test.com', 'User 1', '2026-01-01'], ['user2@test.com', 'User 2', '2026-01-02']]. NULL values supported as null."
        },
        "returning": {
          "type": "string",
          "description": "Optional: Column to return after insert. Example: 'id' returns inserted IDs, 'id, email' returns multiple columns. Useful for getting auto-generated IDs. Omit if not needed."
        }
      },
      "required": [
        "table",
        "columns",
        "rows"
      ]
    }
  },
  {
    "name": "async_batch_insert_copy",
    "description": "Ultra-high-performance bulk insert using PostgreSQL's COPY protocol. Optimized for massive imports (10K+ rows). Uses automatic batching with configurable batch size. Returns total rows affected and batch count. Perfect for data warehouse loads, ETL operations, and large-scale migrations. Much faster than batch_insert for very large datasets.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Target table name (required). Example: 'users', 'events', 'transactions'. Case-insensitive. Should be empty or recently truncated for best performance."
        },
        "columns": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Column names in order matching rows data (required). Example: ['id', 'event_type', 'timestamp', 'value']. All columns must be in the target table."
        },
        "rows": {
          "type": "array",
          "items": {
            "type": "array"
          },
          "description": "Array of rows as arrays of values (required). Can be very large (10K+, 100K+). Each row must have same number of values as columns. NULL values represented as null in JSON."
        },
        "batch_size": {
          "type": "integer",
          "description": "Rows per INSERT batch statement (optional, default: 1,000). Range: 100-5,000. Larger batches = faster but uses more memory. For 100K+ rows, use 1,000-2,000. For small inserts, can use larger values up to 5,000."
        }
      },
      "required": [
        "table",
        "columns",
        "rows"
      ]
    }
  },
  {
    "name": "explain_query",
    "description": "Analyze query execution plans to understand performance characteristics. Shows how PostgreSQL will execute a SELECT query including sequential vs index scans, join types, and estimated rows. ANALYZE option executes the query and shows actual execution metrics. Use to identify missing indexes, slow joins, or inefficient query plans. Output format can be JSON (machine readable) or text (human readable).",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "SELECT query to explain (required). Example: 'SELECT u.id, u.email, COUNT(o.id) FROM users u LEFT JOIN orders o ON u.id = o.user_id GROUP BY u.id HAVING COUNT(o.id) > 5'. Must be a SELECT query."
        },
        "analyze": {
          "type": "boolean",
          "description": "Execute query and show actual metrics (optional, default: false). Set to true to see real execution time, actual rows, and buffer stats. WARNING: This executes the query - avoid on slow queries. Use false for planning without execution."
        },
        "buffers": {
          "type": "boolean",
          "description": "Include buffer usage statistics (optional, default: false). Requires analyze=true. Shows shared_buffers hits/misses and I/O stats. Useful for diagnosing cache efficiency and disk I/O bottlenecks."
        },
        "format": {
          "type": "string",
          "enum": [
            "json",
            "text",
            "xml",
            "yaml"
          ],
          "description": "Output format (optional, default: 'json'). 'json' = machine-readable, structured; 'text' = human-readable plain text (best for reading); 'xml' = structured markup; 'yaml' = human-readable structured. Recommend 'json' for parsing, 'text' for visual inspection."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "analyze_db_health",
    "description": "Comprehensive one-stop health dashboard checking: buffer cache hit ratios, active/idle connection counts, unused and duplicate indexes, VACUUM progress, tables needing maintenance, and tables with excessive sequential scans. Excellent for spotting performance issues, identifying optimization opportunities, and monitoring overall database wellness. Runs multiple diagnostics and returns consolidated health status.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "list_unused_indexes",
    "description": "Identify indexes that have never been used (zero index scans) or are not helping with performance. These indexes consume disk space, slow down writes, and should be considered for removal. Returns index metadata including size estimates. Useful for cleanup and performance tuning. Review before removing to ensure they're truly unused (consider index-only scans).",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "list_duplicate_indexes",
    "description": "Find potentially redundant or duplicate indexes that overlap in functionality. Duplicate indexes waste storage and slow down DML operations without benefiting queries. Shows which indexes are candidates for consolidation or removal. Useful for index optimization and cleanup after schema changes or migrations.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "show_vacuum_progress",
    "description": "Monitor ongoing VACUUM and AUTOVACUUM operations in real-time. Shows which tables are being vacuumed, progress percentage, blocks processed, index vacuum count, and estimated time remaining. Use to track maintenance operations and identify long-running vacuum processes that might impact performance.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "get_object_details",
    "description": "Get comprehensive information about a specific table including: all columns with types, primary key, foreign keys, all indexes with definitions, constraints, table size estimates, row counts, description/comments. Use for thorough schema exploration, dependency mapping, and understanding table relationships. Returns everything needed to understand a table's role in the database.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name to get details for (required). Example: 'users', 'orders', 'products'. Case-insensitive. Returns all columns, indexes, constraints, FKs, and metadata."
        },
        "schema": {
          "type": "string",
          "description": "Schema name containing the table (optional, default: 'public'). Example: 'public', 'staging', 'archive'. Use 'schema.table' format in table parameter to override. Specify if table exists in non-public schema."
        }
      },
      "required": [
        "table"
      ]
    }
  },
  {
    "name": "list_indexes",
    "description": "List all indexes in the database with their definitions, associated tables, columns, and types (unique, partial, expression, etc.). Use for index inventory, migration planning, and understanding database indexing strategy. Shows CREATE INDEX statements that can be copied for replication.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "list_schemas",
    "description": "List all non-system schemas in the database with their owners and descriptions. Shows the organizational structure of database objects. Useful for understanding multi-schema setups, permissions, and logical data organization. Excludes system schemas like pg_catalog and information_schema.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "show_constraints",
    "description": "List all table constraints across the entire database including PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK, and NOT NULL constraints. Shows constraint definitions and which tables/columns are affected. Use for understanding data integrity rules, dependency chains, and constraint-driven optimization opportunities.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "list_triggers",
    "description": "List all triggers defined on a specific table with their trigger names, event types, timing (BEFORE/AFTER), and action statements. Shows what automated actions occur when table data changes. Use to understand table behavior, debug unexpected changes, identify side effects of DML operations, and understand cascade rules. Essential for understanding table automation and data integrity logic.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name to show triggers for (required). Example: 'users', 'orders'. Case-insensitive. Triggers from this table in specified schema will be returned."
        },
        "schema": {
          "type": "string",
          "description": "Schema name to filter triggers (optional, default: 'public'). Example: 'public', 'myschema'. Filters triggers to only those defined in specified schema."
        },
        "limit": {
          "type": "integer",
          "description": "Maximum triggers to return (optional, default: 1000). Range: 1-10000. Prevents memory exhaustion on tables with many triggers."
        }
      },
      "required": [
        "table"
      ]
    }
  },
  {
    "name": "list_database_privileges",
    "description": "List database-level access control lists (ACLs) and permissions for all non-template databases. Shows which users/roles have which privileges on each database (CONNECT, CREATE, TEMPORARY, etc.). Use for auditing access control, understanding permission structure, and verifying security policies.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "list_users",
    "description": "List all database users and roles with their attributes: superuser status, can create databases, can create roles, can login, connection limits, and validity expiration dates. Use for user administration auditing, understanding team access levels, and identifying unused or expired accounts.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "list_role_memberships",
    "description": "Show role membership hierarchy - which users belong to which roles and who has admin grant options. Useful for understanding permission inheritance, group membership structure, and organizational access patterns. Essential for permission auditing and understanding delegation levels.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "get_cache_hit_ratio",
    "description": "Get buffer cache hit ratio metrics from pg_stat_user_tables and pg_stat_user_indexes. Shows what percentage of data is being read from cache vs disk. High ratio (>95%) indicates efficient buffering. Low ratio suggests missing indexes, insufficient shared_buffers setting, or cold cache. Use to diagnose I/O performance issues.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "get_pg_stat_statements",
    "description": "Get top 50 slowest queries from pg_stat_statements extension ranked by total execution time. Shows query text, call count, mean time, max time, and total time. Essential for identifying performance bottlenecks and optimization targets. Requires pg_stat_statements extension to be installed and enabled. Use after enabling statistics for a representative period.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "get_setting",
    "description": "Retrieve a specific PostgreSQL configuration setting with full metadata: current value, unit (bytes/seconds/etc), description, context (when it can be changed), and default value. Use to inspect any configuration parameter (e.g., max_connections, shared_buffers, work_mem). Helpful for understanding database tuning and current configuration state.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "setting_name": {
          "type": "string",
          "description": "PostgreSQL setting name (required). Examples: 'max_connections' (max concurrent connections), 'shared_buffers' (memory for caching), 'work_mem' (memory per operation), 'effective_cache_size' (total available cache), 'random_page_cost' (cost model), 'maintenance_work_mem' (VACUUM/CREATE INDEX memory). Case-insensitive. Returns value, unit, description, and context."
        }
      },
      "required": [
        "setting_name"
      ]
    }
  },
  {
    "name": "show_current_user",
    "description": "Show information about the current database connection: authenticated user, current database, PostgreSQL version with platform details, and system info. Use to verify connection identity, check PostgreSQL version compatibility, and understand session context. Helpful for debugging permission issues or verifying server configuration.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "show_session_info",
    "description": "Show current session connection details: current user, database, client IP address and port, server address and port, and application name. Useful for debugging connection issues, understanding session context in multi-client scenarios, and auditing who is connected where.",
    "inputSchema": {
      "type": "object",
      "properties": {}
    }
  },
  {
    "name": "async_execute_insert",
    "description": "Execute an INSERT statement with optimized performance for high-volume operations (WHERE predicate affects 100+ rows) by temporarily disabling synchronous_commit. Returns the number of rows affected. Optimized when the operation affects more than 100 rows via the WHERE condition. Much faster than execute_insert for large batches but trades immediate durability for speed. Data is still persisted, just not guaranteed to be on disk immediately. Perfect for bulk imports, data migrations, and high-volume inserts.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "INSERT SQL statement (required). Max 10,000 characters. Optimized when WHERE predicate affects more than 100 rows. Examples: 'INSERT INTO users SELECT * FROM staging WHERE active = true', 'INSERT INTO archive (id, data) VALUES (1, ''data1''), (2, ''data2''), ... (500, ''data500'')'. Use RETURNING clause to verify inserted rows. Best when WHERE predicate affects more than 100 rows for significant performance benefit."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "async_execute_update",
    "description": "Execute an UPDATE statement with optimized performance for high-volume operations (WHERE predicate affects 100+ rows) by temporarily disabling synchronous_commit. Returns the number of rows affected. Optimized when the WHERE condition matches more than 100 rows in the table. Much faster than execute_update for bulk updates but trades immediate durability for speed. Always include WHERE clause to prevent accidental updates. Data is persisted but not guaranteed on disk immediately.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "UPDATE SQL statement with WHERE clause (required). Max 10,000 characters. Optimized when WHERE predicate affects more than 100 rows. Examples: 'UPDATE users SET status = ''active'' WHERE updated_at < now() - interval ''7 days'' AND status = ''pending''', 'UPDATE products SET price = price * 1.1 WHERE category IN (1, 2, 3, 4, 5)', 'UPDATE orders SET shipped_at = now() WHERE status = ''ready'' AND created_at > now() - interval ''30 days'''. ALWAYS include WHERE clause. Use RETURNING to verify changes."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "async_execute_delete",
    "description": "Execute a DELETE statement with optimized performance for high-volume operations (WHERE predicate affects 100+ rows) by temporarily disabling synchronous_commit. Returns the number of rows deleted. Optimized when the WHERE condition matches more than 100 rows in the table. Much faster than execute_delete for bulk deletes but trades immediate durability for speed. ALWAYS requires WHERE clause to prevent accidental full table deletion. Data is removed but not guaranteed on disk immediately.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sql": {
          "type": "string",
          "description": "DELETE SQL statement with WHERE clause (required). Max 10,000 characters. Optimized when WHERE predicate affects more than 100 rows. Examples: 'DELETE FROM audit_logs WHERE created_at < now() - interval ''365 days''', 'DELETE FROM temp_uploads WHERE status = ''failed'' AND created_at < now() - interval ''1 day''', 'DELETE FROM sessions WHERE expires_at < now() AND user_id NOT IN (SELECT id FROM users WHERE premium = true)'. CRITICAL: ALWAYS include WHERE clause - deleting without one removes ALL rows. Use RETURNING to verify what was deleted."
        }
      },
      "required": [
        "sql"
      ]
    }
  },
  {
    "name": "create_index",
    "description": "Create a database index on one or more table columns. Indexes improve query performance by allowing faster data lookups. Supports UNIQUE indexes for constraint enforcement and CONCURRENTLY option for non-blocking index creation on live tables. Use for optimizing slow queries or enforcing column uniqueness.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "index_name": {
          "type": "string",
          "description": "Index name (required). Example: 'idx_users_email'. Must be unique within the schema. Follows naming convention: idx_table_column(s)."
        },
        "table": {
          "type": "string",
          "description": "Table name to create index on (required). Example: 'users', 'orders'. Case-insensitive."
        },
        "columns": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Column names to index (required). Example: ['email'] for single column or ['user_id', 'created_at'] for composite index. Order matters for composite indexes."
        },
        "unique": {
          "type": "boolean",
          "description": "Create UNIQUE index to enforce column uniqueness constraint (optional, default: false). Useful for email, username fields. All indexed column combinations must be unique."
        },
        "concurrent": {
          "type": "boolean",
          "description": "Use CONCURRENTLY option to avoid blocking table writes during index creation (optional, default: false). Required for production tables to avoid locks. Slower but non-blocking."
        }
      },
      "required": [
        "index_name",
        "table",
        "columns"
      ]
    }
  },
  {
    "name": "drop_index",
    "description": "Drop (delete) a database index. Frees storage space and removes any locking overhead from index maintenance. Use CONCURRENTLY option on live tables to avoid blocking. Safe to remove unused or duplicate indexes without affecting data.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "index_name": {
          "type": "string",
          "description": "Index name to drop (required). Example: 'idx_users_email'. Must exist in the database."
        },
        "if_exists": {
          "type": "boolean",
          "description": "Only drop index if it exists, don't error if missing (optional, default: false). Use true to avoid errors in scripts."
        },
        "concurrent": {
          "type": "boolean",
          "description": "Use CONCURRENTLY option to avoid blocking table writes during index drop (optional, default: false). Required for production tables. Slower but non-blocking."
        }
      },
      "required": [
        "index_name"
      ]
    }
  },
  {
    "name": "create_partition",
    "description": "Create a new partition for a partitioned table. Partitioning splits large tables into smaller logical pieces for better performance and manageability. Supports RANGE (date ranges), LIST (discrete values), and HASH (modulo) partitioning. Use for tables with millions of rows.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Parent partitioned table name (required). Example: 'events'. Must be defined as partitioned table."
        },
        "partition_name": {
          "type": "string",
          "description": "Name for the new partition (required). Example: 'events_2026_01'. Naming convention: parent_table_partition_identifier."
        },
        "partition_type": {
          "type": "string",
          "enum": [
            "RANGE",
            "LIST",
            "HASH"
          ],
          "description": "Partitioning strategy (required). RANGE: date/number ranges, LIST: specific values, HASH: modulo-based distribution."
        },
        "column": {
          "type": "string",
          "description": "Column name used for partitioning (required). Example: 'created_date' for date partitioning. Must match parent table's partition column."
        },
        "values": {
          "type": "string",
          "description": "Partition bounds (required). Examples: 'FROM (2026-01-01) TO (2026-02-01)' for RANGE, 'IN (value1, value2)' for LIST, 'MODULUS 4 REMAINDER 0' for HASH."
        }
      },
      "required": [
        "table",
        "partition_name",
        "partition_type",
        "column",
        "values"
      ]
    }
  },
  {
    "name": "drop_partition",
    "description": "Drop (delete) a partition from a partitioned table. Removes the partition and its data. Use carefully - deleting a partition deletes all rows in that partition. Use if_exists to avoid errors if partition already missing.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Parent table name (required). Example: 'events'. Used for context/logging, partition is identified by partition_name."
        },
        "partition_name": {
          "type": "string",
          "description": "Partition name to drop (required). Example: 'events_2026_01'. Must be an existing partition."
        },
        "if_exists": {
          "type": "boolean",
          "description": "Only drop if partition exists, don't error if missing (optional, default: false). Use true in cleanup scripts."
        }
      },
      "required": [
        "table",
        "partition_name"
      ]
    }
  },
  {
    "name": "truncate_table",
    "description": "Quickly delete all rows from a table without deleting the table structure. Much faster than DELETE for clearing large tables. Use RESTART IDENTITY to reset auto-increment sequences. Use CASCADE to handle foreign key constraints.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name to truncate (required). Example: 'temp_data', 'logs'. All rows will be deleted. Structure remains."
        },
        "cascade": {
          "type": "boolean",
          "description": "Also truncate tables with foreign keys referencing this table (optional, default: false). Use when dependencies exist. Dangerous - affects related tables."
        },
        "restart_identity": {
          "type": "boolean",
          "description": "Reset auto-increment sequences to their seed values (optional, default: false). Use if table has SERIAL/IDENTITY columns and you want IDs to restart from 1."
        }
      },
      "required": [
        "table"
      ]
    }
  },
  {
    "name": "drop_table",
    "description": "Drop (delete) a table and its data permanently. Use IF EXISTS to avoid errors if table doesn't exist. Use CASCADE to also drop dependent objects (views, constraints, etc). WARNING: This deletes all table data - use carefully.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name to drop (required). Example: 'users', 'temp_data'. Case-insensitive."
        },
        "if_exists": {
          "type": "boolean",
          "description": "Only drop if table exists, don't error if missing (optional, default: false). Use in cleanup scripts."
        },
        "cascade": {
          "type": "boolean",
          "description": "Also drop dependent objects like views and constraints (optional, default: false). WARNING: Drops dependent views, materialized views, and constraints. Use false unless you understand the impact."
        }
      },
      "required": [
        "table"
      ]
    }
  },
  {
    "name": "create_view",
    "description": "Create a database view from a SELECT query. Views are virtual tables that execute the query every time accessed. Use MATERIALIZED for performance (stores results), or regular view for always-current data. Use OR REPLACE to update existing views.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "view_name": {
          "type": "string",
          "description": "View name (required). Example: 'user_summary', 'active_orders'. Case-insensitive."
        },
        "query": {
          "type": "string",
          "description": "SELECT query defining the view (required). Example: 'SELECT id, name, COUNT(*) as count FROM users GROUP BY id, name'. Must be valid SQL SELECT statement."
        },
        "materialized": {
          "type": "boolean",
          "description": "Create materialized view (stores results, fast queries, stale data) vs regular view (always current, slower) (optional, default: false). Materialized views need REFRESH MATERIALIZED VIEW to update."
        },
        "or_replace": {
          "type": "boolean",
          "description": "Replace view if exists (optional, default: false). For materialized views, requires same column names and types. For regular views, allows changing definition."
        }
      },
      "required": [
        "view_name",
        "query"
      ]
    }
  },
  {
    "name": "drop_view",
    "description": "Drop (delete) a view. Works for both regular and materialized views. Use IF EXISTS to avoid errors. Use CASCADE to also drop dependent views/objects.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "view_name": {
          "type": "string",
          "description": "View name to drop (required). Example: 'user_summary', 'active_orders'. Case-insensitive."
        },
        "if_exists": {
          "type": "boolean",
          "description": "Only drop if view exists, don't error if missing (optional, default: false)."
        },
        "cascade": {
          "type": "boolean",
          "description": "Also drop dependent views and objects (optional, default: false). WARNING: Drops dependent views."
        }
      },
      "required": [
        "view_name"
      ]
    }
  },
  {
    "name": "alter_view",
    "description": "Modify a view by renaming it or changing its schema. Use to reorganize views or fix naming.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "view_name": {
          "type": "string",
          "description": "View name to alter (required). Example: 'user_summary'."
        },
        "rename_to": {
          "type": "string",
          "description": "New name for the view (optional). Example: 'users_summary'. Either this or set_schema required."
        },
        "set_schema": {
          "type": "string",
          "description": "New schema for the view (optional). Example: 'analytics'. Either this or rename_to required."
        }
      },
      "required": [
        "view_name"
      ]
    }
  },
  {
    "name": "create_schema",
    "description": "Create a new schema (namespace for database objects). Schemas organize tables, views, and other objects into logical groups. Use IF NOT EXISTS to safely create if not present.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "schema_name": {
          "type": "string",
          "description": "Schema name to create (required). Example: 'analytics', 'reporting', 'archive'. Case-insensitive."
        },
        "if_not_exists": {
          "type": "boolean",
          "description": "Only create if schema doesn't exist, don't error if exists (optional, default: false)."
        }
      },
      "required": [
        "schema_name"
      ]
    }
  },
  {
    "name": "drop_schema",
    "description": "Drop (delete) a schema and optionally its contents. Use IF EXISTS to avoid errors. Use CASCADE to drop all objects in schema.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "schema_name": {
          "type": "string",
          "description": "Schema name to drop (required). Example: 'analytics'. Case-insensitive."
        },
        "if_exists": {
          "type": "boolean",
          "description": "Only drop if exists, don't error if missing (optional, default: false)."
        },
        "cascade": {
          "type": "boolean",
          "description": "Also drop all objects in schema (tables, views, functions, etc) (optional, default: false). WARNING: Drops all schema contents."
        }
      },
      "required": [
        "schema_name"
      ]
    }
  },
  {
    "name": "create_sequence",
    "description": "Create a sequence for generating auto-incrementing values. Used for PRIMARY KEY values and counter columns. Sequences are independent objects that can be shared across multiple tables.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sequence_name": {
          "type": "string",
          "description": "Sequence name to create (required). Example: 'user_id_seq', 'order_seq'. Case-insensitive."
        },
        "if_not_exists": {
          "type": "boolean",
          "description": "Only create if sequence doesn't exist (optional, default: false)."
        },
        "start": {
          "type": "integer",
          "description": "Starting value for sequence (optional, default: 1). Example: 100 to start from 100."
        },
        "increment": {
          "type": "integer",
          "description": "Increment by this value each time (optional, default: 1). Example: 5 increments by 5 each time."
        }
      },
      "required": [
        "sequence_name"
      ]
    }
  },
  {
    "name": "drop_sequence",
    "description": "Drop (delete) a sequence. Use IF EXISTS to avoid errors if sequence doesn't exist.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "sequence_name": {
          "type": "string",
          "description": "Sequence name to drop (required). Example: 'user_id_seq'."
        },
        "if_exists": {
          "type": "boolean",
          "description": "Only drop if exists, don't error if missing (optional, default: false)."
        }
      },
      "required": [
        "sequence_name"
      ]
    }
  },
  {
    "name": "alter_index",
    "description": "Modify an index by renaming it or changing its schema. Use to reorganize indexes or fix naming.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "index_name": {
          "type": "string",
          "description": "Index name to alter (required). Example: 'idx_users_email'."
        },
        "rename_to": {
          "type": "string",
          "description": "New name for the index (optional). Example: 'idx_users_email_v2'. Either this or set_schema required."
        },
        "set_schema": {
          "type": "string",
          "description": "New schema for the index (optional). Example: 'archive'. Either this or rename_to required."
        }
      },
      "required": [
        "index_name"
      ]
    }
  },
  {
    "name": "list_partitions",
    "description": "List all partitions of a partitioned table, including partition names and sizes. Use to understand table partitioning structure.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Partitioned table name (required). Example: 'events', 'logs'. Must be a partitioned table."
        }
      },
      "required": [
        "table"
      ]
    }
  },
  {
    "name": "backup_table",
    "description": "Complete table backup copying columns, data, indexes, and partitions. Creates backup_<table_name> with full schema preservation. Columns: all column definitions (names, types, defaults, nullability). Data: all rows copied (complete dataset). Indexes: all indexes recreated with same structure. Partitions: partition structure preserved for partitioned tables. Essential safety feature - backup before DROP, bulk DELETE, or schema changes. If original deleted: full backup with all data survives. Recovery mechanism for accidental deletion protection.",
    "inputSchema": {
      "type": "object",
      "properties": {
        "table": {
          "type": "string",
          "description": "Table name to backup (required). Example: 'users', 'orders'. Backup will be created as 'backup_users', 'backup_orders'. Case-insensitive."
        }
      },
      "required": [
        "table"
      ]
    }
  }
]