pg-admin-mcp 0.0.0-stage → 0.1.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 (130) hide show
  1. package/README.md +608 -2
  2. package/dist/config/env.js +67 -0
  3. package/dist/config/env.js.map +1 -0
  4. package/dist/config/profiles.js +257 -0
  5. package/dist/config/profiles.js.map +1 -0
  6. package/dist/core/audit-context.js +21 -0
  7. package/dist/core/audit-context.js.map +1 -0
  8. package/dist/core/audit.js +91 -0
  9. package/dist/core/audit.js.map +1 -0
  10. package/dist/core/brands.js +24 -0
  11. package/dist/core/brands.js.map +1 -0
  12. package/dist/core/classifier.js +279 -0
  13. package/dist/core/classifier.js.map +1 -0
  14. package/dist/core/errors.js +197 -0
  15. package/dist/core/errors.js.map +1 -0
  16. package/dist/core/format.js +258 -0
  17. package/dist/core/format.js.map +1 -0
  18. package/dist/core/guards.js +513 -0
  19. package/dist/core/guards.js.map +1 -0
  20. package/dist/core/identifiers.js +431 -0
  21. package/dist/core/identifiers.js.map +1 -0
  22. package/dist/core/limits.js +79 -0
  23. package/dist/core/limits.js.map +1 -0
  24. package/dist/core/logger.js +34 -0
  25. package/dist/core/logger.js.map +1 -0
  26. package/dist/core/paginate.js +195 -0
  27. package/dist/core/paginate.js.map +1 -0
  28. package/dist/core/paths.js +392 -0
  29. package/dist/core/paths.js.map +1 -0
  30. package/dist/core/policy.js +98 -0
  31. package/dist/core/policy.js.map +1 -0
  32. package/dist/core/shutdown.js +10 -0
  33. package/dist/core/shutdown.js.map +1 -0
  34. package/dist/core/stdout-guard.js +25 -0
  35. package/dist/core/stdout-guard.js.map +1 -0
  36. package/dist/db/catalog.js +1006 -0
  37. package/dist/db/catalog.js.map +1 -0
  38. package/dist/db/pool.js +158 -0
  39. package/dist/db/pool.js.map +1 -0
  40. package/dist/db/session.js +258 -0
  41. package/dist/db/session.js.map +1 -0
  42. package/dist/db/types.js +2 -0
  43. package/dist/db/types.js.map +1 -0
  44. package/dist/index.js +91 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/resources/index.js +88 -0
  47. package/dist/resources/index.js.map +1 -0
  48. package/dist/runtime/binaries.js +356 -0
  49. package/dist/runtime/binaries.js.map +1 -0
  50. package/dist/runtime/env-file.js +62 -0
  51. package/dist/runtime/env-file.js.map +1 -0
  52. package/dist/runtime/environment.js +34 -0
  53. package/dist/runtime/environment.js.map +1 -0
  54. package/dist/server.js +106 -0
  55. package/dist/server.js.map +1 -0
  56. package/dist/snapshot/capture.js +189 -0
  57. package/dist/snapshot/capture.js.map +1 -0
  58. package/dist/snapshot/diff.js +254 -0
  59. package/dist/snapshot/diff.js.map +1 -0
  60. package/dist/snapshot/migrate.js +1596 -0
  61. package/dist/snapshot/migrate.js.map +1 -0
  62. package/dist/snapshot/model.js +80 -0
  63. package/dist/snapshot/model.js.map +1 -0
  64. package/dist/tools/_archive_meta.js +138 -0
  65. package/dist/tools/_archive_meta.js.map +1 -0
  66. package/dist/tools/_batch_shared.js +73 -0
  67. package/dist/tools/_batch_shared.js.map +1 -0
  68. package/dist/tools/_export_format.js +107 -0
  69. package/dist/tools/_export_format.js.map +1 -0
  70. package/dist/tools/_object_kinds.js +97 -0
  71. package/dist/tools/_object_kinds.js.map +1 -0
  72. package/dist/tools/_relation_detail.js +55 -0
  73. package/dist/tools/_relation_detail.js.map +1 -0
  74. package/dist/tools/_shared.js +17 -0
  75. package/dist/tools/_shared.js.map +1 -0
  76. package/dist/tools/_snapshot_io.js +238 -0
  77. package/dist/tools/_snapshot_io.js.map +1 -0
  78. package/dist/tools/admin/_shared.js +18 -0
  79. package/dist/tools/admin/_shared.js.map +1 -0
  80. package/dist/tools/admin/extensions.js +80 -0
  81. package/dist/tools/admin/extensions.js.map +1 -0
  82. package/dist/tools/admin/grants.js +207 -0
  83. package/dist/tools/admin/grants.js.map +1 -0
  84. package/dist/tools/admin/index.js +138 -0
  85. package/dist/tools/admin/index.js.map +1 -0
  86. package/dist/tools/admin/maintenance.js +106 -0
  87. package/dist/tools/admin/maintenance.js.map +1 -0
  88. package/dist/tools/admin/roles.js +144 -0
  89. package/dist/tools/admin/roles.js.map +1 -0
  90. package/dist/tools/admin/sessions.js +104 -0
  91. package/dist/tools/admin/sessions.js.map +1 -0
  92. package/dist/tools/admin/stats.js +63 -0
  93. package/dist/tools/admin/stats.js.map +1 -0
  94. package/dist/tools/backup.js +288 -0
  95. package/dist/tools/backup.js.map +1 -0
  96. package/dist/tools/connection_status.js +138 -0
  97. package/dist/tools/connection_status.js.map +1 -0
  98. package/dist/tools/copy.js +355 -0
  99. package/dist/tools/copy.js.map +1 -0
  100. package/dist/tools/delete_batch.js +73 -0
  101. package/dist/tools/delete_batch.js.map +1 -0
  102. package/dist/tools/describe_object.js +87 -0
  103. package/dist/tools/describe_object.js.map +1 -0
  104. package/dist/tools/execute_sql.js +395 -0
  105. package/dist/tools/execute_sql.js.map +1 -0
  106. package/dist/tools/explain.js +134 -0
  107. package/dist/tools/explain.js.map +1 -0
  108. package/dist/tools/export.js +215 -0
  109. package/dist/tools/export.js.map +1 -0
  110. package/dist/tools/get_schema.js +148 -0
  111. package/dist/tools/get_schema.js.map +1 -0
  112. package/dist/tools/index.js +40 -0
  113. package/dist/tools/index.js.map +1 -0
  114. package/dist/tools/insert_batch.js +212 -0
  115. package/dist/tools/insert_batch.js.map +1 -0
  116. package/dist/tools/list_objects.js +160 -0
  117. package/dist/tools/list_objects.js.map +1 -0
  118. package/dist/tools/prepare_migration.js +112 -0
  119. package/dist/tools/prepare_migration.js.map +1 -0
  120. package/dist/tools/restore.js +301 -0
  121. package/dist/tools/restore.js.map +1 -0
  122. package/dist/tools/schema_diff.js +79 -0
  123. package/dist/tools/schema_diff.js.map +1 -0
  124. package/dist/tools/schema_snapshot.js +57 -0
  125. package/dist/tools/schema_snapshot.js.map +1 -0
  126. package/dist/tools/select.js +162 -0
  127. package/dist/tools/select.js.map +1 -0
  128. package/dist/tools/update_batch.js +154 -0
  129. package/dist/tools/update_batch.js.map +1 -0
  130. package/package.json +47 -5
