@neverinfamous/postgres-mcp 1.1.0 → 1.3.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 (243) hide show
  1. package/README.md +95 -81
  2. package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
  3. package/dist/__tests__/mocks/adapter.js +0 -1
  4. package/dist/__tests__/mocks/adapter.js.map +1 -1
  5. package/dist/__tests__/mocks/pool.d.ts.map +1 -1
  6. package/dist/__tests__/mocks/pool.js +0 -1
  7. package/dist/__tests__/mocks/pool.js.map +1 -1
  8. package/dist/adapters/DatabaseAdapter.js +1 -1
  9. package/dist/adapters/DatabaseAdapter.js.map +1 -1
  10. package/dist/adapters/postgresql/PostgresAdapter.d.ts.map +1 -1
  11. package/dist/adapters/postgresql/PostgresAdapter.js +78 -8
  12. package/dist/adapters/postgresql/PostgresAdapter.js.map +1 -1
  13. package/dist/adapters/postgresql/prompts/backup.d.ts.map +1 -1
  14. package/dist/adapters/postgresql/prompts/backup.js +2 -3
  15. package/dist/adapters/postgresql/prompts/backup.js.map +1 -1
  16. package/dist/adapters/postgresql/prompts/citext.d.ts.map +1 -1
  17. package/dist/adapters/postgresql/prompts/citext.js +3 -4
  18. package/dist/adapters/postgresql/prompts/citext.js.map +1 -1
  19. package/dist/adapters/postgresql/prompts/extensionSetup.d.ts.map +1 -1
  20. package/dist/adapters/postgresql/prompts/extensionSetup.js +2 -3
  21. package/dist/adapters/postgresql/prompts/extensionSetup.js.map +1 -1
  22. package/dist/adapters/postgresql/prompts/health.d.ts.map +1 -1
  23. package/dist/adapters/postgresql/prompts/health.js +2 -3
  24. package/dist/adapters/postgresql/prompts/health.js.map +1 -1
  25. package/dist/adapters/postgresql/prompts/index.js +20 -27
  26. package/dist/adapters/postgresql/prompts/index.js.map +1 -1
  27. package/dist/adapters/postgresql/prompts/indexTuning.d.ts.map +1 -1
  28. package/dist/adapters/postgresql/prompts/indexTuning.js +2 -3
  29. package/dist/adapters/postgresql/prompts/indexTuning.js.map +1 -1
  30. package/dist/adapters/postgresql/prompts/kcache.d.ts.map +1 -1
  31. package/dist/adapters/postgresql/prompts/kcache.js +3 -4
  32. package/dist/adapters/postgresql/prompts/kcache.js.map +1 -1
  33. package/dist/adapters/postgresql/prompts/ltree.d.ts.map +1 -1
  34. package/dist/adapters/postgresql/prompts/ltree.js +5 -6
  35. package/dist/adapters/postgresql/prompts/ltree.js.map +1 -1
  36. package/dist/adapters/postgresql/prompts/partman.d.ts.map +1 -1
  37. package/dist/adapters/postgresql/prompts/partman.js +2 -3
  38. package/dist/adapters/postgresql/prompts/partman.js.map +1 -1
  39. package/dist/adapters/postgresql/prompts/pgcron.d.ts.map +1 -1
  40. package/dist/adapters/postgresql/prompts/pgcron.js +2 -3
  41. package/dist/adapters/postgresql/prompts/pgcron.js.map +1 -1
  42. package/dist/adapters/postgresql/prompts/pgcrypto.d.ts.map +1 -1
  43. package/dist/adapters/postgresql/prompts/pgcrypto.js +3 -4
  44. package/dist/adapters/postgresql/prompts/pgcrypto.js.map +1 -1
  45. package/dist/adapters/postgresql/prompts/pgvector.d.ts.map +1 -1
  46. package/dist/adapters/postgresql/prompts/pgvector.js +3 -4
  47. package/dist/adapters/postgresql/prompts/pgvector.js.map +1 -1
  48. package/dist/adapters/postgresql/prompts/postgis.d.ts.map +1 -1
  49. package/dist/adapters/postgresql/prompts/postgis.js +2 -3
  50. package/dist/adapters/postgresql/prompts/postgis.js.map +1 -1
  51. package/dist/adapters/postgresql/schemas/admin.d.ts +10 -5
  52. package/dist/adapters/postgresql/schemas/admin.d.ts.map +1 -1
  53. package/dist/adapters/postgresql/schemas/admin.js +10 -5
  54. package/dist/adapters/postgresql/schemas/admin.js.map +1 -1
  55. package/dist/adapters/postgresql/schemas/backup.d.ts +8 -4
  56. package/dist/adapters/postgresql/schemas/backup.d.ts.map +1 -1
  57. package/dist/adapters/postgresql/schemas/backup.js +11 -4
  58. package/dist/adapters/postgresql/schemas/backup.js.map +1 -1
  59. package/dist/adapters/postgresql/schemas/core.d.ts +54 -19
  60. package/dist/adapters/postgresql/schemas/core.d.ts.map +1 -1
  61. package/dist/adapters/postgresql/schemas/core.js +65 -17
  62. package/dist/adapters/postgresql/schemas/core.js.map +1 -1
  63. package/dist/adapters/postgresql/schemas/cron.d.ts +51 -32
  64. package/dist/adapters/postgresql/schemas/cron.d.ts.map +1 -1
  65. package/dist/adapters/postgresql/schemas/cron.js +64 -44
  66. package/dist/adapters/postgresql/schemas/cron.js.map +1 -1
  67. package/dist/adapters/postgresql/schemas/extensions.d.ts +168 -73
  68. package/dist/adapters/postgresql/schemas/extensions.d.ts.map +1 -1
  69. package/dist/adapters/postgresql/schemas/extensions.js +179 -62
  70. package/dist/adapters/postgresql/schemas/extensions.js.map +1 -1
  71. package/dist/adapters/postgresql/schemas/index.d.ts +5 -5
  72. package/dist/adapters/postgresql/schemas/index.d.ts.map +1 -1
  73. package/dist/adapters/postgresql/schemas/index.js +9 -7
  74. package/dist/adapters/postgresql/schemas/index.js.map +1 -1
  75. package/dist/adapters/postgresql/schemas/jsonb.d.ts +94 -42
  76. package/dist/adapters/postgresql/schemas/jsonb.d.ts.map +1 -1
  77. package/dist/adapters/postgresql/schemas/jsonb.js +101 -30
  78. package/dist/adapters/postgresql/schemas/jsonb.js.map +1 -1
  79. package/dist/adapters/postgresql/schemas/monitoring.d.ts +28 -11
  80. package/dist/adapters/postgresql/schemas/monitoring.d.ts.map +1 -1
  81. package/dist/adapters/postgresql/schemas/monitoring.js +49 -24
  82. package/dist/adapters/postgresql/schemas/monitoring.js.map +1 -1
  83. package/dist/adapters/postgresql/schemas/partitioning.d.ts +15 -11
  84. package/dist/adapters/postgresql/schemas/partitioning.d.ts.map +1 -1
  85. package/dist/adapters/postgresql/schemas/partitioning.js +17 -13
  86. package/dist/adapters/postgresql/schemas/partitioning.js.map +1 -1
  87. package/dist/adapters/postgresql/schemas/performance.d.ts +62 -31
  88. package/dist/adapters/postgresql/schemas/performance.d.ts.map +1 -1
  89. package/dist/adapters/postgresql/schemas/performance.js +86 -24
  90. package/dist/adapters/postgresql/schemas/performance.js.map +1 -1
  91. package/dist/adapters/postgresql/schemas/postgis.d.ts +20 -0
  92. package/dist/adapters/postgresql/schemas/postgis.d.ts.map +1 -1
  93. package/dist/adapters/postgresql/schemas/postgis.js +20 -3
  94. package/dist/adapters/postgresql/schemas/postgis.js.map +1 -1
  95. package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts +35 -23
  96. package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts.map +1 -1
  97. package/dist/adapters/postgresql/schemas/schema-mgmt.js +69 -26
  98. package/dist/adapters/postgresql/schemas/schema-mgmt.js.map +1 -1
  99. package/dist/adapters/postgresql/schemas/stats.d.ts +33 -20
  100. package/dist/adapters/postgresql/schemas/stats.d.ts.map +1 -1
  101. package/dist/adapters/postgresql/schemas/stats.js +36 -20
  102. package/dist/adapters/postgresql/schemas/stats.js.map +1 -1
  103. package/dist/adapters/postgresql/schemas/text-search.d.ts +8 -5
  104. package/dist/adapters/postgresql/schemas/text-search.d.ts.map +1 -1
  105. package/dist/adapters/postgresql/schemas/text-search.js +15 -5
  106. package/dist/adapters/postgresql/schemas/text-search.js.map +1 -1
  107. package/dist/adapters/postgresql/tools/admin.d.ts.map +1 -1
  108. package/dist/adapters/postgresql/tools/admin.js +211 -140
  109. package/dist/adapters/postgresql/tools/admin.js.map +1 -1
  110. package/dist/adapters/postgresql/tools/backup/dump.d.ts.map +1 -1
  111. package/dist/adapters/postgresql/tools/backup/dump.js +410 -387
  112. package/dist/adapters/postgresql/tools/backup/dump.js.map +1 -1
  113. package/dist/adapters/postgresql/tools/backup/planning.d.ts.map +1 -1
  114. package/dist/adapters/postgresql/tools/backup/planning.js +175 -172
  115. package/dist/adapters/postgresql/tools/backup/planning.js.map +1 -1
  116. package/dist/adapters/postgresql/tools/citext.d.ts.map +1 -1
  117. package/dist/adapters/postgresql/tools/citext.js +221 -163
  118. package/dist/adapters/postgresql/tools/citext.js.map +1 -1
  119. package/dist/adapters/postgresql/tools/core/convenience.d.ts +9 -1
  120. package/dist/adapters/postgresql/tools/core/convenience.d.ts.map +1 -1
  121. package/dist/adapters/postgresql/tools/core/convenience.js +96 -9
  122. package/dist/adapters/postgresql/tools/core/convenience.js.map +1 -1
  123. package/dist/adapters/postgresql/tools/core/error-helpers.d.ts +48 -0
  124. package/dist/adapters/postgresql/tools/core/error-helpers.d.ts.map +1 -0
  125. package/dist/adapters/postgresql/tools/core/error-helpers.js +256 -0
  126. package/dist/adapters/postgresql/tools/core/error-helpers.js.map +1 -0
  127. package/dist/adapters/postgresql/tools/core/health.d.ts.map +1 -1
  128. package/dist/adapters/postgresql/tools/core/health.js +23 -6
  129. package/dist/adapters/postgresql/tools/core/health.js.map +1 -1
  130. package/dist/adapters/postgresql/tools/core/indexes.d.ts.map +1 -1
  131. package/dist/adapters/postgresql/tools/core/indexes.js +45 -4
  132. package/dist/adapters/postgresql/tools/core/indexes.js.map +1 -1
  133. package/dist/adapters/postgresql/tools/core/objects.d.ts.map +1 -1
  134. package/dist/adapters/postgresql/tools/core/objects.js +104 -85
  135. package/dist/adapters/postgresql/tools/core/objects.js.map +1 -1
  136. package/dist/adapters/postgresql/tools/core/query.d.ts.map +1 -1
  137. package/dist/adapters/postgresql/tools/core/query.js +100 -42
  138. package/dist/adapters/postgresql/tools/core/query.js.map +1 -1
  139. package/dist/adapters/postgresql/tools/core/schemas.d.ts +52 -25
  140. package/dist/adapters/postgresql/tools/core/schemas.d.ts.map +1 -1
  141. package/dist/adapters/postgresql/tools/core/schemas.js +55 -25
  142. package/dist/adapters/postgresql/tools/core/schemas.js.map +1 -1
  143. package/dist/adapters/postgresql/tools/core/tables.d.ts.map +1 -1
  144. package/dist/adapters/postgresql/tools/core/tables.js +74 -30
  145. package/dist/adapters/postgresql/tools/core/tables.js.map +1 -1
  146. package/dist/adapters/postgresql/tools/cron.d.ts.map +1 -1
  147. package/dist/adapters/postgresql/tools/cron.js +274 -179
  148. package/dist/adapters/postgresql/tools/cron.js.map +1 -1
  149. package/dist/adapters/postgresql/tools/jsonb/advanced.d.ts.map +1 -1
  150. package/dist/adapters/postgresql/tools/jsonb/advanced.js +372 -284
  151. package/dist/adapters/postgresql/tools/jsonb/advanced.js.map +1 -1
  152. package/dist/adapters/postgresql/tools/jsonb/basic.d.ts.map +1 -1
  153. package/dist/adapters/postgresql/tools/jsonb/basic.js +617 -398
  154. package/dist/adapters/postgresql/tools/jsonb/basic.js.map +1 -1
  155. package/dist/adapters/postgresql/tools/kcache.d.ts.map +1 -1
  156. package/dist/adapters/postgresql/tools/kcache.js +282 -220
  157. package/dist/adapters/postgresql/tools/kcache.js.map +1 -1
  158. package/dist/adapters/postgresql/tools/ltree.d.ts.map +1 -1
  159. package/dist/adapters/postgresql/tools/ltree.js +126 -35
  160. package/dist/adapters/postgresql/tools/ltree.js.map +1 -1
  161. package/dist/adapters/postgresql/tools/monitoring.d.ts.map +1 -1
  162. package/dist/adapters/postgresql/tools/monitoring.js +59 -40
  163. package/dist/adapters/postgresql/tools/monitoring.js.map +1 -1
  164. package/dist/adapters/postgresql/tools/partitioning.d.ts.map +1 -1
  165. package/dist/adapters/postgresql/tools/partitioning.js +150 -15
  166. package/dist/adapters/postgresql/tools/partitioning.js.map +1 -1
  167. package/dist/adapters/postgresql/tools/partman/management.d.ts.map +1 -1
  168. package/dist/adapters/postgresql/tools/partman/management.js +12 -5
  169. package/dist/adapters/postgresql/tools/partman/management.js.map +1 -1
  170. package/dist/adapters/postgresql/tools/partman/operations.d.ts.map +1 -1
  171. package/dist/adapters/postgresql/tools/partman/operations.js +135 -22
  172. package/dist/adapters/postgresql/tools/partman/operations.js.map +1 -1
  173. package/dist/adapters/postgresql/tools/performance/analysis.d.ts.map +1 -1
  174. package/dist/adapters/postgresql/tools/performance/analysis.js +264 -160
  175. package/dist/adapters/postgresql/tools/performance/analysis.js.map +1 -1
  176. package/dist/adapters/postgresql/tools/performance/explain.d.ts.map +1 -1
  177. package/dist/adapters/postgresql/tools/performance/explain.js +61 -21
  178. package/dist/adapters/postgresql/tools/performance/explain.js.map +1 -1
  179. package/dist/adapters/postgresql/tools/performance/monitoring.d.ts.map +1 -1
  180. package/dist/adapters/postgresql/tools/performance/monitoring.js +44 -7
  181. package/dist/adapters/postgresql/tools/performance/monitoring.js.map +1 -1
  182. package/dist/adapters/postgresql/tools/performance/optimization.d.ts.map +1 -1
  183. package/dist/adapters/postgresql/tools/performance/optimization.js +92 -81
  184. package/dist/adapters/postgresql/tools/performance/optimization.js.map +1 -1
  185. package/dist/adapters/postgresql/tools/performance/stats.d.ts.map +1 -1
  186. package/dist/adapters/postgresql/tools/performance/stats.js +128 -37
  187. package/dist/adapters/postgresql/tools/performance/stats.js.map +1 -1
  188. package/dist/adapters/postgresql/tools/pgcrypto.d.ts.map +1 -1
  189. package/dist/adapters/postgresql/tools/pgcrypto.js +242 -87
  190. package/dist/adapters/postgresql/tools/pgcrypto.js.map +1 -1
  191. package/dist/adapters/postgresql/tools/postgis/advanced.d.ts.map +1 -1
  192. package/dist/adapters/postgresql/tools/postgis/advanced.js +293 -201
  193. package/dist/adapters/postgresql/tools/postgis/advanced.js.map +1 -1
  194. package/dist/adapters/postgresql/tools/postgis/basic.d.ts.map +1 -1
  195. package/dist/adapters/postgresql/tools/postgis/basic.js +359 -249
  196. package/dist/adapters/postgresql/tools/postgis/basic.js.map +1 -1
  197. package/dist/adapters/postgresql/tools/postgis/standalone.d.ts.map +1 -1
  198. package/dist/adapters/postgresql/tools/postgis/standalone.js +135 -51
  199. package/dist/adapters/postgresql/tools/postgis/standalone.js.map +1 -1
  200. package/dist/adapters/postgresql/tools/schema.d.ts.map +1 -1
  201. package/dist/adapters/postgresql/tools/schema.js +515 -226
  202. package/dist/adapters/postgresql/tools/schema.js.map +1 -1
  203. package/dist/adapters/postgresql/tools/stats/advanced.d.ts.map +1 -1
  204. package/dist/adapters/postgresql/tools/stats/advanced.js +515 -476
  205. package/dist/adapters/postgresql/tools/stats/advanced.js.map +1 -1
  206. package/dist/adapters/postgresql/tools/stats/basic.d.ts.map +1 -1
  207. package/dist/adapters/postgresql/tools/stats/basic.js +302 -293
  208. package/dist/adapters/postgresql/tools/stats/basic.js.map +1 -1
  209. package/dist/adapters/postgresql/tools/text.d.ts.map +1 -1
  210. package/dist/adapters/postgresql/tools/text.js +398 -220
  211. package/dist/adapters/postgresql/tools/text.js.map +1 -1
  212. package/dist/adapters/postgresql/tools/transactions.d.ts.map +1 -1
  213. package/dist/adapters/postgresql/tools/transactions.js +157 -50
  214. package/dist/adapters/postgresql/tools/transactions.js.map +1 -1
  215. package/dist/adapters/postgresql/tools/vector/advanced.d.ts.map +1 -1
  216. package/dist/adapters/postgresql/tools/vector/advanced.js +70 -38
  217. package/dist/adapters/postgresql/tools/vector/advanced.js.map +1 -1
  218. package/dist/adapters/postgresql/tools/vector/basic.d.ts +8 -0
  219. package/dist/adapters/postgresql/tools/vector/basic.d.ts.map +1 -1
  220. package/dist/adapters/postgresql/tools/vector/basic.js +194 -82
  221. package/dist/adapters/postgresql/tools/vector/basic.js.map +1 -1
  222. package/dist/cli/args.d.ts +2 -0
  223. package/dist/cli/args.d.ts.map +1 -1
  224. package/dist/cli/args.js +15 -0
  225. package/dist/cli/args.js.map +1 -1
  226. package/dist/cli.js +7 -6
  227. package/dist/cli.js.map +1 -1
  228. package/dist/codemode/api.d.ts.map +1 -1
  229. package/dist/codemode/api.js +4 -3
  230. package/dist/codemode/api.js.map +1 -1
  231. package/dist/constants/ServerInstructions.d.ts +1 -1
  232. package/dist/constants/ServerInstructions.d.ts.map +1 -1
  233. package/dist/constants/ServerInstructions.js +76 -34
  234. package/dist/constants/ServerInstructions.js.map +1 -1
  235. package/dist/filtering/ToolConstants.d.ts +29 -13
  236. package/dist/filtering/ToolConstants.d.ts.map +1 -1
  237. package/dist/filtering/ToolConstants.js +44 -27
  238. package/dist/filtering/ToolConstants.js.map +1 -1
  239. package/dist/utils/logger.js +2 -2
  240. package/dist/utils/logger.js.map +1 -1
  241. package/dist/utils/progress-utils.js +1 -1
  242. package/dist/utils/progress-utils.js.map +1 -1
  243. package/package.json +13 -9
