Skip to main content
Glama

Paprika SQL MCP Server

by jonaheaton
README.md10.3 kB
# Paprika MCP Server A Model Context Protocol (MCP) desktop extension for connecting Claude to your custom SQL database. This server allows Claude to query and interact with your database in real-time during conversations. ## Overview MCP desktop extensions enable you to create custom tools that Claude can use directly through the desktop app. This implementation provides a SQL database interface that allows Claude to execute queries, explore schema, and analyze your data. ## Project Setup ### 1. Initialize the Project ```bash cd /Users/jonaheaton/Documents/paprika_mcp_server npm init -y ``` ### 2. Install Dependencies ```bash npm install @modelcontextprotocol/sdk npm install better-sqlite3 # For SQLite # OR for other databases: # npm install mysql2 # For MySQL # npm install pg # For PostgreSQL ``` ### 3. Create the MCP Server Create a file called `server.js`: ```javascript #!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import Database from 'better-sqlite3'; // or your preferred SQL driver class SQLMCPServer { constructor() { this.server = new Server( { name: 'paprika-sql-server', version: '0.1.0', }, { capabilities: { tools: {}, }, } ); // Initialize your database connection this.db = new Database('path/to/your/database.db'); // Update with your database path this.setupToolHandlers(); } setupToolHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'query_sql', description: 'Execute a SQL query on the database', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'SQL query to execute', }, }, required: ['query'], }, }, { name: 'describe_tables', description: 'Get schema information for all tables', inputSchema: { type: 'object', properties: {}, }, }, { name: 'get_table_schema', description: 'Get detailed schema for a specific table', inputSchema: { type: 'object', properties: { table_name: { type: 'string', description: 'Name of the table to describe', }, }, required: ['table_name'], }, }, ], }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'query_sql': return await this.executeQuery(args.query); case 'describe_tables': return await this.describeTables(); case 'get_table_schema': return await this.getTableSchema(args.table_name); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error.message}`, }, ], }; } }); } async executeQuery(query) { try { // Prevent destructive operations if needed const lowerQuery = query.toLowerCase().trim(); if (lowerQuery.startsWith('drop') || lowerQuery.startsWith('delete') || lowerQuery.startsWith('truncate')) { throw new Error('Destructive operations are not allowed'); } const result = this.db.prepare(query).all(); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { throw new Error(`SQL execution failed: ${error.message}`); } } async describeTables() { try { const tables = this.db.prepare(` SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' `).all(); return { content: [ { type: 'text', text: `Available tables: ${tables.map(t => t.name).join(', ')}`, }, ], }; } catch (error) { throw new Error(`Failed to describe tables: ${error.message}`); } } async getTableSchema(tableName) { try { const schema = this.db.prepare(`PRAGMA table_info(${tableName})`).all(); return { content: [ { type: 'text', text: JSON.stringify(schema, null, 2), }, ], }; } catch (error) { throw new Error(`Failed to get schema for ${tableName}: ${error.message}`); } } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); } } const server = new SQLMCPServer(); server.run().catch(console.error); ``` ### 4. Configure Package.json Update your `package.json`: ```json { "name": "paprika-mcp-server", "version": "1.0.0", "type": "module", "main": "server.js", "bin": { "paprika-mcp-server": "./server.js" }, "scripts": { "start": "node server.js" }, "dependencies": { "@modelcontextprotocol/sdk": "^0.1.0", "better-sqlite3": "^8.7.0" } } ``` ## Installation ### 1. Install the Package Globally ```bash npm install -g . ``` ### 2. Configure Claude Desktop Create or edit the Claude desktop configuration file: **Location:** `~/Library/Application Support/Claude/claude_desktop_config.json` ```json { "mcpServers": { "paprika-database": { "command": "paprika-mcp-server", "args": [] } } } ``` ### 3. Restart Claude Desktop After making the configuration changes, restart the Claude Desktop application. ## Database-Specific Configurations ### SQLite (Default) ```javascript import Database from 'better-sqlite3'; this.db = new Database('/path/to/your/database.db'); ``` ### PostgreSQL ```javascript import pg from 'pg'; const { Pool } = pg; this.db = new Pool({ user: 'your_user', host: 'localhost', database: 'your_database', password: 'your_password', port: 5432, }); // Update query execution method for async/await async executeQuery(query) { const result = await this.db.query(query); return { content: [ { type: 'text', text: JSON.stringify(result.rows, null, 2), }, ], }; } ``` ### MySQL ```javascript import mysql from 'mysql2/promise'; this.db = await mysql.createConnection({ host: 'localhost', user: 'your_user', password: 'your_password', database: 'your_database' }); // Update query execution method async executeQuery(query) { const [rows] = await this.db.execute(query); return { content: [ { type: 'text', text: JSON.stringify(rows, null, 2), }, ], }; } ``` ## Usage Examples Once configured, you can ask Claude to interact with your database: - **"Show me all tables in the database"** - **"Query the users table for recent entries"** - **"What's the schema of the products table?"** - **"Find all records where status is 'active'"** - **"Get a count of records by category"** ## Security Considerations ### Query Restrictions The server includes basic protection against destructive operations: - `DROP` statements are blocked - `DELETE` statements are blocked - `TRUNCATE` statements are blocked ### Additional Security Measures - Consider implementing read-only database access - Add input validation and sanitization - Implement query result size limits - Add authentication if needed - Use environment variables for sensitive configuration ### Example Environment Configuration ```javascript // Use environment variables for database connection this.db = new Database(process.env.DATABASE_PATH || './default.db'); ``` ## Advanced Features ### 1. Query Result Formatting Add methods to format results as tables or charts: ```javascript formatAsTable(data) { // Convert JSON to formatted table } formatAsChart(data) { // Generate chart data } ``` ### 2. Query History and Caching Implement query caching for performance: ```javascript this.queryCache = new Map(); async executeQuery(query) { if (this.queryCache.has(query)) { return this.queryCache.get(query); } // Execute and cache result } ``` ### 3. Multiple Database Support Extend to support multiple database connections: ```javascript this.databases = { primary: new Database('./primary.db'), analytics: new Database('./analytics.db') }; ``` ### 4. Custom Business Logic Add domain-specific functions: ```javascript { name: 'get_recipe_by_ingredient', description: 'Find recipes containing specific ingredients', // ... implementation } ``` ## Troubleshooting ### Common Issues 1. **Server not appearing in Claude** - Check that the configuration file path is correct - Verify the server is installed globally - Restart Claude Desktop 2. **Database connection errors** - Verify database file path is correct - Check database permissions - Ensure database driver is installed 3. **Query execution errors** - Verify SQL syntax - Check table and column names - Review error messages in Claude ### Debugging Enable verbose logging by adding debug statements: ```javascript console.error('Debug:', JSON.stringify(request, null, 2)); ``` ## Development ### Testing the Server ```bash # Test the server directly echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}' | node server.js ``` ### Making Changes 1. Edit `server.js` 2. Reinstall globally: `npm install -g .` 3. Restart Claude Desktop ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make your changes 4. Test thoroughly 5. Submit a pull request ## License MIT License - see LICENSE file for details.

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/jonaheaton/paprika_mcp_server'

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