@neverinfamous/postgres-mcp 1.3.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 (226) hide show
  1. package/README.md +177 -129
  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 +3 -0
  43. package/dist/adapters/postgresql/PostgresAdapter.js.map +1 -1
  44. package/dist/adapters/postgresql/schemas/backup.d.ts +37 -23
  45. package/dist/adapters/postgresql/schemas/backup.d.ts.map +1 -1
  46. package/dist/adapters/postgresql/schemas/backup.js +53 -22
  47. package/dist/adapters/postgresql/schemas/backup.js.map +1 -1
  48. package/dist/adapters/postgresql/schemas/extensions.d.ts +56 -37
  49. package/dist/adapters/postgresql/schemas/extensions.d.ts.map +1 -1
  50. package/dist/adapters/postgresql/schemas/extensions.js +68 -36
  51. package/dist/adapters/postgresql/schemas/extensions.js.map +1 -1
  52. package/dist/adapters/postgresql/schemas/index.d.ts +3 -2
  53. package/dist/adapters/postgresql/schemas/index.d.ts.map +1 -1
  54. package/dist/adapters/postgresql/schemas/index.js +8 -2
  55. package/dist/adapters/postgresql/schemas/index.js.map +1 -1
  56. package/dist/adapters/postgresql/schemas/introspection.d.ts +445 -0
  57. package/dist/adapters/postgresql/schemas/introspection.d.ts.map +1 -0
  58. package/dist/adapters/postgresql/schemas/introspection.js +478 -0
  59. package/dist/adapters/postgresql/schemas/introspection.js.map +1 -0
  60. package/dist/adapters/postgresql/schemas/jsonb.d.ts +8 -0
  61. package/dist/adapters/postgresql/schemas/jsonb.d.ts.map +1 -1
  62. package/dist/adapters/postgresql/schemas/jsonb.js +26 -2
  63. package/dist/adapters/postgresql/schemas/jsonb.js.map +1 -1
  64. package/dist/adapters/postgresql/schemas/monitoring.d.ts +41 -25
  65. package/dist/adapters/postgresql/schemas/monitoring.d.ts.map +1 -1
  66. package/dist/adapters/postgresql/schemas/monitoring.js +49 -16
  67. package/dist/adapters/postgresql/schemas/monitoring.js.map +1 -1
  68. package/dist/adapters/postgresql/schemas/partitioning.d.ts +16 -20
  69. package/dist/adapters/postgresql/schemas/partitioning.d.ts.map +1 -1
  70. package/dist/adapters/postgresql/schemas/partitioning.js +21 -10
  71. package/dist/adapters/postgresql/schemas/partitioning.js.map +1 -1
  72. package/dist/adapters/postgresql/schemas/partman.d.ts +69 -0
  73. package/dist/adapters/postgresql/schemas/partman.d.ts.map +1 -1
  74. package/dist/adapters/postgresql/schemas/partman.js +46 -33
  75. package/dist/adapters/postgresql/schemas/partman.js.map +1 -1
  76. package/dist/adapters/postgresql/schemas/performance.d.ts +37 -19
  77. package/dist/adapters/postgresql/schemas/performance.d.ts.map +1 -1
  78. package/dist/adapters/postgresql/schemas/performance.js +54 -12
  79. package/dist/adapters/postgresql/schemas/performance.js.map +1 -1
  80. package/dist/adapters/postgresql/schemas/postgis.d.ts.map +1 -1
  81. package/dist/adapters/postgresql/schemas/postgis.js +20 -0
  82. package/dist/adapters/postgresql/schemas/postgis.js.map +1 -1
  83. package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts +15 -7
  84. package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts.map +1 -1
  85. package/dist/adapters/postgresql/schemas/schema-mgmt.js +36 -7
  86. package/dist/adapters/postgresql/schemas/schema-mgmt.js.map +1 -1
  87. package/dist/adapters/postgresql/schemas/text-search.d.ts +26 -14
  88. package/dist/adapters/postgresql/schemas/text-search.d.ts.map +1 -1
  89. package/dist/adapters/postgresql/schemas/text-search.js +41 -9
  90. package/dist/adapters/postgresql/schemas/text-search.js.map +1 -1
  91. package/dist/adapters/postgresql/tools/admin.d.ts.map +1 -1
  92. package/dist/adapters/postgresql/tools/admin.js +82 -67
  93. package/dist/adapters/postgresql/tools/admin.js.map +1 -1
  94. package/dist/adapters/postgresql/tools/backup/dump.d.ts.map +1 -1
  95. package/dist/adapters/postgresql/tools/backup/dump.js +27 -24
  96. package/dist/adapters/postgresql/tools/backup/dump.js.map +1 -1
  97. package/dist/adapters/postgresql/tools/citext.js +114 -82
  98. package/dist/adapters/postgresql/tools/citext.js.map +1 -1
  99. package/dist/adapters/postgresql/tools/codemode/index.d.ts.map +1 -1
  100. package/dist/adapters/postgresql/tools/codemode/index.js +2 -11
  101. package/dist/adapters/postgresql/tools/codemode/index.js.map +1 -1
  102. package/dist/adapters/postgresql/tools/core/convenience.d.ts.map +1 -1
  103. package/dist/adapters/postgresql/tools/core/convenience.js +23 -8
  104. package/dist/adapters/postgresql/tools/core/convenience.js.map +1 -1
  105. package/dist/adapters/postgresql/tools/core/indexes.d.ts.map +1 -1
  106. package/dist/adapters/postgresql/tools/core/indexes.js +3 -2
  107. package/dist/adapters/postgresql/tools/core/indexes.js.map +1 -1
  108. package/dist/adapters/postgresql/tools/core/tables.d.ts.map +1 -1
  109. package/dist/adapters/postgresql/tools/core/tables.js +4 -4
  110. package/dist/adapters/postgresql/tools/core/tables.js.map +1 -1
  111. package/dist/adapters/postgresql/tools/cron.js +59 -27
  112. package/dist/adapters/postgresql/tools/cron.js.map +1 -1
  113. package/dist/adapters/postgresql/tools/introspection.d.ts +15 -0
  114. package/dist/adapters/postgresql/tools/introspection.d.ts.map +1 -0
  115. package/dist/adapters/postgresql/tools/introspection.js +1682 -0
  116. package/dist/adapters/postgresql/tools/introspection.js.map +1 -0
  117. package/dist/adapters/postgresql/tools/jsonb/advanced.d.ts.map +1 -1
  118. package/dist/adapters/postgresql/tools/jsonb/advanced.js +26 -17
  119. package/dist/adapters/postgresql/tools/jsonb/advanced.js.map +1 -1
  120. package/dist/adapters/postgresql/tools/jsonb/basic.d.ts.map +1 -1
  121. package/dist/adapters/postgresql/tools/jsonb/basic.js +92 -23
  122. package/dist/adapters/postgresql/tools/jsonb/basic.js.map +1 -1
  123. package/dist/adapters/postgresql/tools/ltree.d.ts.map +1 -1
  124. package/dist/adapters/postgresql/tools/ltree.js +17 -4
  125. package/dist/adapters/postgresql/tools/ltree.js.map +1 -1
  126. package/dist/adapters/postgresql/tools/monitoring.js +32 -21
  127. package/dist/adapters/postgresql/tools/monitoring.js.map +1 -1
  128. package/dist/adapters/postgresql/tools/partman/management.d.ts.map +1 -1
  129. package/dist/adapters/postgresql/tools/partman/management.js +32 -52
  130. package/dist/adapters/postgresql/tools/partman/management.js.map +1 -1
  131. package/dist/adapters/postgresql/tools/partman/operations.d.ts.map +1 -1
  132. package/dist/adapters/postgresql/tools/partman/operations.js +5 -5
  133. package/dist/adapters/postgresql/tools/partman/operations.js.map +1 -1
  134. package/dist/adapters/postgresql/tools/performance/analysis.d.ts.map +1 -1
  135. package/dist/adapters/postgresql/tools/performance/analysis.js +15 -8
  136. package/dist/adapters/postgresql/tools/performance/analysis.js.map +1 -1
  137. package/dist/adapters/postgresql/tools/performance/monitoring.d.ts.map +1 -1
  138. package/dist/adapters/postgresql/tools/performance/monitoring.js +10 -7
  139. package/dist/adapters/postgresql/tools/performance/monitoring.js.map +1 -1
  140. package/dist/adapters/postgresql/tools/performance/stats.d.ts.map +1 -1
  141. package/dist/adapters/postgresql/tools/performance/stats.js +62 -28
  142. package/dist/adapters/postgresql/tools/performance/stats.js.map +1 -1
  143. package/dist/adapters/postgresql/tools/pgcrypto.js +31 -11
  144. package/dist/adapters/postgresql/tools/pgcrypto.js.map +1 -1
  145. package/dist/adapters/postgresql/tools/postgis/advanced.d.ts.map +1 -1
  146. package/dist/adapters/postgresql/tools/postgis/advanced.js +30 -25
  147. package/dist/adapters/postgresql/tools/postgis/advanced.js.map +1 -1
  148. package/dist/adapters/postgresql/tools/postgis/basic.d.ts.map +1 -1
  149. package/dist/adapters/postgresql/tools/postgis/basic.js +24 -15
  150. package/dist/adapters/postgresql/tools/postgis/basic.js.map +1 -1
  151. package/dist/adapters/postgresql/tools/schema.js +79 -5
  152. package/dist/adapters/postgresql/tools/schema.js.map +1 -1
  153. package/dist/adapters/postgresql/tools/stats/advanced.d.ts.map +1 -1
  154. package/dist/adapters/postgresql/tools/stats/advanced.js +61 -39
  155. package/dist/adapters/postgresql/tools/stats/advanced.js.map +1 -1
  156. package/dist/adapters/postgresql/tools/stats/basic.d.ts.map +1 -1
  157. package/dist/adapters/postgresql/tools/stats/basic.js +45 -30
  158. package/dist/adapters/postgresql/tools/stats/basic.js.map +1 -1
  159. package/dist/adapters/postgresql/tools/text.js +327 -148
  160. package/dist/adapters/postgresql/tools/text.js.map +1 -1
  161. package/dist/auth/auth-context.d.ts +28 -0
  162. package/dist/auth/auth-context.d.ts.map +1 -0
  163. package/dist/auth/auth-context.js +37 -0
  164. package/dist/auth/auth-context.js.map +1 -0
  165. package/dist/auth/scope-map.d.ts +20 -0
  166. package/dist/auth/scope-map.d.ts.map +1 -0
  167. package/dist/auth/scope-map.js +40 -0
  168. package/dist/auth/scope-map.js.map +1 -0
  169. package/dist/auth/scopes.d.ts.map +1 -1
  170. package/dist/auth/scopes.js +2 -0
  171. package/dist/auth/scopes.js.map +1 -1
  172. package/dist/cli.js +1 -1
  173. package/dist/cli.js.map +1 -1
  174. package/dist/codemode/api.d.ts +1 -0
  175. package/dist/codemode/api.d.ts.map +1 -1
  176. package/dist/codemode/api.js +34 -0
  177. package/dist/codemode/api.js.map +1 -1
  178. package/dist/codemode/index.d.ts +0 -2
  179. package/dist/codemode/index.d.ts.map +1 -1
  180. package/dist/codemode/index.js +0 -4
  181. package/dist/codemode/index.js.map +1 -1
  182. package/dist/codemode/sandbox.d.ts +14 -1
  183. package/dist/codemode/sandbox.d.ts.map +1 -1
  184. package/dist/codemode/sandbox.js +58 -19
  185. package/dist/codemode/sandbox.js.map +1 -1
  186. package/dist/codemode/types.d.ts.map +1 -1
  187. package/dist/codemode/types.js +3 -0
  188. package/dist/codemode/types.js.map +1 -1
  189. package/dist/constants/ServerInstructions.d.ts +5 -1
  190. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  191. package/dist/constants/ServerInstructions.js +91 -43
  192. package/dist/constants/ServerInstructions.js.map +1 -1
  193. package/dist/filtering/ToolConstants.d.ts +22 -19
  194. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  195. package/dist/filtering/ToolConstants.js +48 -37
  196. package/dist/filtering/ToolConstants.js.map +1 -1
  197. package/dist/filtering/ToolFilter.d.ts.map +1 -1
  198. package/dist/filtering/ToolFilter.js +10 -13
  199. package/dist/filtering/ToolFilter.js.map +1 -1
  200. package/dist/pool/ConnectionPool.js +1 -1
  201. package/dist/pool/ConnectionPool.js.map +1 -1
  202. package/dist/transports/http.d.ts +1 -0
  203. package/dist/transports/http.d.ts.map +1 -1
  204. package/dist/transports/http.js +75 -21
  205. package/dist/transports/http.js.map +1 -1
  206. package/dist/types/filtering.d.ts +2 -2
  207. package/dist/types/filtering.d.ts.map +1 -1
  208. package/dist/utils/icons.d.ts.map +1 -1
  209. package/dist/utils/icons.js +5 -0
  210. package/dist/utils/icons.js.map +1 -1
  211. package/dist/utils/where-clause.d.ts.map +1 -1
  212. package/dist/utils/where-clause.js +24 -0
  213. package/dist/utils/where-clause.js.map +1 -1
  214. package/package.json +15 -12
  215. package/dist/codemode/sandbox-factory.d.ts +0 -72
  216. package/dist/codemode/sandbox-factory.d.ts.map +0 -1
  217. package/dist/codemode/sandbox-factory.js +0 -88
  218. package/dist/codemode/sandbox-factory.js.map +0 -1
  219. package/dist/codemode/worker-sandbox.d.ts +0 -82
  220. package/dist/codemode/worker-sandbox.d.ts.map +0 -1
  221. package/dist/codemode/worker-sandbox.js +0 -244
  222. package/dist/codemode/worker-sandbox.js.map +0 -1
  223. package/dist/codemode/worker-script.d.ts +0 -8
  224. package/dist/codemode/worker-script.d.ts.map +0 -1
  225. package/dist/codemode/worker-script.js +0 -113
  226. package/dist/codemode/worker-script.js.map +0 -1