@@ -0,0 +1,207 @@
1
+ import { z } from 'zod';
2
+ import { PgMcpError } from '../../core/errors.js';
3
+ import { CONFIRM_PROTOCOL_DESCRIPTION, runGuardedMutation } from '../../core/guards.js';
4
+ import { resolveCurrentDatabase, resolveFunctionSignature, resolveRelation, resolveRole, resolveSchemaIdent, resolveSequence } from '../../core/identifiers.js';
5
+ import { getPermissionsByKind } from '../../db/catalog.js';
6
+ import { withSession } from '../../db/session.js';
7
+ import { confirmFragment, toExpectToken } from '../_batch_shared.js';
8
+ import { reportList } from './_shared.js';
9
+ /**
10
+ * `grants` sub-operation. `grants_get` (read-only, no capability) reports
11
+ * effective privileges via `getPermissionsByKind`, which is the fix for the
12
+ * `acldefault('r', …)` bug: table/sequence/function/database/schema each get
13
+ * their own `aclexplode` type code.
14
+ *
15
+ * `grants_grant`/`grants_revoke` require `admin` — matching
16
+ * `execute_sql.ts`'s `WRITE_PATH_CAPABILITY` table, which already maps
17
+ * GRANT/REVOKE to `admin`. Unlike `execute_sql`'s raw-SQL path, this tool
18
+ * does not additionally require `write`: `postgres_admin` is a
19
+ * purpose-built administrative tool, and an operator who wants to hand out
20
+ * grants without also opening the DML write path should not have to enable
21
+ * both.
22
+ *
23
+ * Mutation is supported for table/sequence/schema/function objects.
24
+ * Database-level GRANT is deliberately out of scope (read-only via
25
+ * `grants_get` only) to avoid adding a caller-supplied database-name
26
+ * resolver purely for a rarely-used case — see `resolveCurrentDatabase`'s
27
+ * doc comment for why database grants always target the profile's own
28
+ * database when read.
29
+ */
30
+ const readObjectKind = z.enum(['table', 'sequence', 'function', 'database', 'schema']);
31
+ const mutableObjectKind = z.enum(['table', 'sequence', 'schema', 'function']);
32
+ const PRIVILEGES_BY_KIND = {
33
+ table: ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER', 'ALL'],
34
+ sequence: ['SELECT', 'UPDATE', 'USAGE', 'ALL'],
35
+ schema: ['CREATE', 'USAGE', 'ALL'],
36
+ function: ['EXECUTE', 'ALL'],
37
+ };
38
+ const ON_WORD = {
39
+ table: 'TABLE',
40
+ sequence: 'SEQUENCE',
41
+ schema: 'SCHEMA',
42
+ function: 'FUNCTION',
43
+ };
44
+ export const grantsGetSchema = z
45
+ .object({
46
+ op: z.literal('grants_get'),
47
+ objectKind: readObjectKind,
48
+ schema: z.string().min(1).optional(),
49
+ name: z.string().min(1).optional().describe('Object name. Not used (and not required) when objectKind is "schema" or "database".'),
50
+ })
51
+ .superRefine((v, ctx) => {
52
+ if (v.objectKind === 'database')
53
+ return;
54
+ if (v.objectKind === 'schema') {
55
+ if (v.schema === undefined)
56
+ ctx.addIssue({ code: 'custom', message: 'objectKind "schema" requires "schema"' });
57
+ return;
58
+ }
59
+ if (v.schema === undefined || v.name === undefined) {
60
+ ctx.addIssue({ code: 'custom', message: `objectKind "${v.objectKind}" requires both "schema" and "name"` });
61
+ }
62
+ });
63
+ const grantsMutationBase = {
64
+ objectKind: mutableObjectKind,
65
+ schema: z.string().min(1),
66
+ name: z.string().min(1).optional().describe('Required unless objectKind is "schema" (the schema itself is the object).'),
67
+ roles: z.array(z.string().min(1)).min(1).describe('Grantee role names, or "PUBLIC".'),
68
+ privileges: z.array(z.string().min(1)).min(1).describe('Privilege keywords valid for objectKind, e.g. SELECT/INSERT/UPDATE/DELETE for a table, USAGE for a schema, EXECUTE for a function, or ALL.'),
69
+ };
70
+ export const grantsGrantSchema = z
71
+ .object({
72
+ op: z.literal('grants_grant'),
73
+ ...grantsMutationBase,
74
+ grantOption: z.boolean().optional().default(false).describe('Adds WITH GRANT OPTION.'),
75
+ ...confirmFragment,
76
+ })
77
+ .superRefine((v, ctx) => {
78
+ if (v.objectKind !== 'schema' && v.name === undefined)
79
+ ctx.addIssue({ code: 'custom', message: `objectKind "${v.objectKind}" requires "name"` });
80
+ });
81
+ export const grantsRevokeSchema = z
82
+ .object({
83
+ op: z.literal('grants_revoke'),
84
+ ...grantsMutationBase,
85
+ cascade: z.boolean().optional().default(false),
86
+ ...confirmFragment,
87
+ })
88
+ .superRefine((v, ctx) => {
89
+ if (v.objectKind !== 'schema' && v.name === undefined)
90
+ ctx.addIssue({ code: 'custom', message: `objectKind "${v.objectKind}" requires "name"` });
91
+ });
92
+ async function resolveGrantObject(profile, objectKind, schema, name) {
93
+ switch (objectKind) {
94
+ case 'table': {
95
+ const rel = await resolveRelation(profile, schema, name);
96
+ return { target: `${rel.schema}.${rel.name}`, aclKind: 'table' };
97
+ }
98
+ case 'sequence': {
99
+ const seq = await resolveSequence(profile, schema, name);
100
+ return { target: `${seq.schema}.${seq.name}`, aclKind: 'sequence' };
101
+ }
102
+ case 'function': {
103
+ const fn = await resolveFunctionSignature(profile, schema, name);
104
+ return { target: fn.signature, aclKind: 'function' };
105
+ }
106
+ case 'schema': {
107
+ const sch = await resolveSchemaIdent(profile, schema);
108
+ return { target: sch.name, aclKind: 'schema' };
109
+ }
110
+ }
111
+ }
112
+ async function resolveGranteeIdent(profile, name) {
113
+ if (name.toUpperCase() === 'PUBLIC')
114
+ return 'PUBLIC';
115
+ const role = await resolveRole(profile, name);
116
+ return role.name;
117
+ }
118
+ function validatePrivileges(objectKind, privileges) {
119
+ const allowed = PRIVILEGES_BY_KIND[objectKind];
120
+ const normalized = privileges.map((p) => p.toUpperCase());
121
+ for (const p of normalized) {
122
+ if (!allowed.includes(p)) {
123
+ throw new PgMcpError({
124
+ code: 'PG_ERROR',
125
+ message: `privilege "${p}" is not valid for objectKind "${objectKind}"`,
126
+ hint: `valid privileges for "${objectKind}": ${allowed.join(', ')}`,
127
+ details: { objectKind, privilege: p, allowed },
128
+ });
129
+ }
130
+ }
131
+ return normalized;
132
+ }
133
+ export async function handleGrantsGet(profile, args) {
134
+ let aclKind;
135
+ let oid;
136
+ let label;
137
+ if (args.objectKind === 'database') {
138
+ const db = await resolveCurrentDatabase(profile);
139
+ aclKind = 'database';
140
+ oid = db.oid;
141
+ label = profile.database;
142
+ }
143
+ else if (args.objectKind === 'schema') {
144
+ const sch = await resolveSchemaIdent(profile, args.schema);
145
+ aclKind = 'schema';
146
+ oid = sch.oid;
147
+ label = args.schema;
148
+ }
149
+ else if (args.objectKind === 'sequence') {
150
+ const seq = await resolveSequence(profile, args.schema, args.name);
151
+ aclKind = 'sequence';
152
+ oid = seq.oid;
153
+ label = `${args.schema}.${args.name}`;
154
+ }
155
+ else if (args.objectKind === 'function') {
156
+ const fn = await resolveFunctionSignature(profile, args.schema, args.name);
157
+ aclKind = 'function';
158
+ oid = fn.oid;
159
+ label = `${args.schema}.${args.name}`;
160
+ }
161
+ else {
162
+ const rel = await resolveRelation(profile, args.schema, args.name);
163
+ aclKind = 'table';
164
+ oid = rel.oid;
165
+ label = `${args.schema}.${args.name}`;
166
+ }
167
+ const perms = await withSession(profile, (client) => getPermissionsByKind(client, aclKind, oid), { operation: 'admin_grants_get' });
168
+ return reportList(profile, perms.map((p) => ({ object: label, objectKind: args.objectKind, ...p })));
169
+ }
170
+ export async function handleGrantsGrant(profile, args) {
171
+ const { target } = await resolveGrantObject(profile, args.objectKind, args.schema, args.name);
172
+ const privileges = validatePrivileges(args.objectKind, args.privileges);
173
+ const grantees = await Promise.all(args.roles.map((r) => resolveGranteeIdent(profile, r)));
174
+ const sql = `GRANT ${privileges.join(', ')} ON ${ON_WORD[args.objectKind]} ${target} TO ${grantees.join(', ')}${args.grantOption ? ' WITH GRANT OPTION' : ''}`;
175
+ return runGuardedMutation({
176
+ profile,
177
+ capability: 'admin',
178
+ operation: 'admin_grants_grant',
179
+ sql,
180
+ params: [],
181
+ keyColumns: [],
182
+ confirm: args.confirm,
183
+ expect: toExpectToken(args.expect),
184
+ allowRowDrift: args.allowRowDrift,
185
+ });
186
+ }
187
+ export async function handleGrantsRevoke(profile, args) {
188
+ const { target } = await resolveGrantObject(profile, args.objectKind, args.schema, args.name);
189
+ const privileges = validatePrivileges(args.objectKind, args.privileges);
190
+ const grantees = await Promise.all(args.roles.map((r) => resolveGranteeIdent(profile, r)));
191
+ const sql = `REVOKE ${privileges.join(', ')} ON ${ON_WORD[args.objectKind]} ${target} FROM ${grantees.join(', ')}${args.cascade ? ' CASCADE' : ''}`;
192
+ return runGuardedMutation({
193
+ profile,
194
+ capability: 'admin',
195
+ operation: 'admin_grants_revoke',
196
+ sql,
197
+ params: [],
198
+ keyColumns: [],
199
+ confirm: args.confirm,
200
+ expect: toExpectToken(args.expect),
201
+ allowRowDrift: args.allowRowDrift,
202
+ });
203
+ }
204
+ export const GRANTS_DESCRIPTION = `\`grants_get\` (read-only, no capability) inspects effective privileges — correct aclexplode/acldefault type code per object kind ` +
205
+ `('r' table, 'S' sequence, 'f' function, 'd' database, 'n' schema). \`grants_grant\`/\`grants_revoke\` require \`admin\` (matching ` +
206
+ `execute_sql's GRANT/REVOKE routing) and support table/sequence/schema/function objects; database-level GRANT is read-only here. ${CONFIRM_PROTOCOL_DESCRIPTION}`;
207
+ //# sourceMappingURL=grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../../../src/tools/admin/grants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ import { z } from 'zod';
2
+ import { loadProfiles } from '../../config/profiles.js';
3
+ import { toToolResult } from '../../core/errors.js';
4
+ import { formatOutcome } from '../../core/format.js';
5
+ import { assertNever, defineTool, profileParam } from '../_shared.js';
6
+ import { extensionsCreateSchema, extensionsDropSchema, extensionsListSchema, EXTENSIONS_DESCRIPTION, handleExtensionsCreate, handleExtensionsDrop, handleExtensionsList } from './extensions.js';
7
+ import { grantsGetSchema, grantsGrantSchema, grantsRevokeSchema, GRANTS_DESCRIPTION, handleGrantsGet, handleGrantsGrant, handleGrantsRevoke } from './grants.js';
8
+ import { handleMaintenanceAnalyze, handleMaintenanceReindex, handleMaintenanceVacuum, maintenanceAnalyzeSchema, maintenanceReindexSchema, maintenanceVacuumSchema, MAINTENANCE_DESCRIPTION } from './maintenance.js';
9
+ import { handleRolesAlter, handleRolesCreate, handleRolesDrop, handleRolesList, rolesAlterSchema, rolesCreateSchema, rolesDropSchema, rolesListSchema, ROLES_DESCRIPTION } from './roles.js';
10
+ import { handleSessionsCancel, handleSessionsList, handleSessionsTerminate, sessionsCancelSchema, sessionsListSchema, sessionsTerminateSchema, SESSIONS_DESCRIPTION } from './sessions.js';
11
+ import { handleStatsActivity, handleStatsIndexes, handleStatsTables, statsActivitySchema, statsIndexesSchema, statsTablesSchema, STATS_DESCRIPTION } from './stats.js';
12
+ /**
13
+ * `postgres_admin` — one dispatcher, six sub-operations, each its own file.
14
+ * The widest-blast-radius tool in this server: it can create/alter/drop
15
+ * roles, grant/revoke privileges, install/remove extensions (arbitrary SQL
16
+ * as superuser), cancel/terminate other sessions, and run maintenance that
17
+ * takes locks. Every mutating op requires `admin`; every destructive one
18
+ * routes through `runGuardedMutation`'s confirm protocol or, where that
19
+ * protocol cannot be honest (see `maintenance.ts`/`sessions.ts`), a plain
20
+ * `confirm: true` gate with no dry run offered rather than a fake one.
21
+ *
22
+ * One flat `z.discriminatedUnion('op', [...])` rather than nested unions —
23
+ * Zod's nested-discriminated-union support is friction for nineteen leaf
24
+ * shapes with no shared parent shape worth factoring out, and a flat union
25
+ * still gives each `op` its own independently typed argument shape with
26
+ * schema-level rejection of any invalid op/argument combination.
27
+ */
28
+ const inputSchema = z.discriminatedUnion('op', [
29
+ rolesListSchema,
30
+ rolesCreateSchema,
31
+ rolesAlterSchema,
32
+ rolesDropSchema,
33
+ grantsGetSchema,
34
+ grantsGrantSchema,
35
+ grantsRevokeSchema,
36
+ extensionsListSchema,
37
+ extensionsCreateSchema,
38
+ extensionsDropSchema,
39
+ sessionsListSchema,
40
+ sessionsCancelSchema,
41
+ sessionsTerminateSchema,
42
+ maintenanceVacuumSchema,
43
+ maintenanceAnalyzeSchema,
44
+ maintenanceReindexSchema,
45
+ statsTablesSchema,
46
+ statsIndexesSchema,
47
+ statsActivitySchema,
48
+ ]);
49
+ // z.discriminatedUnion does not support spreading profileParam into each
50
+ // branch without repeating it in all nineteen schemas, so profile is layered
51
+ // on as an intersection instead: `profileParam` first (broad), intersected
52
+ // with the discriminated union (narrow, decides `op`'s shape). TypeScript
53
+ // still narrows `args.op` correctly through the intersection — verified: an
54
+ // intersection of an object type with a union distributes for discriminant
55
+ // narrowing the same way the union alone would.
56
+ const adminInputSchema = z.intersection(z.object(profileParam), inputSchema);
57
+ export const adminTool = defineTool('postgres_admin', {
58
+ title: 'PostgreSQL administrative operations',
59
+ description: 'Widest-blast-radius tool in this server. Six sub-operations selected by `op`: roles_* (create/alter/drop a role), ' +
60
+ 'grants_* (GRANT/REVOKE), extensions_* (CREATE/DROP EXTENSION — installing runs arbitrary SQL as superuser), ' +
61
+ 'sessions_* (cancel/terminate another backend), maintenance_* (VACUUM/ANALYZE/REINDEX), stats_* (read-only). Every ' +
62
+ 'mutating op requires the `admin` capability. ' +
63
+ `${ROLES_DESCRIPTION} ${GRANTS_DESCRIPTION} ${EXTENSIONS_DESCRIPTION} ${SESSIONS_DESCRIPTION} ${MAINTENANCE_DESCRIPTION} ${STATS_DESCRIPTION}`,
64
+ inputSchema: adminInputSchema,
65
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
66
+ }, async (args) => {
67
+ try {
68
+ const registry = loadProfiles();
69
+ const profile = registry.get(args.profile);
70
+ let outcome;
71
+ switch (args.op) {
72
+ case 'roles_list':
73
+ outcome = await handleRolesList(profile, args);
74
+ break;
75
+ case 'roles_create':
76
+ outcome = await handleRolesCreate(profile, args);
77
+ break;
78
+ case 'roles_alter':
79
+ outcome = await handleRolesAlter(profile, args);
80
+ break;
81
+ case 'roles_drop':
82
+ outcome = await handleRolesDrop(profile, args);
83
+ break;
84
+ case 'grants_get':
85
+ outcome = await handleGrantsGet(profile, args);
86
+ break;
87
+ case 'grants_grant':
88
+ outcome = await handleGrantsGrant(profile, args);
89
+ break;
90
+ case 'grants_revoke':
91
+ outcome = await handleGrantsRevoke(profile, args);
92
+ break;
93
+ case 'extensions_list':
94
+ outcome = await handleExtensionsList(profile, args);
95
+ break;
96
+ case 'extensions_create':
97
+ outcome = await handleExtensionsCreate(profile, args);
98
+ break;
99
+ case 'extensions_drop':
100
+ outcome = await handleExtensionsDrop(profile, args);
101
+ break;
102
+ case 'sessions_list':
103
+ outcome = await handleSessionsList(profile, args);
104
+ break;
105
+ case 'sessions_cancel':
106
+ outcome = await handleSessionsCancel(profile, args);
107
+ break;
108
+ case 'sessions_terminate':
109
+ outcome = await handleSessionsTerminate(profile, args);
110
+ break;
111
+ case 'maintenance_vacuum':
112
+ outcome = await handleMaintenanceVacuum(profile, args);
113
+ break;
114
+ case 'maintenance_analyze':
115
+ outcome = await handleMaintenanceAnalyze(profile, args);
116
+ break;
117
+ case 'maintenance_reindex':
118
+ outcome = await handleMaintenanceReindex(profile, args);
119
+ break;
120
+ case 'stats_tables':
121
+ outcome = await handleStatsTables(profile, args);
122
+ break;
123
+ case 'stats_indexes':
124
+ outcome = await handleStatsIndexes(profile, args);
125
+ break;
126
+ case 'stats_activity':
127
+ outcome = await handleStatsActivity(profile, args);
128
+ break;
129
+ default:
130
+ return assertNever(args);
131
+ }
132
+ return formatOutcome(outcome);
133
+ }
134
+ catch (err) {
135
+ return toToolResult(err);
136
+ }
137
+ });
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/admin/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ import { z } from 'zod';
2
+ import { CONFIRM_PROTOCOL_DESCRIPTION, runGuardedMutation } from '../../core/guards.js';
3
+ import { resolveIndex, resolveRelation } from '../../core/identifiers.js';
4
+ import { requireCapability } from '../../core/policy.js';
5
+ import { withSession } from '../../db/session.js';
6
+ import { confirmFragment, toExpectToken } from '../_batch_shared.js';
7
+ /**
8
+ * `maintenance` sub-operation: VACUUM, ANALYZE, REINDEX. All require `admin`.
9
+ *
10
+ * **The transaction-block problem, and the decision.** `runGuardedMutation`
11
+ * always opens a transaction (`withTx`, for both the dry-run and the confirm
12
+ * call — confirmed by reading it end to end, there is no code path that
13
+ * skips `BEGIN`). PostgreSQL refuses `VACUUM` inside a transaction block
14
+ * unconditionally, and refuses `REINDEX ... CONCURRENTLY` inside one too
15
+ * (plain `REINDEX TABLE`/`REINDEX INDEX` on a single object CAN run inside a
16
+ * transaction). Wrapping either operation in a `GuardedExecutor` would not
17
+ * help: an executor's `run(client)` still executes inside whatever
18
+ * transaction `withTx` opened around it — it does not escape it. So:
19
+ *
20
+ * - `maintenance_vacuum` and `maintenance_analyze` never go through
21
+ * `runGuardedMutation`. They run immediately via `withSession` (no
22
+ * transaction at all), gated by an explicit `requireCapability('admin', …)`
23
+ * call since there is no guard to do it for them. No dry run is offered —
24
+ * one is not possible, and pretending otherwise (e.g. by wrapping VACUUM in
25
+ * a transaction that always rolls back) would either lie about what
26
+ * happened or simply fail with PostgreSQL's own
27
+ * `25001 VACUUM cannot run inside a transaction block`. Neither VACUUM nor
28
+ * ANALYZE deletes or hides live rows a caller can see — the honest
29
+ * description is "no dry run because none is possible for a
30
+ * non-transactional operation", not "defeats the guard".
31
+ * - `maintenance_reindex` with `concurrently: false` (default) targets a
32
+ * single table or index, which CAN run inside a transaction — it goes
33
+ * through `runGuardedMutation` like any other DDL-shaped mutation
34
+ * (`keyColumns: []`, no `RETURNING`). Its dry run genuinely rebuilds the
35
+ * index and then rolls back: a truthful, if I/O-costly, proof that the
36
+ * REINDEX will succeed — unlike VACUUM, this one is not a lie.
37
+ * - `maintenance_reindex` with `concurrently: true` cannot run inside a
38
+ * transaction block either (PostgreSQL's own restriction), so it takes the
39
+ * same immediate/no-dry-run path as VACUUM, documented the same way.
40
+ */
41
+ const targetKind = z.enum(['table', 'index']);
42
+ export const maintenanceVacuumSchema = z.object({
43
+ op: z.literal('maintenance_vacuum'),
44
+ schema: z.string().min(1),
45
+ table: z.string().min(1),
46
+ full: z.boolean().optional().default(false).describe('VACUUM FULL rewrites the table and takes ACCESS EXCLUSIVE — no dry run either way.'),
47
+ analyze: z.boolean().optional().default(false).describe('Also update planner statistics in the same pass.'),
48
+ });
49
+ export const maintenanceAnalyzeSchema = z.object({
50
+ op: z.literal('maintenance_analyze'),
51
+ schema: z.string().min(1),
52
+ table: z.string().min(1),
53
+ });
54
+ export const maintenanceReindexSchema = z.object({
55
+ op: z.literal('maintenance_reindex'),
56
+ target: targetKind,
57
+ schema: z.string().min(1),
58
+ name: z.string().min(1),
59
+ concurrently: z.boolean().optional().default(false).describe('REINDEX CONCURRENTLY cannot run inside a transaction block, so no dry run is offered when true.'),
60
+ ...confirmFragment,
61
+ });
62
+ export async function handleMaintenanceVacuum(profile, args) {
63
+ requireCapability('admin', profile);
64
+ const rel = await resolveRelation(profile, args.schema, args.table);
65
+ const options = [args.full ? 'FULL' : null, args.analyze ? 'ANALYZE' : null].filter((o) => o !== null);
66
+ const sql = options.length > 0 ? `VACUUM (${options.join(', ')}) ${rel.schema}.${rel.name}` : `VACUUM ${rel.schema}.${rel.name}`;
67
+ await withSession(profile, (client) => client.query({ text: sql, values: [], queryMode: 'extended' }), { operation: 'admin_maintenance_vacuum' });
68
+ return { kind: 'mutation', rowCount: 0, committed: true };
69
+ }
70
+ export async function handleMaintenanceAnalyze(profile, args) {
71
+ requireCapability('admin', profile);
72
+ const rel = await resolveRelation(profile, args.schema, args.table);
73
+ const sql = `ANALYZE ${rel.schema}.${rel.name}`;
74
+ await withSession(profile, (client) => client.query({ text: sql, values: [], queryMode: 'extended' }), { operation: 'admin_maintenance_analyze' });
75
+ return { kind: 'mutation', rowCount: 0, committed: true };
76
+ }
77
+ export async function handleMaintenanceReindex(profile, args) {
78
+ const targetIdent = args.target === 'table' ? await resolveRelation(profile, args.schema, args.name) : await resolveIndex(profile, args.schema, args.name);
79
+ const onWord = args.target === 'table' ? 'TABLE' : 'INDEX';
80
+ const object = `${targetIdent.schema}.${targetIdent.name}`;
81
+ if (args.concurrently) {
82
+ requireCapability('admin', profile);
83
+ const sql = `REINDEX ${onWord} CONCURRENTLY ${object}`;
84
+ await withSession(profile, (client) => client.query({ text: sql, values: [], queryMode: 'extended' }), { operation: 'admin_maintenance_reindex_concurrently' });
85
+ return { kind: 'mutation', rowCount: 0, committed: true };
86
+ }
87
+ const sql = `REINDEX ${onWord} ${object}`;
88
+ return runGuardedMutation({
89
+ profile,
90
+ capability: 'admin',
91
+ operation: 'admin_maintenance_reindex',
92
+ sql,
93
+ params: [],
94
+ keyColumns: [],
95
+ confirm: args.confirm,
96
+ expect: toExpectToken(args.expect),
97
+ allowRowDrift: args.allowRowDrift,
98
+ });
99
+ }
100
+ export const MAINTENANCE_DESCRIPTION = '`maintenance_vacuum`/`maintenance_analyze` require `admin` and run immediately with NO dry run — VACUUM cannot run inside a transaction ' +
101
+ 'block at all, so no truthful preview is possible; neither operation deletes or hides live rows. `maintenance_reindex` with ' +
102
+ 'concurrently:false (default, single table/index) DOES support a real dry run through the usual confirm protocol — it actually rebuilds ' +
103
+ 'the index inside a rolled-back transaction. concurrently:true cannot run inside a transaction either, so it also runs immediately with ' +
104
+ 'no dry run. REINDEX without CONCURRENTLY takes an ACCESS EXCLUSIVE lock on the target — expect it to block other queries on a busy ' +
105
+ `table. ${CONFIRM_PROTOCOL_DESCRIPTION}`;
106
+ //# sourceMappingURL=maintenance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance.js","sourceRoot":"","sources":["../../../src/tools/admin/maintenance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ import { z } from 'zod';
2
+ import { PgMcpError } from '../../core/errors.js';
3
+ import { CONFIRM_PROTOCOL_DESCRIPTION, runGuardedMutation } from '../../core/guards.js';
4
+ import { assertRoleAvailable, resolveRole } from '../../core/identifiers.js';
5
+ import { requireCapability } from '../../core/policy.js';
6
+ import { getRoleDependencies, listRoles } from '../../db/catalog.js';
7
+ import { withSession } from '../../db/session.js';
8
+ import { confirmFragment, toExpectToken } from '../_batch_shared.js';
9
+ import { reportList } from './_shared.js';
10
+ /**
11
+ * `roles` sub-operation: list roles/attributes/memberships (read-only, no
12
+ * capability), and create/alter/drop a role (requires `admin`, guarded via
13
+ * `runGuardedMutation` — no `RETURNING`, so `keyColumns` is always empty and
14
+ * the dry run's row count is not meaningful for these, same caveat as DDL in
15
+ * `execute_sql`).
16
+ */
17
+ export const rolesListSchema = z.object({
18
+ op: z.literal('roles_list'),
19
+ namePattern: z.string().optional().describe('SQL ILIKE pattern to filter role names, e.g. "app_%".'),
20
+ });
21
+ export const rolesCreateSchema = z.object({
22
+ op: z.literal('roles_create'),
23
+ role: z.string().min(1),
24
+ login: z.boolean().optional().default(false),
25
+ superuser: z.boolean().optional().default(false),
26
+ createDb: z.boolean().optional().default(false),
27
+ createRole: z.boolean().optional().default(false),
28
+ replication: z.boolean().optional().default(false),
29
+ connectionLimit: z.number().int().optional().describe('-1 (default in PostgreSQL) means unlimited.'),
30
+ ...confirmFragment,
31
+ });
32
+ export const rolesAlterSchema = z.object({
33
+ op: z.literal('roles_alter'),
34
+ role: z.string().min(1),
35
+ set: z
36
+ .object({
37
+ login: z.boolean().optional(),
38
+ superuser: z.boolean().optional(),
39
+ createDb: z.boolean().optional(),
40
+ createRole: z.boolean().optional(),
41
+ replication: z.boolean().optional(),
42
+ connectionLimit: z.number().int().optional(),
43
+ validUntil: z.string().datetime().nullable().optional().describe('ISO 8601 timestamp; null clears it to VALID UNTIL infinity.'),
44
+ })
45
+ .refine((v) => Object.values(v).some((x) => x !== undefined), { message: 'set must include at least one attribute to change' })
46
+ .describe('Attributes to change. Password changes are out of scope for postgres_admin — use postgres_execute_sql on a profile with ALLOW_DDL for ALTER ROLE ... PASSWORD.'),
47
+ ...confirmFragment,
48
+ });
49
+ export const rolesDropSchema = z.object({
50
+ op: z.literal('roles_drop'),
51
+ role: z.string().min(1),
52
+ ...confirmFragment,
53
+ });
54
+ export async function handleRolesList(profile, args) {
55
+ const roles = await withSession(profile, (client) => listRoles(client, args.namePattern), { operation: 'admin_roles_list' });
56
+ return reportList(profile, roles);
57
+ }
58
+ function alterOptionClause(set) {
59
+ const parts = [];
60
+ if (set.login !== undefined)
61
+ parts.push(set.login ? 'LOGIN' : 'NOLOGIN');
62
+ if (set.superuser !== undefined)
63
+ parts.push(set.superuser ? 'SUPERUSER' : 'NOSUPERUSER');
64
+ if (set.createDb !== undefined)
65
+ parts.push(set.createDb ? 'CREATEDB' : 'NOCREATEDB');
66
+ if (set.createRole !== undefined)
67
+ parts.push(set.createRole ? 'CREATEROLE' : 'NOCREATEROLE');
68
+ if (set.replication !== undefined)
69
+ parts.push(set.replication ? 'REPLICATION' : 'NOREPLICATION');
70
+ if (set.connectionLimit !== undefined)
71
+ parts.push(`CONNECTION LIMIT ${set.connectionLimit}`);
72
+ return parts;
73
+ }
74
+ export async function handleRolesCreate(profile, args) {
75
+ const roleIdent = await assertRoleAvailable(profile, args.role);
76
+ const parts = alterOptionClause(args);
77
+ const sql = `CREATE ROLE ${roleIdent} WITH ${parts.join(' ')}`;
78
+ return runGuardedMutation({
79
+ profile,
80
+ capability: 'admin',
81
+ operation: 'admin_roles_create',
82
+ sql,
83
+ params: [],
84
+ keyColumns: [],
85
+ confirm: args.confirm,
86
+ expect: toExpectToken(args.expect),
87
+ allowRowDrift: args.allowRowDrift,
88
+ });
89
+ }
90
+ export async function handleRolesAlter(profile, args) {
91
+ const role = await resolveRole(profile, args.role);
92
+ const parts = alterOptionClause(args.set);
93
+ if (args.set.validUntil !== undefined) {
94
+ const escaped = (args.set.validUntil ?? 'infinity').replace(/'/g, "''");
95
+ parts.push(`VALID UNTIL '${escaped}'`);
96
+ }
97
+ const sql = `ALTER ROLE ${role.name} WITH ${parts.join(' ')}`;
98
+ return runGuardedMutation({
99
+ profile,
100
+ capability: 'admin',
101
+ operation: 'admin_roles_alter',
102
+ sql,
103
+ params: [],
104
+ keyColumns: [],
105
+ confirm: args.confirm,
106
+ expect: toExpectToken(args.expect),
107
+ allowRowDrift: args.allowRowDrift,
108
+ });
109
+ }
110
+ export async function handleRolesDrop(profile, args) {
111
+ // Extra catalog work (the dependency precheck) happens outside
112
+ // runGuardedMutation, so it needs its own gate — resolveRole/create/alter
113
+ // above rely on runGuardedMutation's internal check, same as
114
+ // delete_batch.ts's resolveRelation-before-guard convention.
115
+ requireCapability('admin', profile);
116
+ const role = await resolveRole(profile, args.role);
117
+ const deps = await withSession(profile, (client) => getRoleDependencies(client, role.oid), { operation: 'admin_roles_drop_precheck' });
118
+ if (deps.length > 0) {
119
+ const shown = deps.slice(0, 20);
120
+ throw new PgMcpError({
121
+ code: 'PG_ERROR',
122
+ message: `role "${args.role}" owns or is referenced by ${deps.length} object(s) and cannot be dropped as-is: ${shown.join('; ')}${deps.length > shown.length ? ', …' : ''}`,
123
+ hint: 'reassign ownership first — e.g. `REASSIGN OWNED BY <role> TO <new_owner>; DROP OWNED BY <role>;` via postgres_execute_sql on a profile with ' +
124
+ `ALLOW_DDL — or run \`SELECT * FROM pg_shdepend WHERE refobjid = '${args.role}'::regrole\` to see every dependent yourself, then retry roles_drop`,
125
+ details: { profile: profile.alias, role: args.role, dependents: deps },
126
+ });
127
+ }
128
+ const sql = `DROP ROLE ${role.name}`;
129
+ return runGuardedMutation({
130
+ profile,
131
+ capability: 'admin',
132
+ operation: 'admin_roles_drop',
133
+ sql,
134
+ params: [],
135
+ keyColumns: [],
136
+ confirm: args.confirm,
137
+ expect: toExpectToken(args.expect),
138
+ allowRowDrift: args.allowRowDrift,
139
+ });
140
+ }
141
+ export const ROLES_DESCRIPTION = `\`roles_list\` (read-only, no capability) lists roles with attributes and memberships. \`roles_create\`/\`roles_alter\`/\`roles_drop\` ` +
142
+ `require the \`admin\` capability. Password changes are out of scope — use postgres_execute_sql for those. \`roles_drop\` checks ` +
143
+ `pg_shdepend first and refuses with the exact dependent objects instead of PostgreSQL's raw error when the role still owns something. ${CONFIRM_PROTOCOL_DESCRIPTION}`;
144
+ //# sourceMappingURL=roles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.js","sourceRoot":"","sources":["../../../src/tools/admin/roles.ts"],"names":[],"mappings":"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"}