@neverinfamous/postgres-mcp 1.2.0 → 2.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.
Files changed (293) hide show
  1. package/README.md +202 -148
  2. package/dist/__tests__/benchmarks/codemode.bench.d.ts +10 -0
  3. package/dist/__tests__/benchmarks/codemode.bench.d.ts.map +1 -0
  4. package/dist/__tests__/benchmarks/codemode.bench.js +159 -0
  5. package/dist/__tests__/benchmarks/codemode.bench.js.map +1 -0
  6. package/dist/__tests__/benchmarks/connection-pool.bench.d.ts +10 -0
  7. package/dist/__tests__/benchmarks/connection-pool.bench.d.ts.map +1 -0
  8. package/dist/__tests__/benchmarks/connection-pool.bench.js +123 -0
  9. package/dist/__tests__/benchmarks/connection-pool.bench.js.map +1 -0
  10. package/dist/__tests__/benchmarks/handler-dispatch.bench.d.ts +11 -0
  11. package/dist/__tests__/benchmarks/handler-dispatch.bench.d.ts.map +1 -0
  12. package/dist/__tests__/benchmarks/handler-dispatch.bench.js +199 -0
  13. package/dist/__tests__/benchmarks/handler-dispatch.bench.js.map +1 -0
  14. package/dist/__tests__/benchmarks/logger-sanitization.bench.d.ts +15 -0
  15. package/dist/__tests__/benchmarks/logger-sanitization.bench.d.ts.map +1 -0
  16. package/dist/__tests__/benchmarks/logger-sanitization.bench.js +155 -0
  17. package/dist/__tests__/benchmarks/logger-sanitization.bench.js.map +1 -0
  18. package/dist/__tests__/benchmarks/resource-prompts.bench.d.ts +10 -0
  19. package/dist/__tests__/benchmarks/resource-prompts.bench.d.ts.map +1 -0
  20. package/dist/__tests__/benchmarks/resource-prompts.bench.js +181 -0
  21. package/dist/__tests__/benchmarks/resource-prompts.bench.js.map +1 -0
  22. package/dist/__tests__/benchmarks/schema-parsing.bench.d.ts +11 -0
  23. package/dist/__tests__/benchmarks/schema-parsing.bench.d.ts.map +1 -0
  24. package/dist/__tests__/benchmarks/schema-parsing.bench.js +209 -0
  25. package/dist/__tests__/benchmarks/schema-parsing.bench.js.map +1 -0
  26. package/dist/__tests__/benchmarks/tool-filtering.bench.d.ts +9 -0
  27. package/dist/__tests__/benchmarks/tool-filtering.bench.d.ts.map +1 -0
  28. package/dist/__tests__/benchmarks/tool-filtering.bench.js +83 -0
  29. package/dist/__tests__/benchmarks/tool-filtering.bench.js.map +1 -0
  30. package/dist/__tests__/benchmarks/transport-auth.bench.d.ts +10 -0
  31. package/dist/__tests__/benchmarks/transport-auth.bench.d.ts.map +1 -0
  32. package/dist/__tests__/benchmarks/transport-auth.bench.js +128 -0
  33. package/dist/__tests__/benchmarks/transport-auth.bench.js.map +1 -0
  34. package/dist/__tests__/benchmarks/utilities.bench.d.ts +10 -0
  35. package/dist/__tests__/benchmarks/utilities.bench.d.ts.map +1 -0
  36. package/dist/__tests__/benchmarks/utilities.bench.js +164 -0
  37. package/dist/__tests__/benchmarks/utilities.bench.js.map +1 -0
  38. package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
  39. package/dist/adapters/DatabaseAdapter.js +12 -0
  40. package/dist/adapters/DatabaseAdapter.js.map +1 -1
  41. package/dist/adapters/postgresql/PostgresAdapter.d.ts.map +1 -1
  42. package/dist/adapters/postgresql/PostgresAdapter.js +56 -3
  43. package/dist/adapters/postgresql/PostgresAdapter.js.map +1 -1
  44. package/dist/adapters/postgresql/prompts/ltree.js +2 -2
  45. package/dist/adapters/postgresql/prompts/ltree.js.map +1 -1
  46. package/dist/adapters/postgresql/schemas/admin.d.ts +10 -5
  47. package/dist/adapters/postgresql/schemas/admin.d.ts.map +1 -1
  48. package/dist/adapters/postgresql/schemas/admin.js +10 -5
  49. package/dist/adapters/postgresql/schemas/admin.js.map +1 -1
  50. package/dist/adapters/postgresql/schemas/backup.d.ts +45 -27
  51. package/dist/adapters/postgresql/schemas/backup.d.ts.map +1 -1
  52. package/dist/adapters/postgresql/schemas/backup.js +64 -26
  53. package/dist/adapters/postgresql/schemas/backup.js.map +1 -1
  54. package/dist/adapters/postgresql/schemas/core.d.ts +53 -19
  55. package/dist/adapters/postgresql/schemas/core.d.ts.map +1 -1
  56. package/dist/adapters/postgresql/schemas/core.js +61 -17
  57. package/dist/adapters/postgresql/schemas/core.js.map +1 -1
  58. package/dist/adapters/postgresql/schemas/cron.d.ts +51 -32
  59. package/dist/adapters/postgresql/schemas/cron.d.ts.map +1 -1
  60. package/dist/adapters/postgresql/schemas/cron.js +64 -44
  61. package/dist/adapters/postgresql/schemas/cron.js.map +1 -1
  62. package/dist/adapters/postgresql/schemas/extensions.d.ts +224 -110
  63. package/dist/adapters/postgresql/schemas/extensions.d.ts.map +1 -1
  64. package/dist/adapters/postgresql/schemas/extensions.js +245 -96
  65. package/dist/adapters/postgresql/schemas/extensions.js.map +1 -1
  66. package/dist/adapters/postgresql/schemas/index.d.ts +7 -6
  67. package/dist/adapters/postgresql/schemas/index.d.ts.map +1 -1
  68. package/dist/adapters/postgresql/schemas/index.js +16 -8
  69. package/dist/adapters/postgresql/schemas/index.js.map +1 -1
  70. package/dist/adapters/postgresql/schemas/introspection.d.ts +445 -0
  71. package/dist/adapters/postgresql/schemas/introspection.d.ts.map +1 -0
  72. package/dist/adapters/postgresql/schemas/introspection.js +478 -0
  73. package/dist/adapters/postgresql/schemas/introspection.js.map +1 -0
  74. package/dist/adapters/postgresql/schemas/jsonb.d.ts +102 -42
  75. package/dist/adapters/postgresql/schemas/jsonb.d.ts.map +1 -1
  76. package/dist/adapters/postgresql/schemas/jsonb.js +125 -30
  77. package/dist/adapters/postgresql/schemas/jsonb.js.map +1 -1
  78. package/dist/adapters/postgresql/schemas/monitoring.d.ts +69 -36
  79. package/dist/adapters/postgresql/schemas/monitoring.d.ts.map +1 -1
  80. package/dist/adapters/postgresql/schemas/monitoring.js +98 -40
  81. package/dist/adapters/postgresql/schemas/monitoring.js.map +1 -1
  82. package/dist/adapters/postgresql/schemas/partitioning.d.ts +21 -24
  83. package/dist/adapters/postgresql/schemas/partitioning.d.ts.map +1 -1
  84. package/dist/adapters/postgresql/schemas/partitioning.js +26 -14
  85. package/dist/adapters/postgresql/schemas/partitioning.js.map +1 -1
  86. package/dist/adapters/postgresql/schemas/partman.d.ts +69 -0
  87. package/dist/adapters/postgresql/schemas/partman.d.ts.map +1 -1
  88. package/dist/adapters/postgresql/schemas/partman.js +46 -33
  89. package/dist/adapters/postgresql/schemas/partman.js.map +1 -1
  90. package/dist/adapters/postgresql/schemas/performance.d.ts +97 -49
  91. package/dist/adapters/postgresql/schemas/performance.d.ts.map +1 -1
  92. package/dist/adapters/postgresql/schemas/performance.js +139 -34
  93. package/dist/adapters/postgresql/schemas/performance.js.map +1 -1
  94. package/dist/adapters/postgresql/schemas/postgis.d.ts +20 -0
  95. package/dist/adapters/postgresql/schemas/postgis.d.ts.map +1 -1
  96. package/dist/adapters/postgresql/schemas/postgis.js +40 -0
  97. package/dist/adapters/postgresql/schemas/postgis.js.map +1 -1
  98. package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts +50 -30
  99. package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts.map +1 -1
  100. package/dist/adapters/postgresql/schemas/schema-mgmt.js +105 -33
  101. package/dist/adapters/postgresql/schemas/schema-mgmt.js.map +1 -1
  102. package/dist/adapters/postgresql/schemas/stats.d.ts +33 -20
  103. package/dist/adapters/postgresql/schemas/stats.d.ts.map +1 -1
  104. package/dist/adapters/postgresql/schemas/stats.js +36 -20
  105. package/dist/adapters/postgresql/schemas/stats.js.map +1 -1
  106. package/dist/adapters/postgresql/schemas/text-search.d.ts +34 -19
  107. package/dist/adapters/postgresql/schemas/text-search.d.ts.map +1 -1
  108. package/dist/adapters/postgresql/schemas/text-search.js +52 -13
  109. package/dist/adapters/postgresql/schemas/text-search.js.map +1 -1
  110. package/dist/adapters/postgresql/tools/admin.d.ts.map +1 -1
  111. package/dist/adapters/postgresql/tools/admin.js +272 -186
  112. package/dist/adapters/postgresql/tools/admin.js.map +1 -1
  113. package/dist/adapters/postgresql/tools/backup/dump.d.ts.map +1 -1
  114. package/dist/adapters/postgresql/tools/backup/dump.js +376 -350
  115. package/dist/adapters/postgresql/tools/backup/dump.js.map +1 -1
  116. package/dist/adapters/postgresql/tools/citext.d.ts.map +1 -1
  117. package/dist/adapters/postgresql/tools/citext.js +333 -243
  118. package/dist/adapters/postgresql/tools/citext.js.map +1 -1
  119. package/dist/adapters/postgresql/tools/codemode/index.d.ts.map +1 -1
  120. package/dist/adapters/postgresql/tools/codemode/index.js +2 -11
  121. package/dist/adapters/postgresql/tools/codemode/index.js.map +1 -1
  122. package/dist/adapters/postgresql/tools/core/convenience.d.ts +9 -1
  123. package/dist/adapters/postgresql/tools/core/convenience.d.ts.map +1 -1
  124. package/dist/adapters/postgresql/tools/core/convenience.js +101 -19
  125. package/dist/adapters/postgresql/tools/core/convenience.js.map +1 -1
  126. package/dist/adapters/postgresql/tools/core/error-helpers.d.ts +48 -0
  127. package/dist/adapters/postgresql/tools/core/error-helpers.d.ts.map +1 -0
  128. package/dist/adapters/postgresql/tools/core/error-helpers.js +256 -0
  129. package/dist/adapters/postgresql/tools/core/error-helpers.js.map +1 -0
  130. package/dist/adapters/postgresql/tools/core/health.d.ts.map +1 -1
  131. package/dist/adapters/postgresql/tools/core/health.js +18 -4
  132. package/dist/adapters/postgresql/tools/core/health.js.map +1 -1
  133. package/dist/adapters/postgresql/tools/core/indexes.d.ts.map +1 -1
  134. package/dist/adapters/postgresql/tools/core/indexes.js +48 -6
  135. package/dist/adapters/postgresql/tools/core/indexes.js.map +1 -1
  136. package/dist/adapters/postgresql/tools/core/objects.d.ts.map +1 -1
  137. package/dist/adapters/postgresql/tools/core/objects.js +104 -85
  138. package/dist/adapters/postgresql/tools/core/objects.js.map +1 -1
  139. package/dist/adapters/postgresql/tools/core/query.d.ts.map +1 -1
  140. package/dist/adapters/postgresql/tools/core/query.js +100 -42
  141. package/dist/adapters/postgresql/tools/core/query.js.map +1 -1
  142. package/dist/adapters/postgresql/tools/core/schemas.d.ts +51 -25
  143. package/dist/adapters/postgresql/tools/core/schemas.d.ts.map +1 -1
  144. package/dist/adapters/postgresql/tools/core/schemas.js +51 -25
  145. package/dist/adapters/postgresql/tools/core/schemas.js.map +1 -1
  146. package/dist/adapters/postgresql/tools/core/tables.d.ts.map +1 -1
  147. package/dist/adapters/postgresql/tools/core/tables.js +72 -32
  148. package/dist/adapters/postgresql/tools/core/tables.js.map +1 -1
  149. package/dist/adapters/postgresql/tools/cron.d.ts.map +1 -1
  150. package/dist/adapters/postgresql/tools/cron.js +333 -206
  151. package/dist/adapters/postgresql/tools/cron.js.map +1 -1
  152. package/dist/adapters/postgresql/tools/introspection.d.ts +15 -0
  153. package/dist/adapters/postgresql/tools/introspection.d.ts.map +1 -0
  154. package/dist/adapters/postgresql/tools/introspection.js +1682 -0
  155. package/dist/adapters/postgresql/tools/introspection.js.map +1 -0
  156. package/dist/adapters/postgresql/tools/jsonb/advanced.d.ts.map +1 -1
  157. package/dist/adapters/postgresql/tools/jsonb/advanced.js +394 -297
  158. package/dist/adapters/postgresql/tools/jsonb/advanced.js.map +1 -1
  159. package/dist/adapters/postgresql/tools/jsonb/basic.d.ts.map +1 -1
  160. package/dist/adapters/postgresql/tools/jsonb/basic.js +686 -398
  161. package/dist/adapters/postgresql/tools/jsonb/basic.js.map +1 -1
  162. package/dist/adapters/postgresql/tools/kcache.d.ts.map +1 -1
  163. package/dist/adapters/postgresql/tools/kcache.js +278 -246
  164. package/dist/adapters/postgresql/tools/kcache.js.map +1 -1
  165. package/dist/adapters/postgresql/tools/ltree.d.ts.map +1 -1
  166. package/dist/adapters/postgresql/tools/ltree.js +137 -38
  167. package/dist/adapters/postgresql/tools/ltree.js.map +1 -1
  168. package/dist/adapters/postgresql/tools/monitoring.d.ts.map +1 -1
  169. package/dist/adapters/postgresql/tools/monitoring.js +86 -55
  170. package/dist/adapters/postgresql/tools/monitoring.js.map +1 -1
  171. package/dist/adapters/postgresql/tools/partitioning.d.ts.map +1 -1
  172. package/dist/adapters/postgresql/tools/partitioning.js +79 -15
  173. package/dist/adapters/postgresql/tools/partitioning.js.map +1 -1
  174. package/dist/adapters/postgresql/tools/partman/management.d.ts.map +1 -1
  175. package/dist/adapters/postgresql/tools/partman/management.js +43 -56
  176. package/dist/adapters/postgresql/tools/partman/management.js.map +1 -1
  177. package/dist/adapters/postgresql/tools/partman/operations.d.ts.map +1 -1
  178. package/dist/adapters/postgresql/tools/partman/operations.js +137 -24
  179. package/dist/adapters/postgresql/tools/partman/operations.js.map +1 -1
  180. package/dist/adapters/postgresql/tools/performance/analysis.d.ts.map +1 -1
  181. package/dist/adapters/postgresql/tools/performance/analysis.js +276 -165
  182. package/dist/adapters/postgresql/tools/performance/analysis.js.map +1 -1
  183. package/dist/adapters/postgresql/tools/performance/explain.d.ts.map +1 -1
  184. package/dist/adapters/postgresql/tools/performance/explain.js +61 -21
  185. package/dist/adapters/postgresql/tools/performance/explain.js.map +1 -1
  186. package/dist/adapters/postgresql/tools/performance/monitoring.d.ts.map +1 -1
  187. package/dist/adapters/postgresql/tools/performance/monitoring.js +52 -12
  188. package/dist/adapters/postgresql/tools/performance/monitoring.js.map +1 -1
  189. package/dist/adapters/postgresql/tools/performance/optimization.d.ts.map +1 -1
  190. package/dist/adapters/postgresql/tools/performance/optimization.js +92 -81
  191. package/dist/adapters/postgresql/tools/performance/optimization.js.map +1 -1
  192. package/dist/adapters/postgresql/tools/performance/stats.d.ts.map +1 -1
  193. package/dist/adapters/postgresql/tools/performance/stats.js +182 -60
  194. package/dist/adapters/postgresql/tools/performance/stats.js.map +1 -1
  195. package/dist/adapters/postgresql/tools/pgcrypto.d.ts.map +1 -1
  196. package/dist/adapters/postgresql/tools/pgcrypto.js +277 -102
  197. package/dist/adapters/postgresql/tools/pgcrypto.js.map +1 -1
  198. package/dist/adapters/postgresql/tools/postgis/advanced.d.ts.map +1 -1
  199. package/dist/adapters/postgresql/tools/postgis/advanced.js +298 -230
  200. package/dist/adapters/postgresql/tools/postgis/advanced.js.map +1 -1
  201. package/dist/adapters/postgresql/tools/postgis/basic.d.ts.map +1 -1
  202. package/dist/adapters/postgresql/tools/postgis/basic.js +370 -251
  203. package/dist/adapters/postgresql/tools/postgis/basic.js.map +1 -1
  204. package/dist/adapters/postgresql/tools/postgis/standalone.d.ts.map +1 -1
  205. package/dist/adapters/postgresql/tools/postgis/standalone.js +135 -51
  206. package/dist/adapters/postgresql/tools/postgis/standalone.js.map +1 -1
  207. package/dist/adapters/postgresql/tools/schema.d.ts.map +1 -1
  208. package/dist/adapters/postgresql/tools/schema.js +580 -233
  209. package/dist/adapters/postgresql/tools/schema.js.map +1 -1
  210. package/dist/adapters/postgresql/tools/stats/advanced.d.ts.map +1 -1
  211. package/dist/adapters/postgresql/tools/stats/advanced.js +567 -506
  212. package/dist/adapters/postgresql/tools/stats/advanced.js.map +1 -1
  213. package/dist/adapters/postgresql/tools/stats/basic.d.ts.map +1 -1
  214. package/dist/adapters/postgresql/tools/stats/basic.js +340 -316
  215. package/dist/adapters/postgresql/tools/stats/basic.js.map +1 -1
  216. package/dist/adapters/postgresql/tools/text.d.ts.map +1 -1
  217. package/dist/adapters/postgresql/tools/text.js +690 -337
  218. package/dist/adapters/postgresql/tools/text.js.map +1 -1
  219. package/dist/adapters/postgresql/tools/transactions.d.ts.map +1 -1
  220. package/dist/adapters/postgresql/tools/transactions.js +157 -50
  221. package/dist/adapters/postgresql/tools/transactions.js.map +1 -1
  222. package/dist/adapters/postgresql/tools/vector/advanced.d.ts.map +1 -1
  223. package/dist/adapters/postgresql/tools/vector/advanced.js +18 -0
  224. package/dist/adapters/postgresql/tools/vector/advanced.js.map +1 -1
  225. package/dist/adapters/postgresql/tools/vector/basic.d.ts.map +1 -1
  226. package/dist/adapters/postgresql/tools/vector/basic.js +100 -53
  227. package/dist/adapters/postgresql/tools/vector/basic.js.map +1 -1
  228. package/dist/auth/auth-context.d.ts +28 -0
  229. package/dist/auth/auth-context.d.ts.map +1 -0
  230. package/dist/auth/auth-context.js +37 -0
  231. package/dist/auth/auth-context.js.map +1 -0
  232. package/dist/auth/scope-map.d.ts +20 -0
  233. package/dist/auth/scope-map.d.ts.map +1 -0
  234. package/dist/auth/scope-map.js +40 -0
  235. package/dist/auth/scope-map.js.map +1 -0
  236. package/dist/auth/scopes.d.ts.map +1 -1
  237. package/dist/auth/scopes.js +2 -0
  238. package/dist/auth/scopes.js.map +1 -1
  239. package/dist/cli.js +1 -1
  240. package/dist/cli.js.map +1 -1
  241. package/dist/codemode/api.d.ts +1 -0
  242. package/dist/codemode/api.d.ts.map +1 -1
  243. package/dist/codemode/api.js +35 -1
  244. package/dist/codemode/api.js.map +1 -1
  245. package/dist/codemode/index.d.ts +0 -2
  246. package/dist/codemode/index.d.ts.map +1 -1
  247. package/dist/codemode/index.js +0 -4
  248. package/dist/codemode/index.js.map +1 -1
  249. package/dist/codemode/sandbox.d.ts +14 -1
  250. package/dist/codemode/sandbox.d.ts.map +1 -1
  251. package/dist/codemode/sandbox.js +58 -19
  252. package/dist/codemode/sandbox.js.map +1 -1
  253. package/dist/codemode/types.d.ts.map +1 -1
  254. package/dist/codemode/types.js +3 -0
  255. package/dist/codemode/types.js.map +1 -1
  256. package/dist/constants/ServerInstructions.d.ts +5 -1
  257. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  258. package/dist/constants/ServerInstructions.js +117 -31
  259. package/dist/constants/ServerInstructions.js.map +1 -1
  260. package/dist/filtering/ToolConstants.d.ts +22 -19
  261. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  262. package/dist/filtering/ToolConstants.js +48 -37
  263. package/dist/filtering/ToolConstants.js.map +1 -1
  264. package/dist/filtering/ToolFilter.d.ts.map +1 -1
  265. package/dist/filtering/ToolFilter.js +10 -13
  266. package/dist/filtering/ToolFilter.js.map +1 -1
  267. package/dist/pool/ConnectionPool.js +1 -1
  268. package/dist/pool/ConnectionPool.js.map +1 -1
  269. package/dist/transports/http.d.ts +1 -0
  270. package/dist/transports/http.d.ts.map +1 -1
  271. package/dist/transports/http.js +75 -21
  272. package/dist/transports/http.js.map +1 -1
  273. package/dist/types/filtering.d.ts +2 -2
  274. package/dist/types/filtering.d.ts.map +1 -1
  275. package/dist/utils/icons.d.ts.map +1 -1
  276. package/dist/utils/icons.js +5 -0
  277. package/dist/utils/icons.js.map +1 -1
  278. package/dist/utils/where-clause.d.ts.map +1 -1
  279. package/dist/utils/where-clause.js +24 -0
  280. package/dist/utils/where-clause.js.map +1 -1
  281. package/package.json +20 -13
  282. package/dist/codemode/sandbox-factory.d.ts +0 -72
  283. package/dist/codemode/sandbox-factory.d.ts.map +0 -1
  284. package/dist/codemode/sandbox-factory.js +0 -88
  285. package/dist/codemode/sandbox-factory.js.map +0 -1
  286. package/dist/codemode/worker-sandbox.d.ts +0 -82
  287. package/dist/codemode/worker-sandbox.d.ts.map +0 -1
  288. package/dist/codemode/worker-sandbox.js +0 -244
  289. package/dist/codemode/worker-sandbox.js.map +0 -1
  290. package/dist/codemode/worker-script.d.ts +0 -8
  291. package/dist/codemode/worker-script.d.ts.map +0 -1
  292. package/dist/codemode/worker-script.js +0 -113
  293. package/dist/codemode/worker-script.js.map +0 -1