@@ -79,15 +79,30 @@ function createTextSearchTool(adapter) {
79
79
  const tsvector = sanitizedCols
80
80
  .map((c) => `coalesce(${c}, '')`)
81
81
  .join(" || ' ' || ");
82
- const limitClause = parsed.limit !== undefined && parsed.limit > 0
83
- ? ` LIMIT ${String(parsed.limit)}`
84
- : "";
82
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
83
+ const limitVal = parsed.limit === 0
84
+ ? null
85
+ : parsed.limit !== undefined && parsed.limit > 0
86
+ ? parsed.limit
87
+ : 100;
88
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
85
89
  const sql = `SELECT ${selectCols}, ts_rank_cd(to_tsvector('${cfg}', ${tsvector}), plainto_tsquery('${cfg}', $1)) as rank
86
90
  FROM ${tableName}
87
91
  WHERE to_tsvector('${cfg}', ${tsvector}) @@ plainto_tsquery('${cfg}', $1)
88
92
  ORDER BY rank DESC${limitClause}`;
89
93
  const result = await adapter.executeQuery(sql, [parsed.query]);
90
- return { rows: result.rows, count: result.rows?.length ?? 0 };
94
+ const count = result.rows?.length ?? 0;
95
+ const truncated = limitVal !== null && count === limitVal;
96
+ return {
97
+ rows: result.rows,
98
+ count,
99
+ ...(truncated
100
+ ? {
101
+ truncated: true,
102
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
103
+ }
104
+ : {}),
105
+ };
91
106
  }
