sqlcipher-mcp-server 1.0.0 → 1.0.3

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.
@@ -0,0 +1,76 @@
1
+ /**
2
+ * MCP Server
3
+ * Model Context Protocol server setup and initialization
4
+ */
5
+
6
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import {
9
+ CallToolRequestSchema,
10
+ ListToolsRequestSchema,
11
+ } from '@modelcontextprotocol/sdk/types.js';
12
+
13
+ import { SERVER_CONFIG } from '../config/constants.js';
14
+ import { getConfigurationWarnings } from '../config/environment.js';
15
+ import { handleListTools, handleExecuteQuery, handleUnknownTool } from '../handlers/mcp-handlers.js';
16
+
17
+ /**
18
+ * Create and configure MCP server
19
+ * @returns {Server} Configured MCP server instance
20
+ */
21
+ export function createMcpServer() {
22
+ const server = new Server(
23
+ {
24
+ name: SERVER_CONFIG.name,
25
+ version: SERVER_CONFIG.version,
26
+ },
27
+ {
28
+ capabilities: {
29
+ tools: {},
30
+ },
31
+ }
32
+ );
33
+
34
+ // Register list tools handler
35
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
36
+ return handleListTools();
37
+ });
38
+
39
+ // Register tool execution handler
40
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
41
+ const { name, arguments: args } = request.params;
42
+
43
+ if (name === 'execute_query') {
44
+ return await handleExecuteQuery(args);
45
+ } else {
46
+ return handleUnknownTool(name);
47
+ }
48
+ });
49
+
50
+ return server;
51
+ }
52
+
53
+ /**
54
+ * Start the MCP server
55
+ * @returns {Promise<void>}
56
+ */
57
+ export async function startMcpServer() {
58
+ // Check configuration and log warnings
59
+ const warnings = getConfigurationWarnings();
60
+ if (warnings.length > 0) {
61
+ console.error('Warning: ' + warnings.join(' '));
62
+ } else {
63
+ console.error('Configuration loaded: Database path and password set via environment variables.');
64
+ }
65
+
66
+ // Create server
67
+ const server = createMcpServer();
68
+
69
+ // Create stdio transport
70
+ const transport = new StdioServerTransport();
71
+
72
+ // Connect server to transport
73
+ await server.connect(transport);
74
+
75
+ console.error('SQLCipher MCP Server running on stdio');
76
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Database Service
3
+ * Service layer that wraps database operations with error handling
4
+ */
5
+
6
+ import { connectDatabase, executeQuery, closeConnection } from '../../lib/database.js';
7
+
8
+ /**
9
+ * Execute a query on a database
10
+ * Handles connection, query execution, and cleanup
11
+ * @param {string} dbPath - Path to the database file
12
+ * @param {string|undefined} password - Database password (optional)
13
+ * @param {string} query - SQL query to execute
14
+ * @returns {Promise<Object>} Query results
15
+ * @throws {Error} If connection or query execution fails
16
+ */
17
+ export async function executeQueryOnDatabase(dbPath, password, query) {
18
+ let db = null;
19
+
20
+ try {
21
+ // Connect to database
22
+ db = await connectDatabase(dbPath, password);
23
+
24
+ // Execute query
25
+ const result = await executeQuery(db, query);
26
+
27
+ return result;
28
+ } finally {
29
+ // Always close the database connection
30
+ if (db) {
31
+ closeConnection(db);
32
+ }
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Test database connection
38
+ * @param {string} dbPath - Path to the database file
39
+ * @param {string|undefined} password - Database password (optional)
40
+ * @returns {Promise<boolean>} True if connection successful
41
+ */
42
+ export async function testDatabaseConnection(dbPath, password) {
43
+ let db = null;
44
+
45
+ try {
46
+ db = await connectDatabase(dbPath, password);
47
+ return true;
48
+ } catch (error) {
49
+ throw new Error(`Failed to connect to database: ${error.message}`);
50
+ } finally {
51
+ if (db) {
52
+ closeConnection(db);
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Error Handling Utilities
3
+ * Standardized error response creation for MCP and HTTP
4
+ */
5
+
6
+ /**
7
+ * Create MCP error response
8
+ * @param {string} message - Error message
9
+ * @returns {Object} MCP error response object
10
+ */
11
+ export function createMcpErrorResponse(message) {
12
+ return {
13
+ content: [
14
+ {
15
+ type: 'text',
16
+ text: message,
17
+ },
18
+ ],
19
+ isError: true,
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Create MCP success response
25
+ * @param {string} text - Response text
26
+ * @returns {Object} MCP success response object
27
+ */
28
+ export function createMcpSuccessResponse(text) {
29
+ return {
30
+ content: [
31
+ {
32
+ type: 'text',
33
+ text: text,
34
+ },
35
+ ],
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Create HTTP error response
41
+ * @param {number} statusCode - HTTP status code
42
+ * @param {string} message - Error message
43
+ * @returns {Object} HTTP error response object
44
+ */
45
+ export function createHttpErrorResponse(statusCode, message) {
46
+ return {
47
+ statusCode,
48
+ body: {
49
+ error: message,
50
+ },
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Create HTTP success response
56
+ * @param {Object} data - Response data
57
+ * @param {string} message - Success message
58
+ * @returns {Object} HTTP success response object
59
+ */
60
+ export function createHttpSuccessResponse(data, message) {
61
+ return {
62
+ statusCode: 200,
63
+ body: {
64
+ success: true,
65
+ data: data,
66
+ message: message,
67
+ },
68
+ };
69
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Formatting Utilities
3
+ * Functions for formatting query results and other data
4
+ */
5
+
6
+ import { QUERY_CONFIG } from '../config/constants.js';
7
+
8
+ /**
9
+ * Format query results as a readable string
10
+ * @param {Object} result - Query result object with columns, rows, and rowCount
11
+ * @param {string[]} result.columns - Array of column names
12
+ * @param {Object[]} result.rows - Array of row objects
13
+ * @param {number} result.rowCount - Number of rows returned
14
+ * @returns {string} Formatted result string
15
+ */
16
+ export function formatQueryResults(result) {
17
+ const { columns, rows, rowCount } = result;
18
+
19
+ if (rowCount === 0) {
20
+ return `Query executed successfully. No rows returned.\nColumns: ${columns.join(', ')}`;
21
+ }
22
+
23
+ // Build table-like output
24
+ let output = `Query executed successfully. ${rowCount} row(s) returned.\n\n`;
25
+
26
+ // Add column headers
27
+ output += `Columns: ${columns.join(' | ')}\n`;
28
+ output += '-'.repeat(columns.join(' | ').length) + '\n';
29
+
30
+ // Add rows (limit to first maxDisplayRows for display)
31
+ const displayRows = rows.slice(0, QUERY_CONFIG.maxDisplayRows);
32
+ for (const row of displayRows) {
33
+ const values = columns.map(col => formatCellValue(row[col]));
34
+ output += values.join(' | ') + '\n';
35
+ }
36
+
37
+ if (rows.length > QUERY_CONFIG.maxDisplayRows) {
38
+ output += `\n... (showing first ${QUERY_CONFIG.maxDisplayRows} of ${rowCount} rows)`;
39
+ }
40
+
41
+ // Add JSON representation for programmatic access
42
+ output += '\n\nJSON representation:\n';
43
+ output += JSON.stringify(result, null, 2);
44
+
45
+ return output;
46
+ }
47
+
48
+ /**
49
+ * Format a single cell value for display
50
+ * @param {any} value - Cell value to format
51
+ * @returns {string} Formatted cell value
52
+ */
53
+ function formatCellValue(value) {
54
+ // Handle null/undefined
55
+ if (value === null || value === undefined) {
56
+ return 'NULL';
57
+ }
58
+
59
+ // Convert to string and truncate long values
60
+ const str = String(value);
61
+ return str.length > QUERY_CONFIG.maxValueLength
62
+ ? str.substring(0, QUERY_CONFIG.maxValueLength - 3) + '...'
63
+ : str;
64
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Validation Utilities
3
+ * Input validation and sanitization functions
4
+ */
5
+
6
+ import { getDatabasePath } from '../config/environment.js';
7
+
8
+ /**
9
+ * Validate that arguments is a valid object
10
+ * @param {any} args - Arguments to validate
11
+ * @throws {Error} If args is not a valid object
12
+ */
13
+ export function validateArguments(args) {
14
+ if (!args || typeof args !== 'object') {
15
+ throw new Error('Invalid arguments: arguments must be an object');
16
+ }
17
+ }
18
+
19
+ /**
20
+ * Validate query parameter
21
+ * @param {any} query - Query to validate
22
+ * @throws {Error} If query is invalid
23
+ */
24
+ export function validateQuery(query) {
25
+ if (!query || typeof query !== 'string') {
26
+ throw new Error('query is required and must be a string');
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Validate and resolve database path
32
+ * Uses provided path or falls back to environment variable
33
+ * @param {string|undefined} providedPath - Database path from arguments
34
+ * @returns {string} Resolved database path
35
+ * @throws {Error} If no valid path is available
36
+ */
37
+ export function resolveDatabasePath(providedPath) {
38
+ const dbPath = providedPath || getDatabasePath();
39
+
40
+ if (!dbPath || typeof dbPath !== 'string') {
41
+ throw new Error(
42
+ 'database_path is required. Provide it as a parameter or set SQLCIPHER_DATABASE_PATH environment variable.'
43
+ );
44
+ }
45
+
46
+ return dbPath;
47
+ }
48
+
49
+ /**
50
+ * Validate database path parameter for HTTP requests
51
+ * @param {any} database_path - Database path to validate
52
+ * @throws {Error} If database_path is invalid
53
+ */
54
+ export function validateDatabasePath(database_path) {
55
+ if (!database_path || typeof database_path !== 'string') {
56
+ throw new Error('database_path is required and must be a string');
57
+ }
58
+ }