@@ -8,6 +8,7 @@ import { z } from "zod";
8
8
  import { readOnly, write, destructive } from "../../../utils/annotations.js";
9
9
  import { getToolIcons } from "../../../utils/icons.js";
10
10
  import { sanitizeIdentifier } from "../../../utils/identifiers.js";
11
+ import { formatPostgresError } from "./core/error-helpers.js";
11
12
  import { CreateSchemaSchema, DropSchemaSchema, CreateSequenceSchemaBase, CreateSequenceSchema, DropSequenceSchemaBase, DropSequenceSchema, CreateViewSchemaBase, CreateViewSchema, DropViewSchemaBase, DropViewSchema, ListFunctionsSchemaBase, ListFunctionsSchema,
12
13
  // Output schemas
13
14
  ListSchemasOutputSchema, CreateSchemaOutputSchema, DropSchemaOutputSchema, ListSequencesOutputSchema, CreateSequenceOutputSchema, DropSequenceOutputSchema, ListViewsOutputSchema, CreateViewOutputSchema, DropViewOutputSchema, ListFunctionsOutputSchema, ListTriggersOutputSchema, ListConstraintsOutputSchema, } from "../schemas/index.js";
@@ -18,6 +19,7 @@ ListSchemasOutputSchema, CreateSchemaOutputSchema, DropSchemaOutputSchema, ListS
18
19
  */