92
107
  catch (error) {
93
108
  if (error instanceof ZodError) {
@@ -172,15 +187,30 @@ function createTextRankTool(adapter) {
172
187
  const tsvector = sanitizedCols
173
188
  .map((c) => `coalesce(${c}, '')`)
174
189
  .join(" || ' ' || ");
175
- const limitClause = parsed.limit !== undefined && parsed.limit > 0
176
- ? ` LIMIT ${String(parsed.limit)}`
177
- : "";
190
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
191
+ const limitVal = parsed.limit === 0
192
+ ? null
193
+ : parsed.limit !== undefined && parsed.limit > 0
194
+ ? parsed.limit
195
+ : 100;
196
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
178
197
  const sql = `SELECT ${selectCols}, ts_rank_cd(to_tsvector('${cfg}', ${tsvector}), plainto_tsquery('${cfg}', $1), ${String(norm)}) as rank
179
198
  FROM ${tableName}
180
199
  WHERE to_tsvector('${cfg}', ${tsvector}) @@ plainto_tsquery('${cfg}', $1)
181
200
  ORDER BY rank DESC${limitClause}`;
182
201
  const result = await adapter.executeQuery(sql, [parsed.query]);
183
- return { rows: result.rows, count: result.rows?.length ?? 0 };
202
+ const count = result.rows?.length ?? 0;
203
+ const truncated = limitVal !== null && count === limitVal;
204
+ return {
205
+ rows: result.rows,
206
+ count,
207
+ ...(truncated
208
+ ? {
209
+ truncated: true,
210
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
211
+ }
212
+ : {}),
213
+ };
184
214
  }
185
215
  catch (error) {
186
216
  if (error instanceof ZodError) {
@@ -212,8 +242,13 @@ function createTrigramSimilarityTool(adapter) {
212
242
  try {
213
243
  const parsed = TrigramSimilaritySchema.parse(params);
214
244
  const thresh = parsed.threshold ?? 0.3;
215
- // Default limit to 100 to prevent large payloads
216
- const limitVal = parsed.limit !== undefined && parsed.limit > 0 ? parsed.limit : 100;
245
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
246
+ const limitVal = parsed.limit === 0
247
+ ? null
248
+ : parsed.limit !== undefined && parsed.limit > 0
249
+ ? parsed.limit
250
+ : 100;
251
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
217
252
  // The preprocessor guarantees table is set (converts tableName → table)
218
253
  const resolvedTable = parsed.table ?? parsed.tableName;
219
254
  if (!resolvedTable) {
@@ -233,9 +268,20 @@ function createTrigramSimilarityTool(adapter) {
233
268
  const sql = `SELECT ${selectCols}, similarity(${columnName}, $1) as similarity
234
269
  FROM ${tableName}
235
270
  WHERE similarity(${columnName}, $1) > ${String(thresh)}${additionalWhere}
236
- ORDER BY similarity DESC LIMIT ${String(limitVal)}`;
271
+ ORDER BY similarity DESC${limitClause}`;
237
272
  const result = await adapter.executeQuery(sql, [parsed.value]);
238
- return { rows: result.rows, count: result.rows?.length ?? 0 };
273
+ const count = result.rows?.length ?? 0;
274
+ const truncated = limitVal !== null && count === limitVal;
275
+ return {
276
+ rows: result.rows,
277
+ count,
278
+ ...(truncated
279
+ ? {
280
+ truncated: true,
281
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
282
+ }
283
+ : {}),
284
+ };
239
285
  }
240
286
  catch (error) {
241
287
  if (error instanceof ZodError) {
@@ -309,8 +355,13 @@ function createFuzzyMatchTool(adapter) {
309
355
  }
310
356
  const method = rawMethod;
311
357
  const maxDist = parsed.maxDistance ?? 3;
312
- // Default limit to 100 to prevent large payloads
313
- const limitVal = parsed.limit !== undefined && parsed.limit > 0 ? parsed.limit : 100;
358
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
359
+ const limitVal = parsed.limit === 0
360
+ ? null
361
+ : parsed.limit !== undefined && parsed.limit > 0
362
+ ? parsed.limit
363
+ : 100;
364
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
314
365
  // The preprocessor guarantees table is set (converts tableName → table)
315
366
  const resolvedTable = parsed.table ?? parsed.tableName;
316
367
  if (!resolvedTable) {
@@ -329,16 +380,27 @@ function createFuzzyMatchTool(adapter) {
329
380
  : "";
330
381
  let sql;
331
382
  if (method === "soundex") {
332
- sql = `SELECT ${selectCols}, soundex(${columnName}) as code FROM ${tableName} WHERE soundex(${columnName}) = soundex($1)${additionalWhere} LIMIT ${String(limitVal)}`;
383
+ sql = `SELECT ${selectCols}, soundex(${columnName}) as code FROM ${tableName} WHERE soundex(${columnName}) = soundex($1)${additionalWhere}${limitClause}`;
333
384
  }
334
385
  else if (method === "metaphone") {
335
- sql = `SELECT ${selectCols}, metaphone(${columnName}, 10) as code FROM ${tableName} WHERE metaphone(${columnName}, 10) = metaphone($1, 10)${additionalWhere} LIMIT ${String(limitVal)}`;
386
+ sql = `SELECT ${selectCols}, metaphone(${columnName}, 10) as code FROM ${tableName} WHERE metaphone(${columnName}, 10) = metaphone($1, 10)${additionalWhere}${limitClause}`;
336
387
  }
337
388
  else {
338
- sql = `SELECT ${selectCols}, levenshtein(${columnName}, $1) as distance FROM ${tableName} WHERE levenshtein(${columnName}, $1) <= ${String(maxDist)}${additionalWhere} ORDER BY distance LIMIT ${String(limitVal)}`;
389
+ sql = `SELECT ${selectCols}, levenshtein(${columnName}, $1) as distance FROM ${tableName} WHERE levenshtein(${columnName}, $1) <= ${String(maxDist)}${additionalWhere} ORDER BY distance${limitClause}`;
339
390
  }
340
391
  const result = await adapter.executeQuery(sql, [parsed.value]);
341
- return { rows: result.rows, count: result.rows?.length ?? 0 };
392
+ const count = result.rows?.length ?? 0;
393
+ const truncated = limitVal !== null && count === limitVal;
394
+ return {
395
+ rows: result.rows,
396
+ count,
397
+ ...(truncated
398
+ ? {
399
+ truncated: true,
400
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
401
+ }
402
+ : {}),
403
+ };
342
404
  }
343
405
  catch (error) {
344
406
  if (error instanceof ZodError) {
@@ -386,12 +448,27 @@ function createRegexpMatchTool(adapter) {
386
448
  const additionalWhere = parsed.where
387
449
  ? ` AND (${sanitizeWhereClause(parsed.where)})`
388
450
  : "";
389
- // Default limit to 100 to prevent large payloads
390
- const limitVal = parsed.limit !== undefined && parsed.limit > 0 ? parsed.limit : 100;
391
- const limitClause = ` LIMIT ${String(limitVal)}`;
451
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
452
+ const limitVal = parsed.limit === 0
453
+ ? null
454
+ : parsed.limit !== undefined && parsed.limit > 0
455
+ ? parsed.limit
456
+ : 100;
457
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
392
458
  const sql = `SELECT ${selectCols} FROM ${tableName} WHERE ${columnName} ${op} $1${additionalWhere}${limitClause}`;
393
459
  const result = await adapter.executeQuery(sql, [parsed.pattern]);
394
- return { rows: result.rows, count: result.rows?.length ?? 0 };
460
+ const count = result.rows?.length ?? 0;
461
+ const truncated = limitVal !== null && count === limitVal;
462
+ return {
463
+ rows: result.rows,
464
+ count,
465
+ ...(truncated
466
+ ? {
467
+ truncated: true,
468
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
469
+ }
470
+ : {}),
471
+ };
395
472
  }
396
473
  catch (error) {
397
474
  if (error instanceof ZodError) {
@@ -463,12 +540,27 @@ function createLikeSearchTool(adapter) {
463
540
  const additionalWhere = parsed.where
464
541
  ? ` AND (${sanitizeWhereClause(parsed.where)})`
465
542
  : "";
466
- // Default limit to 100 to prevent large payloads
467
- const limitVal = parsed.limit !== undefined && parsed.limit > 0 ? parsed.limit : 100;
468
- const limitClause = ` LIMIT ${String(limitVal)}`;
543
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
544
+ const limitVal = parsed.limit === 0
545
+ ? null
546
+ : parsed.limit !== undefined && parsed.limit > 0
547
+ ? parsed.limit
548
+ : 100;
549
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
469
550
  const sql = `SELECT ${selectCols} FROM ${tableName} WHERE ${columnName} ${op} $1${additionalWhere}${limitClause}`;
470
551
  const result = await adapter.executeQuery(sql, [parsed.pattern]);
471
- return { rows: result.rows, count: result.rows?.length ?? 0 };
552
+ const count = result.rows?.length ?? 0;
553
+ const truncated = limitVal !== null && count === limitVal;
554
+ return {
555
+ rows: result.rows,
556
+ count,
557
+ ...(truncated
558
+ ? {
559
+ truncated: true,
560
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
561
+ }
562
+ : {}),
563
+ };
472
564
  }
473
565
  catch (error) {
474
566
  if (error instanceof ZodError) {
@@ -561,14 +653,29 @@ function createTextHeadlineTool(adapter) {
561
653
  const selectCols = parsed.select !== undefined && parsed.select.length > 0
562
654
  ? sanitizeIdentifiers(parsed.select).join(", ") + ", "
563
655
  : "";
564
- const limitClause = parsed.limit !== undefined && parsed.limit > 0
565
- ? ` LIMIT ${String(parsed.limit)}`
566
- : "";
656
+ // Default limit to 100 to prevent large payloads; limit: 0 means no limit
657
+ const limitVal = parsed.limit === 0
658
+ ? null
659
+ : parsed.limit !== undefined && parsed.limit > 0
660
+ ? parsed.limit
661
+ : 100;
662
+ const limitClause = limitVal !== null ? ` LIMIT ${String(limitVal)}` : "";
567
663
  const sql = `SELECT ${selectCols}ts_headline('${cfg}', ${columnName}, plainto_tsquery('${cfg}', $1), '${opts}') as headline
568
664
  FROM ${tableName}
569
665
  WHERE to_tsvector('${cfg}', ${columnName}) @@ plainto_tsquery('${cfg}', $1)${limitClause}`;
570
666
  const result = await adapter.executeQuery(sql, [parsed.query]);
571
- return { rows: result.rows, count: result.rows?.length ?? 0 };
667
+ const count = result.rows?.length ?? 0;
668
+ const truncated = limitVal !== null && count === limitVal;
669
+ return {
670
+ rows: result.rows,
671
+ count,
672
+ ...(truncated
673
+ ? {
674
+ truncated: true,
675
+ hint: `Results limited to ${String(limitVal)}. Use limit: 0 for all rows.`,
676
+ }
677
+ : {}),
678
+ };
572
679
  }
573
680
  catch (error) {
574
681
  if (error instanceof ZodError) {
@@ -681,11 +788,27 @@ function createTextNormalizeTool(adapter) {
681
788
  annotations: readOnly("Text Normalize"),
682
789
  icons: getToolIcons("text", readOnly("Text Normalize")),
683
790
  handler: async (params, _context) => {
684
- const parsed = NormalizeSchema.parse(params ?? {});
685
- // Ensure unaccent extension is available
686
- await adapter.executeQuery("CREATE EXTENSION IF NOT EXISTS unaccent");
687
- const result = await adapter.executeQuery(`SELECT unaccent($1) as normalized`, [parsed.text]);
688
- return { normalized: result.rows?.[0]?.["normalized"] };
791
+ try {
792
+ const parsed = NormalizeSchema.parse(params ?? {});
793
+ // Ensure unaccent extension is available
794
+ await adapter.executeQuery("CREATE EXTENSION IF NOT EXISTS unaccent");
795
+ const result = await adapter.executeQuery(`SELECT unaccent($1) as normalized`, [parsed.text]);
796
+ return { normalized: result.rows?.[0]?.["normalized"] };
797
+ }
798
+ catch (error) {
799
+ if (error instanceof ZodError) {
800
+ return {
801
+ success: false,
802
+ error: `pg_text_normalize validation error: ${error.issues.map((e) => e.message).join(", ")}`,
803
+ };
804
+ }
805
+ return {
806
+ success: false,
807
+ error: formatPostgresError(error, {
808
+ tool: "pg_text_normalize",
809
+ }),
810
+ };
811
+ }
689
812
  },
690
813
  };
691
814
  }
@@ -709,95 +832,109 @@ function createTextSentimentTool(_adapter) {
709
832
  annotations: readOnly("Text Sentiment"),
710
833
  icons: getToolIcons("text", readOnly("Text Sentiment")),
711
834
  handler: (params, _context) => {
712
- const parsed = SentimentSchema.parse(params ?? {});
713
- const text = parsed.text.toLowerCase();
714
- const positiveWords = [
715
- "good",
716
- "great",
717
- "excellent",
718
- "amazing",
719
- "wonderful",
720
- "fantastic",
721
- "love",
722
- "happy",
723
- "positive",
724
- "best",
725
- "beautiful",
726
- "awesome",
727
- "perfect",
728
- "nice",
729
- "helpful",
730
- "thank",
731
- "thanks",
732
- "pleased",
733
- "satisfied",
734
- "recommend",
735
- "enjoy",
736
- "impressive",
737
- "brilliant",
738
- ];
739
- const negativeWords = [
740
- "bad",
741
- "terrible",
742
- "awful",
743
- "horrible",
744
- "worst",
745
- "hate",
746
- "angry",
747
- "disappointed",
748
- "poor",
749
- "wrong",
750
- "problem",
751
- "issue",
752
- "fail",
753
- "failed",
754
- "broken",
755
- "useless",
756
- "waste",
757
- "frustrating",
758
- "annoyed",
759
- "unhappy",
760
- "negative",
761
- "complaint",
762
- "slow",
763
- ];
764
- const words = text.split(/\s+/);
765
- const matchedPositive = words
766
- .map((w) => w.replace(/[^a-z]/g, ""))
767
- .filter((w) => positiveWords.includes(w));
768
- const matchedNegative = words
769
- .map((w) => w.replace(/[^a-z]/g, ""))
770
- .filter((w) => negativeWords.includes(w));
771
- const positiveScore = matchedPositive.length;
772
- const negativeScore = matchedNegative.length;
773
- const totalScore = positiveScore - negativeScore;
774
- let sentiment;
775
- if (totalScore > 2)
776
- sentiment = "very_positive";
777
- else if (totalScore > 0)
778
- sentiment = "positive";
779
- else if (totalScore < -2)
780
- sentiment = "very_negative";
781
- else if (totalScore < 0)
782
- sentiment = "negative";
783
- else
784
- sentiment = "neutral";
785
- const result = {
786
- sentiment,
787
- score: totalScore,
788
- positiveCount: positiveScore,
789
- negativeCount: negativeScore,
790
- confidence: positiveScore + negativeScore > 3
791
- ? "high"
792
- : positiveScore + negativeScore > 1
793
- ? "medium"
794
- : "low",
795
- };
796
- if (parsed.returnWords) {
797
- result.matchedPositive = matchedPositive;
798
- result.matchedNegative = matchedNegative;
835
+ try {
836
+ const parsed = SentimentSchema.parse(params ?? {});
837
+ const text = parsed.text.toLowerCase();
838
+ const positiveWords = [
839
+ "good",
840
+ "great",
841
+ "excellent",
842
+ "amazing",
843
+ "wonderful",
844
+ "fantastic",
845
+ "love",
846
+ "happy",
847
+ "positive",
848
+ "best",
849
+ "beautiful",
850
+ "awesome",
851
+ "perfect",
852
+ "nice",
853
+ "helpful",
854
+ "thank",
855
+ "thanks",
856
+ "pleased",
857
+ "satisfied",
858
+ "recommend",
859
+ "enjoy",
860
+ "impressive",
861
+ "brilliant",
862
+ ];
863
+ const negativeWords = [
864
+ "bad",
865
+ "terrible",
866
+ "awful",
867
+ "horrible",
868
+ "worst",
869
+ "hate",
870
+ "angry",
871
+ "disappointed",
872
+ "poor",
873
+ "wrong",
874
+ "problem",
875
+ "issue",
876
+ "fail",
877
+ "failed",
878
+ "broken",
879
+ "useless",
880
+ "waste",
881
+ "frustrating",
882
+ "annoyed",
883
+ "unhappy",
884
+ "negative",
885
+ "complaint",
886
+ "slow",
887
+ ];
888
+ const words = text.split(/\s+/);
889
+ const matchedPositive = words
890
+ .map((w) => w.replace(/[^a-z]/g, ""))
891
+ .filter((w) => positiveWords.includes(w));
892
+ const matchedNegative = words
893
+ .map((w) => w.replace(/[^a-z]/g, ""))
894
+ .filter((w) => negativeWords.includes(w));
895
+ const positiveScore = matchedPositive.length;
896
+ const negativeScore = matchedNegative.length;
897
+ const totalScore = positiveScore - negativeScore;
898
+ let sentiment;
899
+ if (totalScore > 2)
900
+ sentiment = "very_positive";
901
+ else if (totalScore > 0)
902
+ sentiment = "positive";
903
+ else if (totalScore < -2)
904
+ sentiment = "very_negative";
905
+ else if (totalScore < 0)
906
+ sentiment = "negative";
907
+ else
908
+ sentiment = "neutral";
909
+ const result = {
910
+ sentiment,
911
+ score: totalScore,
912
+ positiveCount: positiveScore,
913
+ negativeCount: negativeScore,
914
+ confidence: positiveScore + negativeScore > 3
915
+ ? "high"
916
+ : positiveScore + negativeScore > 1
917
+ ? "medium"
918
+ : "low",
919
+ };
920
+ if (parsed.returnWords) {
921
+ result.matchedPositive = matchedPositive;
922
+ result.matchedNegative = matchedNegative;
923
+ }
924
+ return Promise.resolve(result);
925
+ }
926
+ catch (error) {
927
+ if (error instanceof ZodError) {
928
+ return Promise.resolve({
929
+ success: false,
930
+ error: `pg_text_sentiment validation error: ${error.issues.map((e) => e.message).join(", ")}`,
931
+ });
932
+ }
933
+ return Promise.resolve({
934
+ success: false,
935
+ error: error instanceof Error ? error.message : "Unknown error occurred",
936
+ });
799
937
  }
800
- return Promise.resolve(result);
801
938
  },
802
939
  };
803
940
  }
@@ -821,10 +958,26 @@ function createTextToVectorTool(adapter) {
821
958
  annotations: readOnly("Text to Vector"),
822
959
  icons: getToolIcons("text", readOnly("Text to Vector")),
823
960
  handler: async (params, _context) => {
824
- const parsed = ToVectorSchema.parse(params ?? {});
825
- const cfg = parsed.config ?? "english";
826
- const result = await adapter.executeQuery(`SELECT to_tsvector($1, $2) as vector`, [cfg, parsed.text]);
827
- return { vector: result.rows?.[0]?.["vector"] };
961
+ try {
962
+ const parsed = ToVectorSchema.parse(params ?? {});
963
+ const cfg = parsed.config ?? "english";
964
+ const result = await adapter.executeQuery(`SELECT to_tsvector($1, $2) as vector`, [cfg, parsed.text]);
965
+ return { vector: result.rows?.[0]?.["vector"] };
966
+ }
967
+ catch (error) {
968
+ if (error instanceof ZodError) {
969
+ return {
970
+ success: false,
971
+ error: `pg_text_to_vector validation error: ${error.issues.map((e) => e.message).join(", ")}`,
972
+ };
973
+ }
974
+ return {
975
+ success: false,
976
+ error: formatPostgresError(error, {
977
+ tool: "pg_text_to_vector",
978
+ }),
979
+ };
980
+ }
828
981
  },
829
982
  };
830
983
  }
@@ -852,22 +1005,38 @@ function createTextToQueryTool(adapter) {
852
1005
  annotations: readOnly("Text to Query"),
853
1006
  icons: getToolIcons("text", readOnly("Text to Query")),
854
1007
  handler: async (params, _context) => {
855
- const parsed = ToQuerySchema.parse(params ?? {});
856
- const cfg = parsed.config ?? "english";
857
- const mode = parsed.mode ?? "plain";
858
- let fn;
859
- switch (mode) {
860
- case "phrase":
861
- fn = "phraseto_tsquery";
862
- break;
863
- case "websearch":
864
- fn = "websearch_to_tsquery";
865
- break;
866
- default:
867
- fn = "plainto_tsquery";
1008
+ try {
1009
+ const parsed = ToQuerySchema.parse(params ?? {});
1010
+ const cfg = parsed.config ?? "english";
1011
+ const mode = parsed.mode ?? "plain";
1012
+ let fn;
1013
+ switch (mode) {
1014
+ case "phrase":
1015
+ fn = "phraseto_tsquery";
1016
+ break;
1017
+ case "websearch":
1018
+ fn = "websearch_to_tsquery";
1019
+ break;
1020
+ default:
1021
+ fn = "plainto_tsquery";
1022
+ }
1023
+ const result = await adapter.executeQuery(`SELECT ${fn}($1, $2) as query`, [cfg, parsed.text]);
1024
+ return { query: result.rows?.[0]?.["query"], mode };
1025
+ }
1026
+ catch (error) {
1027
+ if (error instanceof ZodError) {
1028
+ return {
1029
+ success: false,
1030
+ error: `pg_text_to_query validation error: ${error.issues.map((e) => e.message).join(", ")}`,
1031
+ };
1032
+ }
1033
+ return {
1034
+ success: false,
1035
+ error: formatPostgresError(error, {
1036
+ tool: "pg_text_to_query",
1037
+ }),
1038
+ };
868
1039
  }
869
- const result = await adapter.executeQuery(`SELECT ${fn}($1, $2) as query`, [cfg, parsed.text]);
870
- return { query: result.rows?.[0]?.["query"], mode };
871
1040
  },
872
1041
  };
873
1042
  }
@@ -884,8 +1053,9 @@ function createTextSearchConfigTool(adapter) {
884
1053
  annotations: readOnly("Search Configurations"),
885
1054
  icons: getToolIcons("text", readOnly("Search Configurations")),
886
1055
  handler: async (_params, _context) => {
887
- const result = await adapter.executeQuery(`
888
- SELECT
1056
+ try {
1057
+ const result = await adapter.executeQuery(`
1058
+ SELECT
889
1059
  c.cfgname as name,
890
1060
  n.nspname as schema,
891
1061
  obj_description(c.oid, 'pg_ts_config') as description
@@ -893,10 +1063,19 @@ function createTextSearchConfigTool(adapter) {
893
1063
  JOIN pg_namespace n ON n.oid = c.cfgnamespace
894
1064
  ORDER BY c.cfgname
895
1065
  `);
896
- return {
897
- configs: result.rows ?? [],
898
- count: result.rows?.length ?? 0,
899
- };
1066
+ return {
1067
+ configs: result.rows ?? [],
1068
+ count: result.rows?.length ?? 0,
1069
+ };
1070
+ }
1071
+ catch (error) {
1072
+ return {
1073
+ success: false,
1074
+ error: formatPostgresError(error, {
1075
+ tool: "pg_text_search_config",
1076
+ }),
1077
+ };
1078
+ }
900
1079
  },
901
1080
  };
902
1081
  }