Skip to main content
Glama

USQL MCP Server

by jvm
CLAUDE.md9.12 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Repository Overview This repository implements an **MCP Server** (Model Context Protocol Server) that exposes [usql](https://github.com/xo/usql) capabilities to AI assistants and LLM applications. The server enables AI models to execute SQL queries and inspect database schemas across any database system supported by usql. **Key Responsibility**: Safely bridge user queries to usql CLI execution, handle connection strings, parse results, and return structured data to the AI model. ## Development Language & Stack The project is implemented in **TypeScript/Node.js** with the following core dependencies: - **@modelcontextprotocol/sdk**: Official SDK for building MCP servers - **usql**: Invoked as an external CLI process (must be installed system-wide) - **node-sql-parser**: Optional, for query validation/analysis - Other standard Node.js utilities for process execution and error handling ## Project Structure ``` usql-mcp/ ├── src/ │ ├── index.ts # MCP server initialization and tool registration │ ├── tools/ │ │ ├── execute-query.ts # execute_query tool implementation │ │ ├── list-databases.ts # list_databases tool implementation │ │ ├── list-tables.ts # list_tables tool implementation │ │ ├── describe-table.ts # describe_table tool implementation │ │ └── execute-script.ts # execute_script tool implementation │ ├── usql/ │ │ ├── connection.ts # Connection string validation and usql invocation │ │ ├── process-executor.ts # Spawn and manage usql subprocesses │ │ └── parser.ts # Parse usql output into structured data │ ├── types/ │ │ └── index.ts # Shared TypeScript interfaces │ └── utils/ │ ├── error-handler.ts # Consistent error formatting │ └── logger.ts # Debug logging ├── dist/ # Compiled JavaScript output ├── tests/ │ ├── integration/ # Tests requiring usql installation │ └── unit/ # Unit tests with mocked usql ├── package.json ├── tsconfig.json ├── .npmrc # npm configuration └── README.md ``` ## Essential Commands ### Development Workflow ```bash # Install dependencies (includes MCP SDK) npm install # TypeScript compilation npm run build # Run compiled server (outputs to stdio for MCP protocol) node dist/index.js # Development mode with auto-rebuild npm run dev # Run test suite npm test # Run single test file npm test -- describe-table.test.ts # Type checking npm run type-check # Linting npm run lint # Format code npm run format ``` ### Testing Strategy - **Unit Tests**: Mock usql subprocess output, test tool parameter validation, test output parsing - **Integration Tests**: Require actual usql CLI + test databases (SQLite recommended for portability) - **Test Database Setup**: Include minimal test fixtures (SQLite .db file or schema init script) ```bash # Run only unit tests (no external dependencies) npm run test:unit # Run integration tests (requires usql + test databases) npm run test:integration # Watch mode during development npm run test -- --watch ``` ## Architecture & Design Patterns ### Core Concept: Process-Based Execution usql is a CLI tool, not a library. The MCP server spawns usql subprocesses for each query: 1. **Subprocess Invocation**: `usql 'connection_string' -c 'SELECT ...'` 2. **Output Parsing**: Parse usql's text/table output into structured JSON 3. **Error Handling**: Capture stderr for connection/permission errors 4. **Resource Cleanup**: Ensure subprocess termination and timeout handling ### Tool Architecture Each tool (`execute-query.ts`, `list-databases.ts`, etc.) follows this pattern: ```typescript // 1. Define schema (MCP tool parameters) const schema = { name: "execute_query", description: "...", inputSchema: { type: "object", properties: { connection_string: { type: "string" }, query: { type: "string" }, parameters: { type: "array" } }, required: ["connection_string", "query"] } }; // 2. Implement handler async function execute(input) { validateInput(input); const result = await invokeUsql(input.connection_string, input.query); return parseResult(result); } ``` ### Connection String Handling - **Validation**: Verify connection strings follow dburl format before invocation - **Security**: Never log full connection strings (redact credentials in debug output) - **Environment Variables**: Support `process.env.USQL_*` for default connections - **Error Messages**: Never expose raw connection string errors to client ### Output Parsing Strategy usql outputs in multiple formats. Default parsing assumes: 1. **JSON Output** (preferred): `usql --json` for structured data 2. **Table Output** (fallback): Parse psql-style text tables 3. **Error Messages**: Detect and format errors consistently Consider using [`json` output format](https://github.com/xo/usql#formatting) when available. ### Error Handling All errors must follow MCP error format: ```typescript { error: "ExecutionError", message: "Human-readable error description", details: { cause: "underlying cause if available", connectionString: "sanitized connection string (redacted)", query: "the query that failed" } } ``` **Never expose**: - Passwords or tokens - Full database error details that might reveal schema/security info - System paths or internal server state ## Key Implementation Notes ### 1. Query Parameter Binding For tools accepting `parameters` array: - Map to usql's parameter binding syntax (varies by database) - PostgreSQL: `$1, $2, ...` - MySQL: `?, ?, ...` - Validate parameter count matches placeholders ### 2. Timeout Management Set appropriate timeout logic for subprocess execution. The server now defaults to unlimited duration and only applies a timeout when `USQL_QUERY_TIMEOUT_MS` (or `defaults.queryTimeout`) is provided. Ensure any future changes preserve the ability to kill queries once a timeout is configured. ### 3. Connection Pooling (Optional Enhancement) For future optimization, consider caching connections but ensure: - Connections are properly closed on server shutdown - Per-connection state doesn't leak between requests - Thread safety if using connection pools ### 4. Schema Inspection Commands Different databases require different syntax: ``` PostgreSQL: SELECT * FROM information_schema.tables MySQL: SHOW TABLES SQLite: SELECT name FROM sqlite_master WHERE type='table' Oracle: SELECT table_name FROM user_tables ``` Consider using usql's built-in schema commands (`\dt`, `\d table_name`) where possible. ## Testing Databases For integration tests, use **SQLite** (no external server needed): ```bash # Create test database sqlite3 test.db < schema.sql # In tests, use connection string: sqlite:///$(pwd)/test.db ``` ## Security Checklist When implementing a new tool: - [ ] Validate connection string format - [ ] Use prepared statements for parameterized queries - [ ] Sanitize error messages before returning to client - [ ] Set query timeout to prevent resource exhaustion - [ ] Log queries without credentials (for debugging) - [ ] Document that users should create read-only database accounts for AI queries ## Debugging Tips Enable debug logging via environment variable: ```bash DEBUG=usql-mcp:* node dist/index.js ``` This enables detailed logs for: - Connection attempts - usql subprocess invocation - Query execution - Output parsing Use structured logging with consistent prefixes: ```typescript logger.debug("[process-executor] Spawning usql with timeout 30s"); logger.debug("[parser] Parsing JSON output, rows=" + result.rows.length); logger.error("[error-handler] Query failed", { sanitized: true, query: "SELECT..." }); ``` ## Dependencies to Avoid - **Database drivers** (libpq, mysql, etc.): usql handles this via subprocess - **Heavy ORMs**: usql is the abstraction layer - **Global mutable state**: Keep tool handlers pure/stateless for MCP protocol ## Building & Deployment The MCP server runs as a Node.js process managed by Claude Desktop or other MCP clients. **Build Output**: `npm run build` generates `dist/index.js` as the entry point **Configuration**: Users add to `claude_desktop_config.json`: ```json { "mcpServers": { "usql": { "command": "node", "args": ["/path/to/usql-mcp/dist/index.js"] } } } ``` The server outputs MCP protocol messages via stdout and reads requests via stdin. ## References - **MCP SDK Documentation**: https://github.com/modelcontextprotocol/sdk-typescript - **MCP Server Examples**: https://github.com/modelcontextprotocol/servers - **usql CLI Reference**: https://github.com/xo/usql - **dburl Format**: https://github.com/xo/dburl

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jvm/usql-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server