()
| 87 | } |
| 88 | |
| 89 | export async function startHttpServer() { |
| 90 | await checkAndTruncateLogFile(); |
| 91 | |
| 92 | if (port) { |
| 93 | writeMcpLog('MCP HTTP server is already running', 'info', { port }); |
| 94 | return port; |
| 95 | } |
| 96 | |
| 97 | writeMcpLog('Starting HTTP server for MCP'); |
| 98 | |
| 99 | try { |
| 100 | const app = express(); |
| 101 | app.use(express.json()); |
| 102 | |
| 103 | app.use((req: Request, res: Response, next: NextFunction) => { |
| 104 | const clientIp = req.ip || req.socket.remoteAddress; |
| 105 | if (clientIp === '127.0.0.1' || clientIp === '::1' || clientIp === '::ffff:127.0.0.1') { |
| 106 | next(); |
| 107 | } else { |
| 108 | logger.warn('Rejected connection from non-localhost IP', { clientIp, method: req.method, url: req.url }); |
| 109 | logToOutput(`Rejected connection from non-localhost IP: ${clientIp}`, 'MCP Server'); |
| 110 | res.status(403).send('Access denied: This server only accepts connections from localhost'); |
| 111 | } |
| 112 | }); |
| 113 | |
| 114 | app.get('/tables', async function (req: any, res: any) { |
| 115 | logger.debug('HTTP request: GET /tables'); |
| 116 | const db = getDatabase(); |
| 117 | if (!db) { |
| 118 | logger.error('No database connected for /tables request'); |
| 119 | return res.status(500).json({ error: 'No DB connected' }); |
| 120 | } |
| 121 | const tables = await db.getTables(); |
| 122 | logger.debug('Successfully fetched tables', { tableCount: tables.length }); |
| 123 | res.json({ tables }); |
| 124 | }); |
| 125 | |
| 126 | app.get('/tables/:tableName/schema', async function (req: any, res: any) { |
| 127 | const { tableName } = req.params; |
| 128 | logger.debug('HTTP request: GET /tables/:tableName/schema', { tableName }); |
| 129 | const db = getDatabase(); |
| 130 | if (!db) { |
| 131 | logger.error('No database connected for schema request', { tableName }); |
| 132 | return res.status(500).json({ error: 'No DB connected' }); |
| 133 | } |
| 134 | const sql = await db.getTableCreationSql(tableName); |
| 135 | logger.debug('Successfully fetched table schema', { tableName, schemaLength: sql.length }); |
| 136 | res.json({ schema: sql }); |
| 137 | }); |
| 138 | |
| 139 | app.post('/query', async function (req: any, res: any) { |
| 140 | const { query } = req.body; |
| 141 | logger.info('HTTP request: POST /query', { queryType: getQueryType(query), queryLength: query?.length }); |
| 142 | logger.debug('Full query text', { query }); |
| 143 | |
| 144 | if (!query) { |
| 145 | logger.error('Query is required but not provided'); |
| 146 | return res.status(400).json({ error: 'Query is required' }); |
no test coverage detected