19
20
  const EXTENSION_ALIASES = {
20
21
  pgvector: "vector",
22
+ vector: "vector",
21
23
  partman: "pg_partman",
22
24
  fuzzymatch: "fuzzystrmatch",
23
25
  fuzzy: "fuzzystrmatch",
@@ -66,25 +68,47 @@ function createCreateSchemaTool(adapter) {
66
68
  annotations: write("Create Schema"),
67
69
  icons: getToolIcons("schema", write("Create Schema")),
68
70
  handler: async (params, _context) => {
69
- const { name, authorization, ifNotExists } = CreateSchemaSchema.parse(params);
70
- // Check if schema already exists when ifNotExists is true
71
- let alreadyExisted;
72
- if (ifNotExists === true) {
73
- const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = '${name}'`);
74
- alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
71
+ try {
72
+ const { name, authorization, ifNotExists } = CreateSchemaSchema.parse(params);
73
+ // Check if schema already exists when ifNotExists is true
74
+ let alreadyExisted;
75
+ if (ifNotExists === true) {
76
+ const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [name]);
77
+ alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
78
+ }
79
+ const ifNotExistsClause = ifNotExists ? "IF NOT EXISTS " : "";
80
+ const schemaName = sanitizeIdentifier(name);
81
+ const authClause = authorization
82
+ ? ` AUTHORIZATION ${sanitizeIdentifier(authorization)}`
83
+ : "";
84
+ const sql = `CREATE SCHEMA ${ifNotExistsClause}${schemaName}${authClause}`;
85
+ try {
86
+ await adapter.executeQuery(sql);
87
+ }
88
+ catch (error) {
89
+ return {
90
+ success: false,
91
+ error: formatPostgresError(error, {
92
+ tool: "pg_create_schema",
93
+ schema: name,
94
+ objectType: "schema",
95
+ }),
96
+ };
97
+ }
98
+ const result = { success: true, schema: name };
99
+ if (alreadyExisted !== undefined) {
100
+ result["alreadyExisted"] = alreadyExisted;
101
+ }
102
+ return result;
75
103
  }
76
- const ifNotExistsClause = ifNotExists ? "IF NOT EXISTS " : "";
77
- const schemaName = sanitizeIdentifier(name);
78
- const authClause = authorization
79
- ? ` AUTHORIZATION ${sanitizeIdentifier(authorization)}`
80
- : "";
81
- const sql = `CREATE SCHEMA ${ifNotExistsClause}${schemaName}${authClause}`;
82
- await adapter.executeQuery(sql);
83
- const result = { success: true, schema: name };
84
- if (alreadyExisted !== undefined) {
85
- result["alreadyExisted"] = alreadyExisted;
104
+ catch (error) {
105
+ return {
106
+ success: false,
107
+ error: error instanceof z.ZodError
108
+ ? error.issues.map((i) => i.message).join("; ")
109
+ : formatPostgresError(error, { tool: "pg_create_schema" }),
110
+ };
86
111
  }
87
- return result;
88
112
  },
89
113
  };
90
114
  }
@@ -98,23 +122,44 @@ function createDropSchemaTool(adapter) {
98
122
  annotations: destructive("Drop Schema"),
99
123
  icons: getToolIcons("schema", destructive("Drop Schema")),
100
124
  handler: async (params, _context) => {
101
- const { name, cascade, ifExists } = DropSchemaSchema.parse(params);
102
- // Check if schema exists before dropping (for accurate response)
103
- const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = '${name}'`);
104
- const existed = (existsResult.rows?.length ?? 0) > 0;
105
- const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
106
- const cascadeClause = cascade === true ? " CASCADE" : "";
107
- const schemaName = sanitizeIdentifier(name);
108
- const sql = `DROP SCHEMA ${ifExistsClause}${schemaName}${cascadeClause}`;
109
- await adapter.executeQuery(sql);
110
- return {
111
- success: true,
112
- schema: name,
113
- existed,
114
- note: existed
115
- ? undefined
116
- : `Schema '${name}' did not exist (ifExists: true)`,
117
- };
125
+ try {
126
+ const { name, cascade, ifExists } = DropSchemaSchema.parse(params);
127
+ // Check if schema exists before dropping (for accurate response)
128
+ const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [name]);
129
+ const existed = (existsResult.rows?.length ?? 0) > 0;
130
+ const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
131
+ const cascadeClause = cascade === true ? " CASCADE" : "";
132
+ const schemaName = sanitizeIdentifier(name);
133
+ const sql = `DROP SCHEMA ${ifExistsClause}${schemaName}${cascadeClause}`;
134
+ try {
135
+ await adapter.executeQuery(sql);
136
+ }
137
+ catch (error) {
138
+ return {
139
+ success: false,
140
+ error: formatPostgresError(error, {
141
+ tool: "pg_drop_schema",
142
+ schema: name,
143
+ }),
144
+ };
145
+ }
146
+ return {
147
+ success: true,
148
+ schema: name,
149
+ existed,
150
+ note: existed
151
+ ? undefined
152
+ : `Schema '${name}' did not exist (ifExists: true)`,
153
+ };
154
+ }
155
+ catch (error) {
156
+ return {
157
+ success: false,
158
+ error: error instanceof z.ZodError
159
+ ? error.issues.map((i) => i.message).join("; ")
160
+ : formatPostgresError(error, { tool: "pg_drop_schema" }),
161
+ };
162
+ }
118
163
  },
119
164
  };
