@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.
- package/README.md +95 -81
- package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
- package/dist/__tests__/mocks/adapter.js +0 -1
- package/dist/__tests__/mocks/adapter.js.map +1 -1
- package/dist/__tests__/mocks/pool.d.ts.map +1 -1
- package/dist/__tests__/mocks/pool.js +0 -1
- package/dist/__tests__/mocks/pool.js.map +1 -1
- package/dist/adapters/DatabaseAdapter.js +1 -1
- package/dist/adapters/DatabaseAdapter.js.map +1 -1
- package/dist/adapters/postgresql/PostgresAdapter.d.ts.map +1 -1
- package/dist/adapters/postgresql/PostgresAdapter.js +78 -8
- package/dist/adapters/postgresql/PostgresAdapter.js.map +1 -1
- package/dist/adapters/postgresql/prompts/backup.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/backup.js +2 -3
- package/dist/adapters/postgresql/prompts/backup.js.map +1 -1
- package/dist/adapters/postgresql/prompts/citext.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/citext.js +3 -4
- package/dist/adapters/postgresql/prompts/citext.js.map +1 -1
- package/dist/adapters/postgresql/prompts/extensionSetup.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/extensionSetup.js +2 -3
- package/dist/adapters/postgresql/prompts/extensionSetup.js.map +1 -1
- package/dist/adapters/postgresql/prompts/health.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/health.js +2 -3
- package/dist/adapters/postgresql/prompts/health.js.map +1 -1
- package/dist/adapters/postgresql/prompts/index.js +20 -27
- package/dist/adapters/postgresql/prompts/index.js.map +1 -1
- package/dist/adapters/postgresql/prompts/indexTuning.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/indexTuning.js +2 -3
- package/dist/adapters/postgresql/prompts/indexTuning.js.map +1 -1
- package/dist/adapters/postgresql/prompts/kcache.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/kcache.js +3 -4
- package/dist/adapters/postgresql/prompts/kcache.js.map +1 -1
- package/dist/adapters/postgresql/prompts/ltree.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/ltree.js +5 -6
- package/dist/adapters/postgresql/prompts/ltree.js.map +1 -1
- package/dist/adapters/postgresql/prompts/partman.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/partman.js +2 -3
- package/dist/adapters/postgresql/prompts/partman.js.map +1 -1
- package/dist/adapters/postgresql/prompts/pgcron.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/pgcron.js +2 -3
- package/dist/adapters/postgresql/prompts/pgcron.js.map +1 -1
- package/dist/adapters/postgresql/prompts/pgcrypto.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/pgcrypto.js +3 -4
- package/dist/adapters/postgresql/prompts/pgcrypto.js.map +1 -1
- package/dist/adapters/postgresql/prompts/pgvector.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/pgvector.js +3 -4
- package/dist/adapters/postgresql/prompts/pgvector.js.map +1 -1
- package/dist/adapters/postgresql/prompts/postgis.d.ts.map +1 -1
- package/dist/adapters/postgresql/prompts/postgis.js +2 -3
- package/dist/adapters/postgresql/prompts/postgis.js.map +1 -1
- package/dist/adapters/postgresql/schemas/admin.d.ts +10 -5
- package/dist/adapters/postgresql/schemas/admin.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/admin.js +10 -5
- package/dist/adapters/postgresql/schemas/admin.js.map +1 -1
- package/dist/adapters/postgresql/schemas/backup.d.ts +8 -4
- package/dist/adapters/postgresql/schemas/backup.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/backup.js +11 -4
- package/dist/adapters/postgresql/schemas/backup.js.map +1 -1
- package/dist/adapters/postgresql/schemas/core.d.ts +54 -19
- package/dist/adapters/postgresql/schemas/core.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/core.js +65 -17
- package/dist/adapters/postgresql/schemas/core.js.map +1 -1
- package/dist/adapters/postgresql/schemas/cron.d.ts +51 -32
- package/dist/adapters/postgresql/schemas/cron.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/cron.js +64 -44
- package/dist/adapters/postgresql/schemas/cron.js.map +1 -1
- package/dist/adapters/postgresql/schemas/extensions.d.ts +168 -73
- package/dist/adapters/postgresql/schemas/extensions.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/extensions.js +179 -62
- package/dist/adapters/postgresql/schemas/extensions.js.map +1 -1
- package/dist/adapters/postgresql/schemas/index.d.ts +5 -5
- package/dist/adapters/postgresql/schemas/index.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/index.js +9 -7
- package/dist/adapters/postgresql/schemas/index.js.map +1 -1
- package/dist/adapters/postgresql/schemas/jsonb.d.ts +94 -42
- package/dist/adapters/postgresql/schemas/jsonb.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/jsonb.js +101 -30
- package/dist/adapters/postgresql/schemas/jsonb.js.map +1 -1
- package/dist/adapters/postgresql/schemas/monitoring.d.ts +28 -11
- package/dist/adapters/postgresql/schemas/monitoring.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/monitoring.js +49 -24
- package/dist/adapters/postgresql/schemas/monitoring.js.map +1 -1
- package/dist/adapters/postgresql/schemas/partitioning.d.ts +15 -11
- package/dist/adapters/postgresql/schemas/partitioning.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/partitioning.js +17 -13
- package/dist/adapters/postgresql/schemas/partitioning.js.map +1 -1
- package/dist/adapters/postgresql/schemas/performance.d.ts +62 -31
- package/dist/adapters/postgresql/schemas/performance.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/performance.js +86 -24
- package/dist/adapters/postgresql/schemas/performance.js.map +1 -1
- package/dist/adapters/postgresql/schemas/postgis.d.ts +20 -0
- package/dist/adapters/postgresql/schemas/postgis.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/postgis.js +20 -3
- package/dist/adapters/postgresql/schemas/postgis.js.map +1 -1
- package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts +35 -23
- package/dist/adapters/postgresql/schemas/schema-mgmt.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/schema-mgmt.js +69 -26
- package/dist/adapters/postgresql/schemas/schema-mgmt.js.map +1 -1
- package/dist/adapters/postgresql/schemas/stats.d.ts +33 -20
- package/dist/adapters/postgresql/schemas/stats.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/stats.js +36 -20
- package/dist/adapters/postgresql/schemas/stats.js.map +1 -1
- package/dist/adapters/postgresql/schemas/text-search.d.ts +8 -5
- package/dist/adapters/postgresql/schemas/text-search.d.ts.map +1 -1
- package/dist/adapters/postgresql/schemas/text-search.js +15 -5
- package/dist/adapters/postgresql/schemas/text-search.js.map +1 -1
- package/dist/adapters/postgresql/tools/admin.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/admin.js +211 -140
- package/dist/adapters/postgresql/tools/admin.js.map +1 -1
- package/dist/adapters/postgresql/tools/backup/dump.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/backup/dump.js +410 -387
- package/dist/adapters/postgresql/tools/backup/dump.js.map +1 -1
- package/dist/adapters/postgresql/tools/backup/planning.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/backup/planning.js +175 -172
- package/dist/adapters/postgresql/tools/backup/planning.js.map +1 -1
- package/dist/adapters/postgresql/tools/citext.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/citext.js +221 -163
- package/dist/adapters/postgresql/tools/citext.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/convenience.d.ts +9 -1
- package/dist/adapters/postgresql/tools/core/convenience.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/convenience.js +96 -9
- package/dist/adapters/postgresql/tools/core/convenience.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/error-helpers.d.ts +48 -0
- package/dist/adapters/postgresql/tools/core/error-helpers.d.ts.map +1 -0
- package/dist/adapters/postgresql/tools/core/error-helpers.js +256 -0
- package/dist/adapters/postgresql/tools/core/error-helpers.js.map +1 -0
- package/dist/adapters/postgresql/tools/core/health.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/health.js +23 -6
- package/dist/adapters/postgresql/tools/core/health.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/indexes.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/indexes.js +45 -4
- package/dist/adapters/postgresql/tools/core/indexes.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/objects.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/objects.js +104 -85
- package/dist/adapters/postgresql/tools/core/objects.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/query.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/query.js +100 -42
- package/dist/adapters/postgresql/tools/core/query.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/schemas.d.ts +52 -25
- package/dist/adapters/postgresql/tools/core/schemas.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/schemas.js +55 -25
- package/dist/adapters/postgresql/tools/core/schemas.js.map +1 -1
- package/dist/adapters/postgresql/tools/core/tables.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/core/tables.js +74 -30
- package/dist/adapters/postgresql/tools/core/tables.js.map +1 -1
- package/dist/adapters/postgresql/tools/cron.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/cron.js +274 -179
- package/dist/adapters/postgresql/tools/cron.js.map +1 -1
- package/dist/adapters/postgresql/tools/jsonb/advanced.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/jsonb/advanced.js +372 -284
- package/dist/adapters/postgresql/tools/jsonb/advanced.js.map +1 -1
- package/dist/adapters/postgresql/tools/jsonb/basic.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/jsonb/basic.js +617 -398
- package/dist/adapters/postgresql/tools/jsonb/basic.js.map +1 -1
- package/dist/adapters/postgresql/tools/kcache.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/kcache.js +282 -220
- package/dist/adapters/postgresql/tools/kcache.js.map +1 -1
- package/dist/adapters/postgresql/tools/ltree.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/ltree.js +126 -35
- package/dist/adapters/postgresql/tools/ltree.js.map +1 -1
- package/dist/adapters/postgresql/tools/monitoring.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/monitoring.js +59 -40
- package/dist/adapters/postgresql/tools/monitoring.js.map +1 -1
- package/dist/adapters/postgresql/tools/partitioning.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/partitioning.js +150 -15
- package/dist/adapters/postgresql/tools/partitioning.js.map +1 -1
- package/dist/adapters/postgresql/tools/partman/management.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/partman/management.js +12 -5
- package/dist/adapters/postgresql/tools/partman/management.js.map +1 -1
- package/dist/adapters/postgresql/tools/partman/operations.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/partman/operations.js +135 -22
- package/dist/adapters/postgresql/tools/partman/operations.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/analysis.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/analysis.js +264 -160
- package/dist/adapters/postgresql/tools/performance/analysis.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/explain.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/explain.js +61 -21
- package/dist/adapters/postgresql/tools/performance/explain.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/monitoring.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/monitoring.js +44 -7
- package/dist/adapters/postgresql/tools/performance/monitoring.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/optimization.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/optimization.js +92 -81
- package/dist/adapters/postgresql/tools/performance/optimization.js.map +1 -1
- package/dist/adapters/postgresql/tools/performance/stats.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/performance/stats.js +128 -37
- package/dist/adapters/postgresql/tools/performance/stats.js.map +1 -1
- package/dist/adapters/postgresql/tools/pgcrypto.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/pgcrypto.js +242 -87
- package/dist/adapters/postgresql/tools/pgcrypto.js.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/advanced.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/advanced.js +293 -201
- package/dist/adapters/postgresql/tools/postgis/advanced.js.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/basic.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/basic.js +359 -249
- package/dist/adapters/postgresql/tools/postgis/basic.js.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/standalone.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/postgis/standalone.js +135 -51
- package/dist/adapters/postgresql/tools/postgis/standalone.js.map +1 -1
- package/dist/adapters/postgresql/tools/schema.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/schema.js +515 -226
- package/dist/adapters/postgresql/tools/schema.js.map +1 -1
- package/dist/adapters/postgresql/tools/stats/advanced.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/stats/advanced.js +515 -476
- package/dist/adapters/postgresql/tools/stats/advanced.js.map +1 -1
- package/dist/adapters/postgresql/tools/stats/basic.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/stats/basic.js +302 -293
- package/dist/adapters/postgresql/tools/stats/basic.js.map +1 -1
- package/dist/adapters/postgresql/tools/text.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/text.js +398 -220
- package/dist/adapters/postgresql/tools/text.js.map +1 -1
- package/dist/adapters/postgresql/tools/transactions.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/transactions.js +157 -50
- package/dist/adapters/postgresql/tools/transactions.js.map +1 -1
- package/dist/adapters/postgresql/tools/vector/advanced.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/vector/advanced.js +70 -38
- package/dist/adapters/postgresql/tools/vector/advanced.js.map +1 -1
- package/dist/adapters/postgresql/tools/vector/basic.d.ts +8 -0
- package/dist/adapters/postgresql/tools/vector/basic.d.ts.map +1 -1
- package/dist/adapters/postgresql/tools/vector/basic.js +194 -82
- package/dist/adapters/postgresql/tools/vector/basic.js.map +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +15 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli.js +7 -6
- package/dist/cli.js.map +1 -1
- package/dist/codemode/api.d.ts.map +1 -1
- package/dist/codemode/api.js +4 -3
- package/dist/codemode/api.js.map +1 -1
- package/dist/constants/ServerInstructions.d.ts +1 -1
- package/dist/constants/ServerInstructions.d.ts.map +1 -1
- package/dist/constants/ServerInstructions.js +76 -34
- package/dist/constants/ServerInstructions.js.map +1 -1
- package/dist/filtering/ToolConstants.d.ts +29 -13
- package/dist/filtering/ToolConstants.d.ts.map +1 -1
- package/dist/filtering/ToolConstants.js +44 -27
- package/dist/filtering/ToolConstants.js.map +1 -1
- package/dist/utils/logger.js +2 -2
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/progress-utils.js +1 -1
- package/dist/utils/progress-utils.js.map +1 -1
- package/package.json +13 -9
|
@@ -8,9 +8,22 @@ 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";
|
|
15
|
+
/**
|
|
16
|
+
* Well-known aliases for PostgreSQL extension names.
|
|
17
|
+
* Users naturally write "pgvector" but the extension registers as "vector".
|
|
18
|
+
* This map normalizes user input so exclude filters work correctly.
|
|
19
|
+
*/
|
|
20
|
+
const EXTENSION_ALIASES = {
|
|
21
|
+
pgvector: "vector",
|
|
22
|
+
vector: "vector",
|
|
23
|
+
partman: "pg_partman",
|
|
24
|
+
fuzzymatch: "fuzzystrmatch",
|
|
25
|
+
fuzzy: "fuzzystrmatch",
|
|
26
|
+
};
|
|
14
27
|
/**
|
|
15
28
|
* Get all schema management tools
|
|
16
29
|
*/
|
|
@@ -55,25 +68,47 @@ function createCreateSchemaTool(adapter) {
|
|
|
55
68
|
annotations: write("Create Schema"),
|
|
56
69
|
icons: getToolIcons("schema", write("Create Schema")),
|
|
57
70
|
handler: async (params, _context) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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;
|
|
64
103
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const result = { success: true, schema: name };
|
|
73
|
-
if (alreadyExisted !== undefined) {
|
|
74
|
-
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
|
+
};
|
|
75
111
|
}
|
|
76
|
-
return result;
|
|
77
112
|
},
|
|
78
113
|
};
|
|
79
114
|
}
|
|
@@ -87,23 +122,44 @@ function createDropSchemaTool(adapter) {
|
|
|
87
122
|
annotations: destructive("Drop Schema"),
|
|
88
123
|
icons: getToolIcons("schema", destructive("Drop Schema")),
|
|
89
124
|
handler: async (params, _context) => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
}
|
|
107
163
|
},
|
|
108
164
|
};
|
|
109
165
|
}
|
|
@@ -122,8 +178,10 @@ function createListSequencesTool(adapter) {
|
|
|
122
178
|
icons: getToolIcons("schema", readOnly("List Sequences")),
|
|
123
179
|
handler: async (params, _context) => {
|
|
124
180
|
const parsed = (params ?? {});
|
|
181
|
+
const queryParams = [];
|
|
125
182
|
const schemaClause = parsed.schema
|
|
126
|
-
?
|
|
183
|
+
? (queryParams.push(parsed.schema),
|
|
184
|
+
`AND n.nspname = $${String(queryParams.length)}`)
|
|
127
185
|
: "";
|
|
128
186
|
// Use subquery for owned_by to avoid duplicate rows from JOINs
|
|
129
187
|
const sql = `SELECT n.nspname as schema, c.relname as name,
|
|
@@ -139,7 +197,9 @@ function createListSequencesTool(adapter) {
|
|
|
139
197
|
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
140
198
|
${schemaClause}
|
|
141
199
|
ORDER BY n.nspname, c.relname`;
|
|
142
|
-
const result =
|
|
200
|
+
const result = queryParams.length > 0
|
|
201
|
+
? await adapter.executeQuery(sql, queryParams)
|
|
202
|
+
: await adapter.executeQuery(sql);
|
|
143
203
|
return { sequences: result.rows, count: result.rows?.length ?? 0 };
|
|
144
204
|
},
|
|
145
205
|
};
|
|
@@ -154,44 +214,78 @@ function createCreateSequenceTool(adapter) {
|
|
|
154
214
|
annotations: write("Create Sequence"),
|
|
155
215
|
icons: getToolIcons("schema", write("Create Sequence")),
|
|
156
216
|
handler: async (params, _context) => {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
217
|
+
try {
|
|
218
|
+
const { name, schema, start, increment, minValue, maxValue, cache, cycle, ownedBy, ifNotExists, } = CreateSequenceSchema.parse(params);
|
|
219
|
+
const schemaName = schema ?? "public";
|
|
220
|
+
// Check if sequence already exists when ifNotExists is true
|
|
221
|
+
let alreadyExisted;
|
|
222
|
+
if (ifNotExists === true) {
|
|
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 = $1 AND c.relname = $2`, [schemaName, name]);
|
|
224
|
+
alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
|
|
225
|
+
}
|
|
226
|
+
const schemaPrefix = schema ? `${sanitizeIdentifier(schema)}.` : "";
|
|
227
|
+
const ifNotExistsClause = ifNotExists === true ? "IF NOT EXISTS " : "";
|
|
228
|
+
const parts = [
|
|
229
|
+
`CREATE SEQUENCE ${ifNotExistsClause}${schemaPrefix}${sanitizeIdentifier(name)}`,
|
|
230
|
+
];
|
|
231
|
+
if (start !== undefined)
|
|
232
|
+
parts.push(`START WITH ${String(start)}`);
|
|
233
|
+
if (increment !== undefined)
|
|
234
|
+
parts.push(`INCREMENT BY ${String(increment)}`);
|
|
235
|
+
if (minValue !== undefined)
|
|
236
|
+
parts.push(`MINVALUE ${String(minValue)}`);
|
|
237
|
+
if (maxValue !== undefined)
|
|
238
|
+
parts.push(`MAXVALUE ${String(maxValue)}`);
|
|
239
|
+
if (cache !== undefined)
|
|
240
|
+
parts.push(`CACHE ${String(cache)}`);
|
|
241
|
+
if (cycle)
|
|
242
|
+
parts.push("CYCLE");
|
|
243
|
+
if (ownedBy !== undefined) {
|
|
244
|
+
// Validate and sanitize ownedBy: table.column or schema.table.column
|
|
245
|
+
const ownedByParts = ownedBy.split(".");
|
|
246
|
+
if (ownedByParts.length < 2 || ownedByParts.length > 3) {
|
|
247
|
+
return {
|
|
248
|
+
success: false,
|
|
249
|
+
error: `Invalid ownedBy format: '${ownedBy}'. Expected 'table.column' or 'schema.table.column'.`,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const sanitizedOwnedBy = ownedByParts
|
|
253
|
+
.map((p) => sanitizeIdentifier(p))
|
|
254
|
+
.join(".");
|
|
255
|
+
parts.push(`OWNED BY ${sanitizedOwnedBy}`);
|
|
256
|
+
}
|
|
257
|
+
const sql = parts.join(" ");
|
|
258
|
+
try {
|
|
259
|
+
await adapter.executeQuery(sql);
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
return {
|
|
263
|
+
success: false,
|
|
264
|
+
error: formatPostgresError(error, {
|
|
265
|
+
tool: "pg_create_sequence",
|
|
266
|
+
objectType: "sequence",
|
|
267
|
+
...(schema !== undefined && { schema }),
|
|
268
|
+
}),
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const result = {
|
|
272
|
+
success: true,
|
|
273
|
+
sequence: `${schemaName}.${name}`,
|
|
274
|
+
ifNotExists: ifNotExists ?? false,
|
|
275
|
+
};
|
|
276
|
+
if (alreadyExisted !== undefined) {
|
|
277
|
+
result["alreadyExisted"] = alreadyExisted;
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
164
280
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (increment !== undefined)
|
|
173
|
-
parts.push(`INCREMENT BY ${String(increment)}`);
|
|
174
|
-
if (minValue !== undefined)
|
|
175
|
-
parts.push(`MINVALUE ${String(minValue)}`);
|
|
176
|
-
if (maxValue !== undefined)
|
|
177
|
-
parts.push(`MAXVALUE ${String(maxValue)}`);
|
|
178
|
-
if (cache !== undefined)
|
|
179
|
-
parts.push(`CACHE ${String(cache)}`);
|
|
180
|
-
if (cycle)
|
|
181
|
-
parts.push("CYCLE");
|
|
182
|
-
if (ownedBy !== undefined)
|
|
183
|
-
parts.push(`OWNED BY ${ownedBy}`);
|
|
184
|
-
const sql = parts.join(" ");
|
|
185
|
-
await adapter.executeQuery(sql);
|
|
186
|
-
const result = {
|
|
187
|
-
success: true,
|
|
188
|
-
sequence: `${schemaName}.${name}`,
|
|
189
|
-
ifNotExists: ifNotExists ?? false,
|
|
190
|
-
};
|
|
191
|
-
if (alreadyExisted !== undefined) {
|
|
192
|
-
result["alreadyExisted"] = alreadyExisted;
|
|
281
|
+
catch (error) {
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
error: error instanceof z.ZodError
|
|
285
|
+
? error.issues.map((i) => i.message).join("; ")
|
|
286
|
+
: formatPostgresError(error, { tool: "pg_create_sequence" }),
|
|
287
|
+
};
|
|
193
288
|
}
|
|
194
|
-
return result;
|
|
195
289
|
},
|
|
196
290
|
};
|
|
197
291
|
}
|
|
@@ -206,16 +300,37 @@ function createDropSequenceTool(adapter) {
|
|
|
206
300
|
annotations: destructive("Drop Sequence"),
|
|
207
301
|
icons: getToolIcons("schema", destructive("Drop Sequence")),
|
|
208
302
|
handler: async (params, _context) => {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
303
|
+
try {
|
|
304
|
+
const { name, schema, ifExists, cascade } = DropSequenceSchema.parse(params);
|
|
305
|
+
const schemaName = schema ?? "public";
|
|
306
|
+
// Check if sequence exists before dropping (for accurate response)
|
|
307
|
+
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]);
|
|
308
|
+
const existed = (existsResult.rows?.length ?? 0) > 0;
|
|
309
|
+
const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
|
|
310
|
+
const cascadeClause = cascade === true ? " CASCADE" : "";
|
|
311
|
+
const sql = `DROP SEQUENCE ${ifExistsClause}"${schemaName}"."${name}"${cascadeClause}`;
|
|
312
|
+
try {
|
|
313
|
+
await adapter.executeQuery(sql);
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
return {
|
|
317
|
+
success: false,
|
|
318
|
+
error: formatPostgresError(error, {
|
|
319
|
+
tool: "pg_drop_sequence",
|
|
320
|
+
...(schema !== undefined && { schema }),
|
|
321
|
+
}),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return { success: true, sequence: `${schemaName}.${name}`, existed };
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
return {
|
|
328
|
+
success: false,
|
|
329
|
+
error: error instanceof z.ZodError
|
|
330
|
+
? error.issues.map((i) => i.message).join("; ")
|
|
331
|
+
: formatPostgresError(error, { tool: "pg_drop_sequence" }),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
219
334
|
},
|
|
220
335
|
};
|
|
221
336
|
}
|
|
@@ -241,8 +356,10 @@ function createListViewsTool(adapter) {
|
|
|
241
356
|
icons: getToolIcons("schema", readOnly("List Views")),
|
|
242
357
|
handler: async (params, _context) => {
|
|
243
358
|
const parsed = (params ?? {});
|
|
359
|
+
const queryParams = [];
|
|
244
360
|
const schemaClause = parsed.schema
|
|
245
|
-
?
|
|
361
|
+
? (queryParams.push(parsed.schema),
|
|
362
|
+
`AND n.nspname = $${String(queryParams.length)}`)
|
|
246
363
|
: "";
|
|
247
364
|
const kindClause = parsed.includeMaterialized !== false ? "IN ('v', 'm')" : "= 'v'";
|
|
248
365
|
// Default truncation: 500 chars, 0 = no truncation
|
|
@@ -260,7 +377,9 @@ function createListViewsTool(adapter) {
|
|
|
260
377
|
${schemaClause}
|
|
261
378
|
ORDER BY n.nspname, c.relname
|
|
262
379
|
${limitClause}`;
|
|
263
|
-
const result =
|
|
380
|
+
const result = queryParams.length > 0
|
|
381
|
+
? await adapter.executeQuery(sql, queryParams)
|
|
382
|
+
: await adapter.executeQuery(sql);
|
|
264
383
|
let views = result.rows ?? [];
|
|
265
384
|
// Check if there are more results than the limit
|
|
266
385
|
const hasMore = limitVal > 0 && views.length > limitVal;
|
|
@@ -312,35 +431,57 @@ function createCreateViewTool(adapter) {
|
|
|
312
431
|
annotations: write("Create View"),
|
|
313
432
|
icons: getToolIcons("schema", write("Create View")),
|
|
314
433
|
handler: async (params, _context) => {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
434
|
+
try {
|
|
435
|
+
const { name, schema, query, materialized, orReplace, checkOption } = CreateViewSchema.parse(params);
|
|
436
|
+
const schemaName = schema ?? "public";
|
|
437
|
+
// Check if view already exists when orReplace is true (for informational response)
|
|
438
|
+
let alreadyExisted;
|
|
439
|
+
if (orReplace === true) {
|
|
440
|
+
const relkind = materialized === true ? "m" : "v";
|
|
441
|
+
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]);
|
|
442
|
+
alreadyExisted = (existsResult.rows?.length ?? 0) > 0;
|
|
443
|
+
}
|
|
444
|
+
const schemaPrefix = schema ? `${sanitizeIdentifier(schema)}.` : "";
|
|
445
|
+
const replaceClause = orReplace && !materialized ? "OR REPLACE " : "";
|
|
446
|
+
const matClause = materialized ? "MATERIALIZED " : "";
|
|
447
|
+
const viewName = sanitizeIdentifier(name);
|
|
448
|
+
// WITH CHECK OPTION clause (not available for materialized views)
|
|
449
|
+
let checkClause = "";
|
|
450
|
+
if (checkOption && checkOption !== "none" && !materialized) {
|
|
451
|
+
checkClause = ` WITH ${checkOption.toUpperCase()} CHECK OPTION`;
|
|
452
|
+
}
|
|
453
|
+
const sql = `CREATE ${replaceClause}${matClause}VIEW ${schemaPrefix}${viewName} AS ${query}${checkClause}`;
|
|
454
|
+
try {
|
|
455
|
+
await adapter.executeQuery(sql);
|
|
456
|
+
}
|
|
457
|
+
catch (error) {
|
|
458
|
+
return {
|
|
459
|
+
success: false,
|
|
460
|
+
error: formatPostgresError(error, {
|
|
461
|
+
tool: "pg_create_view",
|
|
462
|
+
objectType: "view",
|
|
463
|
+
...(schema !== undefined && { schema }),
|
|
464
|
+
}),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
const result = {
|
|
468
|
+
success: true,
|
|
469
|
+
view: `${schemaName}.${name}`,
|
|
470
|
+
materialized: !!materialized,
|
|
471
|
+
};
|
|
472
|
+
if (alreadyExisted !== undefined) {
|
|
473
|
+
result["alreadyExisted"] = alreadyExisted;
|
|
474
|
+
}
|
|
475
|
+
return result;
|
|
332
476
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
if (alreadyExisted !== undefined) {
|
|
341
|
-
result["alreadyExisted"] = alreadyExisted;
|
|
477
|
+
catch (error) {
|
|
478
|
+
return {
|
|
479
|
+
success: false,
|
|
480
|
+
error: error instanceof z.ZodError
|
|
481
|
+
? error.issues.map((i) => i.message).join("; ")
|
|
482
|
+
: formatPostgresError(error, { tool: "pg_create_view" }),
|
|
483
|
+
};
|
|
342
484
|
}
|
|
343
|
-
return result;
|
|
344
485
|
},
|
|
345
486
|
};
|
|
346
487
|
}
|
|
@@ -355,23 +496,44 @@ function createDropViewTool(adapter) {
|
|
|
355
496
|
annotations: destructive("Drop View"),
|
|
356
497
|
icons: getToolIcons("schema", destructive("Drop View")),
|
|
357
498
|
handler: async (params, _context) => {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
499
|
+
try {
|
|
500
|
+
const { name, schema, materialized, ifExists, cascade } = DropViewSchema.parse(params);
|
|
501
|
+
const schemaName = schema ?? "public";
|
|
502
|
+
// Check if view exists before dropping (for accurate response)
|
|
503
|
+
const relkind = materialized === true ? "m" : "v";
|
|
504
|
+
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]);
|
|
505
|
+
const existed = (existsResult.rows?.length ?? 0) > 0;
|
|
506
|
+
const matClause = materialized === true ? "MATERIALIZED " : "";
|
|
507
|
+
const ifExistsClause = ifExists === true ? "IF EXISTS " : "";
|
|
508
|
+
const cascadeClause = cascade === true ? " CASCADE" : "";
|
|
509
|
+
const sql = `DROP ${matClause}VIEW ${ifExistsClause}"${schemaName}"."${name}"${cascadeClause}`;
|
|
510
|
+
try {
|
|
511
|
+
await adapter.executeQuery(sql);
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
return {
|
|
515
|
+
success: false,
|
|
516
|
+
error: formatPostgresError(error, {
|
|
517
|
+
tool: "pg_drop_view",
|
|
518
|
+
...(schema !== undefined && { schema }),
|
|
519
|
+
}),
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
return {
|
|
523
|
+
success: true,
|
|
524
|
+
view: `${schemaName}.${name}`,
|
|
525
|
+
materialized: materialized ?? false,
|
|
526
|
+
existed,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
return {
|
|
531
|
+
success: false,
|
|
532
|
+
error: error instanceof z.ZodError
|
|
533
|
+
? error.issues.map((i) => i.message).join("; ")
|
|
534
|
+
: formatPostgresError(error, { tool: "pg_drop_view" }),
|
|
535
|
+
};
|
|
536
|
+
}
|
|
375
537
|
},
|
|
376
538
|
};
|
|
377
539
|
}
|
|
@@ -386,51 +548,85 @@ function createListFunctionsTool(adapter) {
|
|
|
386
548
|
annotations: readOnly("List Functions"),
|
|
387
549
|
icons: getToolIcons("schema", readOnly("List Functions")),
|
|
388
550
|
handler: async (params, _context) => {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
551
|
+
try {
|
|
552
|
+
// Use full schema with preprocessing for validation
|
|
553
|
+
const parsed = ListFunctionsSchema.parse(params);
|
|
554
|
+
const queryParams = [];
|
|
555
|
+
// Validate schema existence when filtering by schema
|
|
556
|
+
if (parsed.schema !== undefined) {
|
|
557
|
+
const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
|
|
558
|
+
if ((schemaCheck.rows?.length ?? 0) === 0) {
|
|
559
|
+
return {
|
|
560
|
+
success: false,
|
|
561
|
+
error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const conditions = [
|
|
566
|
+
"n.nspname NOT IN ('pg_catalog', 'information_schema')",
|
|
567
|
+
];
|
|
568
|
+
if (parsed.schema !== undefined) {
|
|
569
|
+
queryParams.push(parsed.schema);
|
|
570
|
+
conditions.push(`n.nspname = $${String(queryParams.length)}`);
|
|
571
|
+
}
|
|
572
|
+
if (parsed.exclude !== undefined && parsed.exclude.length > 0) {
|
|
573
|
+
// Expand well-known aliases (e.g. "pgvector" -> ["pgvector", "vector"])
|
|
574
|
+
const normalizedExclude = parsed.exclude.flatMap((s) => {
|
|
575
|
+
const alias = EXTENSION_ALIASES[s];
|
|
576
|
+
return alias ? [s, alias] : [s];
|
|
577
|
+
});
|
|
578
|
+
const excludePlaceholders = normalizedExclude.map((s) => {
|
|
579
|
+
queryParams.push(s);
|
|
580
|
+
return `$${String(queryParams.length)}`;
|
|
581
|
+
});
|
|
582
|
+
const excludeList = excludePlaceholders.join(", ");
|
|
583
|
+
// Exclude by schema name
|
|
584
|
+
conditions.push(`n.nspname NOT IN (${excludeList})`);
|
|
585
|
+
// Also exclude extension-owned functions (e.g., ltree functions in public schema)
|
|
586
|
+
conditions.push(`NOT EXISTS (
|
|
587
|
+
SELECT 1 FROM pg_depend d
|
|
588
|
+
JOIN pg_extension e ON d.refobjid = e.oid
|
|
589
|
+
WHERE d.objid = p.oid
|
|
590
|
+
AND d.deptype = 'e'
|
|
591
|
+
AND e.extname IN (${excludeList})
|
|
592
|
+
)`);
|
|
593
|
+
}
|
|
594
|
+
if (parsed.language !== undefined) {
|
|
595
|
+
queryParams.push(parsed.language);
|
|
596
|
+
conditions.push(`l.lanname = $${String(queryParams.length)}`);
|
|
597
|
+
}
|
|
598
|
+
const limitVal = parsed.limit ?? 500;
|
|
599
|
+
const sql = `SELECT n.nspname as schema, p.proname as name,
|
|
600
|
+
pg_get_function_arguments(p.oid) as arguments,
|
|
601
|
+
pg_get_function_result(p.oid) as returns,
|
|
602
|
+
l.lanname as language,
|
|
603
|
+
p.provolatile as volatility
|
|
604
|
+
FROM pg_proc p
|
|
605
|
+
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
606
|
+
JOIN pg_language l ON l.oid = p.prolang
|
|
607
|
+
WHERE ${conditions.join(" AND ")}
|
|
608
|
+
ORDER BY n.nspname, p.proname
|
|
609
|
+
LIMIT ${String(limitVal)}`;
|
|
610
|
+
const result = queryParams.length > 0
|
|
611
|
+
? await adapter.executeQuery(sql, queryParams)
|
|
612
|
+
: await adapter.executeQuery(sql);
|
|
613
|
+
return {
|
|
614
|
+
functions: result.rows,
|
|
615
|
+
count: result.rows?.length ?? 0,
|
|
616
|
+
limit: limitVal,
|
|
617
|
+
note: (result.rows?.length ?? 0) >= limitVal
|
|
618
|
+
? `Results limited to ${String(limitVal)}. Use 'limit' param for more, or 'exclude' to filter out extension schemas.`
|
|
619
|
+
: undefined,
|
|
620
|
+
};
|
|
409
621
|
}
|
|
410
|
-
|
|
411
|
-
|
|
622
|
+
catch (error) {
|
|
623
|
+
return {
|
|
624
|
+
success: false,
|
|
625
|
+
error: error instanceof z.ZodError
|
|
626
|
+
? error.issues.map((i) => i.message).join("; ")
|
|
627
|
+
: formatPostgresError(error, { tool: "pg_list_functions" }),
|
|
628
|
+
};
|
|
412
629
|
}
|
|
413
|
-
const limitVal = parsed.limit ?? 500;
|
|
414
|
-
const sql = `SELECT n.nspname as schema, p.proname as name,
|
|
415
|
-
pg_get_function_arguments(p.oid) as arguments,
|
|
416
|
-
pg_get_function_result(p.oid) as returns,
|
|
417
|
-
l.lanname as language,
|
|
418
|
-
p.provolatile as volatility
|
|
419
|
-
FROM pg_proc p
|
|
420
|
-
JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
421
|
-
JOIN pg_language l ON l.oid = p.prolang
|
|
422
|
-
WHERE ${conditions.join(" AND ")}
|
|
423
|
-
ORDER BY n.nspname, p.proname
|
|
424
|
-
LIMIT ${String(limitVal)}`;
|
|
425
|
-
const result = await adapter.executeQuery(sql);
|
|
426
|
-
return {
|
|
427
|
-
functions: result.rows,
|
|
428
|
-
count: result.rows?.length ?? 0,
|
|
429
|
-
limit: limitVal,
|
|
430
|
-
note: (result.rows?.length ?? 0) >= limitVal
|
|
431
|
-
? `Results limited to ${String(limitVal)}. Use 'limit' param for more, or 'exclude' to filter out extension schemas.`
|
|
432
|
-
: undefined,
|
|
433
|
-
};
|
|
434
630
|
},
|
|
435
631
|
};
|
|
436
632
|
}
|
|
@@ -447,31 +643,77 @@ function createListTriggersTool(adapter) {
|
|
|
447
643
|
annotations: readOnly("List Triggers"),
|
|
448
644
|
icons: getToolIcons("schema", readOnly("List Triggers")),
|
|
449
645
|
handler: async (params, _context) => {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
646
|
+
try {
|
|
647
|
+
const parsed = (params ?? {});
|
|
648
|
+
// Parse schema.table format
|
|
649
|
+
if (typeof parsed.table === "string" &&
|
|
650
|
+
parsed.table.includes(".") &&
|
|
651
|
+
!parsed.schema) {
|
|
652
|
+
const parts = parsed.table.split(".");
|
|
653
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
654
|
+
parsed.schema = parts[0];
|
|
655
|
+
parsed.table = parts[1];
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
const schemaName = parsed.schema ?? "public";
|
|
659
|
+
// Validate schema existence when filtering by schema
|
|
660
|
+
if (parsed.schema) {
|
|
661
|
+
const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
|
|
662
|
+
if ((schemaCheck.rows?.length ?? 0) === 0) {
|
|
663
|
+
return {
|
|
664
|
+
success: false,
|
|
665
|
+
error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
// Validate table existence when filtering by table
|
|
670
|
+
if (parsed.table) {
|
|
671
|
+
const tableCheck = await adapter.executeQuery(`SELECT 1 FROM information_schema.tables WHERE table_schema = $1 AND table_name = $2`, [schemaName, parsed.table]);
|
|
672
|
+
if ((tableCheck.rows?.length ?? 0) === 0) {
|
|
673
|
+
return {
|
|
674
|
+
success: false,
|
|
675
|
+
error: `Table '${schemaName}.${parsed.table}' not found. Use pg_list_tables to see available tables.`,
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
const queryParams = [];
|
|
680
|
+
let whereClause = "n.nspname NOT IN ('pg_catalog', 'information_schema')";
|
|
681
|
+
if (parsed.schema) {
|
|
682
|
+
queryParams.push(parsed.schema);
|
|
683
|
+
whereClause += ` AND n.nspname = $${String(queryParams.length)}`;
|
|
684
|
+
}
|
|
685
|
+
if (parsed.table) {
|
|
686
|
+
queryParams.push(parsed.table);
|
|
687
|
+
whereClause += ` AND c.relname = $${String(queryParams.length)}`;
|
|
688
|
+
}
|
|
689
|
+
const sql = `SELECT n.nspname as schema, c.relname as table_name, t.tgname as name,
|
|
690
|
+
CASE t.tgtype::int & 2 WHEN 2 THEN 'BEFORE' ELSE 'AFTER' END as timing,
|
|
691
|
+
array_remove(ARRAY[
|
|
692
|
+
CASE WHEN t.tgtype::int & 4 = 4 THEN 'INSERT' END,
|
|
693
|
+
CASE WHEN t.tgtype::int & 8 = 8 THEN 'DELETE' END,
|
|
694
|
+
CASE WHEN t.tgtype::int & 16 = 16 THEN 'UPDATE' END,
|
|
695
|
+
CASE WHEN t.tgtype::int & 32 = 32 THEN 'TRUNCATE' END
|
|
696
|
+
], NULL) as events,
|
|
697
|
+
p.proname as function_name,
|
|
698
|
+
t.tgenabled != 'D' as enabled
|
|
699
|
+
FROM pg_trigger t
|
|
700
|
+
JOIN pg_class c ON c.oid = t.tgrelid
|
|
701
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
702
|
+
JOIN pg_proc p ON p.oid = t.tgfoid
|
|
703
|
+
WHERE NOT t.tgisinternal
|
|
704
|
+
AND ${whereClause}
|
|
705
|
+
ORDER BY n.nspname, c.relname, t.tgname`;
|
|
706
|
+
const result = queryParams.length > 0
|
|
707
|
+
? await adapter.executeQuery(sql, queryParams)
|
|
708
|
+
: await adapter.executeQuery(sql);
|
|
709
|
+
return { triggers: result.rows, count: result.rows?.length ?? 0 };
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
return {
|
|
713
|
+
success: false,
|
|
714
|
+
error: formatPostgresError(error, { tool: "pg_list_triggers" }),
|
|
715
|
+
};
|
|
716
|
+
}
|
|
475
717
|
},
|
|
476
718
|
};
|
|
477
719
|
}
|
|
@@ -491,38 +733,85 @@ function createListConstraintsTool(adapter) {
|
|
|
491
733
|
annotations: readOnly("List Constraints"),
|
|
492
734
|
icons: getToolIcons("schema", readOnly("List Constraints")),
|
|
493
735
|
handler: async (params, _context) => {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
736
|
+
try {
|
|
737
|
+
const parsed = (params ?? {});
|
|
738
|
+
// Parse schema.table format
|
|
739
|
+
if (typeof parsed.table === "string" &&
|
|
740
|
+
parsed.table.includes(".") &&
|
|
741
|
+
!parsed.schema) {
|
|
742
|
+
const parts = parsed.table.split(".");
|
|
743
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
744
|
+
parsed.schema = parts[0];
|
|
745
|
+
parsed.table = parts[1];
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const schemaName = parsed.schema ?? "public";
|
|
749
|
+
// Validate schema existence when filtering by schema
|
|
750
|
+
if (parsed.schema) {
|
|
751
|
+
const schemaCheck = await adapter.executeQuery(`SELECT 1 FROM pg_namespace WHERE nspname = $1`, [parsed.schema]);
|
|
752
|
+
if ((schemaCheck.rows?.length ?? 0) === 0) {
|
|
753
|
+
return {
|
|
754
|
+
success: false,
|
|
755
|
+
error: `Schema '${parsed.schema}' does not exist. Use pg_list_schemas to see available schemas.`,
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
// Validate table existence when filtering by table
|
|
760
|
+
if (parsed.table) {
|
|
761
|
+
const tableCheck = await adapter.executeQuery(`SELECT 1 FROM information_schema.tables WHERE table_schema = $1 AND table_name = $2`, [schemaName, parsed.table]);
|
|
762
|
+
if ((tableCheck.rows?.length ?? 0) === 0) {
|
|
763
|
+
return {
|
|
764
|
+
success: false,
|
|
765
|
+
error: `Table '${schemaName}.${parsed.table}' not found. Use pg_list_tables to see available tables.`,
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
const queryParams = [];
|
|
770
|
+
let whereClause = "n.nspname NOT IN ('pg_catalog', 'information_schema') AND con.contype != 'n'";
|
|
771
|
+
if (parsed.schema) {
|
|
772
|
+
queryParams.push(parsed.schema);
|
|
773
|
+
whereClause += ` AND n.nspname = $${String(queryParams.length)}`;
|
|
774
|
+
}
|
|
775
|
+
if (parsed.table) {
|
|
776
|
+
queryParams.push(parsed.table);
|
|
777
|
+
whereClause += ` AND c.relname = $${String(queryParams.length)}`;
|
|
778
|
+
}
|
|
779
|
+
if (parsed.type) {
|
|
780
|
+
const typeMap = {
|
|
781
|
+
primary_key: "p",
|
|
782
|
+
foreign_key: "f",
|
|
783
|
+
unique: "u",
|
|
784
|
+
check: "c",
|
|
785
|
+
};
|
|
786
|
+
queryParams.push(typeMap[parsed.type] ?? "");
|
|
787
|
+
whereClause += ` AND con.contype = $${String(queryParams.length)}`;
|
|
788
|
+
}
|
|
789
|
+
const sql = `SELECT n.nspname as schema, c.relname as table_name, con.conname as name,
|
|
790
|
+
CASE con.contype
|
|
791
|
+
WHEN 'p' THEN 'primary_key'
|
|
792
|
+
WHEN 'f' THEN 'foreign_key'
|
|
793
|
+
WHEN 'u' THEN 'unique'
|
|
794
|
+
WHEN 'c' THEN 'check'
|
|
795
|
+
WHEN 'n' THEN 'not_null'
|
|
796
|
+
ELSE con.contype
|
|
797
|
+
END as type,
|
|
798
|
+
pg_get_constraintdef(con.oid) as definition
|
|
799
|
+
FROM pg_constraint con
|
|
800
|
+
JOIN pg_class c ON c.oid = con.conrelid
|
|
801
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
802
|
+
WHERE ${whereClause}
|
|
803
|
+
ORDER BY n.nspname, c.relname, con.conname`;
|
|
804
|
+
const result = queryParams.length > 0
|
|
805
|
+
? await adapter.executeQuery(sql, queryParams)
|
|
806
|
+
: await adapter.executeQuery(sql);
|
|
807
|
+
return { constraints: result.rows, count: result.rows?.length ?? 0 };
|
|
808
|
+
}
|
|
809
|
+
catch (error) {
|
|
810
|
+
return {
|
|
811
|
+
success: false,
|
|
812
|
+
error: formatPostgresError(error, { tool: "pg_list_constraints" }),
|
|
506
813
|
};
|
|
507
|
-
whereClause += ` AND con.contype = '${typeMap[parsed.type] ?? ""}'`;
|
|
508
814
|
}
|
|
509
|
-
const sql = `SELECT n.nspname as schema, c.relname as table_name, con.conname as name,
|
|
510
|
-
CASE con.contype
|
|
511
|
-
WHEN 'p' THEN 'primary_key'
|
|
512
|
-
WHEN 'f' THEN 'foreign_key'
|
|
513
|
-
WHEN 'u' THEN 'unique'
|
|
514
|
-
WHEN 'c' THEN 'check'
|
|
515
|
-
WHEN 'n' THEN 'not_null'
|
|
516
|
-
ELSE con.contype
|
|
517
|
-
END as type,
|
|
518
|
-
pg_get_constraintdef(con.oid) as definition
|
|
519
|
-
FROM pg_constraint con
|
|
520
|
-
JOIN pg_class c ON c.oid = con.conrelid
|
|
521
|
-
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
522
|
-
WHERE ${whereClause}
|
|
523
|
-
ORDER BY n.nspname, c.relname, con.conname`;
|
|
524
|
-
const result = await adapter.executeQuery(sql);
|
|
525
|
-
return { constraints: result.rows, count: result.rows?.length ?? 0 };
|
|
526
815
|
},
|
|
527
816
|
};
|
|
528
817
|
}
|