@@ -14,11 +14,10 @@
14
14
  import { z } from "zod";
15
15
  import { readOnly, write, destructive } from "../../../utils/annotations.js";
16
16
  import { getToolIcons } from "../../../utils/icons.js";
17
- import { KcacheQueryStatsSchema, KcacheDatabaseStatsSchema, KcacheResourceAnalysisSchema,
17
+ import { formatPostgresError } from "./core/error-helpers.js";
18
+ import { KcacheQueryStatsSchemaBase, KcacheQueryStatsSchema, KcacheTopCpuSchemaBase, KcacheTopIoSchemaBase, KcacheDatabaseStatsSchemaBase, KcacheDatabaseStatsSchema, KcacheResourceAnalysisSchemaBase, KcacheResourceAnalysisSchema,
18
19
  // Output schemas
19
20
  KcacheCreateExtensionOutputSchema, KcacheQueryStatsOutputSchema, KcacheTopCpuOutputSchema, KcacheTopIoOutputSchema, KcacheDatabaseStatsOutputSchema, KcacheResourceAnalysisOutputSchema, KcacheResetOutputSchema, } from "../schemas/index.js";
20
- // Helper to handle undefined params (allows tools to be called without {})
21
- const defaultToEmpty = (val) => val ?? {};
22
21
  async function getKcacheColumnNames(adapter) {
23
22
  const result = await adapter.executeQuery(`
24
23
  SELECT column_name FROM information_schema.columns
@@ -105,37 +104,52 @@ Joins pg_stat_statements with pg_stat_kcache to show what SQL did AND what syste
105
104
 
106
105
  orderBy options: 'total_time' (default), 'cpu_time', 'reads', 'writes'. Use minCalls parameter to filter by call count.`,
107
106
  group: "kcache",
108
- inputSchema: KcacheQueryStatsSchema,
107
+ inputSchema: KcacheQueryStatsSchemaBase,
109
108
  outputSchema: KcacheQueryStatsOutputSchema,
110
109
  annotations: readOnly("Kcache Query Stats"),
111
110
  icons: getToolIcons("kcache", readOnly("Kcache Query Stats")),
112
111
  handler: async (params, _context) => {
113
- const { limit, orderBy, minCalls, queryPreviewLength } = KcacheQueryStatsSchema.parse(params);
114
- const cols = await getKcacheColumnNames(adapter);
115
- const DEFAULT_LIMIT = 50;
116
- // limit: 0 means "no limit" (return all rows), undefined means use default
117
- const limitVal = limit === 0 ? null : (limit ?? DEFAULT_LIMIT);
118
- // Bound queryPreviewLength: 0 = full query, default 100, max 500
119
- const previewLen = queryPreviewLength === 0
120
- ? 10000
121
- : Math.min(queryPreviewLength ?? 100, 500);
122
- const orderColumn = orderBy === "cpu_time"
123
- ? `(k.${cols.userTime} + k.${cols.systemTime})`
124
- : orderBy === "reads"
125
- ? `k.${cols.reads}`
126
- : orderBy === "writes"
127
- ? `k.${cols.writes}`
128
- : "s.total_exec_time";
129
- const conditions = [];
130
- const queryParams = [];
131
- let paramIndex = 1;
132
- if (minCalls !== undefined) {
133
- conditions.push(`s.calls >= $${String(paramIndex++)}`);
134
- queryParams.push(minCalls);
135
- }
136
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
137
- // Get total count first for truncation indicator
138
- const countSql = `
112
+ try {
113
+ const { limit, orderBy, minCalls, queryPreviewLength } = KcacheQueryStatsSchema.parse(params);
114
+ // Validate orderBy inside handler for structured error response
115
+ const VALID_ORDER_BY = [
116
+ "total_time",
117
+ "cpu_time",
118
+ "reads",
119
+ "writes",
120
+ ];
121
+ if (orderBy !== undefined &&
122
+ !VALID_ORDER_BY.includes(orderBy)) {
123
+ return {
124
+ success: false,
125
+ error: `Invalid orderBy value "${orderBy}". Valid options: ${VALID_ORDER_BY.join(", ")}`,
126
+ };
127
+ }
128
+ const cols = await getKcacheColumnNames(adapter);
129
+ const DEFAULT_LIMIT = 20;
130
+ // limit: 0 means "no limit" (return all rows), undefined means use default
131
+ const limitVal = limit === 0 ? null : (limit ?? DEFAULT_LIMIT);
132
+ // Bound queryPreviewLength: 0 = full query, default 100, max 500
133
+ const previewLen = queryPreviewLength === 0
134
+ ? 10000
135
+ : Math.min(queryPreviewLength ?? 100, 500);
136
+ const orderColumn = orderBy === "cpu_time"
137
+ ? `(k.${cols.userTime} + k.${cols.systemTime})`
138
+ : orderBy === "reads"
139
+ ? `k.${cols.reads}`
140
+ : orderBy === "writes"
141
+ ? `k.${cols.writes}`
142
+ : "s.total_exec_time";
143
+ const conditions = [];
144
+ const queryParams = [];
145
+ const paramIndex = 1;
146
+ if (minCalls !== undefined) {
147
+ conditions.push(`s.calls >= $${String(paramIndex)}`);
148
+ queryParams.push(minCalls);
149
+ }
150
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
151
+ // Get total count first for truncation indicator
152
+ const countSql = `
139
153
  SELECT COUNT(*) as total
140
154
  FROM pg_stat_statements s
141
155
  JOIN pg_stat_kcache() k ON s.queryid = k.queryid
@@ -143,10 +157,10 @@ orderBy options: 'total_time' (default), 'cpu_time', 'reads', 'writes'. Use minC
143
157
  AND s.dbid = k.dbid
144
158
  ${whereClause}
145
159
  `;
146
- const countResult = await adapter.executeQuery(countSql, queryParams);
147
- const totalRaw = countResult.rows?.[0]?.["total"];
148
- const totalCount = Number(totalRaw) || 0;
149
- const sql = `
160
+ const countResult = await adapter.executeQuery(countSql, queryParams);
161
+ const totalRaw = countResult.rows?.[0]?.["total"];
162
+ const totalCount = Number(totalRaw) || 0;
163
+ const sql = `
150
164
  SELECT
151
165
  s.queryid,
152
166
  LEFT(s.query, ${String(previewLen)}) as query_preview,
@@ -170,17 +184,25 @@ orderBy options: 'total_time' (default), 'cpu_time', 'reads', 'writes'. Use minC
170
184
  ORDER BY ${orderColumn} DESC
171
185
  ${limitVal !== null ? `LIMIT ${String(limitVal)}` : ""}
172
186
  `;
173
- const result = await adapter.executeQuery(sql, queryParams);
174
- const rowCount = result.rows?.length ?? 0;
175
- const truncated = rowCount < totalCount;
176
- const response = {
177
- queries: result.rows ?? [],
178
- count: rowCount,
179
- orderBy: orderBy ?? "total_time",
180
- truncated,
181
- totalCount,
182
- };
183
- return response;
187
+ const result = await adapter.executeQuery(sql, queryParams);
188
+ const rowCount = result.rows?.length ?? 0;
189
+ const effectiveTotalCount = Math.max(totalCount, rowCount);
190
+ const truncated = rowCount < effectiveTotalCount;
191
+ const response = {
192
+ queries: result.rows ?? [],
193
+ count: rowCount,
194
+ orderBy: orderBy ?? "total_time",
195
+ truncated,
196
+ totalCount: effectiveTotalCount,
197
+ };
198
+ return response;
199
+ }
200
+ catch (error) {
201
+ return {
202
+ success: false,
203
+ error: formatPostgresError(error, { tool: "pg_kcache_query_stats" }),
204
+ };
205
+ }
184
206
  },
185
207
  };
186
208
  }
