jaikishpai/mcp-server-nodejs
If you are the rightful owner of mcp-server-nodejs and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
The MCP Oracle Server is a production-grade Node.js server designed for Oracle Database integration with HTTP transport, enabling compatibility with Telnyx AI Agent and other HTTP-based MCP clients.
MCP Oracle Server (HTTP Transport)
A production-grade Node.js Model Context Protocol (MCP) server for Oracle Database with HTTP transport for Telnyx AI Agent compatibility. This server exposes MCP tools over HTTP/JSON-RPC, enabling integration with Telnyx and other HTTP-based MCP clients.
Features
- ✅ HTTP-based MCP Protocol: Full HTTP/JSON-RPC implementation (not STDIO)
- ✅ Telnyx Compatible: Designed for Telnyx AI Agent MCP integration
- ✅ Oracle Database Integration: Connection pooling with
oracledbdriver - ✅ API Key Authentication: Secure
/mcpendpoint with API key validation - ✅ MCP Tools:
runQuery: Execute SQL queries with bind parameterslistTables: List all tables in the databasegetSchema: Get detailed table schema informationnl2sql: Convert natural language to SQL using external service
- ✅ Web Server: Express server with
/health,/ready,/metrics,/webhook/telnyx - ✅ Production Ready: Logging, error handling, connection pooling, graceful shutdown
- ✅ Dockerized: Fully containerized with Docker Compose
Project Structure
mcp-oracle/
├── src/
│ ├── server.js # Main entrypoint: HTTP server + MCP setup
│ ├── oracle.js # Oracle connection pool management
│ ├── auth.js # API key authentication middleware
│ ├── web.js # Express app and routes
│ ├── mcpTransport.js # HTTP transport wrapper for MCP
│ ├── logger.js # Winston logger with file rotation
│ └── tools/
│ ├── runQuery.js # Execute SQL queries
│ ├── listTables.js # List database tables
│ ├── getSchema.js # Get table schema
│ └── nl2sql.js # Natural language to SQL
├── tests/
│ ├── integration.test.sh # Integration test script
│ └── lint-setup.md # Linting setup guide
├── package.json
├── Dockerfile
├── docker-compose.yml
├── .env.example
└── README.md
Prerequisites
- Node.js 20+ (for local development)
- Docker and Docker Compose (for containerized deployment)
- Oracle Database (accessible via network)
- Oracle Instant Client (handled automatically in Docker)
Quick Start
1. Setup Environment
# Copy environment file
cp .env.example .env
# Edit .env with your Oracle credentials
nano .env
Required environment variables:
ORACLE_USER: Oracle database usernameORACLE_PASS: Oracle database passwordORACLE_CONN: Connection string (format:host:port/service)MCP_API_KEY: API key for/mcpendpoint authentication (recommended)
2. Run with Docker Compose
# Build and start all services
docker-compose up --build
# Run in detached mode
docker-compose up -d
# View logs
docker-compose logs -f mcp-oracle
3. Run Locally (Development)
# Install dependencies
npm install
# Set environment variables (or use .env file)
export ORACLE_USER=your_user
export ORACLE_PASS=your_password
export ORACLE_CONN=host:1521/XEPDB1
export MCP_API_KEY=your_api_key
# Start the server
npm start
Configuration
Environment Variables
See .env.example for all available configuration options:
Required:
ORACLE_USER: Oracle database usernameORACLE_PASS: Oracle database passwordORACLE_CONN: Oracle connection string (format:host:port/service)
Recommended:
MCP_API_KEY: API key for/mcpendpoint (if not set, allows unauthenticated requests in dev mode)
Optional:
PORT: HTTP server port (default:3000)NL2SQL_URL: URL of NL2SQL service (default:http://nl2sql-service:8500/query)LOG_LEVEL: Logging level (default:info)CORS_ORIGIN: CORS origin (default:*)MAX_REQUEST_SIZE: Maximum request size (default:10mb)
Oracle Connection Pool
Configure pool settings via environment variables:
ORACLE_POOL_MIN: Minimum pool size (default:2)ORACLE_POOL_MAX: Maximum pool size (default:10)ORACLE_POOL_INCREMENT: Pool increment (default:1)ORACLE_POOL_TIMEOUT: Pool timeout in seconds (default:60)
API Endpoints
MCP Endpoint
POST /mcp
Main MCP protocol endpoint. Accepts JSON-RPC 2.0 requests.
Authentication:
- Header:
x-mcp-api-key: <your-api-key> - Or:
Authorization: Bearer <your-api-key>
Request Format:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Response Format:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [...]
}
}
Health & Monitoring
- GET
/health: Basic health check - GET
/ready: Readiness check (verifies DB pool) - GET
/metrics: Prometheus-formatted metrics - POST
/webhook/telnyx: Telnyx webhook handler
MCP Tools
1. runQuery
Execute a SQL query against the Oracle database.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "runQuery",
"arguments": {
"sql": "SELECT * FROM employees WHERE department_id = :dept_id",
"binds": { "dept_id": 10 },
"maxRows": 100
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{
"type": "text",
"text": "{\"success\":true,\"data\":{\"rows\":[...],\"rowCount\":5}}"
}]
}
}
2. listTables
List all tables in the database.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "listTables",
"arguments": {
"schema": "HR"
}
}
}
3. getSchema
Get detailed schema information for a table.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "getSchema",
"arguments": {
"tableName": "employees",
"schema": "HR"
}
}
}
4. nl2sql
Convert natural language query to SQL.
Request:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "nl2sql",
"arguments": {
"query": "Show me all customers from New York"
}
}
}
Telnyx Configuration
Setting up Telnyx AI Agent
-
Configure MCP URL:
- In Telnyx AI Agent settings, set the MCP URL to:
https://<your-host>:<port>/mcp - Example:
https://mcp.example.com:3000/mcp
- In Telnyx AI Agent settings, set the MCP URL to:
-
Configure API Key:
- In Telnyx AI Agent MCP configuration, set the API key to match your
MCP_API_KEYenvironment variable - The agent should send requests with header:
x-mcp-api-key: <your-api-key>
- In Telnyx AI Agent MCP configuration, set the API key to match your
-
Example Telnyx Configuration JSON:
{
"mcp": {
"url": "https://your-server.com:3000/mcp",
"apiKey": "your-secure-api-key-here",
"transport": "http"
}
}
Testing Telnyx Integration
# Test MCP endpoint with API key
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "x-mcp-api-key: your-api-key" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}'
Example curl Commands
List Available Tools
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "x-mcp-api-key: changeme" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}'
Execute a Query
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "x-mcp-api-key: changeme" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "runQuery",
"arguments": {
"sql": "SELECT table_name FROM user_tables WHERE ROWNUM <= 5"
}
}
}'
Health Check
curl http://localhost:3000/health
Telnyx Webhook
curl -X POST http://localhost:3000/webhook/telnyx \
-H "Content-Type: application/json" \
-d '{
"event_type": "message.received",
"data": {
"from": "+1234567890",
"to": "+0987654321",
"text": "Hello"
}
}'
Running Tests
Integration Tests
The project includes a bash integration test script:
# Make script executable
chmod +x tests/integration.test.sh
# Run tests (defaults to http://localhost:3000)
./tests/integration.test.sh
# Run with custom URL and API key
BASE_URL=http://your-server:3000 MCP_API_KEY=your-key ./tests/integration.test.sh
The test script validates:
- Health endpoint
- Readiness endpoint
- Metrics endpoint
- MCP authentication
- MCP tools/list
- MCP tools/call (listTables)
Docker Services
mcp-oracle
The main MCP server container:
- Runs HTTP server on port 3000
- Exposes MCP endpoint at
/mcp - Mounts logs directory
- Connects to Oracle database
nl2sql-service
FastAPI service for natural language to SQL conversion:
- Placeholder implementation included
- Exposes API on port 8500
- Replace with your actual NL2SQL service by updating the
imageindocker-compose.yml
oracle-db (Optional)
Local Oracle database for testing:
- Uses
gvenzl/oracle-freeimage - Exposes port 1521
- Data persisted in Docker volume
- Commented out by default - uncomment in
docker-compose.ymlif needed
Logging
Logs are written to:
- Console: Structured JSON logs with timestamps
- Files: Rotating log files in
logs/directory- Format:
mcp-oracle-YYYY-MM-DD.log - Max size: 20MB per file
- Retention: 14 days
- Format:
Security
API Key Authentication
The /mcp endpoint requires API key authentication:
- Set
MCP_API_KEYenvironment variable - Send requests with header:
x-mcp-api-key: <key>orAuthorization: Bearer <key> - If
MCP_API_KEYis not set, requests are allowed but a warning is logged (development mode)
TLS/HTTPS
For production, enable TLS:
-
Option 1: Application-level TLS (not recommended)
- Set
TLS_CERTandTLS_KEYenvironment variables - Update server code to use HTTPS
- Set
-
Option 2: Reverse Proxy (recommended)
- Use nginx, traefik, or similar
- Handle TLS termination at the proxy
- Forward requests to the application on port 3000
Request Limits
- Maximum request size: 10MB (configurable via
MAX_REQUEST_SIZE) - Request timeout: 30 seconds (configurable via
MCP_REQUEST_TIMEOUT) - CORS: Configurable via
CORS_ORIGIN
Troubleshooting
Oracle Connection Issues
- Check connection string format:
host:port/service - Verify network connectivity:
telnet host 1521 - Check Oracle Instant Client: Ensure it's installed in Docker
- Review logs: Check
logs/directory for detailed error messages
MCP Endpoint Issues
- Authentication errors: Verify
MCP_API_KEYmatches in request header - Timeout errors: Increase
MCP_REQUEST_TIMEOUTif queries are slow - Connection refused: Ensure service is running and port is exposed
NL2SQL Service Issues
- Verify service is running:
curl http://nl2sql-service:8500/health - Check network: Ensure services are on the same Docker network
- Review timeout: Default is 30 seconds
Design Notes / Choices
This section documents key design decisions and tradeoffs made during implementation:
1. HTTP Transport Implementation
Decision: Implemented custom HTTP transport wrapper instead of using SDK's STDIO transport.
Rationale:
- The MCP SDK (
@modelcontextprotocol/sdk) primarily supports STDIO transport - Telnyx and other HTTP-based clients require HTTP/JSON-RPC endpoints
- Created a wrapper that routes JSON-RPC requests to MCP Server's internal request handlers
- This allows the server to work with HTTP clients while maintaining compatibility with MCP protocol
Tradeoff:
- Requires manual routing of requests to handlers
- May need updates if SDK adds native HTTP transport in the future
- Benefits: Works with Telnyx and any HTTP client
2. API Key Authentication Pattern
Decision: Simple API key authentication via header, with development mode fallback.
Rationale:
- Telnyx requires API key-based authentication
- Supports both
x-mcp-api-keyheader andAuthorization: Bearerfor flexibility - If
MCP_API_KEYis not set, allows requests but logs warning (useful for local development) - Simple to implement and understand
Tradeoff:
- Not as secure as JWT with expiration, but sufficient for API-to-API communication
- Can be enhanced with JWT support in the future (stub provided in
auth.js)
3. Request Timeout Handling
Decision: 30-second default timeout with configurable value.
Rationale:
- Prevents hanging requests from consuming resources
- SQL queries can be slow, but 30 seconds is reasonable for most cases
- Configurable via
MCP_REQUEST_TIMEOUTfor different use cases - Returns proper JSON-RPC error response on timeout
Tradeoff:
- May timeout on very large/complex queries
- Users can increase timeout or optimize queries
4. Streaming Support
Decision: Implemented request-response pattern without streaming.
Rationale:
- MCP SDK's streaming is designed for STDIO
- HTTP request-response is simpler and more compatible
- Large result sets can be paginated using
maxRowsparameter - Can be enhanced with Server-Sent Events (SSE) or WebSockets if needed
Tradeoff:
- Large result sets must be paginated
- No real-time streaming of results
- Benefits: Simpler implementation, better compatibility
5. Error Handling and Response Format
Decision: All errors return JSON-RPC 2.0 compliant responses with proper error codes.
Rationale:
- Maintains JSON-RPC 2.0 protocol compliance
- Provides structured error information
- Tool errors are wrapped in MCP content format
- Database errors are caught and returned as JSON
Tradeoff:
- Error information is nested (JSON-RPC error → MCP content → tool error)
- Benefits: Protocol compliance, structured errors, easier debugging
License
MIT
Contributing
Contributions welcome! Please ensure:
- Code follows existing style
- All tools return consistent JSON responses
- Error handling is comprehensive
- Logging is appropriate
- Tests are updated
Support
For issues and questions:
- Check logs in
logs/directory - Review Docker Compose logs:
docker-compose logs - Verify environment variables
- Test Oracle connectivity independently
- Run integration tests:
./tests/integration.test.sh