mcp-product-manager
Version:
MCP Orchestrator for task and project management with web interface
97 lines • 3.38 kB
JavaScript
// execute.js - POST /api/database/execute
import { Router } from 'express';
import { query, get, run } from '../../utils/database.js';
import { success, error, asyncHandler } from '../../utils/response.js';
const router = Router();
// Execute SQLite query
router.post('/api/database/execute', asyncHandler(async (req, res) => {
const { sql, params = [], mode = 'all' } = req.body;
// Basic security: check if query contains write operations
const upperSQL = sql.toUpperCase();
const isReadOnly = !upperSQL.includes('UPDATE') &&
!upperSQL.includes('INSERT') &&
!upperSQL.includes('DELETE') &&
!upperSQL.includes('CREATE') &&
!upperSQL.includes('DROP') &&
!upperSQL.includes('ALTER');
if (!isReadOnly && process.env.NODE_ENV === 'production') {
return res.status(403).json(error('Only SELECT queries are allowed in production', 403));
}
try {
let result;
// For write operations (UPDATE, INSERT, DELETE), use run()
if (!isReadOnly) {
result = await run(sql, params);
// Get query metadata for write operations
const metadata = {
rowCount: result.changes || 0,
mode,
isReadOnly,
lastID: result.lastID,
changes: result.changes
};
res.json(success({
result,
metadata
}));
return;
}
// For read operations, use get() or query()
if (mode === 'single') {
result = await get(sql, params);
}
else {
result = await query(sql, params);
}
// Get query metadata
const metadata = {
rowCount: Array.isArray(result) ? result.length : (result ? 1 : 0),
mode,
isReadOnly
};
res.json(success({
result,
metadata
}));
}
catch (err) {
console.error('Failed to execute query:', err);
const errorResponse = error('Failed to execute query', 500, {
error: err.message,
sql: sql.substring(0, 100) + (sql.length > 100 ? '...' : '')
});
res.status(errorResponse.status).json(errorResponse.body);
}
}));
// MCP tool definition
export const tool = {
name: 'execute_sqlite',
description: 'Execute SQLite queries on the coordination database. Use mode="single" for queries expecting one row, mode="all" for multiple rows.',
inputSchema: {
type: 'object',
properties: {
sql: {
type: 'string',
description: 'The SQL query to execute'
},
params: {
type: 'array',
description: 'Parameters for parameterized queries (optional)',
items: {
type: ['string', 'number', 'boolean', 'null']
},
default: []
},
mode: {
type: 'string',
enum: ['all', 'single'],
description: 'Query mode: "all" returns all matching rows, "single" returns first row only',
default: 'all'
}
},
required: ['sql']
}
};
export { router };
export default router;
//# sourceMappingURL=execute.js.map