@@ -193,25 +215,28 @@ function createKcacheTopCpuTool(adapter) {
193
215
  description: `Get top CPU-consuming queries. Shows which queries spend the most time
194
216
  in user CPU (application code) vs system CPU (kernel operations).`,
195
217
  group: "kcache",
196
- inputSchema: z.preprocess(defaultToEmpty, z.object({
197
- limit: z
198
- .number()
199
- .optional()
200
- .describe("Number of top queries to return (default: 10)"),
201
- })),
218
+ inputSchema: KcacheTopCpuSchemaBase,
202
219
  outputSchema: KcacheTopCpuOutputSchema,
203
220
  annotations: readOnly("Kcache Top CPU"),
204
221
  icons: getToolIcons("kcache", readOnly("Kcache Top CPU")),
205
222
  handler: async (params, _context) => {
206
- const parsed = z
207
- .object({ limit: z.number().optional() })
208
- .parse(params ?? {});
209
- const DEFAULT_LIMIT = 10;
210
- // limit: 0 means "no limit" (return all rows), undefined means use default
211
- const limitVal = parsed.limit === 0 ? null : (parsed.limit ?? DEFAULT_LIMIT);
212
- const cols = await getKcacheColumnNames(adapter);
213
- // Get total count first for truncation indicator
214
- const countSql = `
223
+ try {
224
+ const parsed = z
225
+ .object({
226
+ limit: z.number().optional(),
227
+ queryPreviewLength: z.number().optional(),
228
+ })
229
+ .parse(params ?? {});
230
+ const DEFAULT_LIMIT = 10;
231
+ // limit: 0 means "no limit" (return all rows), undefined means use default
232
+ const limitVal = parsed.limit === 0 ? null : (parsed.limit ?? DEFAULT_LIMIT);
233
+ // Bound queryPreviewLength: 0 = full query, default 100, max 500
234
+ const previewLen = parsed.queryPreviewLength === 0
235
+ ? 10000
236
+ : Math.min(parsed.queryPreviewLength ?? 100, 500);
237
+ const cols = await getKcacheColumnNames(adapter);
238
+ // Get total count first for truncation indicator
239
+ const countSql = `
215
240
  SELECT COUNT(*) as total
216
241
  FROM pg_stat_statements s
217
242
  JOIN pg_stat_kcache() k ON s.queryid = k.queryid
@@ -219,13 +244,13 @@ in user CPU (application code) vs system CPU (kernel operations).`,
219
244
  AND s.dbid = k.dbid
220
245
  WHERE (k.${cols.userTime} + k.${cols.systemTime}) > 0
221
246
  `;
222
- const countResult = await adapter.executeQuery(countSql);
223
- const totalRaw = countResult.rows?.[0]?.["total"];
224
- const totalCount = Number(totalRaw) || 0;
225
- const sql = `
247
+ const countResult = await adapter.executeQuery(countSql);
248
+ const totalRaw = countResult.rows?.[0]?.["total"];
249
+ const totalCount = Number(totalRaw) || 0;
250
+ const sql = `
226
251
  SELECT
227
252
  s.queryid,
228
- LEFT(s.query, 100) as query_preview,
253
+ LEFT(s.query, ${String(previewLen)}) as query_preview,
229
254
  s.calls,
230
255
  k.${cols.userTime} as user_time,
231
256
  k.${cols.systemTime} as system_time,
@@ -249,17 +274,25 @@ in user CPU (application code) vs system CPU (kernel operations).`,
249
274
  ORDER BY (k.${cols.userTime} + k.${cols.systemTime}) DESC
250
275
  ${limitVal !== null ? `LIMIT ${String(limitVal)}` : ""}
251
276
  `;
252
- const result = await adapter.executeQuery(sql);
253
- const rowCount = result.rows?.length ?? 0;
254
- const truncated = rowCount < totalCount;
255
- const response = {
256
- topCpuQueries: result.rows ?? [],
257
- count: rowCount,
258
- description: "Queries ranked by total CPU time (user + system)",
259
- truncated,
260
- totalCount,
261
- };
262
- return response;
277
+ const result = await adapter.executeQuery(sql);
278
+ const rowCount = result.rows?.length ?? 0;
279
+ const effectiveTotalCount = Math.max(totalCount, rowCount);
280
+ const truncated = rowCount < effectiveTotalCount;
281
+ const response = {
282
+ topCpuQueries: result.rows ?? [],
283
+ count: rowCount,
284
+ description: "Queries ranked by total CPU time (user + system)",
285
+ truncated,
286
+ totalCount: effectiveTotalCount,
287
+ };
288
+ return response;
289
+ }
290
+ catch (error) {
291
+ return {
292
+ success: false,
293
+ error: formatPostgresError(error, { tool: "pg_kcache_top_cpu" }),
294
+ };
295
+ }
263
296
  },
