@jessejoris/mcp-mysql-via-api 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PRD.md +364 -0
- package/README.md +202 -0
- package/bin/mcp-mysql-via-api.js +4 -0
- package/dist/api-client/mysqlApiClient.d.ts +46 -0
- package/dist/api-client/mysqlApiClient.js +318 -0
- package/dist/config/config.d.ts +10 -0
- package/dist/config/config.js +56 -0
- package/dist/formatters/jsonResponse.d.ts +48 -0
- package/dist/formatters/jsonResponse.js +86 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +25 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +75 -0
- package/dist/permissions/permissionManager.d.ts +25 -0
- package/dist/permissions/permissionManager.js +199 -0
- package/dist/server/apiServer.d.ts +7 -0
- package/dist/server/apiServer.js +1502 -0
- package/dist/server/dbPool.d.ts +12 -0
- package/dist/server/dbPool.js +53 -0
- package/dist/server/standalone.d.ts +1 -0
- package/dist/server/standalone.js +19 -0
- package/dist/tools/toolDefinitions.d.ts +5 -0
- package/dist/tools/toolDefinitions.js +725 -0
- package/dist/tools/toolHandlers.d.ts +16 -0
- package/dist/tools/toolHandlers.js +285 -0
- package/dist/types/index.d.ts +184 -0
- package/dist/types/index.js +5 -0
- package/package.json +64 -0
package/PRD.md
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# Product Requirement Document (PRD)
|
|
2
|
+
# MySQL Model Context Protocol (MCP) Server via API (`mcp_mysql_via_api`)
|
|
3
|
+
|
|
4
|
+
**Document Version:** 1.1.0
|
|
5
|
+
**Status:** Approved & Verified
|
|
6
|
+
**Author:** Antigravity Engineering
|
|
7
|
+
**Target Systems:** Hermes AI, OpenClaw, Claude Desktop, Cursor, Windsurf, Cline, Codex, CLI & Local IDEs
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Executive Summary & Problem Statement
|
|
12
|
+
|
|
13
|
+
### 1.1 Context & Background
|
|
14
|
+
The legacy `mcp_mysql` solution establishes direct TCP socket connections (via the `mysql2` driver on port 3306) to MySQL database instances. While effective for local or flat networks, this architectural pattern encounters severe limitations in real-world enterprise, cloud, and distributed environments:
|
|
15
|
+
- **Firewall & Security Boundaries:** Production databases rarely expose port 3306 directly to external networks or AI developer workstations.
|
|
16
|
+
- **Microservices & Multi-Cloud Architecture:** Databases are shielded inside private VPCs / subnets behind API Gateways, ingress controllers, or dedicated internal REST services.
|
|
17
|
+
- **Audit & Governance:** Direct SQL socket connections bypass application-level telemetry, token-based rate limiting, role-based access control (RBAC), and centralized API auditing.
|
|
18
|
+
|
|
19
|
+
### 1.2 The Solution: `mcp_mysql_via_api`
|
|
20
|
+
`mcp_mysql_via_api` decouples the AI Agent interface from the physical database wire protocol. Instead of direct database socket connections:
|
|
21
|
+
1. The **AI Agent** communicates via standard **Model Context Protocol (MCP)** (`stdio` / stream transport) with the `mcp_mysql_via_api` client.
|
|
22
|
+
2. The MCP client translates tool invocations into authenticated HTTP/REST requests against a remote **MySQL API Server Endpoint** hosted in the database's secure environment.
|
|
23
|
+
3. The server exposes structured endpoints for every table, schema discovery, point lookups, execution of guarded queries, and metadata extraction.
|
|
24
|
+
4. Strict access controls (including presets like `only-read`, `read-write`, `admin` and granular permissions) protect against unauthorized mutations.
|
|
25
|
+
5. All tool outputs are **strictly valid JSON**—guaranteed 100% parseable with zero plaintext, HTML, or unstructured error strings.
|
|
26
|
+
6. Multi-record operations feature **default pagination** with an explicit **bypass option** for AI agents requiring complete data extracts.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 2. Core Personas & Target Agents
|
|
31
|
+
|
|
32
|
+
| Persona / Agent | Typical Environment | Primary Needs & Constraints |
|
|
33
|
+
|-----------------|---------------------|-----------------------------|
|
|
34
|
+
| **Hermes AI** | Autonomous Agent / Sandbox | High-reliability JSON schema, determinism, zero non-JSON output, RAG context window optimization, self-describing metadata |
|
|
35
|
+
| **OpenClaw** | Multi-agent Orchestrator | Strict token management via default pagination, schema RAG context, cross-table text search, permission guards |
|
|
36
|
+
| **Cursor / Windsurf / Cline** | IDE Integration | Instant response times, tabular and record browsing, connection health checks, direct single-record access |
|
|
37
|
+
| **Claude Desktop / Codex** | Desktop / CLI Agent | Stdio transport compliance, transparent error codes, ERD and relationship mapping |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 3. Key Design Principles & Requirements
|
|
42
|
+
|
|
43
|
+
### 3.1 Strict JSON Output Guarantee
|
|
44
|
+
- **Mandate:** All outputs returned through the MCP tool interface MUST be strictly valid, well-formed JSON strings (`application/json`).
|
|
45
|
+
- **Forbidden:** No raw markdown backticks, no emoji error prefixes (e.g., `❌ Error`), no unstructured text, and no HTML error pages (even on HTTP 404/500).
|
|
46
|
+
- **Envelope Standard:**
|
|
47
|
+
```json
|
|
48
|
+
// Success Response Envelope
|
|
49
|
+
{
|
|
50
|
+
"success": true,
|
|
51
|
+
"data": { ... },
|
|
52
|
+
"meta": {
|
|
53
|
+
"pagination": {
|
|
54
|
+
"page": 1,
|
|
55
|
+
"limit": 50,
|
|
56
|
+
"total": 120,
|
|
57
|
+
"totalPages": 3,
|
|
58
|
+
"hasMore": true
|
|
59
|
+
},
|
|
60
|
+
"timestamp": "2026-09-03T15:25:00.000Z"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Error Response Envelope
|
|
65
|
+
{
|
|
66
|
+
"success": false,
|
|
67
|
+
"error": {
|
|
68
|
+
"code": "PERMISSION_DENIED",
|
|
69
|
+
"message": "Operation 'create_record' is blocked by active permission policy 'only-read'.",
|
|
70
|
+
"details": {
|
|
71
|
+
"requiredPermission": "create",
|
|
72
|
+
"activePermissions": ["list", "read", "utility"]
|
|
73
|
+
},
|
|
74
|
+
"timestamp": "2026-09-03T15:25:00.000Z"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 3.2 Dual-Layer Permission System & Defense-in-Depth
|
|
80
|
+
To satisfy safety requirements and prevent unauthorized schema alteration or data destruction:
|
|
81
|
+
1. **Permission Presets:**
|
|
82
|
+
- `only-read` (aliases `readonly`, `read-only`, `only_read`, `read_only`, `view-only`): Allows `list`, `read`, `utility`. Strictly forbids `create`, `update`, `delete`, `execute`, `ddl`.
|
|
83
|
+
- `read-write` (alias `read_write`): Allows `list`, `read`, `create`, `update`, `utility`. Blocks `delete`, `execute`, `ddl`.
|
|
84
|
+
- `admin` (aliases `all`, `*`): Allows all operations (`list`, `read`, `create`, `update`, `delete`, `execute`, `ddl`, `utility`, `transaction`).
|
|
85
|
+
- `custom`: Explicit comma-separated permissions (e.g. `list,read,create`).
|
|
86
|
+
2. **Granular Categories:**
|
|
87
|
+
- `list`: Database discovery, table listing, schema inspection, ERD generation, RAG context generation.
|
|
88
|
+
- `read`: Querying records, search data across tables, column statistics, point record lookups, running select queries.
|
|
89
|
+
- `create`: Single record insertion, bulk insert.
|
|
90
|
+
- `update`: Single record update, bulk update.
|
|
91
|
+
- `delete`: Single record deletion, bulk delete.
|
|
92
|
+
- `execute`: Custom SQL query execution via API.
|
|
93
|
+
- `ddl`: Schema alterations (`create_table`, `alter_table`, `drop_table`, `execute_ddl`).
|
|
94
|
+
- `utility`: Connection testing, metadata health checks, CSV exports.
|
|
95
|
+
3. **Dual-Layer Defense Architecture:**
|
|
96
|
+
- **MCP Client Layer:** Pre-execution permission check; blocks requests locally before network calls if unauthorized.
|
|
97
|
+
- **API Server Layer:** HTTP endpoint authorization check via `API_PERMISSIONS` / `MCP_PERMISSIONS`; rejects unauthorized mutation verbs with HTTP 403 Forbidden envelopes.
|
|
98
|
+
- **SQL Keyword Inspection:** Dangerous keywords (`INTO OUTFILE`, `LOAD DATA`, `GRANT`, `REVOKE`) and covert DDL inside `execute_write_query` are intercepted and blocked before execution.
|
|
99
|
+
|
|
100
|
+
### 3.3 Default Pagination & Explicit Bypass System
|
|
101
|
+
To balance LLM context window safety with full data access:
|
|
102
|
+
- **Default Behavior:**
|
|
103
|
+
- Multi-record operations (`read_records`, `run_select_query`, `search_data_across_tables`) paginate results by default.
|
|
104
|
+
- Default: `page = 1`, `limit = 50` (configurable via `DEFAULT_PAGE_SIZE`, default max page size 500).
|
|
105
|
+
- Metadata provides `total`, `page`, `limit`, `totalPages`, `hasMore`.
|
|
106
|
+
- **Bypass Mode:**
|
|
107
|
+
- Agents can specify `bypass_pagination: true` (or `all: true` / `limit: 0`).
|
|
108
|
+
- When active, the server fetches the complete dataset without slicing.
|
|
109
|
+
- Safety guard: A safety ceiling (`MAX_BYPASS_LIMIT`, default 10,000 rows) prevents memory exhaustion (OOM), returning an explicit warning if the table exceeds the ceiling.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 4. System Architecture & Components
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
┌────────────────────────────────────────────────────────┐
|
|
117
|
+
│ AI Agent (Host) │
|
|
118
|
+
│ Hermes / OpenClaw / Cursor / Claude Code │
|
|
119
|
+
└──────────────────────────┬─────────────────────────────┘
|
|
120
|
+
│ MCP Protocol (stdio / JSON-RPC 2.0)
|
|
121
|
+
┌──────────────────────────▼─────────────────────────────┐
|
|
122
|
+
│ mcp_mysql_via_api (MCP Client) │
|
|
123
|
+
│ ┌────────────────────┐ ┌──────────────────────┐ │
|
|
124
|
+
│ │ Permission Engine │ │ Strict JSON Engine │ │
|
|
125
|
+
│ │ (only-read, etc.) │ │ (Guaranteed Parse) │ │
|
|
126
|
+
│ └────────────────────┘ └──────────────────────┘ │
|
|
127
|
+
│ ┌────────────────────┐ ┌──────────────────────┐ │
|
|
128
|
+
│ │ Pagination Handler │ │ Resilient API Client │ │
|
|
129
|
+
│ │ (Default + Bypass) │ │ (Retries & Auth) │ │
|
|
130
|
+
│ └────────────────────┘ └──────────────────────┘ │
|
|
131
|
+
└──────────────────────────┬─────────────────────────────┘
|
|
132
|
+
│ Authenticated HTTP/REST (JSON)
|
|
133
|
+
│ Bearer Token / API Key
|
|
134
|
+
┌──────────────────────────▼─────────────────────────────┐
|
|
135
|
+
│ Remote MySQL API Server (Target Host) │
|
|
136
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
137
|
+
│ │ REST Router (/api/tables, /api/schema, etc.) │ │
|
|
138
|
+
│ ├──────────────────────────────────────────────────┤ │
|
|
139
|
+
│ │ Dual-Layer Auth & RBAC Middleware (HTTP 403) │ │
|
|
140
|
+
│ ├──────────────────────────────────────────────────┤ │
|
|
141
|
+
│ │ MySQL Connection Pool & Query Sanitizer │ │
|
|
142
|
+
│ └──────────────────────────┬───────────────────────┘ │
|
|
143
|
+
└─────────────────────────────┼──────────────────────────┘
|
|
144
|
+
│ TCP (Internal Network)
|
|
145
|
+
┌─────────────────────────────▼──────────────────────────┐
|
|
146
|
+
│ MySQL Database │
|
|
147
|
+
└────────────────────────────────────────────────────────┘
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 5. Tool Catalog (31 Tools Specification)
|
|
153
|
+
|
|
154
|
+
### 5.1 Database & Schema Discovery
|
|
155
|
+
1. `list_databases`
|
|
156
|
+
- **Permission:** `list`
|
|
157
|
+
- **Description:** Lists all accessible databases on the remote MySQL server.
|
|
158
|
+
- **Input:** `{}`
|
|
159
|
+
2. `list_tables`
|
|
160
|
+
- **Permission:** `list`
|
|
161
|
+
- **Description:** Lists all tables in the specified or default database.
|
|
162
|
+
- **Input:** `{ database?: string }`
|
|
163
|
+
3. `read_table_schema`
|
|
164
|
+
- **Permission:** `list`
|
|
165
|
+
- **Description:** Inspects column definitions, data types, primary keys, foreign keys, and indexes for a specific table.
|
|
166
|
+
- **Input:** `{ table_name: string, database?: string }`
|
|
167
|
+
4. `get_database_summary`
|
|
168
|
+
- **Permission:** `list`
|
|
169
|
+
- **Description:** High-level summary of database structure, table count, column details, and approximate row counts.
|
|
170
|
+
- **Input:** `{ database?: string, max_tables?: number, include_relationships?: boolean }`
|
|
171
|
+
5. `get_schema_erd`
|
|
172
|
+
- **Permission:** `list`
|
|
173
|
+
- **Description:** Generates a visual Mermaid.js Entity-Relationship diagram representing the database foreign keys.
|
|
174
|
+
- **Input:** `{ database?: string }`
|
|
175
|
+
6. `get_schema_rag_context` *(New AI-Optimized)*
|
|
176
|
+
- **Permission:** `list`
|
|
177
|
+
- **Description:** 🎯 AI-OPTIMIZED: Returns ultra-compact schema information designed specifically for LLM context windows (Hermes AI, OpenClaw, IDEs). Use keyword_filter for concept-focused schema discovery.
|
|
178
|
+
- **Input:** `{ database?: string, max_tables?: number, max_columns?: number, keyword_filter?: string }`
|
|
179
|
+
7. `get_all_tables_relationships`
|
|
180
|
+
- **Permission:** `list`
|
|
181
|
+
- **Description:** Analyzes foreign key relationships across all tables.
|
|
182
|
+
- **Input:** `{ database?: string }`
|
|
183
|
+
8. `search_schema`
|
|
184
|
+
- **Permission:** `list`
|
|
185
|
+
- **Description:** Searches for keywords across table names, column names, and comments.
|
|
186
|
+
- **Input:** `{ query: string, database?: string }`
|
|
187
|
+
9. `find_tables_by_keyword`
|
|
188
|
+
- **Permission:** `list`
|
|
189
|
+
- **Description:** Fast ranked keyword search for tables matching specific entities (e.g. "users", "orders").
|
|
190
|
+
- **Input:** `{ keyword: string, database?: string, limit?: number }`
|
|
191
|
+
10. `search_data_across_tables` *(New AI-Optimized)*
|
|
192
|
+
- **Permission:** `read`
|
|
193
|
+
- **Description:** 🔍 Guarded read-only keyword scan across text-like column values across tables. Discovers which table contains specific values or IDs when table structure is unknown.
|
|
194
|
+
- **Input:** `{ keyword: string, tables?: string[], database?: string, max_tables?: number, limit_per_table?: number }`
|
|
195
|
+
|
|
196
|
+
### 5.2 CRUD & Data Operations
|
|
197
|
+
11. `read_records`
|
|
198
|
+
- **Permission:** `read`
|
|
199
|
+
- **Description:** Retrieves records from any table with filtering, sorting, column selection, and pagination. Supports legacy operator aliases (`eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `in`, `is null`, `between`) and `conditions` alias.
|
|
200
|
+
- **Input:** `{ table_name: string, columns?: string[], filters?: any[], conditions?: any[], sorting?: object, pagination?: object, bypass_pagination?: boolean, all?: boolean, database?: string }`
|
|
201
|
+
12. `read_record` *(New Direct Point Lookup)*
|
|
202
|
+
- **Permission:** `read`
|
|
203
|
+
- **Description:** Fetches a single record by primary key or ID from a table via API. Fast direct point lookup.
|
|
204
|
+
- **Input:** `{ table_name: string, id: string | number, key_column?: string, database?: string }`
|
|
205
|
+
13. `count_records`
|
|
206
|
+
- **Permission:** `read`
|
|
207
|
+
- **Description:** Returns total count of records matching optional filters/conditions.
|
|
208
|
+
- **Input:** `{ table_name: string, filters?: any[], conditions?: any[], database?: string }`
|
|
209
|
+
14. `create_record`
|
|
210
|
+
- **Permission:** `create`
|
|
211
|
+
- **Description:** Inserts a single record into a table.
|
|
212
|
+
- **Input:** `{ table_name: string, data: Record<string, any>, database?: string }`
|
|
213
|
+
15. `bulk_insert`
|
|
214
|
+
- **Permission:** `create`
|
|
215
|
+
- **Description:** Batch inserts multiple records into a table.
|
|
216
|
+
- **Input:** `{ table_name: string, records: Array<Record<string, any>>, database?: string }`
|
|
217
|
+
16. `update_record`
|
|
218
|
+
- **Permission:** `update`
|
|
219
|
+
- **Description:** Updates records matching specified filter conditions. Accepts `filters` or `conditions`.
|
|
220
|
+
- **Input:** `{ table_name: string, data: Record<string, any>, filters?: any[], conditions?: any[], database?: string }`
|
|
221
|
+
17. `bulk_update`
|
|
222
|
+
- **Permission:** `update`
|
|
223
|
+
- **Description:** Batch updates records by primary key.
|
|
224
|
+
- **Input:** `{ table_name: string, records: Array<Record<string, any>>, key_column: string, database?: string }`
|
|
225
|
+
18. `delete_record`
|
|
226
|
+
- **Permission:** `delete`
|
|
227
|
+
- **Description:** Deletes records matching specified filter conditions. Accepts `filters` or `conditions`.
|
|
228
|
+
- **Input:** `{ table_name: string, filters?: any[], conditions?: any[], database?: string }`
|
|
229
|
+
19. `bulk_delete`
|
|
230
|
+
- **Permission:** `delete`
|
|
231
|
+
- **Description:** Batch deletes records by matching primary key array.
|
|
232
|
+
- **Input:** `{ table_name: string, key_column: string, keys: Array<string | number>, database?: string }`
|
|
233
|
+
|
|
234
|
+
### 5.3 Data Profiling & Analysis
|
|
235
|
+
20. `get_column_statistics` *(New AI-Optimized)*
|
|
236
|
+
- **Permission:** `read`
|
|
237
|
+
- **Description:** Returns detailed statistical analysis for a specific column: total rows, non-null count, null percentage, distinct count, min/max values, and top frequent values.
|
|
238
|
+
- **Input:** `{ table_name: string, column_name: string, database?: string }`
|
|
239
|
+
|
|
240
|
+
### 5.4 Query Management
|
|
241
|
+
21. `run_select_query`
|
|
242
|
+
- **Permission:** `read`
|
|
243
|
+
- **Description:** Executes read-only SQL queries via API with optional pagination or bypass. Semicolon-safe and supports `all: true`.
|
|
244
|
+
- **Input:** `{ query: string, params?: any[], page?: number, limit?: number, bypass_pagination?: boolean, all?: boolean, database?: string }`
|
|
245
|
+
22. `execute_write_query`
|
|
246
|
+
- **Permission:** `execute` (requires `delete` for DELETE statements, `ddl` for DDL statements; blocks dangerous keywords)
|
|
247
|
+
- **Description:** Executes INSERT, UPDATE, or guarded mutation queries via API.
|
|
248
|
+
- **Input:** `{ query: string, params?: any[], database?: string }`
|
|
249
|
+
|
|
250
|
+
### 5.5 Schema Management (DDL)
|
|
251
|
+
23. `create_table`
|
|
252
|
+
- **Permission:** `ddl`
|
|
253
|
+
- **Description:** Creates a new table via API.
|
|
254
|
+
- **Input:** `{ table_name: string, columns: any[], primary_key?: string | string[], database?: string }`
|
|
255
|
+
24. `alter_table`
|
|
256
|
+
- **Permission:** `ddl`
|
|
257
|
+
- **Description:** Adds, modifies, or drops columns via API.
|
|
258
|
+
- **Input:** `{ table_name: string, action: string, column_definition: any, database?: string }`
|
|
259
|
+
25. `drop_table`
|
|
260
|
+
- **Permission:** `ddl`
|
|
261
|
+
- **Description:** Drops a table via API.
|
|
262
|
+
- **Input:** `{ table_name: string, if_exists?: boolean, database?: string }`
|
|
263
|
+
26. `execute_ddl`
|
|
264
|
+
- **Permission:** `ddl`
|
|
265
|
+
- **Description:** Executes raw DDL statements via API with dangerous keyword checks.
|
|
266
|
+
- **Input:** `{ query: string, database?: string }`
|
|
267
|
+
|
|
268
|
+
### 5.6 Utilities & Diagnostics
|
|
269
|
+
27. `test_connection`
|
|
270
|
+
- **Permission:** `utility`
|
|
271
|
+
- **Description:** Pings remote API endpoint, verifies credentials, database connectivity, and latency in milliseconds.
|
|
272
|
+
- **Input:** `{}`
|
|
273
|
+
28. `describe_connection`
|
|
274
|
+
- **Permission:** `utility`
|
|
275
|
+
- **Description:** Reports active API endpoint, server status, permissions profile, and pagination configuration.
|
|
276
|
+
- **Input:** `{}`
|
|
277
|
+
29. `list_all_tools`
|
|
278
|
+
- **Permission:** `utility`
|
|
279
|
+
- **Description:** Returns a dynamic catalog of all 31 MCP tools with active permission status and agent recommendations.
|
|
280
|
+
- **Input:** `{}`
|
|
281
|
+
30. `export_table_to_csv`
|
|
282
|
+
- **Permission:** `utility`
|
|
283
|
+
- **Description:** Exports table data as CSV string via API.
|
|
284
|
+
- **Input:** `{ table_name: string, limit?: number, database?: string }`
|
|
285
|
+
31. `export_query_to_csv`
|
|
286
|
+
- **Permission:** `utility`
|
|
287
|
+
- **Description:** Exports SELECT query results as CSV string via API (guarded to read-only queries).
|
|
288
|
+
- **Input:** `{ query: string, limit?: number, database?: string }`
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## 6. API Server Endpoint Specifications (Companion Server)
|
|
293
|
+
|
|
294
|
+
The standalone companion Express API server (`src/server/apiServer.ts`) provides full REST access for all tables:
|
|
295
|
+
|
|
296
|
+
| Method | Endpoint | Description | Auth Required | Permission Checked |
|
|
297
|
+
|--------|----------|-------------|---------------|--------------------|
|
|
298
|
+
| `GET` | `/health` | Server & DB health check + latency measurement | No | Public |
|
|
299
|
+
| `GET` | `/api/info` | Server metadata, version & permission policy | Yes | Utility |
|
|
300
|
+
| `GET` | `/api/databases` | List all databases | Yes | `list` |
|
|
301
|
+
| `GET` | `/api/tables` | List tables in database | Yes | `list` |
|
|
302
|
+
| `GET` | `/api/tables/find` | Find tables by keyword | Yes | `list` |
|
|
303
|
+
| `GET` | `/api/tables/search-data` | Search text data across tables | Yes | `read` |
|
|
304
|
+
| `GET` | `/api/tables/:table/schema` | Get column metadata & indexes | Yes | `list` |
|
|
305
|
+
| `GET` | `/api/tables/:table/records` | Read records with query params (`page`, `limit`, `bypass`, `sort`, `filters`) | Yes | `read` |
|
|
306
|
+
| `GET` | `/api/tables/:table/records/:id` | Point lookup single record by ID | Yes | `read` |
|
|
307
|
+
| `POST` | `/api/tables/:table/records` | Insert single record | Yes | `create` |
|
|
308
|
+
| `POST` | `/api/tables/:table/records/bulk` | Bulk insert records | Yes | `create` |
|
|
309
|
+
| `PUT` | `/api/tables/:table/records/:id` | Update single record by ID | Yes | `update` |
|
|
310
|
+
| `PUT` | `/api/tables/:table/records` | Update records matching condition | Yes | `update` |
|
|
311
|
+
| `PUT` | `/api/tables/:table/records/bulk` | Bulk update records | Yes | `update` |
|
|
312
|
+
| `DELETE` | `/api/tables/:table/records/:id` | Delete single record by ID | Yes | `delete` |
|
|
313
|
+
| `DELETE` | `/api/tables/:table/records` | Delete records matching condition | Yes | `delete` |
|
|
314
|
+
| `POST` | `/api/tables/:table/records/bulk-delete` | Bulk delete records by IDs | Yes | `delete` |
|
|
315
|
+
| `GET` | `/api/tables/:table/count` | Count records matching filter | Yes | `read` |
|
|
316
|
+
| `GET` | `/api/tables/:table/columns/:column/stats` | Statistical profile of column | Yes | `read` |
|
|
317
|
+
| `POST` | `/api/query/select` | Execute SELECT query | Yes | `read` |
|
|
318
|
+
| `POST` | `/api/query/write` | Execute INSERT/UPDATE query | Yes | `execute` |
|
|
319
|
+
| `POST` | `/api/tables` | Create new table | Yes | `ddl` |
|
|
320
|
+
| `PUT` | `/api/tables/:table` | Alter existing table | Yes | `ddl` |
|
|
321
|
+
| `DELETE` | `/api/tables/:table` | Drop existing table | Yes | `ddl` |
|
|
322
|
+
| `POST` | `/api/ddl` | Execute DDL statements | Yes | `ddl` |
|
|
323
|
+
| `GET` | `/api/schema/summary` | Get database summary | Yes | `list` |
|
|
324
|
+
| `GET` | `/api/schema/rag-context` | Generate ultra-compact RAG schema | Yes | `list` |
|
|
325
|
+
| `GET` | `/api/schema/erd` | Generate ER diagram data | Yes | `list` |
|
|
326
|
+
| `GET` | `/api/schema/relationships` | Get foreign key relationships | Yes | `list` |
|
|
327
|
+
| `GET` | `/api/schema/search` | Search schema metadata | Yes | `list` |
|
|
328
|
+
| `GET` | `/api/tables/:table/export` | Export table to CSV | Yes | `utility` |
|
|
329
|
+
| `POST` | `/api/query/export` | Export SELECT query to CSV | Yes | `utility` |
|
|
330
|
+
| `ALL` | `*` (Catch-all) | 404 Handler guaranteeing strict JSON error | Yes | None |
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## 7. Configuration & Environment Variables
|
|
335
|
+
|
|
336
|
+
| Variable | Default | Description |
|
|
337
|
+
|----------|---------|-------------|
|
|
338
|
+
| `MYSQL_API_ENDPOINT` | `http://localhost:3300` | Remote MySQL API server URL |
|
|
339
|
+
| `MYSQL_API_KEY` | `""` | API Key or Bearer token for authentication |
|
|
340
|
+
| `MCP_PERMISSIONS` | `all` | Permission preset (`only-read`, `read-write`, `admin`, or comma-separated list) |
|
|
341
|
+
| `API_PERMISSIONS` | `all` | Server-level permission preset enforced on HTTP endpoints |
|
|
342
|
+
| `DEFAULT_PAGE_SIZE` | `50` | Default records per page |
|
|
343
|
+
| `MAX_PAGE_SIZE` | `500` | Maximum allowed records per page |
|
|
344
|
+
| `MAX_BYPASS_LIMIT` | `10000` | Maximum allowed records during pagination bypass |
|
|
345
|
+
| `API_TIMEOUT_MS` | `30000` | Network timeout for API requests in milliseconds |
|
|
346
|
+
| `PORT` | `3300` | HTTP port for the companion API server |
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## 8. Verification & Testing Strategy
|
|
351
|
+
|
|
352
|
+
1. **Unit Testing:**
|
|
353
|
+
- Permissions engine: verify `only-read` blocks all mutating tools; verify custom lists; verify queryContext inspection.
|
|
354
|
+
- Strict JSON formatter: guarantee that every response envelope parses via `JSON.parse()`.
|
|
355
|
+
- Pagination engine: verify default limit applied; verify bypass mode logic.
|
|
356
|
+
2. **Integration Testing:**
|
|
357
|
+
- In-memory mock API server simulating remote endpoints.
|
|
358
|
+
- Full MCP tool invocation cycles over simulated stdio transport.
|
|
359
|
+
- Security tests: operator normalization, SQL injection rejection, dangerous SQL keyword blocking.
|
|
360
|
+
- Dual-layer tests: API server blocking mutations with HTTP 403 under `only-read`.
|
|
361
|
+
- Strict JSON 404/500 tests: verify zero HTML output.
|
|
362
|
+
3. **Build & Type Safety:**
|
|
363
|
+
- Zero TypeScript compile errors (`tsc`).
|
|
364
|
+
- Clean Jest test execution (100% passing across 6 test suites and 61 tests).
|
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# MySQL MCP via API (`mcp-mysql-via-api`)
|
|
2
|
+
|
|
3
|
+
A production-grade **Model Context Protocol (MCP)** server for interacting with MySQL databases **via HTTP/REST API endpoints** on a remote server. Specially optimized for autonomous AI agents like **Hermes AI** and **OpenClaw**, as well as IDEs (Cursor, Windsurf, Cline) and desktop/CLI environments.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🌟 Key Features
|
|
8
|
+
|
|
9
|
+
- **Decoupled Architecture:** Access MySQL securely without exposing port 3306 or direct database socket connections across corporate firewalls or VPCs. Connects via an authenticated HTTP/REST API endpoint.
|
|
10
|
+
- **Strict Valid JSON Output Guarantee:** 100% of all tool responses (both success results and error envelopes) are strictly formatted as valid JSON (`application/json`). Never plain text, no raw markdown backticks, no emoji error prefixes, and never HTML error pages (even on HTTP 404/500).
|
|
11
|
+
- **Default Pagination + Instant Bypass:**
|
|
12
|
+
- Multi-row operations (`read_records`, `run_select_query`, `search_data_across_tables`) paginate by default (`page=1`, `limit=50`).
|
|
13
|
+
- Supports instant bypass (`bypass_pagination: true` or `all: true`) for full dataset extraction with memory safety guards (`MAX_BYPASS_LIMIT`).
|
|
14
|
+
- **Dual-Layer Defense Permission System:**
|
|
15
|
+
- **MCP Client Level:** Pre-execution verification preventing unauthorized tool dispatch.
|
|
16
|
+
- **API Server Level:** HTTP endpoint authorization via `API_PERMISSIONS` returning HTTP 403 Forbidden envelopes.
|
|
17
|
+
- Presets: `only-read` (read-only), `read-write`, `admin` (all operations).
|
|
18
|
+
- Granular permissions: `list`, `read`, `create`, `update`, `delete`, `execute`, `ddl`, `utility`.
|
|
19
|
+
- **AI Agent Context Window Optimization (Hermes & OpenClaw):**
|
|
20
|
+
- `get_schema_rag_context`: Ultra-compact schema representation designed to preserve LLM token context windows.
|
|
21
|
+
- `search_data_across_tables`: Cross-table text search when schema storage location is unknown.
|
|
22
|
+
- `get_column_statistics`: Statistical data profiling (null percentage, distinct values, min/max, distribution).
|
|
23
|
+
- `read_record`: Direct point lookup by primary key or ID.
|
|
24
|
+
- **Direct Table REST Endpoints:** Every table exposes standard REST endpoints (`/api/tables/:table/records`, `/api/tables/:table/records/:id`, `/api/tables/:table/count`, etc.).
|
|
25
|
+
- **Companion MySQL REST API Server Included:** Comes with a standalone Express/Node.js API server (`npm run start:server`) that can be deployed directly to the remote database machine.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 🚀 Quick Start
|
|
30
|
+
|
|
31
|
+
### 1. Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cd C:\DEKSTOP\MCP\mcp_mysql_via_api
|
|
35
|
+
npm install
|
|
36
|
+
npm run build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Configure Environment
|
|
40
|
+
|
|
41
|
+
Copy `.env.example` to `.env`:
|
|
42
|
+
|
|
43
|
+
```env
|
|
44
|
+
MYSQL_API_ENDPOINT=http://remote-mysql-server:3300
|
|
45
|
+
MYSQL_API_KEY=your-secure-api-token
|
|
46
|
+
MCP_PERMISSIONS=only-read
|
|
47
|
+
API_PERMISSIONS=only-read
|
|
48
|
+
DEFAULT_PAGE_SIZE=50
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3. Start the MCP Server
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npm start
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or run directly via Node/CLI:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
node dist/mcp-server.js http://remote-server:3300 only-read your-api-key
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 🤖 AI Agent Integration
|
|
66
|
+
|
|
67
|
+
### Hermes AI / OpenClaw Configuration
|
|
68
|
+
|
|
69
|
+
Add to your agent's MCP servers config (`mcp_config.json` or agent YAML):
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"mysql_via_api": {
|
|
75
|
+
"command": "npx",
|
|
76
|
+
"args": [
|
|
77
|
+
"-y",
|
|
78
|
+
"@jessejoris/mcp-mysql-via-api",
|
|
79
|
+
"http://your-remote-api-server:3300",
|
|
80
|
+
"only-read",
|
|
81
|
+
"your-api-key"
|
|
82
|
+
],
|
|
83
|
+
"env": {
|
|
84
|
+
"MYSQL_API_ENDPOINT": "http://your-remote-api-server:3300",
|
|
85
|
+
"MYSQL_API_KEY": "your-api-key",
|
|
86
|
+
"MCP_PERMISSIONS": "only-read",
|
|
87
|
+
"DEFAULT_PAGE_SIZE": "50"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Cursor / Windsurf / Claude Desktop (`claude_desktop_config.json`)
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"mcpServers": {
|
|
99
|
+
"mysql_api": {
|
|
100
|
+
"command": "npx",
|
|
101
|
+
"args": [
|
|
102
|
+
"-y",
|
|
103
|
+
"@jessejoris/mcp-mysql-via-api"
|
|
104
|
+
],
|
|
105
|
+
"env": {
|
|
106
|
+
"MYSQL_API_ENDPOINT": "https://api.internal.example.com",
|
|
107
|
+
"MYSQL_API_KEY": "secret-bearer-token",
|
|
108
|
+
"MCP_PERMISSIONS": "only-read"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 🔒 Permission Profiles
|
|
118
|
+
|
|
119
|
+
Set via `MCP_PERMISSIONS` and `API_PERMISSIONS` environment variables or CLI arguments:
|
|
120
|
+
|
|
121
|
+
| Preset | Allowed Categories | Mutating Actions Blocked? |
|
|
122
|
+
|--------|-------------------|--------------------------|
|
|
123
|
+
| `only-read` / `readonly` | `list`, `read`, `utility` | ✅ Blocks `create`, `update`, `delete`, `execute`, `ddl` |
|
|
124
|
+
| `read-write` | `list`, `read`, `create`, `update`, `utility` | ✅ Blocks `delete`, `execute`, `ddl` |
|
|
125
|
+
| `admin` / `all` | All permissions | None blocked |
|
|
126
|
+
| Custom (e.g. `list,read`) | Explicit list | Blocks anything omitted |
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 🧰 Available Tools (31 Tools Catalog)
|
|
131
|
+
|
|
132
|
+
### Discovery & Schema
|
|
133
|
+
1. `list_databases`: Lists all accessible databases.
|
|
134
|
+
2. `list_tables`: Lists tables in database.
|
|
135
|
+
3. `read_table_schema`: Full column and index definitions.
|
|
136
|
+
4. `get_database_summary`: Structural overview of tables and rows.
|
|
137
|
+
5. `get_schema_erd`: Generates Mermaid.js ER diagram.
|
|
138
|
+
6. `get_schema_rag_context`: Ultra-compact schema for LLM context windows.
|
|
139
|
+
7. `get_all_tables_relationships`: Analyzes foreign key relationships.
|
|
140
|
+
8. `search_schema`: Searches table and column metadata.
|
|
141
|
+
9. `find_tables_by_keyword`: Ranked keyword search for candidate tables.
|
|
142
|
+
10. `search_data_across_tables`: Scans text data across tables for keywords.
|
|
143
|
+
|
|
144
|
+
### CRUD & Data
|
|
145
|
+
11. `read_records`: Reads rows with pagination, sorting, and filter conditions.
|
|
146
|
+
12. `read_record`: Direct point lookup by primary key or ID.
|
|
147
|
+
13. `count_records`: Counts matching rows.
|
|
148
|
+
14. `create_record`: Inserts single record.
|
|
149
|
+
15. `bulk_insert`: Batch inserts multiple records.
|
|
150
|
+
16. `update_record`: Updates records matching filter conditions.
|
|
151
|
+
17. `bulk_update`: Batch updates records by primary key.
|
|
152
|
+
18. `delete_record`: Deletes records matching filter conditions.
|
|
153
|
+
19. `bulk_delete`: Batch deletes records by primary keys.
|
|
154
|
+
|
|
155
|
+
### Data Profiling
|
|
156
|
+
20. `get_column_statistics`: Statistical data profiling of column values.
|
|
157
|
+
|
|
158
|
+
### Query Execution
|
|
159
|
+
21. `run_select_query`: Runs read-only SELECT queries with pagination/bypass.
|
|
160
|
+
22. `execute_write_query`: Executes guarded mutation queries with DDL/dangerous keyword checks.
|
|
161
|
+
|
|
162
|
+
### Schema Management (DDL)
|
|
163
|
+
23. `create_table`: Creates table.
|
|
164
|
+
24. `alter_table`: Alters table columns.
|
|
165
|
+
25. `drop_table`: Drops table.
|
|
166
|
+
26. `execute_ddl`: Executes raw DDL statements.
|
|
167
|
+
|
|
168
|
+
### Diagnostics & Utilities
|
|
169
|
+
27. `test_connection`: Pings remote API, checks DB connection and latency.
|
|
170
|
+
28. `describe_connection`: Returns endpoint, status, and active permission policies.
|
|
171
|
+
29. `list_all_tools`: Live catalog of all 31 tools with active permission status.
|
|
172
|
+
30. `export_table_to_csv`: Exports table data to CSV.
|
|
173
|
+
31. `export_query_to_csv`: Exports SELECT query results to CSV.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🖥️ Companion MySQL API Server
|
|
178
|
+
|
|
179
|
+
Deploy `src/server/` on your remote server running MySQL:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# On remote server
|
|
183
|
+
export DB_HOST=localhost
|
|
184
|
+
export DB_USER=root
|
|
185
|
+
export DB_PASSWORD=my-password
|
|
186
|
+
export DB_NAME=production_db
|
|
187
|
+
export MYSQL_API_KEY=my-secret-key
|
|
188
|
+
export API_PERMISSIONS=only-read # Optional server-level guard
|
|
189
|
+
export PORT=3300
|
|
190
|
+
|
|
191
|
+
npm run start:server
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 🧪 Testing
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm test
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Runs all 6 test suites covering 61 unit and integration tests.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReadRecordsParams, ReadRecordParams, CreateRecordParams, BulkInsertParams, UpdateRecordParams, BulkUpdateParams, DeleteRecordParams, BulkDeleteParams, CountRecordsParams, SelectQueryParams, WriteQueryParams, DdlQueryParams, CreateTableParams, DropTableParams, RagContextParams, SearchDataParams, ColumnStatsParams, ServerConfig } from "../types/index.js";
|
|
2
|
+
export declare class MysqlApiClient {
|
|
3
|
+
private endpoint;
|
|
4
|
+
private apiKey;
|
|
5
|
+
private timeoutMs;
|
|
6
|
+
private defaultPageSize;
|
|
7
|
+
private maxPageSize;
|
|
8
|
+
private maxBypassLimit;
|
|
9
|
+
constructor(config: ServerConfig);
|
|
10
|
+
private getHeaders;
|
|
11
|
+
private request;
|
|
12
|
+
testConnection(): Promise<any>;
|
|
13
|
+
getInfo(): Promise<any>;
|
|
14
|
+
listDatabases(): Promise<any>;
|
|
15
|
+
listTables(database?: string): Promise<any>;
|
|
16
|
+
readTableSchema(tableName: string, database?: string): Promise<any>;
|
|
17
|
+
getDatabaseSummary(options?: {
|
|
18
|
+
database?: string;
|
|
19
|
+
maxTables?: number;
|
|
20
|
+
includeRelationships?: boolean;
|
|
21
|
+
}): Promise<any>;
|
|
22
|
+
getSchemaRagContext(options?: RagContextParams): Promise<any>;
|
|
23
|
+
getSchemaErd(database?: string): Promise<any>;
|
|
24
|
+
getAllTablesRelationships(database?: string): Promise<any>;
|
|
25
|
+
searchSchema(query: string, database?: string): Promise<any>;
|
|
26
|
+
findTablesByKeyword(keyword: string, database?: string, limit?: number): Promise<any>;
|
|
27
|
+
searchDataAcrossTables(options: SearchDataParams): Promise<any>;
|
|
28
|
+
readRecords(params: ReadRecordsParams): Promise<any>;
|
|
29
|
+
readRecord(params: ReadRecordParams): Promise<any>;
|
|
30
|
+
countRecords(params: CountRecordsParams): Promise<any>;
|
|
31
|
+
getColumnStatistics(params: ColumnStatsParams): Promise<any>;
|
|
32
|
+
createRecord(params: CreateRecordParams): Promise<any>;
|
|
33
|
+
bulkInsert(params: BulkInsertParams): Promise<any>;
|
|
34
|
+
updateRecord(params: UpdateRecordParams): Promise<any>;
|
|
35
|
+
bulkUpdate(params: BulkUpdateParams): Promise<any>;
|
|
36
|
+
deleteRecord(params: DeleteRecordParams): Promise<any>;
|
|
37
|
+
bulkDelete(params: BulkDeleteParams): Promise<any>;
|
|
38
|
+
runSelectQuery(params: SelectQueryParams): Promise<any>;
|
|
39
|
+
executeWriteQuery(params: WriteQueryParams): Promise<any>;
|
|
40
|
+
createTable(params: CreateTableParams): Promise<any>;
|
|
41
|
+
alterTable(tableName: string, action: string, columnDefinition: any, database?: string): Promise<any>;
|
|
42
|
+
dropTable(params: DropTableParams): Promise<any>;
|
|
43
|
+
executeDdl(params: DdlQueryParams): Promise<any>;
|
|
44
|
+
exportTableToCsv(tableName: string, limit?: number, database?: string): Promise<any>;
|
|
45
|
+
exportQueryToCsv(query: string, limit?: number, database?: string): Promise<any>;
|
|
46
|
+
}
|