120
165
  }
@@ -126,6 +171,10 @@ function createListSequencesTool(adapter) {
126
171
  inputSchema: z
127
172
  .object({
128
173
  schema: z.string().optional(),
174
+ limit: z
175
+ .number()
176
+ .optional()
177
+ .describe("Maximum number of sequences to return (default: 50). Use 0 for all."),
129
178
  })
130
179
  .default({}),
131
180
  outputSchema: ListSequencesOutputSchema,
@@ -133,9 +182,24 @@ function createListSequencesTool(adapter) {
133
182
  icons: getToolIcons("schema", readOnly("List Sequences")),
134
183
  handler: async (params, _context) => {
135
184
  const parsed = (params ?? {});
185
+ const queryParams = [];
186
+ // Validate schema existence when filtering by schema
187
+ if (parsed.schema) {
188
+ const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
189
+ if ((schemaCheck.rows?.length ?? 0) === 0) {
190
+ return {
191
+ success: false,
192
+ error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
193
+ };
194
+ }
195
+ }
136
196
  const schemaClause = parsed.schema
137
- ? `AND n.nspname = '${parsed.schema}'`
197
+ ? (queryParams.push(parsed.schema),
198
+ `AND n.nspname = $${String(queryParams.length)}`)
138
199
  : "";
200
+ // Default limit: 50, 0 = no limit
201
+ const limitVal = parsed.limit ?? 50;
202
+ const limitClause = limitVal > 0 ? `LIMIT ${String(limitVal + 1)}` : "";
139
203
  // Use subquery for owned_by to avoid duplicate rows from JOINs
140
204
  const sql = `SELECT n.nspname as schema, c.relname as name,
141
205
  (SELECT tc.relname || '.' || a.attname
@@ -149,9 +213,44 @@ function createListSequencesTool(adapter) {
149
213
  WHERE c.relkind = 'S'
150
214
  AND n.nspname NOT IN ('pg_catalog', 'information_schema')
151
215
  ${schemaClause}
152
- ORDER BY n.nspname, c.relname`;
153
- const result = await adapter.executeQuery(sql);
154
- return { sequences: result.rows, count: result.rows?.length ?? 0 };
216
+ ORDER BY n.nspname, c.relname
217
+ ${limitClause}`;
218
+ const result = queryParams.length > 0
219
+ ? await adapter.executeQuery(sql, queryParams)
220
+ : await adapter.executeQuery(sql);
221
+ let sequences = result.rows ?? [];
222
+ // Check if there are more results than the limit
223
+ const hasMore = limitVal > 0 && sequences.length > limitVal;
224
+ if (hasMore) {
225
+ sequences = sequences.slice(0, limitVal);
226
+ }
227
+ const response = {
228
+ sequences,
229
+ count: sequences.length,
230
+ };
231
+ // Always include truncated field for consistent response structure
232
+ response["truncated"] = hasMore;
233
+ if (hasMore) {
234
+ // Get total count
235
+ const countParams = [];
236
+ const countSchemaClause = parsed.schema
237
+ ? (countParams.push(parsed.schema),
238
+ `AND n.nspname = $${String(countParams.length)}`)
239
+ : "";
240
+ const countSql = `SELECT COUNT(*)::int as total FROM pg_class c
241
+ JOIN pg_namespace n ON n.oid = c.relnamespace
242
+ WHERE c.relkind = 'S'
243
+ AND n.nspname NOT IN ('pg_catalog', 'information_schema')
244
+ ${countSchemaClause}`;
245
+ const countResult = countParams.length > 0
246
+ ? await adapter.executeQuery(countSql, countParams)
247
+ : await adapter.executeQuery(countSql);
248
+ response["totalCount"] =
249
+ countResult.rows?.[0]?.["total"] ?? sequences.length;
250
+ response["note"] =
251
+ `Results limited to ${String(limitVal)}. Use 'limit: 0' for all sequences.`;
252
+ }
253
+ return response;
155
254
  },
156
255
  };
157
256
  }
@@ -165,44 +264,78 @@ function createCreateSequenceTool(adapter) {
165
264
  annotations: write("Create Sequence"),
166
265
  icons: getToolIcons("schema", write("Create Sequence")),
167
266
  handler: async (params, _context) => {
168
- const { name, schema, start, increment, minValue, maxValue, cache, cycle, ownedBy, ifNotExists, } = CreateSequenceSchema.parse(params);
169
- const schemaName = schema ?? "public";
170
- // Check if sequence already exists when ifNotExists is true
171
- let alreadyExisted;
172
- if (ifNotExists === true) {
173
- const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'S' AND n.nspname = '${schemaName}' AND c.relname = '${name}'`);
174
- alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
267
+ try {
268
+ const { name, schema, start, increment, minValue, maxValue, cache, cycle, ownedBy, ifNotExists, } = CreateSequenceSchema.parse(params);
269
+ const schemaName = schema ?? "public";
270
+ // Check if sequence already exists when ifNotExists is true
271
+ let alreadyExisted;
272
+ if (ifNotExists === true) {
273
+ const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'S' AND n.nspname = $1 AND c.relname = $2`, [schemaName, name]);
274
+ alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
275
+ }
276
+ const schemaPrefix = schema ? `${sanitizeIdentifier(schema)}.` : "";
277
+ const ifNotExistsClause = ifNotExists === true ? "IF NOT EXISTS " : "";
278
+ const parts = [
279
+ `CREATE SEQUENCE ${ifNotExistsClause}${schemaPrefix}${sanitizeIdentifier(name)}`,
280
+ ];
281
+ if (start !== undefined)
282
+ parts.push(`START WITH ${String(start)}`);
283
+ if (increment !== undefined)
284
+ parts.push(`INCREMENT BY ${String(increment)}`);
285
+ if (minValue !== undefined)
286
+ parts.push(`MINVALUE ${String(minValue)}`);
287
+ if (maxValue !== undefined)
288
+ parts.push(`MAXVALUE ${String(maxValue)}`);
289
+ if (cache !== undefined)
290
+ parts.push(`CACHE ${String(cache)}`);
291
+ if (cycle)
292
+ parts.push("CYCLE");
293
+ if (ownedBy !== undefined) {
294
+ // Validate and sanitize ownedBy: table.column or schema.table.column
295
+ const ownedByParts = ownedBy.split(".");
296
+ if (ownedByParts.length < 2 || ownedByParts.length > 3) {
297
+ return {
298
+ success: false,
299
+ error: `Invalid ownedBy format: '${ownedBy}'. Expected 'table.column' or 'schema.table.column'.`,
300
+ };
301
+ }
302
+ const sanitizedOwnedBy = ownedByParts
303
+ .map((p) => sanitizeIdentifier(p))
304
+ .join(".");
305
+ parts.push(`OWNED BY ${sanitizedOwnedBy}`);
306
+ }
307
+ const sql = parts.join(" ");
308
+ try {
309
+ await adapter.executeQuery(sql);
310
+ }
311
+ catch (error) {
312
+ return {
313
+ success: false,
314
+ error: formatPostgresError(error, {
315
+ tool: "pg_create_sequence",
316
+ objectType: "sequence",
317
+ ...(schema !== undefined && { schema }),
318
+ }),
319
+ };
320
+ }
321
+ const result = {
322
+ success: true,
323
+ sequence: `${schemaName}.${name}`,
324
+ ifNotExists: ifNotExists ?? false,
325
+ };
326
+ if (alreadyExisted !== undefined) {
327
+ result["alreadyExisted"] = alreadyExisted;
328
+ }
329
+ return result;
175
330
  }
176
- const schemaPrefix = schema ? `${sanitizeIdentifier(schema)}.` : "";
177
- const ifNotExistsClause = ifNotExists === true ? "IF NOT EXISTS " : "";
178
- const parts = [
179
- `CREATE SEQUENCE ${ifNotExistsClause}${schemaPrefix}${sanitizeIdentifier(name)}`,
180
- ];
181
- if (start !== undefined)
182
- parts.push(`START WITH ${String(start)}`);
183
- if (increment !== undefined)
184
- parts.push(`INCREMENT BY ${String(increment)}`);
185
- if (minValue !== undefined)
186
- parts.push(`MINVALUE ${String(minValue)}`);
187
- if (maxValue !== undefined)
188
- parts.push(`MAXVALUE ${String(maxValue)}`);
189
- if (cache !== undefined)
190
- parts.push(`CACHE ${String(cache)}`);
191
- if (cycle)
192
- parts.push("CYCLE");
193
- if (ownedBy !== undefined)
194
- parts.push(`OWNED BY ${ownedBy}`);
195
- const sql = parts.join(" ");
196
- await adapter.executeQuery(sql);
197
- const result = {
198
- success: true,
199
- sequence: `${schemaName}.${name}`,
200
- ifNotExists: ifNotExists ?? false,
201
- };
202
- if (alreadyExisted !== undefined) {
203
- result["alreadyExisted"] = alreadyExisted;
331
+ catch (error) {
332
+ return {
333
+ success: false,
334
+ error: error instanceof z.ZodError
335
+ ? error.issues.map((i) => i.message).join("; ")
336
+ : formatPostgresError(error, { tool: "pg_create_sequence" }),
337
+ };
204
338
  }
205
- return result;
206
339
  },
207
340
  };
208
341
  }
@@ -217,16 +350,37 @@ function createDropSequenceTool(adapter) {
217
350
  annotations: destructive("Drop Sequence"),
218
351
  icons: getToolIcons("schema", destructive("Drop Sequence")),
219
352
  handler: async (params, _context) => {
220
- const { name, schema, ifExists, cascade } = DropSequenceSchema.parse(params);
221
- const schemaName = schema ?? "public";
222
- // Check if sequence exists before dropping (for accurate response)
223
- const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'S' AND n.nspname = '${schemaName}' AND c.relname = '${name}'`);
224
- const existed = (existsResult.rows?.length ?? 0) > 0;
225
- const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
226
- const cascadeClause = cascade === true ? " CASCADE" : "";
227
- const sql = `DROP SEQUENCE ${ifExistsClause}"${schemaName}"."${name}"${cascadeClause}`;
228
- await adapter.executeQuery(sql);
229
- return { success: true, sequence: `${schemaName}.${name}`, existed };
353
+ try {
354
+ const { name, schema, ifExists, cascade } = DropSequenceSchema.parse(params);
355
+ const schemaName = schema ?? "public";
356
+ // Check if sequence exists before dropping (for accurate response)
357
+ const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'S' AND n.nspname = $1 AND c.relname = $2`, [schemaName, name]);
358
+ const existed = (existsResult.rows?.length ?? 0) > 0;
359
+ const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
360
+ const cascadeClause = cascade === true ? " CASCADE" : "";
361
+ const sql = `DROP SEQUENCE ${ifExistsClause}"${schemaName}"."${name}"${cascadeClause}`;
362
+ try {
363
+ await adapter.executeQuery(sql);
364
+ }
365
+ catch (error) {
366
+ return {
367
+ success: false,
368
+ error: formatPostgresError(error, {
369
+ tool: "pg_drop_sequence",
370
+ ...(schema !== undefined && { schema }),
371
+ }),
372
+ };
373
+ }
374
+ return { success: true, sequence: `${schemaName}.${name}`, existed };
375
+ }
376
+ catch (error) {
377
+ return {
378
+ success: false,
379
+ error: error instanceof z.ZodError
380
+ ? error.issues.map((i) => i.message).join("; ")
381
+ : formatPostgresError(error, { tool: "pg_drop_sequence" }),
382
+ };
383
+ }
230
384
  },
231
385
  };
232
386
  }
@@ -252,8 +406,20 @@ function createListViewsTool(adapter) {
252
406
  icons: getToolIcons("schema", readOnly("List Views")),
253
407
  handler: async (params, _context) => {
254
408
  const parsed = (params ?? {});
409
+ const queryParams = [];
410
+ // Validate schema existence when filtering by schema
411
+ if (parsed.schema) {
412
+ const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
413
+ if ((schemaCheck.rows?.length ?? 0) === 0) {
414
+ return {
415
+ success: false,
416
+ error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
417
+ };
418
+ }
419
+ }
255
420
  const schemaClause = parsed.schema
256
- ? `AND n.nspname = '${parsed.schema}'`
421
+ ? (queryParams.push(parsed.schema),
422
+ `AND n.nspname = $${String(queryParams.length)}`)
257
423
  : "";
258
424
  const kindClause = parsed.includeMaterialized !== false ? "IN ('v', 'm')" : "= 'v'";
259
425
  // Default truncation: 500 chars, 0 = no truncation
@@ -271,7 +437,9 @@ function createListViewsTool(adapter) {
271
437
  ${schemaClause}
272
438
  ORDER BY n.nspname, c.relname
273
439
  ${limitClause}`;
274
- const result = await adapter.executeQuery(sql);
440
+ const result = queryParams.length > 0
441
+ ? await adapter.executeQuery(sql, queryParams)
442
+ : await adapter.executeQuery(sql);
275
443
  let views = result.rows ?? [];
276
444
  // Check if there are more results than the limit
277
445
  const hasMore = limitVal > 0 && views.length > limitVal;
@@ -306,6 +474,22 @@ function createListViewsTool(adapter) {
306
474
  // Always include truncated field for consistent response structure
307
475
  response["truncated"] = hasMore;
308
476
  if (hasMore) {
477
+ // Get total count
478
+ const countParams = [];
479
+ const countSchemaClause = parsed.schema
480
+ ? (countParams.push(parsed.schema),
481
+ `AND n.nspname = $${String(countParams.length)}`)
482
+ : "";
483
+ const countSql = `SELECT COUNT(*)::int as total FROM pg_class c
484
+ JOIN pg_namespace n ON n.oid = c.relnamespace
485
+ WHERE c.relkind ${kindClause}
486
+ AND n.nspname NOT IN ('pg_catalog', 'information_schema')
487
+ ${countSchemaClause}`;
488
+ const countResult = countParams.length > 0
489
+ ? await adapter.executeQuery(countSql, countParams)
490
+ : await adapter.executeQuery(countSql);
491
+ response["totalCount"] =
492
+ countResult.rows?.[0]?.["total"] ?? views.length;
309
493
  response["note"] =
310
494
  `Results limited to ${String(limitVal)}. Use 'limit: 0' for all views.`;
311
495
  }
@@ -323,35 +507,57 @@ function createCreateViewTool(adapter) {
323
507
  annotations: write("Create View"),
324
508
  icons: getToolIcons("schema", write("Create View")),
325
509
  handler: async (params, _context) => {
326
- const { name, schema, query, materialized, orReplace, checkOption } = CreateViewSchema.parse(params);
327
- const schemaName = schema ?? "public";
328
- // Check if view already exists when orReplace is true (for informational response)
329
- let alreadyExisted;
330
- if (orReplace === true) {
331
- const relkind = materialized === true ? "'m'" : "'v'";
332
- const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = ${relkind} AND n.nspname = '${schemaName}' AND c.relname = '${name}'`);
333
- alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
334
- }
335
- const schemaPrefix = schema ? `${sanitizeIdentifier(schema)}.` : "";
336
- const replaceClause = orReplace && !materialized ? "OR REPLACE " : "";
337
- const matClause = materialized ? "MATERIALIZED " : "";
338
- const viewName = sanitizeIdentifier(name);
339
- // WITH CHECK OPTION clause (not available for materialized views)
340
- let checkClause = "";
341
- if (checkOption && checkOption !== "none" && !materialized) {
342
- checkClause = ` WITH ${checkOption.toUpperCase()} CHECK OPTION`;
510
+ try {
511
+ const { name, schema, query, materialized, orReplace, checkOption } = CreateViewSchema.parse(params);
512
+ const schemaName = schema ?? "public";
513
+ // Check if view already exists when orReplace is true (for informational response)
514
+ let alreadyExisted;
515
+ if (orReplace === true) {
516
+ const relkind = materialized === true ? "m" : "v";
517
+ const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = $1 AND n.nspname = $2 AND c.relname = $3`, [relkind, schemaName, name]);
518
+ alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
519
+ }
520
+ const schemaPrefix = schema ? `${sanitizeIdentifier(schema)}.` : "";
521
+ const replaceClause = orReplace && !materialized ? "OR REPLACE " : "";
522
+ const matClause = materialized ? "MATERIALIZED " : "";
523
+ const viewName = sanitizeIdentifier(name);
524
+ // WITH CHECK OPTION clause (not available for materialized views)
525
+ let checkClause = "";
526
+ if (checkOption && checkOption !== "none" && !materialized) {
527
+ checkClause = ` WITH ${checkOption.toUpperCase()} CHECK OPTION`;
528
+ }
529
+ const sql = `CREATE ${replaceClause}${matClause}VIEW ${schemaPrefix}${viewName} AS ${query}${checkClause}`;
530
+ try {
531
+ await adapter.executeQuery(sql);
532
+ }
533
+ catch (error) {
534
+ return {
535
+ success: false,
536
+ error: formatPostgresError(error, {
537
+ tool: "pg_create_view",
538
+ objectType: "view",
539
+ ...(schema !== undefined && { schema }),
540
+ }),
541
+ };
542
+ }
543
+ const result = {
544
+ success: true,
545
+ view: `${schemaName}.${name}`,
546
+ materialized: !!materialized,
547
+ };
548
+ if (alreadyExisted !== undefined) {
549
+ result["alreadyExisted"] = alreadyExisted;
550
+ }
551
+ return result;
343
552
  }
344
- const sql = `CREATE ${replaceClause}${matClause}VIEW ${schemaPrefix}${viewName} AS ${query}${checkClause}`;
345
- await adapter.executeQuery(sql);
346
- const result = {
347
- success: true,
348
- view: `${schemaName}.${name}`,
349
- materialized: !!materialized,
350
- };
351
- if (alreadyExisted !== undefined) {
352
- result["alreadyExisted"] = alreadyExisted;
553
+ catch (error) {
554
+ return {
555
+ success: false,
556
+ error: error instanceof z.ZodError
557
+ ? error.issues.map((i) => i.message).join("; ")
558
+ : formatPostgresError(error, { tool: "pg_create_view" }),
559
+ };
353
560
  }
354
- return result;
355
561
  },
356
562
  };
357
563
  }
@@ -366,23 +572,44 @@ function createDropViewTool(adapter) {
366
572
  annotations: destructive("Drop View"),
367
573
  icons: getToolIcons("schema", destructive("Drop View")),
368
574
  handler: async (params, _context) => {
369
- const { name, schema, materialized, ifExists, cascade } = DropViewSchema.parse(params);
370
- const schemaName = schema ?? "public";
371
- // Check if view exists before dropping (for accurate response)
372
- const relkind = materialized === true ? "'m'" : "'v'";
373
- const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = ${relkind} AND n.nspname = '${schemaName}' AND c.relname = '${name}'`);
374
- const existed = (existsResult.rows?.length ?? 0) > 0;
375
- const matClause = materialized === true ? "MATERIALIZED " : "";
376
- const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
377
- const cascadeClause = cascade === true ? " CASCADE" : "";
378
- const sql = `DROP ${matClause}VIEW ${ifExistsClause}"${schemaName}"."${name}"${cascadeClause}`;
379
- await adapter.executeQuery(sql);
380
- return {
381
- success: true,
382
- view: `${schemaName}.${name}`,
383
- materialized: materialized ?? false,
384
- existed,
385
- };
575
+ try {
576
+ const { name, schema, materialized, ifExists, cascade } = DropViewSchema.parse(params);
577
+ const schemaName = schema ?? "public";
578
+ // Check if view exists before dropping (for accurate response)
579
+ const relkind = materialized === true ? "m" : "v";
580
+ const existsResult = await adapter.executeQuery(`SELECT 1 FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = $1 AND n.nspname = $2 AND c.relname = $3`, [relkind, schemaName, name]);
581
+ const existed = (existsResult.rows?.length ?? 0) > 0;
582
+ const matClause = materialized === true ? "MATERIALIZED " : "";
583
+ const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
584
+ const cascadeClause = cascade === true ? " CASCADE" : "";
585
+ const sql = `DROP ${matClause}VIEW ${ifExistsClause}"${schemaName}"."${name}"${cascadeClause}`;
586
+ try {
587
+ await adapter.executeQuery(sql);
588
+ }
589
+ catch (error) {
590
+ return {
591
+ success: false,
592
+ error: formatPostgresError(error, {
593
+ tool: "pg_drop_view",
594
+ ...(schema !== undefined && { schema }),
595
+ }),
596
+ };
597
+ }
598
+ return {
599
+ success: true,
600
+ view: `${schemaName}.${name}`,
601
+ materialized: materialized ?? false,
602
+ existed,
603
+ };
604
+ }
605
+ catch (error) {
606
+ return {
607
+ success: false,
608
+ error: error instanceof z.ZodError
609
+ ? error.issues.map((i) => i.message).join("; ")
610
+ : formatPostgresError(error, { tool: "pg_drop_view" }),
611
+ };
612
+ }
386
613
  },
387
614
  };
388
615
  }
@@ -397,56 +624,85 @@ function createListFunctionsTool(adapter) {
397
624
  annotations: readOnly("List Functions"),
398
625
  icons: getToolIcons("schema", readOnly("List Functions")),
399
626
  handler: async (params, _context) => {
400
- // Use full schema with preprocessing for validation
401
- const parsed = ListFunctionsSchema.parse(params);
402
- const conditions = [
403
- "n.nspname NOT IN ('pg_catalog', 'information_schema')",
404
- ];
405
- if (parsed.schema !== undefined) {
406
- conditions.push(`n.nspname = '${parsed.schema}'`);
407
- }
408
- if (parsed.exclude !== undefined && parsed.exclude.length > 0) {
409
- // Expand well-known aliases (e.g. "pgvector" -> ["pgvector", "vector"])
410
- const normalizedExclude = parsed.exclude.flatMap((s) => {
411
- const alias = EXTENSION_ALIASES[s];
412
- return alias ? [s, alias] : [s];
413
- });
414
- const excludeList = normalizedExclude.map((s) => `'${s}'`).join(", ");
415
- // Exclude by schema name
416
- conditions.push(`n.nspname NOT IN (${excludeList})`);
417
- // Also exclude extension-owned functions (e.g., ltree functions in public schema)
418
- conditions.push(`NOT EXISTS (
419
- SELECT 1 FROM pg_depend d
420
- JOIN pg_extension e ON d.refobjid = e.oid
421
- WHERE d.objid = p.oid
422
- AND d.deptype = 'e'
423
- AND e.extname IN (${excludeList})
424
- )`);
627
+ try {
628
+ // Use full schema with preprocessing for validation
629
+ const parsed = ListFunctionsSchema.parse(params);
630
+ const queryParams = [];
631
+ // Validate schema existence when filtering by schema
632
+ if (parsed.schema !== undefined) {
633
+ const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
634
+ if ((schemaCheck.rows?.length ?? 0) === 0) {
635
+ return {
636
+ success: false,
637
+ error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
638
+ };
639
+ }
640
+ }
641
+ const conditions = [
642
+ "n.nspname NOT IN ('pg_catalog', 'information_schema')",
643
+ ];
644
+ if (parsed.schema !== undefined) {
645
+ queryParams.push(parsed.schema);
646
+ conditions.push(`n.nspname = $${String(queryParams.length)}`);
647
+ }
648
+ if (parsed.exclude !== undefined && parsed.exclude.length > 0) {
649
+ // Expand well-known aliases (e.g. "pgvector" -> ["pgvector", "vector"])
650
+ const normalizedExclude = parsed.exclude.flatMap((s) => {
651
+ const alias = EXTENSION_ALIASES[s];
652
+ return alias ? [s, alias] : [s];
653
+ });
654
+ const excludePlaceholders = normalizedExclude.map((s) => {
655
+ queryParams.push(s);
656
+ return `$${String(queryParams.length)}`;
657
+ });
658
+ const excludeList = excludePlaceholders.join(", ");
659
+ // Exclude by schema name
660
+ conditions.push(`n.nspname NOT IN (${excludeList})`);
661
+ // Also exclude extension-owned functions (e.g., ltree functions in public schema)
662
+ conditions.push(`NOT EXISTS (
663
+ SELECT 1 FROM pg_depend d
664
+ JOIN pg_extension e ON d.refobjid = e.oid
665
+ WHERE d.objid = p.oid
666
+ AND d.deptype = 'e'
667
+ AND e.extname IN (${excludeList})
668
+ )`);
669
+ }
670
+ if (parsed.language !== undefined) {
671
+ queryParams.push(parsed.language);
672
+ conditions.push(`l.lanname = $${String(queryParams.length)}`);
673
+ }
674
+ const limitVal = parsed.limit ?? 500;
675
+ const sql = `SELECT n.nspname as schema, p.proname as name,
676
+ pg_get_function_arguments(p.oid) as arguments,
677
+ pg_get_function_result(p.oid) as returns,
678
+ l.lanname as language,
679
+ p.provolatile as volatility
680
+ FROM pg_proc p
681
+ JOIN pg_namespace n ON n.oid = p.pronamespace
682
+ JOIN pg_language l ON l.oid = p.prolang
683
+ WHERE ${conditions.join(" AND ")}
684
+ ORDER BY n.nspname, p.proname
685
+ LIMIT ${String(limitVal)}`;
686
+ const result = queryParams.length > 0
687
+ ? await adapter.executeQuery(sql, queryParams)
688
+ : await adapter.executeQuery(sql);
689
+ return {
690
+ functions: result.rows,
691
+ count: result.rows?.length ?? 0,
692
+ limit: limitVal,
693
+ note: (result.rows?.length ?? 0) >= limitVal
694
+ ? `Results limited to ${String(limitVal)}. Use 'limit' param for more, or 'exclude' to filter out extension schemas.`
695
+ : undefined,
696
+ };
425
697
  }
426
- if (parsed.language !== undefined) {
427
- conditions.push(`l.lanname = '${parsed.language}'`);
698
+ catch (error) {
699
+ return {
700
+ success: false,
701
+ error: error instanceof z.ZodError
702
+ ? error.issues.map((i) => i.message).join("; ")
703
+ : formatPostgresError(error, { tool: "pg_list_functions" }),
704
+ };
428
705
  }
429
- const limitVal = parsed.limit ?? 500;
430
- const sql = `SELECT n.nspname as schema, p.proname as name,
431
- pg_get_function_arguments(p.oid) as arguments,
432
- pg_get_function_result(p.oid) as returns,
433
- l.lanname as language,
434
- p.provolatile as volatility
435
- FROM pg_proc p
436
- JOIN pg_namespace n ON n.oid = p.pronamespace
437
- JOIN pg_language l ON l.oid = p.prolang
438
- WHERE ${conditions.join(" AND ")}
439
- ORDER BY n.nspname, p.proname
440
- LIMIT ${String(limitVal)}`;
441
- const result = await adapter.executeQuery(sql);
442
- return {
443
- functions: result.rows,
444
- count: result.rows?.length ?? 0,
445
- limit: limitVal,
446
- note: (result.rows?.length ?? 0) >= limitVal
447
- ? `Results limited to ${String(limitVal)}. Use 'limit' param for more, or 'exclude' to filter out extension schemas.`
448
- : undefined,
449
- };
450
706
  },
451
707
  };
452
708
  }
@@ -463,31 +719,77 @@ function createListTriggersTool(adapter) {
463
719
  annotations: readOnly("List Triggers"),
464
720
  icons: getToolIcons("schema", readOnly("List Triggers")),
465
721
  handler: async (params, _context) => {
466
- const parsed = (params ?? {});
467
- let whereClause = "n.nspname NOT IN ('pg_catalog', 'information_schema')";
468
- if (parsed.schema)
469
- whereClause += ` AND n.nspname = '${parsed.schema}'`;
470
- if (parsed.table)
471
- whereClause += ` AND c.relname = '${parsed.table}'`;
472
- const sql = `SELECT n.nspname as schema, c.relname as table_name, t.tgname as name,
473
- CASE t.tgtype::int & 2 WHEN 2 THEN 'BEFORE' ELSE 'AFTER' END as timing,
474
- array_remove(ARRAY[
475
- CASE WHEN t.tgtype::int & 4 = 4 THEN 'INSERT' END,
476
- CASE WHEN t.tgtype::int & 8 = 8 THEN 'DELETE' END,
477
- CASE WHEN t.tgtype::int & 16 = 16 THEN 'UPDATE' END,
478
- CASE WHEN t.tgtype::int & 32 = 32 THEN 'TRUNCATE' END
479
- ], NULL) as events,
480
- p.proname as function_name,
481
- t.tgenabled != 'D' as enabled
482
- FROM pg_trigger t
483
- JOIN pg_class c ON c.oid = t.tgrelid
484
- JOIN pg_namespace n ON n.oid = c.relnamespace
485
- JOIN pg_proc p ON p.oid = t.tgfoid
486
- WHERE NOT t.tgisinternal
487
- AND ${whereClause}
488
- ORDER BY n.nspname, c.relname, t.tgname`;
489
- const result = await adapter.executeQuery(sql);
490
- return { triggers: result.rows, count: result.rows?.length ?? 0 };
722
+ try {
723
+ const parsed = (params ?? {});
724
+ // Parse schema.table format
725
+ if (typeof parsed.table === "string" &&
726
+ parsed.table.includes(".") &&
727
+ !parsed.schema) {
728
+ const parts = parsed.table.split(".");
729
+ if (parts.length === 2 && parts[0] && parts[1]) {
730
+ parsed.schema = parts[0];
731
+ parsed.table = parts[1];
732
+ }
733
+ }
734
+ const schemaName = parsed.schema ?? "public";
735
+ // Validate schema existence when filtering by schema
736
+ if (parsed.schema) {
737
+ const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
738
+ if ((schemaCheck.rows?.length ?? 0) === 0) {
739
+ return {
740
+ success: false,
741
+ error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
742
+ };
743
+ }
744
+ }
745
+ // Validate table existence when filtering by table
746
+ if (parsed.table) {
747
+ const tableCheck = await adapter.executeQuery(`SELECT 1 FROM information_schema.tables WHERE table_schema = $1 AND table_name = $2`, [schemaName, parsed.table]);
748
+ if ((tableCheck.rows?.length ?? 0) === 0) {
749
+ return {
750
+ success: false,
751
+ error: `Table '${schemaName}.${parsed.table}' not found. Use pg_list_tables to see available tables.`,
752
+ };
753
+ }
754
+ }
755
+ const queryParams = [];
756
+ let whereClause = "n.nspname NOT IN ('pg_catalog', 'information_schema')";
757
+ if (parsed.schema) {
758
+ queryParams.push(parsed.schema);
759
+ whereClause += ` AND n.nspname = $${String(queryParams.length)}`;
760
+ }
761
+ if (parsed.table) {
762
+ queryParams.push(parsed.table);
763
+ whereClause += ` AND c.relname = $${String(queryParams.length)}`;
764
+ }
765
+ const sql = `SELECT n.nspname as schema, c.relname as table_name, t.tgname as name,
766
+ CASE t.tgtype::int & 2 WHEN 2 THEN 'BEFORE' ELSE 'AFTER' END as timing,
767
+ array_remove(ARRAY[
768
+ CASE WHEN t.tgtype::int & 4 = 4 THEN 'INSERT' END,
769
+ CASE WHEN t.tgtype::int & 8 = 8 THEN 'DELETE' END,
770
+ CASE WHEN t.tgtype::int & 16 = 16 THEN 'UPDATE' END,
771
+ CASE WHEN t.tgtype::int & 32 = 32 THEN 'TRUNCATE' END
772
+ ], NULL) as events,
773
+ p.proname as function_name,
774
+ t.tgenabled != 'D' as enabled
775
+ FROM pg_trigger t
776
+ JOIN pg_class c ON c.oid = t.tgrelid
777
+ JOIN pg_namespace n ON n.oid = c.relnamespace
778
+ JOIN pg_proc p ON p.oid = t.tgfoid
779
+ WHERE NOT t.tgisinternal
780
+ AND ${whereClause}
781
+ ORDER BY n.nspname, c.relname, t.tgname`;
782
+ const result = queryParams.length > 0
783
+ ? await adapter.executeQuery(sql, queryParams)
784
+ : await adapter.executeQuery(sql);
785
+ return { triggers: result.rows, count: result.rows?.length ?? 0 };
786
+ }
787
+ catch (error) {
788
+ return {
789
+ success: false,
790
+ error: formatPostgresError(error, { tool: "pg_list_triggers" }),
791
+ };
792
+ }
491
793
  },
492
794
  };
493
795
  }
@@ -507,38 +809,83 @@ function createListConstraintsTool(adapter) {
507
809
  annotations: readOnly("List Constraints"),
508
810
  icons: getToolIcons("schema", readOnly("List Constraints")),
509
811
  handler: async (params, _context) => {
510
- const parsed = (params ?? {});
511
- let whereClause = "n.nspname NOT IN ('pg_catalog', 'information_schema') AND con.contype != 'n'";
512
- if (parsed.schema)
513
- whereClause += ` AND n.nspname = '${parsed.schema}'`;
514
- if (parsed.table)
515
- whereClause += ` AND c.relname = '${parsed.table}'`;
516
- if (parsed.type) {
517
- const typeMap = {
518
- primary_key: "p",
519
- foreign_key: "f",
520
- unique: "u",
521
- check: "c",
812
+ try {
813
+ const parsed = (params ?? {});
814
+ // Parse schema.table format
815
+ if (typeof parsed.table === "string" &&
816
+ parsed.table.includes(".") &&
817
+ !parsed.schema) {
818
+ const parts = parsed.table.split(".");
819
+ if (parts.length === 2 && parts[0] && parts[1]) {
820
+ parsed.schema = parts[0];
821
+ parsed.table = parts[1];
822
+ }
823
+ }
824
+ const schemaName = parsed.schema ?? "public";
825
+ // Validate schema existence when filtering by schema
826
+ if (parsed.schema) {
827
+ const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
828
+ if ((schemaCheck.rows?.length ?? 0) === 0) {
829
+ return {
830
+ success: false,
831
+ error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
832
+ };
833
+ }
834
+ }
835
+ // Validate table existence when filtering by table
836
+ if (parsed.table) {
837
+ const tableCheck = await adapter.executeQuery(`SELECT 1 FROM information_schema.tables WHERE table_schema = $1 AND table_name = $2`, [schemaName, parsed.table]);
838
+ if ((tableCheck.rows?.length ?? 0) === 0) {
839
+ return {
840
+ success: false,
841
+ error: `Table '${schemaName}.${parsed.table}' not found. Use pg_list_tables to see available tables.`,
842
+ };
843
+ }
844
+ }
845
+ const queryParams = [];
846
+ let whereClause = "n.nspname NOT IN ('pg_catalog', 'information_schema') AND con.contype != 'n'";
847
+ if (parsed.schema) {
848
+ queryParams.push(parsed.schema);
849
+ whereClause += ` AND n.nspname = $${String(queryParams.length)}`;
850
+ }
851
+ if (parsed.table) {
852
+ queryParams.push(parsed.table);
853
+ whereClause += ` AND c.relname = $${String(queryParams.length)}`;
854
+ }
855
+ if (parsed.type) {
856
+ const typeMap = {
857
+ primary_key: "p",
858
+ foreign_key: "f",
859
+ unique: "u",
860
+ check: "c",
861
+ };
862
+ queryParams.push(typeMap[parsed.type] ?? "");
863
+ whereClause += ` AND con.contype = $${String(queryParams.length)}`;
864
+ }
865
+ const sql = `SELECT n.nspname as schema, c.relname as table_name, con.conname as name,
866
+ CASE con.contype
867
+ WHEN 'p' THEN 'primary_key'
868
+ WHEN 'f' THEN 'foreign_key'
869
+ WHEN 'u' THEN 'unique'
870
+ WHEN 'c' THEN 'check'
871
+ END as type,
872
+ pg_get_constraintdef(con.oid) as definition
873
+ FROM pg_constraint con
874
+ JOIN pg_class c ON c.oid = con.conrelid
875
+ JOIN pg_namespace n ON n.oid = c.relnamespace
876
+ WHERE ${whereClause}
877
+ ORDER BY n.nspname, c.relname, con.conname`;
878
+ const result = queryParams.length > 0
879
+ ? await adapter.executeQuery(sql, queryParams)
880
+ : await adapter.executeQuery(sql);
881
+ return { constraints: result.rows, count: result.rows?.length ?? 0 };
882
+ }
883
+ catch (error) {
884
+ return {
885
+ success: false,
886
+ error: formatPostgresError(error, { tool: "pg_list_constraints" }),
522
887
  };
523
- whereClause += ` AND con.contype = '${typeMap[parsed.type] ?? ""}'`;
524
888
  }
525
- const sql = `SELECT n.nspname as schema, c.relname as table_name, con.conname as name,
526
- CASE con.contype
527
- WHEN 'p' THEN 'primary_key'
528
- WHEN 'f' THEN 'foreign_key'
529
- WHEN 'u' THEN 'unique'
530
- WHEN 'c' THEN 'check'
531
- WHEN 'n' THEN 'not_null'
532
- ELSE con.contype
533
- END as type,
534
- pg_get_constraintdef(con.oid) as definition
535
- FROM pg_constraint con
536
- JOIN pg_class c ON c.oid = con.conrelid
537
- JOIN pg_namespace n ON n.oid = c.relnamespace
538
- WHERE ${whereClause}
539
- ORDER BY n.nspname, c.relname, con.conname`;
540
- const result = await adapter.executeQuery(sql);
541
- return { constraints: result.rows, count: result.rows?.length ?? 0 };
542
889
  },
543
890
  };
544
891
  }