264
297
  };
265
298
  }
@@ -272,71 +305,63 @@ function createKcacheTopIoTool(adapter) {
272
305
  description: `Get top I/O-consuming queries. Shows filesystem-level reads and writes,
273
306
  which represent actual disk access (not just shared buffer hits).`,
274
307
  group: "kcache",
275
- inputSchema: z.preprocess((input) => {
276
- const obj = defaultToEmpty(input);
277
- // Alias: ioType -> type
278
- if (obj["ioType"] !== undefined && obj["type"] === undefined) {
279
- obj["type"] = obj["ioType"];
280
- }
281
- return obj;
282
- }, z.object({
283
- type: z
284
- .enum(["reads", "writes", "both"])
285
- .optional()
286
- .describe("I/O type to rank by (default: both)"),
287
- ioType: z
288
- .enum(["reads", "writes", "both"])
289
- .optional()
290
- .describe("Alias for type"),
291
- limit: z
292
- .number()
293
- .optional()
294
- .describe("Number of top queries to return (default: 10)"),
295
- })),
308
+ inputSchema: KcacheTopIoSchemaBase,
296
309
  outputSchema: KcacheTopIoOutputSchema,
297
310
  annotations: readOnly("Kcache Top IO"),
298
311
  icons: getToolIcons("kcache", readOnly("Kcache Top IO")),
299
312
  handler: async (params, _context) => {
300
- // Apply the same preprocessing as inputSchema
301
- const preprocessed = (() => {
302
- const obj = (params ?? {});
303
- if (obj["ioType"] !== undefined && obj["type"] === undefined) {
304
- return { ...obj, type: obj["ioType"] };
305
- }
306
- return obj;
307
- })();
308
- const parsed = z
309
- .object({
310
- type: z.enum(["reads", "writes", "both"]).optional(),
311
- limit: z.number().optional(),
312
- })
313
- .parse(preprocessed);
314
- const ioType = parsed.type ?? "both";
315
- const DEFAULT_LIMIT = 10;
316
- // limit: 0 means "no limit" (return all rows), undefined means use default
317
- const limitVal = parsed.limit === 0 ? null : (parsed.limit ?? DEFAULT_LIMIT);
318
- const cols = await getKcacheColumnNames(adapter);
319
- const orderColumn = ioType === "reads"
320
- ? `k.${cols.reads}`
321
- : ioType === "writes"
322
- ? `k.${cols.writes}`
323
- : `(k.${cols.reads} + k.${cols.writes})`;
324
- // Get total count first for truncation indicator
325
- const countSql = `
313
+ try {
314
+ // Apply the same preprocessing as inputSchema
315
+ const preprocessed = (() => {
316
+ const obj = (params ?? {});
317
+ if (obj["ioType"] !== undefined && obj["type"] === undefined) {
318
+ return { ...obj, type: obj["ioType"] };
319
+ }
320
+ return obj;
321
+ })();
322
+ const parsed = z
323
+ .object({
324
+ type: z.enum(["reads", "writes", "both"]).optional(),
325
+ limit: z.number().optional(),
326
+ queryPreviewLength: z.number().optional(),
327
+ })
328
+ .parse(preprocessed);
329
+ const ioType = parsed.type ?? "both";
330
+ const DEFAULT_LIMIT = 10;
331
+ // limit: 0 means "no limit" (return all rows), undefined means use default
332
+ const limitVal = parsed.limit === 0 ? null : (parsed.limit ?? DEFAULT_LIMIT);
333
+ // Bound queryPreviewLength: 0 = full query, default 100, max 500
334
+ const previewLen = parsed.queryPreviewLength === 0
335
+ ? 10000
336
+ : Math.min(parsed.queryPreviewLength ?? 100, 500);
337
+ const cols = await getKcacheColumnNames(adapter);
338
+ const orderColumn = ioType === "reads"
339
+ ? `k.${cols.reads}`
340
+ : ioType === "writes"
341
+ ? `k.${cols.writes}`
342
+ : `(k.${cols.reads} + k.${cols.writes})`;
343
+ // Filter by the type-specific IO column so 'reads' excludes write-only queries
344
+ const ioFilter = ioType === "reads"
345
+ ? `k.${cols.reads} > 0`
346
+ : ioType === "writes"
347
+ ? `k.${cols.writes} > 0`
348
+ : `(k.${cols.reads} + k.${cols.writes}) > 0`;
349
+ // Get total count first for truncation indicator
350
+ const countSql = `
326
351
  SELECT COUNT(*) as total
327
352
  FROM pg_stat_statements s
328
353
  JOIN pg_stat_kcache() k ON s.queryid = k.queryid
329
354
  AND s.userid = k.userid
330
355
  AND s.dbid = k.dbid
331
- WHERE (k.${cols.reads} + k.${cols.writes}) > 0
356
+ WHERE ${ioFilter}
332
357
  `;
333
- const countResult = await adapter.executeQuery(countSql);
334
- const totalRaw = countResult.rows?.[0]?.["total"];
335
- const totalCount = Number(totalRaw) || 0;
336
- const sql = `
358
+ const countResult = await adapter.executeQuery(countSql);
359
+ const totalRaw = countResult.rows?.[0]?.["total"];
360
+ const totalCount = Number(totalRaw) || 0;
361
+ const sql = `
337
362
  SELECT
338
363
  s.queryid,
339
- LEFT(s.query, 100) as query_preview,
364
+ LEFT(s.query, ${String(previewLen)}) as query_preview,
340
365
  s.calls,
341
366
  k.${cols.reads} as read_bytes,
342
367
  k.${cols.writes} as write_bytes,
@@ -348,22 +373,30 @@ which represent actual disk access (not just shared buffer hits).`,
348
373
  JOIN pg_stat_kcache() k ON s.queryid = k.queryid
349
374
  AND s.userid = k.userid
350
375
  AND s.dbid = k.dbid
351
- WHERE (k.${cols.reads} + k.${cols.writes}) > 0
376
+ WHERE ${ioFilter}
352
377
  ORDER BY ${orderColumn} DESC
353
378
  ${limitVal !== null ? `LIMIT ${String(limitVal)}` : ""}
354
379
  `;
355
- const result = await adapter.executeQuery(sql);
356
- const rowCount = result.rows?.length ?? 0;
357
- const truncated = rowCount < totalCount;
358
- const response = {
359
- topIoQueries: result.rows ?? [],
360
- count: rowCount,
361
- ioType,
362
- description: `Queries ranked by ${ioType === "both" ? "total I/O" : ioType}`,
363
- truncated,
364
- totalCount,
365
- };
366
- return response;
380
+ const result = await adapter.executeQuery(sql);
381
+ const rowCount = result.rows?.length ?? 0;
382
+ const effectiveTotalCount = Math.max(totalCount, rowCount);
383
+ const truncated = rowCount < effectiveTotalCount;
384
+ const response = {
385
+ topIoQueries: result.rows ?? [],
386
+ count: rowCount,
387
+ ioType,
388
+ description: `Queries ranked by ${ioType === "both" ? "total I/O" : ioType}`,
389
+ truncated,
390
+ totalCount: effectiveTotalCount,
391
+ };
392
+ return response;
393
+ }
394
+ catch (error) {
395
+ return {
396
+ success: false,
397
+ error: formatPostgresError(error, { tool: "pg_kcache_top_io" }),
398
+ };
399
+ }
367
400
  },
368
401
  };
369
402
  }
@@ -376,17 +409,18 @@ function createKcacheDatabaseStatsTool(adapter) {
376
409
  description: `Get aggregated OS-level statistics for a database.
377
410
  Shows total CPU time, I/O, and page faults across all queries.`,
378
411
  group: "kcache",
379
- inputSchema: KcacheDatabaseStatsSchema,
412
+ inputSchema: KcacheDatabaseStatsSchemaBase,
380
413
  outputSchema: KcacheDatabaseStatsOutputSchema,
381
414
  annotations: readOnly("Kcache Database Stats"),
382
415
  icons: getToolIcons("kcache", readOnly("Kcache Database Stats")),
383
416
  handler: async (params, _context) => {
384
- const { database } = KcacheDatabaseStatsSchema.parse(params);
385
- const cols = await getKcacheColumnNames(adapter);
386
- let sql;
387
- const queryParams = [];
388
- if (database !== undefined) {
389
- sql = `
417
+ try {
418
+ const { database } = KcacheDatabaseStatsSchema.parse(params);
419
+ const cols = await getKcacheColumnNames(adapter);
420
+ let sql;
421
+ const queryParams = [];
422
+ if (database !== undefined) {
423
+ sql = `
390
424
  SELECT
391
425
  d.datname as database,
392
426
  SUM(k.${cols.userTime}) as total_user_time,
@@ -404,10 +438,10 @@ Shows total CPU time, I/O, and page faults across all queries.`,
404
438
  WHERE d.datname = $1
405
439
  GROUP BY d.datname
406
440
  `;
407
- queryParams.push(database);
408
- }
409
- else {
410
- sql = `
441
+ queryParams.push(database);
442
+ }
443
+ else {
444
+ sql = `
411
445
  SELECT
412
446
  datname as database,
413
447
  SUM(${cols.userTime}) as total_user_time,
@@ -424,12 +458,21 @@ Shows total CPU time, I/O, and page faults across all queries.`,
424
458
  GROUP BY datname
425
459
  ORDER BY SUM(${cols.userTime} + ${cols.systemTime}) DESC
426
460
  `;
461
+ }
462
+ const result = await adapter.executeQuery(sql, queryParams);
463
+ return {
464
+ databaseStats: result.rows ?? [],
465
+ count: result.rows?.length ?? 0,
466
+ };
467
+ }
468
+ catch (error) {
469
+ return {
470
+ success: false,
471
+ error: formatPostgresError(error, {
472
+ tool: "pg_kcache_database_stats",
473
+ }),
474
+ };
427
475
  }
428
- const result = await adapter.executeQuery(sql, queryParams);
429
- return {
430
- databaseStats: result.rows ?? [],
431
- count: result.rows?.length ?? 0,
432
- };
433
476
  },
434
477
  };
435
478
  }
@@ -442,36 +485,37 @@ function createKcacheResourceAnalysisTool(adapter) {
442
485
  description: `Analyze queries to classify them as CPU-bound, I/O-bound, or balanced.
443
486
  Helps identify the root cause of performance issues - is the query computation-heavy or disk-heavy?`,
444
487
  group: "kcache",
445
- inputSchema: KcacheResourceAnalysisSchema,
488
+ inputSchema: KcacheResourceAnalysisSchemaBase,
446
489
  outputSchema: KcacheResourceAnalysisOutputSchema,
447
490
  annotations: readOnly("Kcache Resource Analysis"),
448
491
  icons: getToolIcons("kcache", readOnly("Kcache Resource Analysis")),
449
492
  handler: async (params, _context) => {
450
- const { queryId, threshold, limit, minCalls, queryPreviewLength } = KcacheResourceAnalysisSchema.parse(params);
451
- const thresholdVal = threshold ?? 0.5;
452
- const DEFAULT_LIMIT = 50;
453
- // limit: 0 means "no limit" (return all rows), undefined means use default
454
- const limitVal = limit === 0 ? null : (limit ?? DEFAULT_LIMIT);
455
- // Bound queryPreviewLength: 0 = full query, default 100, max 500
456
- const previewLen = queryPreviewLength === 0
457
- ? 10000
458
- : Math.min(queryPreviewLength ?? 100, 500);
459
- const cols = await getKcacheColumnNames(adapter);
460
- const conditions = [];
461
- const queryParams = [];
462
- let paramIndex = 1;
463
- if (queryId !== undefined) {
464
- conditions.push(`s.queryid::text = $${String(paramIndex++)}`);
465
- queryParams.push(queryId);
466
- }
467
- if (minCalls !== undefined) {
468
- conditions.push(`s.calls >= $${String(paramIndex++)}`);
469
- queryParams.push(minCalls);
470
- }
471
- conditions.push(`(k.${cols.userTime} + k.${cols.systemTime} + k.${cols.reads} + k.${cols.writes}) > 0`);
472
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
473
- // Get total count first for truncation indicator
474
- const countSql = `
493
+ try {
494
+ const { queryId, threshold, limit, minCalls, queryPreviewLength } = KcacheResourceAnalysisSchema.parse(params);
495
+ const thresholdVal = threshold ?? 0.5;
496
+ const DEFAULT_LIMIT = 20;
497
+ // limit: 0 means "no limit" (return all rows), undefined means use default
498
+ const limitVal = limit === 0 ? null : (limit ?? DEFAULT_LIMIT);
499
+ // Bound queryPreviewLength: 0 = full query, default 100, max 500
500
+ const previewLen = queryPreviewLength === 0
501
+ ? 10000
502
+ : Math.min(queryPreviewLength ?? 100, 500);
503
+ const cols = await getKcacheColumnNames(adapter);
504
+ const conditions = [];
505
+ const queryParams = [];
506
+ let paramIndex = 1;
507
+ if (queryId !== undefined) {
508
+ conditions.push(`s.queryid::text = $${String(paramIndex++)}`);
509
+ queryParams.push(queryId);
510
+ }
511
+ if (minCalls !== undefined) {
512
+ conditions.push(`s.calls >= $${String(paramIndex)}`);
513
+ queryParams.push(minCalls);
514
+ }
515
+ conditions.push(`(k.${cols.userTime} + k.${cols.systemTime} + k.${cols.reads} + k.${cols.writes}) > 0`);
516
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
517
+ // Get total count first for truncation indicator
518
+ const countSql = `
475
519
  SELECT COUNT(*) as total
476
520
  FROM pg_stat_statements s
477
521
  JOIN pg_stat_kcache() k ON s.queryid = k.queryid
@@ -479,10 +523,10 @@ Helps identify the root cause of performance issues - is the query computation-h
479
523
  AND s.dbid = k.dbid
480
524
  ${whereClause}
481
525
  `;
482
- const countResult = await adapter.executeQuery(countSql, queryParams);
483
- const totalRaw = countResult.rows?.[0]?.["total"];
484
- const totalCount = Number(totalRaw) || 0;
485
- const sql = `
526
+ const countResult = await adapter.executeQuery(countSql, queryParams);
527
+ const totalRaw = countResult.rows?.[0]?.["total"];
528
+ const totalCount = Number(totalRaw) || 0;
529
+ const sql = `
486
530
  WITH query_metrics AS (
487
531
  SELECT
488
532
  s.queryid,
@@ -528,32 +572,42 @@ Helps identify the root cause of performance issues - is the query computation-h
528
572
  ORDER BY total_time_ms DESC
529
573
  ${limitVal !== null ? `LIMIT ${String(limitVal)}` : ""}
530
574
  `;
531
- const result = await adapter.executeQuery(sql, queryParams);
532
- const rows = result.rows ?? [];
533
- const truncated = rows.length < totalCount;
534
- const cpuBound = rows.filter((r) => r["resource_classification"] === "CPU-bound").length;
535
- const ioBound = rows.filter((r) => r["resource_classification"] === "I/O-bound").length;
536
- const balanced = rows.filter((r) => r["resource_classification"] === "Balanced").length;
537
- const response = {
538
- queries: rows,
539
- count: rows.length,
540
- summary: {
541
- cpuBound,
542
- ioBound,
543
- balanced,
544
- threshold: thresholdVal,
545
- },
546
- recommendations: [
547
- cpuBound > ioBound
548
- ? "Most resource-intensive queries are CPU-bound. Consider query optimization or more CPU resources."
549
- : ioBound > cpuBound
550
- ? "Most resource-intensive queries are I/O-bound. Consider more memory, faster storage, or better indexing."
551
- : "Resource usage is balanced between CPU and I/O.",
552
- ],
553
- truncated,
554
- totalCount,
555
- };
556
- return response;
575
+ const result = await adapter.executeQuery(sql, queryParams);
576
+ const rows = result.rows ?? [];
577
+ const effectiveTotalCount = Math.max(totalCount, rows.length);
578
+ const truncated = rows.length < effectiveTotalCount;
579
+ const cpuBound = rows.filter((r) => r["resource_classification"] === "CPU-bound").length;
580
+ const ioBound = rows.filter((r) => r["resource_classification"] === "I/O-bound").length;
581
+ const balanced = rows.filter((r) => r["resource_classification"] === "Balanced").length;
582
+ const response = {
583
+ queries: rows,
584
+ count: rows.length,
585
+ summary: {
586
+ cpuBound,
587
+ ioBound,
588
+ balanced,
589
+ threshold: thresholdVal,
590
+ },
591
+ recommendations: [
592
+ cpuBound > ioBound
593
+ ? "Most resource-intensive queries are CPU-bound. Consider query optimization or more CPU resources."
594
+ : ioBound > cpuBound
595
+ ? "Most resource-intensive queries are I/O-bound. Consider more memory, faster storage, or better indexing."
596
+ : "Resource usage is balanced between CPU and I/O.",
597
+ ],
598
+ truncated,
599
+ totalCount: effectiveTotalCount,
600
+ };
601
+ return response;
602
+ }
603
+ catch (error) {
604
+ return {
605
+ success: false,
606
+ error: formatPostgresError(error, {
607
+ tool: "pg_kcache_resource_analysis",
608
+ }),
609
+ };
610
+ }
557
611
  },
558
612
  };
559
613
  }
@@ -571,12 +625,20 @@ Note: This also resets pg_stat_statements statistics.`,
571
625
  annotations: destructive("Reset Kcache Stats"),
572
626
  icons: getToolIcons("kcache", destructive("Reset Kcache Stats")),
573
627
  handler: async (_params, _context) => {
574
- await adapter.executeQuery("SELECT pg_stat_kcache_reset()");
575
- return {
576
- success: true,
577
- message: "pg_stat_kcache statistics reset",
578
- note: "pg_stat_statements statistics were also reset",
579
- };
628
+ try {
629
+ await adapter.executeQuery("SELECT pg_stat_kcache_reset()");
630
+ return {
631
+ success: true,
632
+ message: "pg_stat_kcache statistics reset",
633
+ note: "pg_stat_statements statistics were also reset",
634
+ };
635
+ }
636
+ catch (error) {
637
+ return {
638
+ success: false,
639
+ error: formatPostgresError(error, { tool: "pg_kcache_reset" }),
640
+ };
641
+ }
580
642
  },
581
643
  };
582
644
  }