import { z } from 'zod';
import { pocketBaseService, PocketBaseError } from '../pocketbase-service.js';
import { logger } from '../utils/logger.js';
import { GetLogsParamsSchema, CreateBackupParamsSchema, } from '../types/mcp.js';
// Helper function to create tool results
function createResult(text, isError = false, meta) {
const result = {
content: [{ type: 'text', text }],
isError,
};
if (meta !== undefined) {
result._meta = meta;
}
return result;
}
// Helper function to validate parameters
function validateParams(schema, params) {
try {
return schema.parse(params);
}
catch (error) {
if (error instanceof z.ZodError) {
const errors = error.errors.map((err) => `${err.path.join('.')}: ${err.message}`);
throw new Error(`Invalid parameters:\n${errors.join('\n')}`);
}
throw error;
}
}
// Health check tool
export const healthCheckTool = {
name: 'pb_health_check',
description: 'Check the health status of the PocketBase server',
inputSchema: {
type: 'object',
properties: {},
},
};
export async function handleHealthCheck() {
try {
logger.info('Processing health check request');
const health = await pocketBaseService.healthCheck();
const result = {
success: true,
status: 'healthy',
code: health.code,
message: health.message,
data: health.data,
timestamp: new Date().toISOString(),
};
return createResult(`PocketBase server is healthy (code: ${health.code})`, false, result);
}
catch (error) {
logger.error('Health check failed', error);
if (error instanceof PocketBaseError) {
return createResult(`Health check failed: ${error.message}`, true, {
success: false,
status: 'unhealthy',
error: error.message,
status_code: error.status,
timestamp: new Date().toISOString(),
});
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`Health check failed: ${message}`, true, {
success: false,
status: 'unhealthy',
error: message,
timestamp: new Date().toISOString(),
});
}
}
// Get server info tool
export const getServerInfoTool = {
name: 'pb_server_info',
description: 'Get PocketBase server information and configuration',
inputSchema: {
type: 'object',
properties: {},
},
};
export async function handleGetServerInfo() {
try {
logger.info('Processing server info request');
// Ensure admin authentication for accessing settings
await pocketBaseService.ensureAdminAuth();
const adminClient = pocketBaseService.getAdminClient();
const settings = await adminClient.settings.getAll();
// Extract non-sensitive server information
const serverInfo = {
meta: {
appName: settings.meta?.appName || 'PocketBase',
appUrl: settings.meta?.appUrl,
hideControls: settings.meta?.hideControls,
senderName: settings.meta?.senderName,
senderAddress: settings.meta?.senderAddress,
},
logs: {
maxDays: settings.logs?.maxDays,
},
smtp: {
enabled: settings.smtp?.enabled,
host: settings.smtp?.host,
port: settings.smtp?.port,
username: settings.smtp?.username,
// Don't expose password
authMethod: settings.smtp?.authMethod,
tls: settings.smtp?.tls,
},
s3: {
enabled: settings.s3?.enabled,
bucket: settings.s3?.bucket,
region: settings.s3?.region,
endpoint: settings.s3?.endpoint,
// Don't expose access keys
forcePathStyle: settings.s3?.forcePathStyle,
},
backups: {
cron: settings.backups?.cron,
cronMaxKeep: settings.backups?.cronMaxKeep,
s3: {
enabled: settings.backups?.s3?.enabled,
bucket: settings.backups?.s3?.bucket,
region: settings.backups?.s3?.region,
endpoint: settings.backups?.s3?.endpoint,
forcePathStyle: settings.backups?.s3?.forcePathStyle,
},
},
};
const result = {
success: true,
serverInfo,
timestamp: new Date().toISOString(),
};
return createResult(`Server information retrieved for: ${serverInfo.meta.appName}`, false, result);
}
catch (error) {
logger.error('Get server info failed', error);
if (error instanceof PocketBaseError) {
return createResult(`Get server info failed: ${error.message}`, true, { error: error.message, status: error.status });
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`Get server info failed: ${message}`, true);
}
}
// Get logs tool
export const getLogsTool = {
name: 'pb_logs_list',
description: 'Get system logs (admin only)',
inputSchema: {
type: 'object',
properties: {
page: {
type: 'number',
minimum: 1,
default: 1,
description: 'Page number',
},
perPage: {
type: 'number',
minimum: 1,
maximum: 100,
default: 30,
description: 'Items per page (max 100)',
},
sort: {
type: 'string',
description: 'Sort criteria (e.g., "-created", "level")',
},
filter: {
type: 'string',
description: 'Filter criteria (e.g., "level = \'error\'")',
},
},
},
};
export async function handleGetLogs(params) {
try {
const { page, perPage, sort, filter } = validateParams(GetLogsParamsSchema, params);
logger.info('Processing get logs request', { page, perPage, sort, filter });
const result = await pocketBaseService.getLogs({
page,
perPage,
sort,
filter,
});
const logs = result.items.map((log) => ({
id: log.id,
level: log.level,
message: log.message,
data: log.data,
created: log.created,
}));
const response = {
success: true,
pagination: {
page: result.page,
perPage: result.perPage,
totalItems: result.totalItems,
totalPages: result.totalPages,
},
logs,
};
return createResult(`Found ${logs.length} logs (page ${page} of ${result.totalPages})`, false, response);
}
catch (error) {
logger.error('Get logs failed', error);
if (error instanceof PocketBaseError) {
return createResult(`Get logs failed: ${error.message}`, true, { error: error.message, status: error.status });
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`Get logs failed: ${message}`, true);
}
}
// Get log statistics tool
export const getLogStatsTool = {
name: 'pb_logs_stats',
description: 'Get log statistics (admin only)',
inputSchema: {
type: 'object',
properties: {
filter: {
type: 'string',
description: 'Filter criteria for stats',
},
},
},
};
export async function handleGetLogStats(params) {
try {
const { filter } = params;
logger.info('Processing get log stats request', { filter });
// Ensure admin authentication
await pocketBaseService.ensureAdminAuth();
const adminClient = pocketBaseService.getAdminClient();
const stats = await adminClient.logs.getStats({ filter });
const result = {
success: true,
stats,
filter,
timestamp: new Date().toISOString(),
};
return createResult('Log statistics retrieved successfully', false, result);
}
catch (error) {
logger.error('Get log stats failed', error);
if (error instanceof PocketBaseError) {
return createResult(`Get log stats failed: ${error.message}`, true, { error: error.message, status: error.status });
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`Get log stats failed: ${message}`, true);
}
}
// Create backup tool
export const createBackupTool = {
name: 'pb_backups_create',
description: 'Create a new backup (admin only)',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Optional backup name/basename',
},
},
},
};
export async function handleCreateBackup(params) {
try {
const { name } = validateParams(CreateBackupParamsSchema, params);
logger.info('Processing create backup request', { name });
await pocketBaseService.createBackup(name);
const result = {
success: true,
backupName: name || 'auto-generated',
timestamp: new Date().toISOString(),
};
return createResult(`Backup created successfully${name ? ` with name: ${name}` : ''}`, false, result);
}
catch (error) {
logger.error('Create backup failed', error);
if (error instanceof PocketBaseError) {
return createResult(`Create backup failed: ${error.message}`, true, { error: error.message, status: error.status });
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`Create backup failed: ${message}`, true);
}
}
// List backups tool
export const listBackupsTool = {
name: 'pb_backups_list',
description: 'List all available backups (admin only)',
inputSchema: {
type: 'object',
properties: {},
},
};
export async function handleListBackups() {
try {
logger.info('Processing list backups request');
const backups = await pocketBaseService.listBackups();
const result = {
success: true,
totalBackups: backups.length,
backups: backups.map((backup) => ({
key: backup.key,
size: backup.size,
modified: backup.modified,
})),
};
return createResult(`Found ${backups.length} available backups`, false, result);
}
catch (error) {
logger.error('List backups failed', error);
if (error instanceof PocketBaseError) {
return createResult(`List backups failed: ${error.message}`, true, { error: error.message, status: error.status });
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`List backups failed: ${message}`, true);
}
}
// Test email tool
export const testEmailTool = {
name: 'pb_system_test_email',
description: 'Send a test email (admin only)',
inputSchema: {
type: 'object',
properties: {
email: {
type: 'string',
format: 'email',
description: 'Email address to send test email to',
},
template: {
type: 'string',
enum: ['verification', 'password-reset', 'email-change'],
description: 'Email template to test',
},
},
required: ['email', 'template'],
},
};
export async function handleTestEmail(params) {
try {
const { email, template } = params;
logger.info('Processing test email request', { email, template });
// Ensure admin authentication
await pocketBaseService.ensureAdminAuth();
const adminClient = pocketBaseService.getAdminClient();
await adminClient.settings.testEmail(email, template);
const result = {
success: true,
email,
template,
timestamp: new Date().toISOString(),
};
return createResult(`Test email sent successfully to ${email} using template: ${template}`, false, result);
}
catch (error) {
logger.error('Test email failed', error);
if (error instanceof PocketBaseError) {
return createResult(`Test email failed: ${error.message}`, true, { error: error.message, status: error.status });
}
const message = error instanceof Error ? error.message : 'Unknown error occurred';
return createResult(`Test email failed: ${message}`, true);
}
}
// Export all system tools and handlers
export const systemTools = [
healthCheckTool,
getServerInfoTool,
getLogsTool,
getLogStatsTool,
createBackupTool,
listBackupsTool,
testEmailTool,
];
export const systemHandlers = {
pb_health_check: handleHealthCheck,
pb_server_info: handleGetServerInfo,
pb_logs_list: handleGetLogs,
pb_logs_stats: handleGetLogStats,
pb_backups_create: handleCreateBackup,
pb_backups_list: handleListBackups,
pb_system_test_email: handleTestEmail,
};
//# sourceMappingURL=system.js.map