import {
ListProjectsParams,
ListSharedProjectsParams,
} from '@neondatabase/api-client';
import { z } from 'zod';
import { NEON_DEFAULT_DATABASE_NAME } from '../constants';
type ZodObjectParams<T> = z.ZodObject<{ [key in keyof T]: z.ZodType<T[key]> }>;
const DATABASE_NAME_DESCRIPTION = `The name of the database. If not provided, the default ${NEON_DEFAULT_DATABASE_NAME} or first available database is used.`;
export const listProjectsInputSchema = z.object({
cursor: z
.string()
.optional()
.describe(
'Specify the cursor value from the previous response to retrieve the next batch of projects.'
),
limit: z
.number()
.default(10)
.describe(
'Specify a value from 1 to 400 to limit number of projects in the response.'
),
search: z
.string()
.optional()
.describe(
'Search by project name or id. You can specify partial name or id values to filter results.'
),
org_id: z.string().optional().describe('Search for projects by org_id.'),
}) satisfies ZodObjectParams<ListProjectsParams>;
export const createProjectInputSchema = z.object({
name: z
.string()
.optional()
.describe('An optional name of the project to create.'),
org_id: z
.string()
.optional()
.describe('Create project in a specific organization.'),
});
export const deleteProjectInputSchema = z.object({
projectId: z.string().describe('The ID of the project to delete'),
});
export const describeProjectInputSchema = z.object({
projectId: z.string().describe('The ID of the project to describe'),
});
export const runSqlInputSchema = z.object({
sql: z.string().describe('The SQL query to execute'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch to execute the query against. If not provided the default branch is used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
});
export const runSqlTransactionInputSchema = z.object({
sqlStatements: z.array(z.string()).describe('The SQL statements to execute'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch to execute the query against. If not provided the default branch is used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
});
export const explainSqlStatementInputSchema = z.object({
sql: z.string().describe('The SQL statement to analyze'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch to execute the query against. If not provided the default branch is used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
analyze: z
.boolean()
.default(true)
.describe('Whether to include ANALYZE in the EXPLAIN command'),
});
export const describeTableSchemaInputSchema = z.object({
tableName: z.string().describe('The name of the table'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch to execute the query against. If not provided the default branch is used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
});
export const getDatabaseTablesInputSchema = z.object({
projectId: z.string().describe('The ID of the project'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch. If not provided the default branch is used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
});
export const createBranchInputSchema = z.object({
projectId: z
.string()
.describe('The ID of the project to create the branch in'),
branchName: z.string().optional().describe('An optional name for the branch'),
});
export const prepareDatabaseMigrationInputSchema = z.object({
migrationSql: z
.string()
.describe('The SQL to execute to create the migration'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
});
export const completeDatabaseMigrationInputSchema = z.object({
migrationId: z
.string()
.describe('The migration ID from prepare_database_migration.'),
migrationSql: z
.string()
.describe(
'The SQL statements to apply. Pass the exact value from prepare_database_migration.'
),
databaseName: z
.string()
.describe(
'The database name. Pass the exact value from prepare_database_migration.'
),
projectId: z
.string()
.describe(
'The project ID. Pass the exact value from prepare_database_migration.'
),
temporaryBranchId: z
.string()
.describe('The temporary branch ID to delete after migration.'),
parentBranchId: z
.string()
.describe('The parent branch ID where migration will be applied.'),
applyChanges: z
.boolean()
.default(true)
.describe(
'Whether to apply the migration. Set to false to just delete the temp branch without applying.'
),
});
export const describeBranchInputSchema = z.object({
projectId: z.string().describe('The ID of the project'),
branchId: z.string().describe('An ID of the branch to describe'),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
});
export const deleteBranchInputSchema = z.object({
projectId: z.string().describe('The ID of the project containing the branch'),
branchId: z.string().describe('The ID of the branch to delete'),
});
export const getConnectionStringInputSchema = z.object({
projectId: z
.string()
.describe(
'The ID of the project. If not provided, the only available project will be used.'
),
branchId: z
.string()
.optional()
.describe(
'The ID or name of the branch. If not provided, the default branch will be used.'
),
computeId: z
.string()
.optional()
.describe(
'The ID of the compute/endpoint. If not provided, the read-write compute associated with the branch will be used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
roleName: z
.string()
.optional()
.describe(
'The name of the role to connect with. If not provided, the database owner name will be used.'
),
});
export const provisionNeonAuthInputSchema = z.object({
projectId: z
.string()
.describe('The ID of the project to provision Neon Auth for'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch to provision Neon Auth for. If not provided, the default branch is used.'
),
databaseName: z
.string()
.optional()
.describe(
'The database name to provision Neon Auth for. If not provided, the default database is used.'
),
});
export const provisionNeonDataApiInputSchema = z.object({
projectId: z
.string()
.describe('The ID of the project to provision the Data API for'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch to provision the Data API for. If not provided, the default branch is used.'
),
databaseName: z
.string()
.optional()
.describe(
'The database name to provision the Data API for. If not provided, the default database is used.'
),
authProvider: z
.enum(['neon_auth', 'external', 'none'])
.optional()
.describe(
'The authentication provider - "neon_auth" for Neon Auth integration, "external" for third-party providers like Clerk, Auth0, or Stytch, or "none" for unauthenticated access (not recommended). If not specified, the tool will check existing auth configuration and return options for selection.'
),
jwksUrl: z
.string()
.optional()
.describe(
'The JWKS URL for external authentication providers. Required when authProvider is "external".'
),
providerName: z
.string()
.optional()
.describe(
'The name of the external authentication provider (e.g., "Clerk", "Auth0", "Stytch"). Used when authProvider is "external".'
),
jwtAudience: z
.string()
.optional()
.describe(
'The expected JWT audience claim. Tokens without an audience claim will still be accepted.'
),
provisionNeonAuthFirst: z
.boolean()
.optional()
.describe(
'When true with authProvider="neon_auth", provisions Neon Auth before Data API if not already set up.'
),
}).refine(
(data) => !(data.authProvider === 'external' && !data.jwksUrl),
{
message: 'jwksUrl is required when authProvider is "external"',
path: ['jwksUrl'],
}
);
export const prepareQueryTuningInputSchema = z.object({
sql: z.string().describe('The SQL statement to analyze and tune'),
databaseName: z
.string()
.describe('The name of the database to execute the query against'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
roleName: z
.string()
.optional()
.describe(
'The name of the role to connect with. If not provided, the default role (usually "neondb_owner") will be used.'
),
});
export const completeQueryTuningInputSchema = z.object({
suggestedSqlStatements: z
.array(z.string())
.describe(
'The SQL DDL statements to execute to improve performance. These statements are the result of the prior steps, for example creating additional indexes.'
),
applyChanges: z
.boolean()
.default(false)
.describe('Whether to apply the suggested changes to the main branch'),
tuningId: z
.string()
.describe(
'The ID of the tuning to complete. This is NOT the branch ID. Remember this ID from the prior step using tool prepare_query_tuning.'
),
databaseName: z
.string()
.describe('The name of the database to execute the query against'),
projectId: z
.string()
.describe('The ID of the project to execute the query against'),
roleName: z
.string()
.optional()
.describe(
'The name of the role to connect with. If you have used a specific role in prepare_query_tuning you MUST pass the same role again to this tool. If not provided, the default role (usually "neondb_owner") will be used.'
),
shouldDeleteTemporaryBranch: z
.boolean()
.default(true)
.describe('Whether to delete the temporary branch after tuning'),
temporaryBranchId: z
.string()
.describe(
'The ID of the temporary branch that needs to be deleted after tuning.'
),
branchId: z
.string()
.optional()
.describe(
'The ID or name of the branch that receives the changes. If not provided, the default (main) branch will be used.'
),
});
export const listSlowQueriesInputSchema = z.object({
projectId: z
.string()
.describe('The ID of the project to list slow queries from'),
branchId: z
.string()
.optional()
.describe(
'An optional ID of the branch. If not provided the default branch is used.'
),
databaseName: z.string().optional().describe(DATABASE_NAME_DESCRIPTION),
computeId: z
.string()
.optional()
.describe(
'The ID of the compute/endpoint. If not provided, the read-write compute associated with the branch will be used.'
),
limit: z
.number()
.optional()
.default(10)
.describe('Maximum number of slow queries to return'),
minExecutionTime: z
.number()
.optional()
.default(1000)
.describe(
'Minimum execution time in milliseconds to consider a query as slow'
),
});
export const listBranchComputesInputSchema = z.object({
projectId: z
.string()
.optional()
.describe(
'The ID of the project. If not provided, the only available project will be used.'
),
branchId: z
.string()
.optional()
.describe(
'The ID of the branch. If provided, endpoints for this specific branch will be listed.'
),
});
export const listOrganizationsInputSchema = z.object({
search: z
.string()
.optional()
.describe(
'Search organizations by name or ID. You can specify partial name or ID values to filter results.'
),
});
export const listSharedProjectsInputSchema = z.object({
cursor: z
.string()
.optional()
.describe(
'Specify the cursor value from the previous response to retrieve the next batch of shared projects.'
),
limit: z
.number()
.default(10)
.describe(
'Specify a value from 1 to 400 to limit number of shared projects in the response.'
),
search: z
.string()
.optional()
.describe(
'Search by project name or id. You can specify partial name or id values to filter results.'
),
}) satisfies ZodObjectParams<ListSharedProjectsParams>;
export const resetFromParentInputSchema = z.object({
projectId: z.string().describe('The ID of the project containing the branch'),
branchIdOrName: z
.string()
.describe('The name or ID of the branch to reset from its parent'),
preserveUnderName: z
.string()
.optional()
.describe(
'Optional name to preserve the current state under a new branch before resetting'
),
});
export const compareDatabaseSchemaInputSchema = z.object({
projectId: z.string().describe('The ID of the project'),
branchId: z.string().describe('The ID of the branch'),
databaseName: z.string().describe(DATABASE_NAME_DESCRIPTION),
});
export const searchInputSchema = z.object({
query: z
.string()
.min(3)
.describe(
'The search query to find matching organizations, projects, or branches'
),
});
export const fetchInputSchema = z.object({
id: z
.string()
.min(1)
.describe(
'The ID returned by the search tool to fetch detailed information about the entity'
),
});
export const loadResourceInputSchema = z.object({
subject: z
.enum(['neon-get-started'])
.describe(
'The subject of the resource to load. Options: neon-get-started (Neon getting started guide).'
),
});