From b3aa070e9e82a1ddbef099c816a5fe2ec08213d6 Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 14:03:16 +0800 Subject: [PATCH 01/26] Added MCP Server for MySQL --- package.json | 5 +- src/mysql/README.md | 53 +++++ src/mysql/index.js | 184 ++++++++++++++++ src/mysql/index.ts | 207 ++++++++++++++++++ src/mysql/package.json | 30 +++ src/mysql/pnpm-lock.yaml | 440 +++++++++++++++++++++++++++++++++++++++ src/mysql/tsconfig.json | 10 + 7 files changed, 927 insertions(+), 2 deletions(-) create mode 100644 src/mysql/README.md create mode 100644 src/mysql/index.js create mode 100644 src/mysql/index.ts create mode 100644 src/mysql/package.json create mode 100644 src/mysql/pnpm-lock.yaml create mode 100644 src/mysql/tsconfig.json diff --git a/package.json b/package.json index 0203ca98..1e7077a3 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@modelcontextprotocol/server-memory": "*", "@modelcontextprotocol/server-filesystem": "*", "@modelcontextprotocol/server-everart": "*", - "@modelcontextprotocol/server-sequential-thinking": "*" + "@modelcontextprotocol/server-sequential-thinking": "*", + "@modelcontextprotocol/server-mysql": "*" } -} \ No newline at end of file +} diff --git a/src/mysql/README.md b/src/mysql/README.md new file mode 100644 index 00000000..56fd7d14 --- /dev/null +++ b/src/mysql/README.md @@ -0,0 +1,53 @@ +# MySQL + +A Model Context Protocol server that provides read-only access to MySQL databases. This server enables LLMs to inspect database schemas and execute read-only queries. + +## Components + +### Tools + +- **query** + - Execute read-only SQL queries against the connected database + - Input: `sql` (string): The SQL query to execute + - All queries are executed within a READ ONLY transaction + +### Resources + +The server provides schema information for each table in the database: + +- **Table Schemas** + - JSON schema information for each table + - Includes column names and data types + - Automatically discovered from database metadata + +## Usage with Claude Desktop + +To use this server with the Claude Desktop app, add the following configuration to the "mcpServers" section of your `claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "mysql": { + "command": "npx", + "args": [ + "-y", + "@modelcontextprotocol/server-mysql", + ], + "env": { + "MYSQL_HOST": "127.0.0.1", + "MYSQL_PORT": "33067", + "MYSQL_USER": "root", + "MYSQL_PASS": "", + "MYSQL_DB": "db_name" + } + + } + } +} +``` + +Replace `/db_name` with your database name or leave it blank to retrieve all databases. + +## License + +This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. diff --git a/src/mysql/index.js b/src/mysql/index.js new file mode 100644 index 00000000..b2992e25 --- /dev/null +++ b/src/mysql/index.js @@ -0,0 +1,184 @@ +#!/usr/bin/env node + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListResourcesRequestSchema, + ListToolsRequestSchema, + ReadResourceRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import mysql from "mysql"; + +const server = new Server( + { + name: "example-servers/mysql", + version: "0.1.0", + }, + { + capabilities: { + resources: {}, + tools: {}, + }, + }, +); + +const MYSQL_HOST = process.env.MYSQL_HOST || "127.0.0.1"; +const MYSQL_PORT = process.env.MYSQL_PORT || "3306"; +const MYSQL_USER = process.env.MYSQL_USER || "root"; +const MYSQL_PASS = process.env.MYSQL_PASS || ""; +const MYSQL_DB = process.env.MYSQL_DB || ""; + +const pool = mysql.createPool({ + connectionLimit: 10, + host: MYSQL_HOST, + port: MYSQL_PORT, + user: MYSQL_USER, + password: MYSQL_PASS, + database: MYSQL_DB, +}); + +const SCHEMA_PATH = "schema"; + +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return new Promise((resolve, reject) => { + pool.query( + "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", + (error, results) => { + if (error) reject(error); + resolve({ + resources: results.map((row) => ({ + uri: new URL(`${row.table_name}/${SCHEMA_PATH}`, resourceBaseUrl) + .href, + mimeType: "application/json", + name: `"${row.table_name}" database schema`, + })), + }); + }, + ); + }); +}); + +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + const resourceUrl = new URL(request.params.uri); + + const pathComponents = resourceUrl.pathname.split("/"); + const schema = pathComponents.pop(); + const tableName = pathComponents.pop(); + + if (schema !== SCHEMA_PATH) { + throw new Error("Invalid resource URI"); + } + + return new Promise((resolve, reject) => { + pool.query( + "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", + [tableName], + (error, results) => { + if (error) reject(error); + resolve({ + contents: [ + { + uri: request.params.uri, + mimeType: "application/json", + text: JSON.stringify(results, null, 2), + }, + ], + }); + }, + ); + }); +}); + +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: "mysql_query", + description: "Run a read-only MySQL query", + inputSchema: { + type: "object", + properties: { + sql: { type: "string" }, + }, + }, + }, + ], + }; +}); + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "mysql_query") { + const sql = request.params.arguments?.sql; + + return new Promise((resolve, reject) => { + pool.getConnection((err, connection) => { + if (err) reject(err); + + // @INFO: Set session to read only BEFORE beginning the transaction + connection.query("SET SESSION TRANSACTION READ ONLY", (err) => { + if (err) { + connection.release(); + reject(err); + return; + } + + connection.beginTransaction((err) => { + if (err) { + connection.release(); + reject(err); + return; + } + + connection.query(sql, (error, results) => { + if (error) { + connection.rollback(() => { + connection.release(); + reject(error); + }); + return; + } + + connection.rollback(() => { + // @INFO: Reset the transaction mode back to default before releasing + connection.query( + "SET SESSION TRANSACTION READ WRITE", + (err) => { + connection.release(); + if (err) { + console.warn("Failed to reset transaction mode:", err); + } + resolve({ + content: [ + { + type: "text", + text: JSON.stringify(results, null, 2), + }, + ], + isError: false, + }); + }, + ); + }); + }); + }); + }); + }); + }); + } + throw new Error(`Unknown tool: ${request.params.name}`); +}); + +async function runServer() { + const transport = new StdioServerTransport(); + await server.connect(transport); +} + +process.on("SIGINT", () => { + pool.end((err) => { + if (err) console.error("Error closing pool:", err); + process.exit(err ? 1 : 0); + }); +}); + +runServer().catch(console.error); diff --git a/src/mysql/index.ts b/src/mysql/index.ts new file mode 100644 index 00000000..7d14aa47 --- /dev/null +++ b/src/mysql/index.ts @@ -0,0 +1,207 @@ +#!/usr/bin/env node + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListResourcesRequestSchema, + ListToolsRequestSchema, + ReadResourceRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import mysql, { MysqlError, PoolConnection, OkPacket } from "mysql"; + +type MySQLErrorType = MysqlError | null; + +interface TableRow { + table_name: string; +} + +interface ColumnRow { + column_name: string; + data_type: string; +} + +type QueryResult = OkPacket | any[] | any; +const server = new Server( + { + name: "example-servers/mysql", + version: "0.1.0", + }, + { + capabilities: { + resources: {}, + tools: {}, + }, + }, +); + +const MYSQL_HOST = process.env.MYSQL_HOST || "127.0.0.1"; +const MYSQL_PORT = process.env.MYSQL_PORT || "3306"; +const MYSQL_USER = process.env.MYSQL_USER || "root"; +const MYSQL_PASS = process.env.MYSQL_PASS || ""; +const MYSQL_DB = process.env.MYSQL_DB || ""; + +const pool = mysql.createPool({ + connectionLimit: 10, + host: MYSQL_HOST, + port: MYSQL_PORT, + user: MYSQL_USER, + password: MYSQL_PASS, + database: MYSQL_DB, +}); + +const SCHEMA_PATH = "schema"; + +server.setRequestHandler(ListResourcesRequestSchema, async () => { + return new Promise((resolve, reject) => { + pool.query( + "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", + (error: MySQLErrorType, results: TableRow[]) => { + if (error) reject(error); + resolve({ + resources: results.map((row: TableRow) => ({ + uri: new URL( + `${row.table_name}/${SCHEMA_PATH}`, + `${MYSQL_HOST}:${MYSQL_PORT}`, + ).href, + mimeType: "application/json", + name: `"${row.table_name}" database schema`, + })), + }); + }, + ); + }); +}); + +server.setRequestHandler(ReadResourceRequestSchema, async (request) => { + const resourceUrl = new URL(request.params.uri); + + const pathComponents = resourceUrl.pathname.split("/"); + const schema = pathComponents.pop(); + const tableName = pathComponents.pop(); + + if (schema !== SCHEMA_PATH) { + throw new Error("Invalid resource URI"); + } + + return new Promise((resolve, reject) => { + pool.query( + "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", + [tableName], + (error: MySQLErrorType, results: ColumnRow[]) => { + if (error) reject(error); + resolve({ + contents: [ + { + uri: request.params.uri, + mimeType: "application/json", + text: JSON.stringify(results, null, 2), + }, + ], + }); + }, + ); + }); +}); + +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: "mysql_query", + description: "Run a read-only MySQL query", + inputSchema: { + type: "object", + properties: { + sql: { type: "string" }, + }, + }, + }, + ], + }; +}); + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (request.params.name === "mysql_query") { + const sql = request.params.arguments?.sql as string; + + return new Promise((resolve, reject) => { + pool.getConnection((err: MySQLErrorType, connection: PoolConnection) => { + if (err) reject(err); + + // @INFO: Set session to read only BEFORE beginning the transaction + connection.query( + "SET SESSION TRANSACTION READ ONLY", + (err: MySQLErrorType) => { + if (err) { + connection.release(); + reject(err); + return; + } + + connection.beginTransaction((err: MySQLErrorType) => { + if (err) { + connection.release(); + reject(err); + return; + } + + connection.query( + sql, + (error: MySQLErrorType, results: QueryResult) => { + if (error) { + connection.rollback(() => { + connection.release(); + reject(error); + }); + return; + } + + // @INFO: Reset the transaction mode back to default before releasing + connection.rollback(() => { + connection.query( + "SET SESSION TRANSACTION READ WRITE", + (err: MySQLErrorType) => { + connection.release(); + if (err) { + console.warn( + "Failed to reset transaction mode:", + err, + ); + } + resolve({ + content: [ + { + type: "text", + text: JSON.stringify(results, null, 2), + }, + ], + isError: false, + }); + }, + ); + }); + }, + ); + }); + }, + ); + }); + }); + } + throw new Error(`Unknown tool: ${request.params.name}`); +}); + +async function runServer() { + const transport = new StdioServerTransport(); + await server.connect(transport); +} + +process.on("SIGINT", () => { + pool.end((err: MySQLErrorType) => { + if (err) console.error("Error closing pool:", err); + process.exit(err ? 1 : 0); + }); +}); + +runServer().catch(console.error); diff --git a/src/mysql/package.json b/src/mysql/package.json new file mode 100644 index 00000000..d3c6dfe8 --- /dev/null +++ b/src/mysql/package.json @@ -0,0 +1,30 @@ +{ + "name": "@modelcontextprotocol/server-mysql", + "version": "0.6.2", + "description": "MCP server for interacting with MySQL databases", + "license": "MIT", + "author": "Ben Borla (https://github.com/benborla)", + "homepage": "https://modelcontextprotocol.io", + "bugs": "https://github.com/modelcontextprotocol/servers/issues", + "type": "module", + "bin": { + "mcp-server-mysql": "dist/index.js" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc && shx chmod +x dist/*.js", + "prepare": "npm run build", + "watch": "tsc --watch" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "1.0.1", + "mysql": "^2.18.1" + }, + "devDependencies": { + "@types/pg": "^8.11.10", + "shx": "^0.3.4", + "typescript": "^5.6.2" + } +} diff --git a/src/mysql/pnpm-lock.yaml b/src/mysql/pnpm-lock.yaml new file mode 100644 index 00000000..e2e2fe59 --- /dev/null +++ b/src/mysql/pnpm-lock.yaml @@ -0,0 +1,440 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@modelcontextprotocol/sdk': + specifier: 1.0.1 + version: 1.0.1 + mysql: + specifier: ^2.18.1 + version: 2.18.1 + devDependencies: + '@types/pg': + specifier: ^8.11.10 + version: 8.11.10 + shx: + specifier: ^0.3.4 + version: 0.3.4 + typescript: + specifier: ^5.6.2 + version: 5.7.2 + +packages: + + '@modelcontextprotocol/sdk@1.0.1': + resolution: {integrity: sha512-slLdFaxQJ9AlRg+hw28iiTtGvShAOgOKXcD0F91nUcRYiOMuS9ZBYjcdNZRXW9G5JQ511GRTdUy1zQVZDpJ+4w==} + + '@types/node@22.10.1': + resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} + + '@types/pg@8.11.10': + resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + bignumber.js@9.0.0: + resolution: {integrity: sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mysql@2.18.1: + resolution: {integrity: sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==} + engines: {node: '>= 0.6'} + + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-protocol@1.7.0: + resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} + + pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + + postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + + readable-stream@2.3.7: + resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} + + rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + + shx@0.3.4: + resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} + engines: {node: '>=6'} + hasBin: true + + sqlstring@2.3.1: + resolution: {integrity: sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==} + engines: {node: '>= 0.6'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + +snapshots: + + '@modelcontextprotocol/sdk@1.0.1': + dependencies: + content-type: 1.0.5 + raw-body: 3.0.0 + zod: 3.23.8 + + '@types/node@22.10.1': + dependencies: + undici-types: 6.20.0 + + '@types/pg@8.11.10': + dependencies: + '@types/node': 22.10.1 + pg-protocol: 1.7.0 + pg-types: 4.0.2 + + balanced-match@1.0.2: {} + + bignumber.js@9.0.0: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + bytes@3.1.2: {} + + concat-map@0.0.1: {} + + content-type@1.0.5: {} + + core-util-is@1.0.3: {} + + depd@2.0.0: {} + + fs.realpath@1.0.0: {} + + function-bind@1.1.2: {} + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + interpret@1.4.0: {} + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + isarray@1.0.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimist@1.2.8: {} + + mysql@2.18.1: + dependencies: + bignumber.js: 9.0.0 + readable-stream: 2.3.7 + safe-buffer: 5.1.2 + sqlstring: 2.3.1 + + obuf@1.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + path-is-absolute@1.0.1: {} + + path-parse@1.0.7: {} + + pg-int8@1.0.1: {} + + pg-numeric@1.0.2: {} + + pg-protocol@1.7.0: {} + + pg-types@4.0.2: + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + + postgres-array@3.0.2: {} + + postgres-bytea@3.0.0: + dependencies: + obuf: 1.1.2 + + postgres-date@2.1.0: {} + + postgres-interval@3.0.0: {} + + postgres-range@1.1.4: {} + + process-nextick-args@2.0.1: {} + + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + + readable-stream@2.3.7: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + rechoir@0.6.2: + dependencies: + resolve: 1.22.8 + + resolve@1.22.8: + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + safe-buffer@5.1.2: {} + + safer-buffer@2.1.2: {} + + setprototypeof@1.2.0: {} + + shelljs@0.8.5: + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + + shx@0.3.4: + dependencies: + minimist: 1.2.8 + shelljs: 0.8.5 + + sqlstring@2.3.1: {} + + statuses@2.0.1: {} + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + supports-preserve-symlinks-flag@1.0.0: {} + + toidentifier@1.0.1: {} + + typescript@5.7.2: {} + + undici-types@6.20.0: {} + + unpipe@1.0.0: {} + + util-deprecate@1.0.2: {} + + wrappy@1.0.2: {} + + zod@3.23.8: {} diff --git a/src/mysql/tsconfig.json b/src/mysql/tsconfig.json new file mode 100644 index 00000000..ec5da158 --- /dev/null +++ b/src/mysql/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "." + }, + "include": [ + "./**/*.ts" + ] +} From c5a2c0f44620159f74c64f9ddd1764cca79a4782 Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 14:19:37 +0800 Subject: [PATCH 02/26] Removed pnpm locked json file --- src/mysql/pnpm-lock.yaml | 440 --------------------------------------- 1 file changed, 440 deletions(-) delete mode 100644 src/mysql/pnpm-lock.yaml diff --git a/src/mysql/pnpm-lock.yaml b/src/mysql/pnpm-lock.yaml deleted file mode 100644 index e2e2fe59..00000000 --- a/src/mysql/pnpm-lock.yaml +++ /dev/null @@ -1,440 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@modelcontextprotocol/sdk': - specifier: 1.0.1 - version: 1.0.1 - mysql: - specifier: ^2.18.1 - version: 2.18.1 - devDependencies: - '@types/pg': - specifier: ^8.11.10 - version: 8.11.10 - shx: - specifier: ^0.3.4 - version: 0.3.4 - typescript: - specifier: ^5.6.2 - version: 5.7.2 - -packages: - - '@modelcontextprotocol/sdk@1.0.1': - resolution: {integrity: sha512-slLdFaxQJ9AlRg+hw28iiTtGvShAOgOKXcD0F91nUcRYiOMuS9ZBYjcdNZRXW9G5JQ511GRTdUy1zQVZDpJ+4w==} - - '@types/node@22.10.1': - resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} - - '@types/pg@8.11.10': - resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - bignumber.js@9.0.0: - resolution: {integrity: sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - - is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} - engines: {node: '>= 0.4'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - mysql@2.18.1: - resolution: {integrity: sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==} - engines: {node: '>= 0.6'} - - obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-numeric@1.0.2: - resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} - engines: {node: '>=4'} - - pg-protocol@1.7.0: - resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} - - pg-types@4.0.2: - resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} - engines: {node: '>=10'} - - postgres-array@3.0.2: - resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} - engines: {node: '>=12'} - - postgres-bytea@3.0.0: - resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} - engines: {node: '>= 6'} - - postgres-date@2.1.0: - resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} - engines: {node: '>=12'} - - postgres-interval@3.0.0: - resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} - engines: {node: '>=12'} - - postgres-range@1.1.4: - resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - raw-body@3.0.0: - resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} - engines: {node: '>= 0.8'} - - readable-stream@2.3.7: - resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} - - rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} - - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true - - shx@0.3.4: - resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} - engines: {node: '>=6'} - hasBin: true - - sqlstring@2.3.1: - resolution: {integrity: sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==} - engines: {node: '>= 0.6'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - typescript@5.7.2: - resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - zod@3.23.8: - resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} - -snapshots: - - '@modelcontextprotocol/sdk@1.0.1': - dependencies: - content-type: 1.0.5 - raw-body: 3.0.0 - zod: 3.23.8 - - '@types/node@22.10.1': - dependencies: - undici-types: 6.20.0 - - '@types/pg@8.11.10': - dependencies: - '@types/node': 22.10.1 - pg-protocol: 1.7.0 - pg-types: 4.0.2 - - balanced-match@1.0.2: {} - - bignumber.js@9.0.0: {} - - brace-expansion@1.1.11: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - bytes@3.1.2: {} - - concat-map@0.0.1: {} - - content-type@1.0.5: {} - - core-util-is@1.0.3: {} - - depd@2.0.0: {} - - fs.realpath@1.0.0: {} - - function-bind@1.1.2: {} - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - interpret@1.4.0: {} - - is-core-module@2.15.1: - dependencies: - hasown: 2.0.2 - - isarray@1.0.0: {} - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.11 - - minimist@1.2.8: {} - - mysql@2.18.1: - dependencies: - bignumber.js: 9.0.0 - readable-stream: 2.3.7 - safe-buffer: 5.1.2 - sqlstring: 2.3.1 - - obuf@1.1.2: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - path-is-absolute@1.0.1: {} - - path-parse@1.0.7: {} - - pg-int8@1.0.1: {} - - pg-numeric@1.0.2: {} - - pg-protocol@1.7.0: {} - - pg-types@4.0.2: - dependencies: - pg-int8: 1.0.1 - pg-numeric: 1.0.2 - postgres-array: 3.0.2 - postgres-bytea: 3.0.0 - postgres-date: 2.1.0 - postgres-interval: 3.0.0 - postgres-range: 1.1.4 - - postgres-array@3.0.2: {} - - postgres-bytea@3.0.0: - dependencies: - obuf: 1.1.2 - - postgres-date@2.1.0: {} - - postgres-interval@3.0.0: {} - - postgres-range@1.1.4: {} - - process-nextick-args@2.0.1: {} - - raw-body@3.0.0: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - unpipe: 1.0.0 - - readable-stream@2.3.7: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - rechoir@0.6.2: - dependencies: - resolve: 1.22.8 - - resolve@1.22.8: - dependencies: - is-core-module: 2.15.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - safe-buffer@5.1.2: {} - - safer-buffer@2.1.2: {} - - setprototypeof@1.2.0: {} - - shelljs@0.8.5: - dependencies: - glob: 7.2.3 - interpret: 1.4.0 - rechoir: 0.6.2 - - shx@0.3.4: - dependencies: - minimist: 1.2.8 - shelljs: 0.8.5 - - sqlstring@2.3.1: {} - - statuses@2.0.1: {} - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - supports-preserve-symlinks-flag@1.0.0: {} - - toidentifier@1.0.1: {} - - typescript@5.7.2: {} - - undici-types@6.20.0: {} - - unpipe@1.0.0: {} - - util-deprecate@1.0.2: {} - - wrappy@1.0.2: {} - - zod@3.23.8: {} From ef0123d8891aa89738d7f28a8443e4991cc5f452 Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 14:51:07 +0800 Subject: [PATCH 03/26] Corrected type and fixed build errors --- src/mysql/index.ts | 6 +++--- src/mysql/package.json | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mysql/index.ts b/src/mysql/index.ts index 7d14aa47..e15f2dae 100644 --- a/src/mysql/index.ts +++ b/src/mysql/index.ts @@ -44,7 +44,7 @@ const MYSQL_DB = process.env.MYSQL_DB || ""; const pool = mysql.createPool({ connectionLimit: 10, host: MYSQL_HOST, - port: MYSQL_PORT, + port: Number(MYSQL_PORT), user: MYSQL_USER, password: MYSQL_PASS, database: MYSQL_DB, @@ -54,7 +54,7 @@ const SCHEMA_PATH = "schema"; server.setRequestHandler(ListResourcesRequestSchema, async () => { return new Promise((resolve, reject) => { - pool.query( + pool.query( "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", (error: MySQLErrorType, results: TableRow[]) => { if (error) reject(error); @@ -85,7 +85,7 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => { } return new Promise((resolve, reject) => { - pool.query( + pool.query( "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", [tableName], (error: MySQLErrorType, results: ColumnRow[]) => { diff --git a/src/mysql/package.json b/src/mysql/package.json index d3c6dfe8..f5c72bdc 100644 --- a/src/mysql/package.json +++ b/src/mysql/package.json @@ -23,7 +23,8 @@ "mysql": "^2.18.1" }, "devDependencies": { - "@types/pg": "^8.11.10", + "@types/node": "^20.10.0", + "@types/mysql": "^2.15.26", "shx": "^0.3.4", "typescript": "^5.6.2" } From 68549532d4dc14686920559251bf4b1712bd5de3 Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 14:52:33 +0800 Subject: [PATCH 04/26] removed index.js, should rely on the build index.js in dist/index.js --- src/mysql/index.js | 184 --------------------------------------------- 1 file changed, 184 deletions(-) delete mode 100644 src/mysql/index.js diff --git a/src/mysql/index.js b/src/mysql/index.js deleted file mode 100644 index b2992e25..00000000 --- a/src/mysql/index.js +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env node - -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - CallToolRequestSchema, - ListResourcesRequestSchema, - ListToolsRequestSchema, - ReadResourceRequestSchema, -} from "@modelcontextprotocol/sdk/types.js"; -import mysql from "mysql"; - -const server = new Server( - { - name: "example-servers/mysql", - version: "0.1.0", - }, - { - capabilities: { - resources: {}, - tools: {}, - }, - }, -); - -const MYSQL_HOST = process.env.MYSQL_HOST || "127.0.0.1"; -const MYSQL_PORT = process.env.MYSQL_PORT || "3306"; -const MYSQL_USER = process.env.MYSQL_USER || "root"; -const MYSQL_PASS = process.env.MYSQL_PASS || ""; -const MYSQL_DB = process.env.MYSQL_DB || ""; - -const pool = mysql.createPool({ - connectionLimit: 10, - host: MYSQL_HOST, - port: MYSQL_PORT, - user: MYSQL_USER, - password: MYSQL_PASS, - database: MYSQL_DB, -}); - -const SCHEMA_PATH = "schema"; - -server.setRequestHandler(ListResourcesRequestSchema, async () => { - return new Promise((resolve, reject) => { - pool.query( - "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", - (error, results) => { - if (error) reject(error); - resolve({ - resources: results.map((row) => ({ - uri: new URL(`${row.table_name}/${SCHEMA_PATH}`, resourceBaseUrl) - .href, - mimeType: "application/json", - name: `"${row.table_name}" database schema`, - })), - }); - }, - ); - }); -}); - -server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - const resourceUrl = new URL(request.params.uri); - - const pathComponents = resourceUrl.pathname.split("/"); - const schema = pathComponents.pop(); - const tableName = pathComponents.pop(); - - if (schema !== SCHEMA_PATH) { - throw new Error("Invalid resource URI"); - } - - return new Promise((resolve, reject) => { - pool.query( - "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", - [tableName], - (error, results) => { - if (error) reject(error); - resolve({ - contents: [ - { - uri: request.params.uri, - mimeType: "application/json", - text: JSON.stringify(results, null, 2), - }, - ], - }); - }, - ); - }); -}); - -server.setRequestHandler(ListToolsRequestSchema, async () => { - return { - tools: [ - { - name: "mysql_query", - description: "Run a read-only MySQL query", - inputSchema: { - type: "object", - properties: { - sql: { type: "string" }, - }, - }, - }, - ], - }; -}); - -server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name === "mysql_query") { - const sql = request.params.arguments?.sql; - - return new Promise((resolve, reject) => { - pool.getConnection((err, connection) => { - if (err) reject(err); - - // @INFO: Set session to read only BEFORE beginning the transaction - connection.query("SET SESSION TRANSACTION READ ONLY", (err) => { - if (err) { - connection.release(); - reject(err); - return; - } - - connection.beginTransaction((err) => { - if (err) { - connection.release(); - reject(err); - return; - } - - connection.query(sql, (error, results) => { - if (error) { - connection.rollback(() => { - connection.release(); - reject(error); - }); - return; - } - - connection.rollback(() => { - // @INFO: Reset the transaction mode back to default before releasing - connection.query( - "SET SESSION TRANSACTION READ WRITE", - (err) => { - connection.release(); - if (err) { - console.warn("Failed to reset transaction mode:", err); - } - resolve({ - content: [ - { - type: "text", - text: JSON.stringify(results, null, 2), - }, - ], - isError: false, - }); - }, - ); - }); - }); - }); - }); - }); - }); - } - throw new Error(`Unknown tool: ${request.params.name}`); -}); - -async function runServer() { - const transport = new StdioServerTransport(); - await server.connect(transport); -} - -process.on("SIGINT", () => { - pool.end((err) => { - if (err) console.error("Error closing pool:", err); - process.exit(err ? 1 : 0); - }); -}); - -runServer().catch(console.error); From 90fabce9d57c46fde3565aac6350fd4b4aa4d63c Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 15:11:37 +0800 Subject: [PATCH 05/26] refactored code for better readability and maintainability --- src/mysql/index.ts | 330 +++++++++++++++++++++++++-------------------- 1 file changed, 186 insertions(+), 144 deletions(-) diff --git a/src/mysql/index.ts b/src/mysql/index.ts index e15f2dae..82f0e4d9 100644 --- a/src/mysql/index.ts +++ b/src/mysql/index.ts @@ -8,7 +8,7 @@ import { ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -import mysql, { MysqlError, PoolConnection, OkPacket } from "mysql"; +import mysql, { MysqlError, PoolConnection } from "mysql"; type MySQLErrorType = MysqlError | null; @@ -21,187 +21,229 @@ interface ColumnRow { data_type: string; } -type QueryResult = OkPacket | any[] | any; -const server = new Server( - { +const config = { + server: { name: "example-servers/mysql", version: "0.1.0", }, - { - capabilities: { - resources: {}, - tools: {}, - }, + mysql: { + host: process.env.MYSQL_HOST || "127.0.0.1", + port: Number(process.env.MYSQL_PORT || "3306"), + user: process.env.MYSQL_USER || "root", + password: process.env.MYSQL_PASS || "", + database: process.env.MYSQL_DB || "", + connectionLimit: 10, }, -); + paths: { + schema: "schema", + }, +}; -const MYSQL_HOST = process.env.MYSQL_HOST || "127.0.0.1"; -const MYSQL_PORT = process.env.MYSQL_PORT || "3306"; -const MYSQL_USER = process.env.MYSQL_USER || "root"; -const MYSQL_PASS = process.env.MYSQL_PASS || ""; -const MYSQL_DB = process.env.MYSQL_DB || ""; +const mysqlQuery = ( + connection: PoolConnection, + sql: string, + params: any[] = [], +): Promise => { + return new Promise((resolve, reject) => { + connection.query(sql, params, (error: MySQLErrorType, results: any) => { + if (error) reject(error); + else resolve(results); + }); + }); +}; -const pool = mysql.createPool({ - connectionLimit: 10, - host: MYSQL_HOST, - port: Number(MYSQL_PORT), - user: MYSQL_USER, - password: MYSQL_PASS, - database: MYSQL_DB, +const mysqlGetConnection = (pool: mysql.Pool): Promise => { + return new Promise( + ( + resolve: (value: PoolConnection | PromiseLike) => void, + reject, + ) => { + pool.getConnection( + (error: MySQLErrorType, connection: PoolConnection) => { + if (error) reject(error); + else resolve(connection); + }, + ); + }, + ); +}; + +const mysqlBeginTransaction = (connection: PoolConnection): Promise => { + return new Promise((resolve, reject) => { + connection.beginTransaction((error: MySQLErrorType) => { + if (error) reject(error); + else resolve(); + }); + }); +}; + +const mysqlRollback = (connection: PoolConnection): Promise => { + return new Promise((resolve, _) => { + connection.rollback(() => resolve()); + }); +}; + +const pool = mysql.createPool(config.mysql); +const server = new Server(config.server, { + capabilities: { + resources: {}, + tools: {}, + }, }); -const SCHEMA_PATH = "schema"; +async function executeQuery(sql: string, params: any[] = []): Promise { + const connection = await mysqlGetConnection(pool); + try { + const results = await mysqlQuery(connection, sql, params); + return results; + } finally { + connection.release(); + } +} +async function executeReadOnlyQuery(sql: string): Promise { + const connection = await mysqlGetConnection(pool); + + try { + // Set read-only mode + await mysqlQuery(connection, "SET SESSION TRANSACTION READ ONLY"); + + // Begin transaction + await mysqlBeginTransaction(connection); + + // Execute query + const results = await mysqlQuery(connection, sql); + + // Rollback transaction (since it's read-only) + await mysqlRollback(connection); + + // Reset to read-write mode + await mysqlQuery(connection, "SET SESSION TRANSACTION READ WRITE"); + + return { + content: [ + { + type: "text", + text: JSON.stringify(results, null, 2), + }, + ], + isError: false, + }; + } catch (error) { + await mysqlRollback(connection); + throw error; + } finally { + connection.release(); + } +} + +// Request handlers server.setRequestHandler(ListResourcesRequestSchema, async () => { - return new Promise((resolve, reject) => { - pool.query( - "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", - (error: MySQLErrorType, results: TableRow[]) => { - if (error) reject(error); - resolve({ - resources: results.map((row: TableRow) => ({ - uri: new URL( - `${row.table_name}/${SCHEMA_PATH}`, - `${MYSQL_HOST}:${MYSQL_PORT}`, - ).href, - mimeType: "application/json", - name: `"${row.table_name}" database schema`, - })), - }); - }, - ); - }); + const results = (await executeQuery( + "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", + )) as TableRow[]; + + return { + resources: results.map((row: TableRow) => ({ + uri: new URL( + `${row.table_name}/${config.paths.schema}`, + `${config.mysql.host}:${config.mysql.port}`, + ).href, + mimeType: "application/json", + name: `"${row.table_name}" database schema`, + })), + }; }); server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const resourceUrl = new URL(request.params.uri); - const pathComponents = resourceUrl.pathname.split("/"); const schema = pathComponents.pop(); const tableName = pathComponents.pop(); - if (schema !== SCHEMA_PATH) { + if (schema !== config.paths.schema) { throw new Error("Invalid resource URI"); } - return new Promise((resolve, reject) => { - pool.query( - "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", - [tableName], - (error: MySQLErrorType, results: ColumnRow[]) => { - if (error) reject(error); - resolve({ - contents: [ - { - uri: request.params.uri, - mimeType: "application/json", - text: JSON.stringify(results, null, 2), - }, - ], - }); - }, - ); - }); -}); + const results = (await executeQuery( + "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", + [tableName], + )) as ColumnRow[]; -server.setRequestHandler(ListToolsRequestSchema, async () => { return { - tools: [ + contents: [ { - name: "mysql_query", - description: "Run a read-only MySQL query", - inputSchema: { - type: "object", - properties: { - sql: { type: "string" }, - }, - }, + uri: request.params.uri, + mimeType: "application/json", + text: JSON.stringify(results, null, 2), }, ], }; }); +server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [ + { + name: "mysql_query", + description: "Run a read-only MySQL query", + inputSchema: { + type: "object", + properties: { + sql: { type: "string" }, + }, + }, + }, + ], +})); + server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name === "mysql_query") { - const sql = request.params.arguments?.sql as string; - - return new Promise((resolve, reject) => { - pool.getConnection((err: MySQLErrorType, connection: PoolConnection) => { - if (err) reject(err); - - // @INFO: Set session to read only BEFORE beginning the transaction - connection.query( - "SET SESSION TRANSACTION READ ONLY", - (err: MySQLErrorType) => { - if (err) { - connection.release(); - reject(err); - return; - } - - connection.beginTransaction((err: MySQLErrorType) => { - if (err) { - connection.release(); - reject(err); - return; - } - - connection.query( - sql, - (error: MySQLErrorType, results: QueryResult) => { - if (error) { - connection.rollback(() => { - connection.release(); - reject(error); - }); - return; - } - - // @INFO: Reset the transaction mode back to default before releasing - connection.rollback(() => { - connection.query( - "SET SESSION TRANSACTION READ WRITE", - (err: MySQLErrorType) => { - connection.release(); - if (err) { - console.warn( - "Failed to reset transaction mode:", - err, - ); - } - resolve({ - content: [ - { - type: "text", - text: JSON.stringify(results, null, 2), - }, - ], - isError: false, - }); - }, - ); - }); - }, - ); - }); - }, - ); - }); - }); + if (request.params.name !== "mysql_query") { + throw new Error(`Unknown tool: ${request.params.name}`); } - throw new Error(`Unknown tool: ${request.params.name}`); + + const sql = request.params.arguments?.sql as string; + return executeReadOnlyQuery(sql); }); +// Server startup and shutdown async function runServer() { const transport = new StdioServerTransport(); await server.connect(transport); } -process.on("SIGINT", () => { - pool.end((err: MySQLErrorType) => { - if (err) console.error("Error closing pool:", err); - process.exit(err ? 1 : 0); +const shutdown = async (signal: string) => { + console.log(`Received ${signal}. Shutting down...`); + return new Promise((resolve, reject) => { + pool.end((err: MySQLErrorType) => { + if (err) { + console.error("Error closing pool:", err); + reject(err); + } else { + resolve(); + } + }); }); +}; + +process.on("SIGINT", async () => { + try { + await shutdown("SIGINT"); + process.exit(0); + } catch (err) { + process.exit(1); + } }); -runServer().catch(console.error); +process.on("SIGTERM", async () => { + try { + await shutdown("SIGTERM"); + process.exit(0); + } catch (err) { + process.exit(1); + } +}); + +runServer().catch((error: unknown) => { + console.error("Server error:", error); + process.exit(1); +}); From bd0a6a9ef22d35e69baf791b1919d07adeb289dc Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 15:26:13 +0800 Subject: [PATCH 06/26] removed unused type --- src/mysql/index.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/mysql/index.ts b/src/mysql/index.ts index 82f0e4d9..d5c32851 100644 --- a/src/mysql/index.ts +++ b/src/mysql/index.ts @@ -21,6 +21,14 @@ interface ColumnRow { data_type: string; } +interface QueryResult { + content: Array<{ + type: string; + text: string; + }>; + isError: boolean; +} + const config = { server: { name: "example-servers/mysql", @@ -39,11 +47,11 @@ const config = { }, }; -const mysqlQuery = ( +const mysqlQuery = ( connection: PoolConnection, sql: string, params: any[] = [], -): Promise => { +): Promise => { return new Promise((resolve, reject) => { connection.query(sql, params, (error: MySQLErrorType, results: any) => { if (error) reject(error); @@ -91,17 +99,17 @@ const server = new Server(config.server, { }, }); -async function executeQuery(sql: string, params: any[] = []): Promise { +async function executeQuery(sql: string, params: any[] = []): Promise { const connection = await mysqlGetConnection(pool); try { - const results = await mysqlQuery(connection, sql, params); + const results = await mysqlQuery(connection, sql, params); return results; } finally { connection.release(); } } -async function executeReadOnlyQuery(sql: string): Promise { +async function executeReadOnlyQuery(sql: string): Promise { const connection = await mysqlGetConnection(pool); try { @@ -120,7 +128,7 @@ async function executeReadOnlyQuery(sql: string): Promise { // Reset to read-write mode await mysqlQuery(connection, "SET SESSION TRANSACTION READ WRITE"); - return { + return { content: [ { type: "text", From 386516cca1938a23717c13d4ef39cda3a135347a Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 15:26:20 +0800 Subject: [PATCH 07/26] removed unusd type --- src/mysql/index.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/mysql/index.ts b/src/mysql/index.ts index d5c32851..b6b5867b 100644 --- a/src/mysql/index.ts +++ b/src/mysql/index.ts @@ -21,14 +21,6 @@ interface ColumnRow { data_type: string; } -interface QueryResult { - content: Array<{ - type: string; - text: string; - }>; - isError: boolean; -} - const config = { server: { name: "example-servers/mysql", From c78b18f08a13a41fe96e5cf482d7de4361d067ed Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Mon, 9 Dec 2024 15:34:00 +0800 Subject: [PATCH 08/26] updated project readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 45899a32..22eeb1c8 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ These servers aim to demonstrate MCP features and the Typescript and Python SDK. - **[Google Maps](src/google-maps)** - Location services, directions, and place details - **[Memory](src/memory)** - Knowledge graph-based persistent memory system - **[PostgreSQL](src/postgres)** - Read-only database access with schema inspection +- **[MySQL](src/mysql)** - Read-only database access with schema inspection for MySQL - **[Puppeteer](src/puppeteer)** - Browser automation and web scraping - **[Sentry](src/sentry)** - Retrieving and analyzing issues from Sentry.io - **[Sequential Thinking](src/sequentialthinking)** - Dynamic and reflective problem-solving through thought sequences From cc154c07ec52ee4160702483687a820b1f150f86 Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Tue, 10 Dec 2024 02:48:42 +0800 Subject: [PATCH 09/26] Updated readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 22eeb1c8..6530e0d9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@ These servers aim to demonstrate MCP features and the Typescript and Python SDK. - **[Google Maps](src/google-maps)** - Location services, directions, and place details - **[Memory](src/memory)** - Knowledge graph-based persistent memory system - **[PostgreSQL](src/postgres)** - Read-only database access with schema inspection -- **[MySQL](src/mysql)** - Read-only database access with schema inspection for MySQL - **[Puppeteer](src/puppeteer)** - Browser automation and web scraping - **[Sentry](src/sentry)** - Retrieving and analyzing issues from Sentry.io - **[Sequential Thinking](src/sequentialthinking)** - Dynamic and reflective problem-solving through thought sequences @@ -54,7 +53,8 @@ A growing set of community-developed and maintained servers demonstrates various - **[MCP Installer](https://github.com/anaisbetts/mcp-installer)** - This server is a server that installs other MCP servers for you. - **[Spotify MCP](https://github.com/varunneal/spotify-mcp)** - This MCP allows an LLM to play and use Spotify. - **[Inoyu](https://github.com/sergehuber/inoyu-mcp-unomi-server)** - Interact with an Apache Unomi CDP customer data platform to retrieve and update customer profiles -- **[MySQL](https://github.com/designcomputer/mysql_mcp_server)** - MySQL database integration with configurable access controls and schema inspection +- **[MySQL](https://github.com/designcomputer/mysql_mcp_server)** - (by DesignComputer) MySQL database integration based on Python with configurable access controls and schema inspection +- **[MySQL](https://github.com/benborla/mcp-server-mysql)** - (by benborla) MySQL database integration based on NodeJS with configurable access controls and schema inspection - **[BigQuery](https://github.com/LucasHild/mcp-server-bigquery)** (by LucasHild) - This server enables LLMs to inspect database schemas and execute queries on BigQuery. - **[BigQuery](https://github.com/ergut/mcp-bigquery-server)** (by ergut) - Server implementation for Google BigQuery integration that enables direct BigQuery database access and querying capabilities - **[Todoist](https://github.com/abhiz123/todoist-mcp-server)** - Interact with Todoist to manage your tasks. From f6f8361f095be0215fb33021a704c3c9de527d59 Mon Sep 17 00:00:00 2001 From: Ben Borla Date: Tue, 10 Dec 2024 02:53:58 +0800 Subject: [PATCH 10/26] removed unused files, this has been moved to its own repo --- package.json | 3 +- src/mysql/README.md | 53 --------- src/mysql/index.ts | 249 ---------------------------------------- src/mysql/package.json | 31 ----- src/mysql/tsconfig.json | 10 -- 5 files changed, 1 insertion(+), 345 deletions(-) delete mode 100644 src/mysql/README.md delete mode 100644 src/mysql/index.ts delete mode 100644 src/mysql/package.json delete mode 100644 src/mysql/tsconfig.json diff --git a/package.json b/package.json index 1e7077a3..9d5e5ee2 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "@modelcontextprotocol/server-memory": "*", "@modelcontextprotocol/server-filesystem": "*", "@modelcontextprotocol/server-everart": "*", - "@modelcontextprotocol/server-sequential-thinking": "*", - "@modelcontextprotocol/server-mysql": "*" + "@modelcontextprotocol/server-sequential-thinking": "*" } } diff --git a/src/mysql/README.md b/src/mysql/README.md deleted file mode 100644 index 56fd7d14..00000000 --- a/src/mysql/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# MySQL - -A Model Context Protocol server that provides read-only access to MySQL databases. This server enables LLMs to inspect database schemas and execute read-only queries. - -## Components - -### Tools - -- **query** - - Execute read-only SQL queries against the connected database - - Input: `sql` (string): The SQL query to execute - - All queries are executed within a READ ONLY transaction - -### Resources - -The server provides schema information for each table in the database: - -- **Table Schemas** - - JSON schema information for each table - - Includes column names and data types - - Automatically discovered from database metadata - -## Usage with Claude Desktop - -To use this server with the Claude Desktop app, add the following configuration to the "mcpServers" section of your `claude_desktop_config.json`: - -```json -{ - "mcpServers": { - "mysql": { - "command": "npx", - "args": [ - "-y", - "@modelcontextprotocol/server-mysql", - ], - "env": { - "MYSQL_HOST": "127.0.0.1", - "MYSQL_PORT": "33067", - "MYSQL_USER": "root", - "MYSQL_PASS": "", - "MYSQL_DB": "db_name" - } - - } - } -} -``` - -Replace `/db_name` with your database name or leave it blank to retrieve all databases. - -## License - -This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. diff --git a/src/mysql/index.ts b/src/mysql/index.ts deleted file mode 100644 index b6b5867b..00000000 --- a/src/mysql/index.ts +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/env node - -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { - CallToolRequestSchema, - ListResourcesRequestSchema, - ListToolsRequestSchema, - ReadResourceRequestSchema, -} from "@modelcontextprotocol/sdk/types.js"; -import mysql, { MysqlError, PoolConnection } from "mysql"; - -type MySQLErrorType = MysqlError | null; - -interface TableRow { - table_name: string; -} - -interface ColumnRow { - column_name: string; - data_type: string; -} - -const config = { - server: { - name: "example-servers/mysql", - version: "0.1.0", - }, - mysql: { - host: process.env.MYSQL_HOST || "127.0.0.1", - port: Number(process.env.MYSQL_PORT || "3306"), - user: process.env.MYSQL_USER || "root", - password: process.env.MYSQL_PASS || "", - database: process.env.MYSQL_DB || "", - connectionLimit: 10, - }, - paths: { - schema: "schema", - }, -}; - -const mysqlQuery = ( - connection: PoolConnection, - sql: string, - params: any[] = [], -): Promise => { - return new Promise((resolve, reject) => { - connection.query(sql, params, (error: MySQLErrorType, results: any) => { - if (error) reject(error); - else resolve(results); - }); - }); -}; - -const mysqlGetConnection = (pool: mysql.Pool): Promise => { - return new Promise( - ( - resolve: (value: PoolConnection | PromiseLike) => void, - reject, - ) => { - pool.getConnection( - (error: MySQLErrorType, connection: PoolConnection) => { - if (error) reject(error); - else resolve(connection); - }, - ); - }, - ); -}; - -const mysqlBeginTransaction = (connection: PoolConnection): Promise => { - return new Promise((resolve, reject) => { - connection.beginTransaction((error: MySQLErrorType) => { - if (error) reject(error); - else resolve(); - }); - }); -}; - -const mysqlRollback = (connection: PoolConnection): Promise => { - return new Promise((resolve, _) => { - connection.rollback(() => resolve()); - }); -}; - -const pool = mysql.createPool(config.mysql); -const server = new Server(config.server, { - capabilities: { - resources: {}, - tools: {}, - }, -}); - -async function executeQuery(sql: string, params: any[] = []): Promise { - const connection = await mysqlGetConnection(pool); - try { - const results = await mysqlQuery(connection, sql, params); - return results; - } finally { - connection.release(); - } -} - -async function executeReadOnlyQuery(sql: string): Promise { - const connection = await mysqlGetConnection(pool); - - try { - // Set read-only mode - await mysqlQuery(connection, "SET SESSION TRANSACTION READ ONLY"); - - // Begin transaction - await mysqlBeginTransaction(connection); - - // Execute query - const results = await mysqlQuery(connection, sql); - - // Rollback transaction (since it's read-only) - await mysqlRollback(connection); - - // Reset to read-write mode - await mysqlQuery(connection, "SET SESSION TRANSACTION READ WRITE"); - - return { - content: [ - { - type: "text", - text: JSON.stringify(results, null, 2), - }, - ], - isError: false, - }; - } catch (error) { - await mysqlRollback(connection); - throw error; - } finally { - connection.release(); - } -} - -// Request handlers -server.setRequestHandler(ListResourcesRequestSchema, async () => { - const results = (await executeQuery( - "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", - )) as TableRow[]; - - return { - resources: results.map((row: TableRow) => ({ - uri: new URL( - `${row.table_name}/${config.paths.schema}`, - `${config.mysql.host}:${config.mysql.port}`, - ).href, - mimeType: "application/json", - name: `"${row.table_name}" database schema`, - })), - }; -}); - -server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - const resourceUrl = new URL(request.params.uri); - const pathComponents = resourceUrl.pathname.split("/"); - const schema = pathComponents.pop(); - const tableName = pathComponents.pop(); - - if (schema !== config.paths.schema) { - throw new Error("Invalid resource URI"); - } - - const results = (await executeQuery( - "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ?", - [tableName], - )) as ColumnRow[]; - - return { - contents: [ - { - uri: request.params.uri, - mimeType: "application/json", - text: JSON.stringify(results, null, 2), - }, - ], - }; -}); - -server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools: [ - { - name: "mysql_query", - description: "Run a read-only MySQL query", - inputSchema: { - type: "object", - properties: { - sql: { type: "string" }, - }, - }, - }, - ], -})); - -server.setRequestHandler(CallToolRequestSchema, async (request) => { - if (request.params.name !== "mysql_query") { - throw new Error(`Unknown tool: ${request.params.name}`); - } - - const sql = request.params.arguments?.sql as string; - return executeReadOnlyQuery(sql); -}); - -// Server startup and shutdown -async function runServer() { - const transport = new StdioServerTransport(); - await server.connect(transport); -} - -const shutdown = async (signal: string) => { - console.log(`Received ${signal}. Shutting down...`); - return new Promise((resolve, reject) => { - pool.end((err: MySQLErrorType) => { - if (err) { - console.error("Error closing pool:", err); - reject(err); - } else { - resolve(); - } - }); - }); -}; - -process.on("SIGINT", async () => { - try { - await shutdown("SIGINT"); - process.exit(0); - } catch (err) { - process.exit(1); - } -}); - -process.on("SIGTERM", async () => { - try { - await shutdown("SIGTERM"); - process.exit(0); - } catch (err) { - process.exit(1); - } -}); - -runServer().catch((error: unknown) => { - console.error("Server error:", error); - process.exit(1); -}); diff --git a/src/mysql/package.json b/src/mysql/package.json deleted file mode 100644 index f5c72bdc..00000000 --- a/src/mysql/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "@modelcontextprotocol/server-mysql", - "version": "0.6.2", - "description": "MCP server for interacting with MySQL databases", - "license": "MIT", - "author": "Ben Borla (https://github.com/benborla)", - "homepage": "https://modelcontextprotocol.io", - "bugs": "https://github.com/modelcontextprotocol/servers/issues", - "type": "module", - "bin": { - "mcp-server-mysql": "dist/index.js" - }, - "files": [ - "dist" - ], - "scripts": { - "build": "tsc && shx chmod +x dist/*.js", - "prepare": "npm run build", - "watch": "tsc --watch" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "1.0.1", - "mysql": "^2.18.1" - }, - "devDependencies": { - "@types/node": "^20.10.0", - "@types/mysql": "^2.15.26", - "shx": "^0.3.4", - "typescript": "^5.6.2" - } -} diff --git a/src/mysql/tsconfig.json b/src/mysql/tsconfig.json deleted file mode 100644 index ec5da158..00000000 --- a/src/mysql/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "." - }, - "include": [ - "./**/*.ts" - ] -} From a56d68495532f025938b59ae1235a4a4adcfd6f2 Mon Sep 17 00:00:00 2001 From: amxv <156369134+amxv@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:18:09 +0530 Subject: [PATCH 11/26] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3dc4777a..59400c74 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Additional resources on MCP. - **[mcp-get](https://mcp-get.com)** - Command line tool for installing and managing MCP servers by **[Michael Latman](https://github.com/michaellatman)** - **[mcp-cli](https://github.com/wong2/mcp-cli)** - A CLI inspector for the Model Context Protocol by **[wong2](https://github.com/wong2)** - **[r/mcp](https://www.reddit.com/r/mcp)** – A Reddit community dedicated to MCP by **[Frank Fiegel](https://github.com/punkpeye)** +- **[mcp-manager](https://github.com/zueai/mcp-manager)** - Simple Web UI to install and manage MCP servers for Claude Desktop by **[Zue](https://github.com/zueai)** ## 🚀 Getting Started From 4b9fca738384255754d77bb1571a504accb5c9dc Mon Sep 17 00:00:00 2001 From: East Agile Date: Tue, 10 Dec 2024 14:28:36 +0700 Subject: [PATCH 12/26] Add mcp-server-rememberizer to community servers in README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3dc4777a..836d148a 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,8 @@ A growing set of community-developed and maintained servers demonstrates various - **[Docker](https://github.com/ckreiling/mcp-server-docker)** - Integrate with Docker to manage containers, images, volumes, and networks. - **[Kubernetes](https://github.com/Flux159/mcp-server-kubernetes)** - Connect to Kubernetes cluster and manage pods, deployments, and services. - **[OpenAPI](https://github.com/snaggle-ai/openapi-mcp-server)** - Interact with [OpenAPI](https://www.openapis.org/) APIs. -- **[Pandoc](https://github.com/vivekVells/mcp-pandoc)** - MCP server for seamless document format conversion using Pandoc, supporting Markdown, HTML, and plain text, with other formats like PDF, csv and docx in development. +- **[Pandoc](https://github.com/vivekVells/mcp-pandoc)** - MCP server for seamless document format conversion using Pandoc, supporting Markdown, HTML, and plain text, with other formats like PDF, csv and docx in development. +- **[Rememberizer AI](https://github.com/skydeckai/mcp-server-rememberizer)** - MCP server for interacting with Rememberizer data source and enhanced knowledge retrieval. ## 📚 Resources From c65601cfc5762084e0f45b27593e2717bf0fe52c Mon Sep 17 00:00:00 2001 From: East Agile Date: Tue, 10 Dec 2024 17:15:11 +0700 Subject: [PATCH 13/26] refine Rememberizer server description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 836d148a..79cd5c5f 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ A growing set of community-developed and maintained servers demonstrates various - **[Kubernetes](https://github.com/Flux159/mcp-server-kubernetes)** - Connect to Kubernetes cluster and manage pods, deployments, and services. - **[OpenAPI](https://github.com/snaggle-ai/openapi-mcp-server)** - Interact with [OpenAPI](https://www.openapis.org/) APIs. - **[Pandoc](https://github.com/vivekVells/mcp-pandoc)** - MCP server for seamless document format conversion using Pandoc, supporting Markdown, HTML, and plain text, with other formats like PDF, csv and docx in development. -- **[Rememberizer AI](https://github.com/skydeckai/mcp-server-rememberizer)** - MCP server for interacting with Rememberizer data source and enhanced knowledge retrieval. +- **[Rememberizer AI](https://github.com/skydeckai/mcp-server-rememberizer)** - An MCP server designed for interacting with the Rememberizer data source, facilitating enhanced knowledge retrieval. ## 📚 Resources From 1c30f54b2dd27f50003a9b1f85c4fce93c09b08d Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Tue, 10 Dec 2024 11:53:23 -0500 Subject: [PATCH 14/26] Change case sensitivity for filesystem server --- src/filesystem/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/filesystem/index.ts b/src/filesystem/index.ts index 730721de..ff74be5e 100644 --- a/src/filesystem/index.ts +++ b/src/filesystem/index.ts @@ -24,7 +24,7 @@ if (args.length === 0) { // Normalize all paths consistently function normalizePath(p: string): string { - return path.normalize(p).toLowerCase(); + return path.normalize(p); } function expandHome(filepath: string): string { From 8cc8c6e7a788f179d57caebd0a2a2efc8f2ecd2b Mon Sep 17 00:00:00 2001 From: Raduan77 Date: Wed, 11 Dec 2024 09:14:25 +0100 Subject: [PATCH 15/26] Allow body to be nullable in GithubIssueSchema --- src/github/schemas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/github/schemas.ts b/src/github/schemas.ts index cefdc1d1..0a322328 100644 --- a/src/github/schemas.ts +++ b/src/github/schemas.ts @@ -274,7 +274,7 @@ export const GitHubIssueSchema = z.object({ created_at: z.string(), updated_at: z.string(), closed_at: z.string().nullable(), - body: z.string(), + body: z.string().nullable(), }); // Pull Request related schemas From fe91dc76eb7ce6a2d63f952d068c266c9d806615 Mon Sep 17 00:00:00 2001 From: Ruud Huijts Date: Wed, 11 Dec 2024 10:01:42 +0100 Subject: [PATCH 16/26] added NS Dutch Railways mcp server to community server list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f511bb2c..0106b8ba 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ A growing set of community-developed and maintained servers demonstrates various > **Note:** Community servers are **untested** and should be used at **your own risk**. They are not affiliated with or endorsed by Anthropic. - **[MCP Installer](https://github.com/anaisbetts/mcp-installer)** - This server is a server that installs other MCP servers for you. +- **[NS Travel Information](https://github.com/r-huijts/ns-mcp-server)** - Access Dutch Railways (NS) real-time train travel information and disruptions through the official NS API. - **[Spotify](https://github.com/varunneal/spotify-mcp)** - This MCP allows an LLM to play and use Spotify. - **[Inoyu](https://github.com/sergehuber/inoyu-mcp-unomi-server)** - Interact with an Apache Unomi CDP customer data platform to retrieve and update customer profiles - **[Snowflake](https://github.com/datawiz168/mcp-snowflake-service)** - This MCP server enables LLMs to interact with Snowflake databases, allowing for secure and controlled data operations. From 14e904958ab230a0fca29172349dceaace450035 Mon Sep 17 00:00:00 2001 From: Ian Borla Date: Wed, 11 Dec 2024 20:23:25 +0800 Subject: [PATCH 17/26] Update README.md Co-authored-by: Justin Spahr-Summers --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6cb67721..66e49582 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ A growing set of community-developed and maintained servers demonstrates various - **[Spotify](https://github.com/varunneal/spotify-mcp)** - This MCP allows an LLM to play and use Spotify. - **[Inoyu](https://github.com/sergehuber/inoyu-mcp-unomi-server)** - Interact with an Apache Unomi CDP customer data platform to retrieve and update customer profiles - **[Snowflake](https://github.com/datawiz168/mcp-snowflake-service)** - This MCP server enables LLMs to interact with Snowflake databases, allowing for secure and controlled data operations. -- **[MySQL](https://github.com/designcomputer/mysql_mcp_server)** - (by DesignComputer) MySQL database integration based on Python with configurable access controls and schema inspection -- **[MySQL](https://github.com/benborla/mcp-server-mysql)** - (by benborla) MySQL database integration based on NodeJS with configurable access controls and schema inspection +- **[MySQL](https://github.com/designcomputer/mysql_mcp_server)** (by DesignComputer) - MySQL database integration in Python with configurable access controls and schema inspection +- **[MySQL](https://github.com/benborla/mcp-server-mysql)** (by benborla) - MySQL database integration in NodeJS with configurable access controls and schema inspection - **[MSSQL](https://github.com/aekanun2020/mcp-server/)** - MSSQL database integration with configurable access controls and schema inspection - **[BigQuery](https://github.com/LucasHild/mcp-server-bigquery)** (by LucasHild) - This server enables LLMs to inspect database schemas and execute queries on BigQuery. - **[BigQuery](https://github.com/ergut/mcp-bigquery-server)** (by ergut) - Server implementation for Google BigQuery integration that enables direct BigQuery database access and querying capabilities From ad37d5f537a9f212726407909835149854b8a6fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Enes=20=C3=87=C4=B1nar?= <91203238+EnesCinr@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:44:27 +0300 Subject: [PATCH 18/26] Update README.md Added twitter mcp server reference to Community Servers section. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dfafef9b..58087587 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ A growing set of community-developed and maintained servers demonstrates various - **[Pandoc](https://github.com/vivekVells/mcp-pandoc)** - MCP server for seamless document format conversion using Pandoc, supporting Markdown, HTML, and plain text, with other formats like PDF, csv and docx in development. - **[HuggingFace Spaces](https://github.com/evalstate/mcp-hfspace)** - Server for using HuggingFace Spaces, supporting Open Source Image, Audio, Text Models and more. Claude Desktop mode for easy integration. - **[ChatSum](https://github.com/mcpso/mcp-server-chatsum)** - Query and Summarize chat messages with LLM. by [mcpso](https://mcp.so) +- **[Twitter](https://github.com/EnesCinr/twitter-mcp)** - Interact with twitter API. Post tweets and search for tweets by query. ## 📚 Resources From 008ddf0ddf1379c62f4027c8ff66a972cd9c7849 Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Wed, 11 Dec 2024 14:53:40 +0100 Subject: [PATCH 19/26] Add an MCP for the Apify's RAG Web Browser. Fix link to Tavily. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dfafef9b..c3184bf9 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ A growing set of community-developed and maintained servers demonstrates various - **[BigQuery](https://github.com/LucasHild/mcp-server-bigquery)** (by LucasHild) - This server enables LLMs to inspect database schemas and execute queries on BigQuery. - **[BigQuery](https://github.com/ergut/mcp-bigquery-server)** (by ergut) - Server implementation for Google BigQuery integration that enables direct BigQuery database access and querying capabilities - **[Todoist](https://github.com/abhiz123/todoist-mcp-server)** - Interact with Todoist to manage your tasks. -- **[Tavily search](https://github.com/RamXX/mcp-tavily")** - An MCP server for Tavily's search & news API, with explicit site inclusions/exclusions +- **[Tavily search](https://github.com/RamXX/mcp-tavily)** - An MCP server for Tavily's search & news API, with explicit site inclusions/exclusions - **[Linear](https://github.com/jerhadf/linear-mcp-server)** - Allows LLM to interact with Linear's API for project management, including searching, creating, and updating issues. - **[Playwright](https://github.com/executeautomation/mcp-playwright)** - This MCP Server will help you run browser automation and webscraping using Playwright - **[AWS](https://github.com/rishikavikondala/mcp-server-aws)** - Perform operations on your AWS resources using an LLM @@ -76,6 +76,9 @@ A growing set of community-developed and maintained servers demonstrates various - **[Pandoc](https://github.com/vivekVells/mcp-pandoc)** - MCP server for seamless document format conversion using Pandoc, supporting Markdown, HTML, and plain text, with other formats like PDF, csv and docx in development. - **[HuggingFace Spaces](https://github.com/evalstate/mcp-hfspace)** - Server for using HuggingFace Spaces, supporting Open Source Image, Audio, Text Models and more. Claude Desktop mode for easy integration. - **[ChatSum](https://github.com/mcpso/mcp-server-chatsum)** - Query and Summarize chat messages with LLM. by [mcpso](https://mcp.so) +- **[RAG Web Browser](https://github.com/apify/mcp-server-rag-web-browser)** An MCP server for the Apify Actor to perform web searches, scrape URLs, and return content in Markdown. + + ## 📚 Resources From 5601512a3cb38728e8e0494e1056212a93b16c7e Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Wed, 11 Dec 2024 14:58:29 +0100 Subject: [PATCH 20/26] Change description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c3184bf9..ecd80432 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ A growing set of community-developed and maintained servers demonstrates various - **[Pandoc](https://github.com/vivekVells/mcp-pandoc)** - MCP server for seamless document format conversion using Pandoc, supporting Markdown, HTML, and plain text, with other formats like PDF, csv and docx in development. - **[HuggingFace Spaces](https://github.com/evalstate/mcp-hfspace)** - Server for using HuggingFace Spaces, supporting Open Source Image, Audio, Text Models and more. Claude Desktop mode for easy integration. - **[ChatSum](https://github.com/mcpso/mcp-server-chatsum)** - Query and Summarize chat messages with LLM. by [mcpso](https://mcp.so) -- **[RAG Web Browser](https://github.com/apify/mcp-server-rag-web-browser)** An MCP server for the Apify Actor to perform web searches, scrape URLs, and return content in Markdown. +- **[RAG Web Browser](https://github.com/apify/mcp-server-rag-web-browser)** An MCP server for Apify's RAG Web Browser Actor to perform web searches, scrape URLs, and return content in Markdown. From c90a557bce00ee20c0c462345600219610d23fb2 Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Wed, 11 Dec 2024 14:59:05 +0100 Subject: [PATCH 21/26] Change description --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index ecd80432..c17b53fc 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,6 @@ A growing set of community-developed and maintained servers demonstrates various - **[RAG Web Browser](https://github.com/apify/mcp-server-rag-web-browser)** An MCP server for Apify's RAG Web Browser Actor to perform web searches, scrape URLs, and return content in Markdown. - ## 📚 Resources Additional resources on MCP. From 9a89ddeea30e1b3c730625d6a02a4341c06fdba3 Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Wed, 11 Dec 2024 14:59:47 +0100 Subject: [PATCH 22/26] Fix line spacing --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index c17b53fc..523ea1a5 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,6 @@ A growing set of community-developed and maintained servers demonstrates various - **[ChatSum](https://github.com/mcpso/mcp-server-chatsum)** - Query and Summarize chat messages with LLM. by [mcpso](https://mcp.so) - **[RAG Web Browser](https://github.com/apify/mcp-server-rag-web-browser)** An MCP server for Apify's RAG Web Browser Actor to perform web searches, scrape URLs, and return content in Markdown. - ## 📚 Resources Additional resources on MCP. From e1ab0938a0eb272ebbe83856b1ccb8ad058c2a44 Mon Sep 17 00:00:00 2001 From: Mahesh Murag Date: Wed, 11 Dec 2024 10:35:00 -0500 Subject: [PATCH 23/26] Add missing servers --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dfafef9b..3064dd29 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,10 @@ Each MCP server is implemented with either the [Typescript MCP SDK](https://gith These servers aim to demonstrate MCP features and the Typescript and Python SDK. -- **[AWS KB Retrieval](src/aws-kb-retrieval)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime +- **[AWS KB Retrieval](src/aws-kb-retrieval-server)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime - **[Brave Search](src/brave-search)** - Web and local search using Brave's Search API - **[EverArt](src/everart)** - AI image generation using various models +- **[Everything](src/everything)** - Reference / test server with prompts, resources, and tools - **[Fetch](src/fetch)** - Web content fetching and conversion for efficient LLM usage - **[Filesystem](src/filesystem)** - Secure file operations with configurable access controls - **[Git](src/git)** - Tools to read, search, and manipulate Git repositories @@ -27,6 +28,7 @@ These servers aim to demonstrate MCP features and the Typescript and Python SDK. - **[Sequential Thinking](src/sequentialthinking)** - Dynamic and reflective problem-solving through thought sequences - **[Slack](src/slack)** - Channel management and messaging capabilities - **[Sqlite](src/sqlite)** - Database interaction and business intelligence capabilities +- **[Time](src/time)** - Time and timezone conversion capabilities ## 🤝 Third-Party Servers From 1f5b50f609fb36ec1c8b33a3efc7acd96c37badb Mon Sep 17 00:00:00 2001 From: Starbird <64431622+StarbirdTech@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:16:48 -0500 Subject: [PATCH 24/26] Fix broken link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dfafef9b..456bb9e1 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ A growing set of community-developed and maintained servers demonstrates various - **[BigQuery](https://github.com/LucasHild/mcp-server-bigquery)** (by LucasHild) - This server enables LLMs to inspect database schemas and execute queries on BigQuery. - **[BigQuery](https://github.com/ergut/mcp-bigquery-server)** (by ergut) - Server implementation for Google BigQuery integration that enables direct BigQuery database access and querying capabilities - **[Todoist](https://github.com/abhiz123/todoist-mcp-server)** - Interact with Todoist to manage your tasks. -- **[Tavily search](https://github.com/RamXX/mcp-tavily")** - An MCP server for Tavily's search & news API, with explicit site inclusions/exclusions +- **[Tavily search](https://github.com/RamXX/mcp-tavily)** - An MCP server for Tavily's search & news API, with explicit site inclusions/exclusions - **[Linear](https://github.com/jerhadf/linear-mcp-server)** - Allows LLM to interact with Linear's API for project management, including searching, creating, and updating issues. - **[Playwright](https://github.com/executeautomation/mcp-playwright)** - This MCP Server will help you run browser automation and webscraping using Playwright - **[AWS](https://github.com/rishikavikondala/mcp-server-aws)** - Perform operations on your AWS resources using an LLM From db0bafbe8d43256a758eaa5f60475a50da3ba4e0 Mon Sep 17 00:00:00 2001 From: TerminalMan <84923604+SecretiveShell@users.noreply.github.com> Date: Thu, 12 Dec 2024 21:57:11 +0000 Subject: [PATCH 25/26] Fix AWS KB Retrieval link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f289c3dd..5060eb26 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Each MCP server is implemented with either the [Typescript MCP SDK](https://gith These servers aim to demonstrate MCP features and the Typescript and Python SDK. -- **[AWS KB Retrieval](src/aws-kb-retrieval)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime +- **[AWS KB Retrieval](src/aws-kb-retrieval-server)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime - **[Brave Search](src/brave-search)** - Web and local search using Brave's Search API - **[EverArt](src/everart)** - AI image generation using various models - **[Fetch](src/fetch)** - Web content fetching and conversion for efficient LLM usage From c1012d7b70909fdfb35c48347ba795c4c8a7316b Mon Sep 17 00:00:00 2001 From: David Soria Parra <167242713+dsp-ant@users.noreply.github.com> Date: Thu, 12 Dec 2024 22:46:04 +0000 Subject: [PATCH 26/26] Update README.md fix indent --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4a7a8c2..7bd08e8e 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Additional resources on MCP. - **[mcp-get](https://mcp-get.com)** - Command line tool for installing and managing MCP servers by **[Michael Latman](https://github.com/michaellatman)** - **[mcp-cli](https://github.com/wong2/mcp-cli)** - A CLI inspector for the Model Context Protocol by **[wong2](https://github.com/wong2)** - **[r/mcp](https://www.reddit.com/r/mcp)** – A Reddit community dedicated to MCP by **[Frank Fiegel](https://github.com/punkpeye)** -- **[mcp-manager](https://github.com/zueai/mcp-manager)** - Simple Web UI to install and manage MCP servers for Claude Desktop by **[Zue](https://github.com/zueai)** +- **[mcp-manager](https://github.com/zueai/mcp-manager)** - Simple Web UI to install and manage MCP servers for Claude Desktop by **[Zue](https://github.com/zueai)** ## 🚀 Getting Started