@mokoconsulting/mokomysql-mcp 0.0.0-stage → 2.5.4
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/LICENSE +696 -0
- package/README.md +112 -3
- package/config.example.json +26 -0
- package/dist/README.md +7 -0
- package/dist/client.d.ts +49 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +180 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +86 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +758 -0
- package/dist/index.js.map +1 -0
- package/dist/secrets.d.ts +8 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +75 -0
- package/dist/secrets.js.map +1 -0
- package/dist/state.d.ts +13 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +59 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -4
- package/source/client.ts +210 -0
- package/source/config.ts +97 -0
- package/source/index.ts +1100 -0
- package/source/secrets.ts +70 -0
- package/source/state.ts +62 -0
- package/source/types.ts +91 -0
- package/tsconfig.json +19 -0
package/README.md
CHANGED
|
@@ -1,3 +1,112 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# mokomysql-mcp
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server for MySQL database management — run queries, inspect
|
|
4
|
+
and modify schema, manage users, perform maintenance, and use Joomla-aware helpers, all
|
|
5
|
+
exposed as MCP tools that AI assistants and MCP clients can call.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Execute SQL queries against a configured MySQL/MariaDB database
|
|
10
|
+
- Inspect and manage schema (tables, columns, indexes)
|
|
11
|
+
- User and privilege management
|
|
12
|
+
- Maintenance operations (analyze, optimize, repair)
|
|
13
|
+
- Joomla-specific helpers for common CMS database tasks
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- An MCP-capable client (for example, Claude Code or another MCP host)
|
|
18
|
+
- Network access to a MySQL or MariaDB server
|
|
19
|
+
- Database credentials with the privileges required for the operations you intend to run
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
The server is published to npm as `@mokoconsulting/mokomysql-mcp`. No manual clone or
|
|
24
|
+
build is required — your MCP client runs it on demand with `npx`:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx -y @mokoconsulting/mokomysql-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or install it globally:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install -g @mokoconsulting/mokomysql-mcp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
Connections are read from a JSON config file at `~/.mcp_mokomysql.json` (override the path
|
|
39
|
+
with the `MYSQL_MCP_CONFIG` environment variable). See [`config.example.json`](config.example.json):
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"defaultConnection": "local",
|
|
44
|
+
"connections": {
|
|
45
|
+
"local": {
|
|
46
|
+
"host": "127.0.0.1",
|
|
47
|
+
"port": 3306,
|
|
48
|
+
"user": "dbuser",
|
|
49
|
+
"password": "secret",
|
|
50
|
+
"database": "joomla",
|
|
51
|
+
"ssl": false
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Full configuration reference is in the wiki — docs are **wiki-first** at MokoConsulting:
|
|
58
|
+
|
|
59
|
+
**→ [Configuration (wiki)](https://git.mokoconsulting.tech/MokoConsulting/mokomysql-mcp/wiki/Configuration)**
|
|
60
|
+
|
|
61
|
+
It covers TLS options, environment variables (`MYSQL_MCP_CONFIG`, `MYSQL_MCP_STATE`), the sidecar
|
|
62
|
+
state file, and **Joomla write safety** — writes to a Joomla database require a two-step
|
|
63
|
+
`confirm_token` (the first call returns a token and does not execute); reads are never gated.
|
|
64
|
+
|
|
65
|
+
The write gate is **operation-aware**. The two-step `confirm_token` is required for *every* Joomla
|
|
66
|
+
write, but the "raw SQL can corrupt the ACL nested set" warning is only shown for the operations
|
|
67
|
+
that can actually cause it. Joomla creates, removes, and renumbers `#__assets` / nested-set rows
|
|
68
|
+
only when a row is **created or deleted** through its Table API (`Table::store()` / `Table::delete()`),
|
|
69
|
+
which raw SQL bypasses — so:
|
|
70
|
+
|
|
71
|
+
- A pure **in-place `UPDATE`** that does not reference a nested-set table (`#__assets`, `#__categories`,
|
|
72
|
+
`#__menu`) gets a lighter message: it still needs the token, but it cannot touch the asset tree.
|
|
73
|
+
- **`INSERT` / `DELETE`** of an asset-bearing row (any table with an `asset_id` column), **DDL**, and
|
|
74
|
+
**any write to a nested-set table** keep the full nested-set/ACL warning and the integrity reminder.
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
Register the server with your MCP client. A typical MCP client configuration entry looks like:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"mcpServers": {
|
|
83
|
+
"mokomysql": {
|
|
84
|
+
"command": "npx",
|
|
85
|
+
"args": ["-y", "@mokoconsulting/mokomysql-mcp"],
|
|
86
|
+
"env": {
|
|
87
|
+
"MYSQL_MCP_CONFIG": "/home/you/.mcp_mokomysql.json",
|
|
88
|
+
"MYSQL_MCP_STATE": "/home/you/.mcp_mokomysql.state.json"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The `env` block is where the config and sidecar paths belong — server-instance settings, kept out
|
|
96
|
+
of any project repository (both are optional; see the [Configuration wiki](https://git.mokoconsulting.tech/MokoConsulting/mokomysql-mcp/wiki/Configuration)).
|
|
97
|
+
Once connected, the client can call the server's tools to query data, inspect schema, manage
|
|
98
|
+
users, run maintenance, and invoke the Joomla helpers.
|
|
99
|
+
|
|
100
|
+
## Contributing
|
|
101
|
+
|
|
102
|
+
Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) and follow the
|
|
103
|
+
[MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home) for
|
|
104
|
+
coding style, commit conventions, and the pull request process.
|
|
105
|
+
|
|
106
|
+
## License
|
|
107
|
+
|
|
108
|
+
Licensed under GPL-3.0-or-later — see [LICENSE](LICENSE).
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
*[Moko Consulting](https://mokoconsulting.tech)*
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultConnection": "local",
|
|
3
|
+
"connections": {
|
|
4
|
+
"local": {
|
|
5
|
+
"host": "127.0.0.1",
|
|
6
|
+
"port": 3306,
|
|
7
|
+
"user": "root",
|
|
8
|
+
"password": "CHANGE_ME",
|
|
9
|
+
"database": "mysql",
|
|
10
|
+
"ssl": false,
|
|
11
|
+
"timezone": "Z",
|
|
12
|
+
"tags": ["localhost", "dev-db"]
|
|
13
|
+
},
|
|
14
|
+
"joomla-site": {
|
|
15
|
+
"host": "db.example.com",
|
|
16
|
+
"port": 3306,
|
|
17
|
+
"user": "joomla",
|
|
18
|
+
"password": "file:~/.ssh/tokens/JOOMLA.db.token",
|
|
19
|
+
"database": "joomla_prod",
|
|
20
|
+
"ssl": true,
|
|
21
|
+
"joomla": true,
|
|
22
|
+
"joomlaPrefix": "vkw4n_",
|
|
23
|
+
"tags": ["prod"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# dist/
|
|
2
|
+
|
|
3
|
+
Distributable artifacts live here — the packaged installer(s) and release
|
|
4
|
+
bundles emitted by the **mokocli-centric build system** (mokocli clones and runs
|
|
5
|
+
the shared build tooling in CI). Generated output, not source.
|
|
6
|
+
|
|
7
|
+
Only this `README.md` is tracked; everything else under `dist/` is git-ignored.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { FieldPacket } from 'mysql2/promise';
|
|
2
|
+
import type { MySqlConfig } from './types.js';
|
|
3
|
+
/** Result of probing a (connection, database) pair for Joomla-ness. */
|
|
4
|
+
export interface JoomlaDetection {
|
|
5
|
+
/** Whether this target is treated as a Joomla database. */
|
|
6
|
+
isJoomla: boolean;
|
|
7
|
+
/** The live table prefix (e.g. "jos_", "vkw4n_"), when known. */
|
|
8
|
+
prefix: string | null;
|
|
9
|
+
/** How the verdict was reached — for surfacing in warnings. */
|
|
10
|
+
source: 'config' | 'marker' | 'auto' | 'none';
|
|
11
|
+
}
|
|
12
|
+
export declare class MysqlClient {
|
|
13
|
+
private pools;
|
|
14
|
+
private config;
|
|
15
|
+
/** Memoized Joomla verdicts, keyed by `${connectionKey}::${schema}`. */
|
|
16
|
+
private joomlaCache;
|
|
17
|
+
constructor(config: MySqlConfig);
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the canonical identity of a target for binding/keying: the config
|
|
20
|
+
* connection key and the effective schema (explicit database or the connection
|
|
21
|
+
* default). Keeps callers consistent with how detection and markers are keyed.
|
|
22
|
+
*/
|
|
23
|
+
resolveIdentity(connectionName?: string, database?: string): {
|
|
24
|
+
connKey: string;
|
|
25
|
+
schema: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Determine whether a target is a Joomla database, so writes can be gated.
|
|
29
|
+
* Resolution order: in-memory cache → explicit per-connection `joomla` flag
|
|
30
|
+
* (authoritative) → persisted sidecar marker (learned on a prior connect) →
|
|
31
|
+
* live schema probe for the Joomla signature (`<prefix>extensions` paired with
|
|
32
|
+
* `<prefix>assets`). A fresh probe result is persisted as a marker so future
|
|
33
|
+
* connects skip the round-trip entirely.
|
|
34
|
+
*/
|
|
35
|
+
detectJoomla(connectionName?: string, database?: string): Promise<JoomlaDetection>;
|
|
36
|
+
private cache;
|
|
37
|
+
private poolFor;
|
|
38
|
+
query(sql: string, params?: unknown[], connectionName?: string, database?: string): Promise<{
|
|
39
|
+
rows: Record<string, unknown>[];
|
|
40
|
+
fields: FieldPacket[];
|
|
41
|
+
}>;
|
|
42
|
+
execute(sql: string, params?: unknown[], connectionName?: string, database?: string): Promise<{
|
|
43
|
+
affectedRows: number;
|
|
44
|
+
insertId: number;
|
|
45
|
+
changedRows: number;
|
|
46
|
+
}>;
|
|
47
|
+
closeAll(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../source/client.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAqB,WAAW,EAAmB,MAAM,gBAAgB,CAAC;AAGtF,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAE/D,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC/B,2DAA2D;IAC3D,QAAQ,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,+DAA+D;IAC/D,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;CAC9C;AAED,qBAAa,WAAW;IACvB,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,MAAM,CAAc;IAC5B,wEAAwE;IACxE,OAAO,CAAC,WAAW,CAA2C;gBAElD,MAAM,EAAE,WAAW;IAI/B;;;;OAIG;IACH,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IAKhG;;;;;;;OAOG;IACG,YAAY,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAqDxF,OAAO,CAAC,KAAK;IAKb,OAAO,CAAC,OAAO;IAoCT,KAAK,CACV,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAAE,EAClB,cAAc,CAAC,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;IAiBhE,OAAO,CACZ,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAAE,EAClB,cAAc,CAAC,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAuBrE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAM/B"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
+
*
|
|
3
|
+
* This file is part of a Moko Consulting project.
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
|
+
*
|
|
7
|
+
* FILE INFORMATION
|
|
8
|
+
* DEFGROUP: mokomysql.Client
|
|
9
|
+
* INGROUP: mokomysql
|
|
10
|
+
* REPO: https://git.mokoconsulting.tech/MokoConsulting/mokomysql-mcp
|
|
11
|
+
* PATH: /src/client.ts
|
|
12
|
+
* VERSION: 01.00.00
|
|
13
|
+
* BRIEF: MySQL client with connection pool management
|
|
14
|
+
*/
|
|
15
|
+
import mysql from 'mysql2/promise';
|
|
16
|
+
import { getConnection } from './config.js';
|
|
17
|
+
import { getMarker, markerKey, setMarker } from './state.js';
|
|
18
|
+
export class MysqlClient {
|
|
19
|
+
pools = new Map();
|
|
20
|
+
config;
|
|
21
|
+
/** Memoized Joomla verdicts, keyed by `${connectionKey}::${schema}`. */
|
|
22
|
+
joomlaCache = new Map();
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the canonical identity of a target for binding/keying: the config
|
|
28
|
+
* connection key and the effective schema (explicit database or the connection
|
|
29
|
+
* default). Keeps callers consistent with how detection and markers are keyed.
|
|
30
|
+
*/
|
|
31
|
+
resolveIdentity(connectionName, database) {
|
|
32
|
+
const { key, conn } = getConnection(this.config, connectionName);
|
|
33
|
+
return { connKey: key, schema: database ?? conn.database ?? '' };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Determine whether a target is a Joomla database, so writes can be gated.
|
|
37
|
+
* Resolution order: in-memory cache → explicit per-connection `joomla` flag
|
|
38
|
+
* (authoritative) → persisted sidecar marker (learned on a prior connect) →
|
|
39
|
+
* live schema probe for the Joomla signature (`<prefix>extensions` paired with
|
|
40
|
+
* `<prefix>assets`). A fresh probe result is persisted as a marker so future
|
|
41
|
+
* connects skip the round-trip entirely.
|
|
42
|
+
*/
|
|
43
|
+
async detectJoomla(connectionName, database) {
|
|
44
|
+
const { key, conn } = getConnection(this.config, connectionName);
|
|
45
|
+
const schema = database ?? conn.database ?? '';
|
|
46
|
+
const cacheKey = `${key}::${schema}`;
|
|
47
|
+
const cached = this.joomlaCache.get(cacheKey);
|
|
48
|
+
if (cached)
|
|
49
|
+
return cached;
|
|
50
|
+
// Explicit config flag is authoritative — no probe, and it overrides any marker.
|
|
51
|
+
if (conn.joomla === true) {
|
|
52
|
+
return this.cache(cacheKey, { isJoomla: true, prefix: conn.joomlaPrefix ?? null, source: 'config' });
|
|
53
|
+
}
|
|
54
|
+
if (conn.joomla === false) {
|
|
55
|
+
return this.cache(cacheKey, { isJoomla: false, prefix: null, source: 'config' });
|
|
56
|
+
}
|
|
57
|
+
// Without a resolvable target schema we cannot probe or key a marker.
|
|
58
|
+
if (!schema) {
|
|
59
|
+
return this.cache(cacheKey, { isJoomla: false, prefix: null, source: 'none' });
|
|
60
|
+
}
|
|
61
|
+
// Learned marker from a previous connect — instant, no round-trip.
|
|
62
|
+
const mKey = markerKey(conn.host, conn.port ?? 3306, schema);
|
|
63
|
+
const marker = await getMarker(mKey);
|
|
64
|
+
if (marker) {
|
|
65
|
+
return this.cache(cacheKey, { isJoomla: marker.joomla, prefix: marker.prefix, source: 'marker' });
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const { rows } = await this.query("SELECT TABLE_NAME AS name FROM information_schema.TABLES " +
|
|
69
|
+
"WHERE TABLE_SCHEMA = ? AND TABLE_NAME REGEXP '(extensions|assets)$'", [schema], connectionName);
|
|
70
|
+
const names = new Set(rows.map((r) => String(r.name)));
|
|
71
|
+
let prefix = null;
|
|
72
|
+
for (const name of names) {
|
|
73
|
+
if (!name.endsWith('extensions'))
|
|
74
|
+
continue;
|
|
75
|
+
const candidate = name.slice(0, -'extensions'.length);
|
|
76
|
+
if (names.has(`${candidate}assets`)) {
|
|
77
|
+
prefix = candidate;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const verdict = prefix !== null
|
|
82
|
+
? { isJoomla: true, prefix, source: 'auto' }
|
|
83
|
+
: { isJoomla: false, prefix: null, source: 'auto' };
|
|
84
|
+
// Persist what we learned so the next connect just knows.
|
|
85
|
+
await setMarker(mKey, { joomla: verdict.isJoomla, prefix: verdict.prefix, detectedAt: new Date().toISOString() });
|
|
86
|
+
return this.cache(cacheKey, verdict);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Probe failed (permissions, missing schema). Degrade to "none" and do
|
|
90
|
+
// not cache or persist, so a later successful probe can still classify it.
|
|
91
|
+
return { isJoomla: false, prefix: null, source: 'none' };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
cache(cacheKey, verdict) {
|
|
95
|
+
this.joomlaCache.set(cacheKey, verdict);
|
|
96
|
+
return verdict;
|
|
97
|
+
}
|
|
98
|
+
poolFor(connectionName) {
|
|
99
|
+
const { key, conn } = getConnection(this.config, connectionName);
|
|
100
|
+
let pool = this.pools.get(key);
|
|
101
|
+
if (!pool) {
|
|
102
|
+
const opts = {
|
|
103
|
+
host: conn.host,
|
|
104
|
+
port: conn.port ?? 3306,
|
|
105
|
+
user: conn.user,
|
|
106
|
+
password: conn.password,
|
|
107
|
+
database: conn.database,
|
|
108
|
+
connectionLimit: 5,
|
|
109
|
+
waitForConnections: true,
|
|
110
|
+
timezone: conn.timezone ?? 'Z',
|
|
111
|
+
multipleStatements: false,
|
|
112
|
+
};
|
|
113
|
+
if (conn.ssl) {
|
|
114
|
+
// Default to verified TLS. A bare `ssl: true` is never silently
|
|
115
|
+
// downgraded — callers who must skip verification (trusted internal
|
|
116
|
+
// hosts with self-signed certs) opt out explicitly via
|
|
117
|
+
// `ssl: { rejectUnauthorized: false }` in their config.
|
|
118
|
+
opts.ssl = typeof conn.ssl === 'object'
|
|
119
|
+
? conn.ssl
|
|
120
|
+
: { rejectUnauthorized: true };
|
|
121
|
+
}
|
|
122
|
+
pool = mysql.createPool(opts);
|
|
123
|
+
this.pools.set(key, pool);
|
|
124
|
+
// On first connect, learn (and persist) the Joomla verdict for the
|
|
125
|
+
// connection's default database so the write-gate knows immediately.
|
|
126
|
+
// Best-effort and non-blocking — never let it break pool creation.
|
|
127
|
+
if (conn.database) {
|
|
128
|
+
void this.detectJoomla(connectionName, conn.database).catch(() => undefined);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return pool;
|
|
132
|
+
}
|
|
133
|
+
async query(sql, params, connectionName, database) {
|
|
134
|
+
const pool = this.poolFor(connectionName);
|
|
135
|
+
const p = (params ?? []);
|
|
136
|
+
if (database) {
|
|
137
|
+
const conn = await pool.getConnection();
|
|
138
|
+
try {
|
|
139
|
+
await conn.query(`USE \`${database.replace(/`/g, '``')}\``);
|
|
140
|
+
const [rows, fields] = await conn.query(sql, p);
|
|
141
|
+
return { rows: rows, fields };
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
conn.release();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const [rows, fields] = await pool.query(sql, p);
|
|
148
|
+
return { rows: rows, fields };
|
|
149
|
+
}
|
|
150
|
+
async execute(sql, params, connectionName, database) {
|
|
151
|
+
const pool = this.poolFor(connectionName);
|
|
152
|
+
const p = (params ?? []);
|
|
153
|
+
if (database) {
|
|
154
|
+
const conn = await pool.getConnection();
|
|
155
|
+
try {
|
|
156
|
+
await conn.query(`USE \`${database.replace(/`/g, '``')}\``);
|
|
157
|
+
const [result] = await conn.execute(sql, p);
|
|
158
|
+
const r = result;
|
|
159
|
+
return { affectedRows: r.affectedRows ?? 0, insertId: r.insertId ?? 0, changedRows: r.changedRows ?? 0 };
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
conn.release();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const [result] = await pool.execute(sql, p);
|
|
166
|
+
const r = result;
|
|
167
|
+
return {
|
|
168
|
+
affectedRows: r.affectedRows ?? 0,
|
|
169
|
+
insertId: r.insertId ?? 0,
|
|
170
|
+
changedRows: r.changedRows ?? 0,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
async closeAll() {
|
|
174
|
+
for (const [, pool] of this.pools) {
|
|
175
|
+
await pool.end();
|
|
176
|
+
}
|
|
177
|
+
this.pools.clear();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../source/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MySqlConfig, MySqlConnection } from './types.js';
|
|
2
|
+
/** Absolute path to the active config file (`MYSQL_MCP_CONFIG` or ~/.mcp_mokomysql.json). */
|
|
3
|
+
export declare function getConfigPath(): string;
|
|
4
|
+
/**
|
|
5
|
+
* Absolute path to the sidecar state file — the MCP-managed learned-marker store.
|
|
6
|
+
* `MYSQL_MCP_STATE` overrides it outright; otherwise it sits beside the config as
|
|
7
|
+
* `<config>.state.json`, so learned state always follows the config that produced it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getStatePath(): string;
|
|
10
|
+
export declare function loadConfig(): Promise<MySqlConfig>;
|
|
11
|
+
/**
|
|
12
|
+
* Normalize a name for tag matching: lowercase and strip every character
|
|
13
|
+
* that isn't a letter or digit. This makes "moko.live", "moko-live",
|
|
14
|
+
* "Moko Live" and "mokolive" all collapse to the same key.
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizeTag(value: string): string;
|
|
17
|
+
export declare function getConnection(config: MySqlConfig, name?: string): {
|
|
18
|
+
key: string;
|
|
19
|
+
conn: MySqlConnection;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../source/config.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAK/D,6FAA6F;AAC7F,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC,CAyBvD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAoBxG"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
|
2
|
+
*
|
|
3
|
+
* This file is part of a Moko Consulting project.
|
|
4
|
+
*
|
|
5
|
+
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
|
+
*
|
|
7
|
+
* FILE INFORMATION
|
|
8
|
+
* DEFGROUP: mokomysql.Config
|
|
9
|
+
* INGROUP: mokomysql
|
|
10
|
+
* REPO: https://git.mokoconsulting.tech/MokoConsulting/mokomysql-mcp
|
|
11
|
+
* PATH: /src/config.ts
|
|
12
|
+
* VERSION: 01.00.00
|
|
13
|
+
* BRIEF: Configuration loader for MySQL MCP connections
|
|
14
|
+
*/
|
|
15
|
+
import { readFile } from 'node:fs/promises';
|
|
16
|
+
import { resolve } from 'node:path';
|
|
17
|
+
import { homedir } from 'node:os';
|
|
18
|
+
import { resolveSecretRefs } from './secrets.js';
|
|
19
|
+
const CONFIG_FILENAME = '.mcp_mokomysql.json';
|
|
20
|
+
/** Absolute path to the active config file (`MYSQL_MCP_CONFIG` or ~/.mcp_mokomysql.json). */
|
|
21
|
+
export function getConfigPath() {
|
|
22
|
+
return process.env.MYSQL_MCP_CONFIG
|
|
23
|
+
? resolve(process.env.MYSQL_MCP_CONFIG)
|
|
24
|
+
: resolve(homedir(), CONFIG_FILENAME);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Absolute path to the sidecar state file — the MCP-managed learned-marker store.
|
|
28
|
+
* `MYSQL_MCP_STATE` overrides it outright; otherwise it sits beside the config as
|
|
29
|
+
* `<config>.state.json`, so learned state always follows the config that produced it.
|
|
30
|
+
*/
|
|
31
|
+
export function getStatePath() {
|
|
32
|
+
if (process.env.MYSQL_MCP_STATE)
|
|
33
|
+
return resolve(process.env.MYSQL_MCP_STATE);
|
|
34
|
+
return getConfigPath().replace(/\.json$/i, '') + '.state.json';
|
|
35
|
+
}
|
|
36
|
+
export async function loadConfig() {
|
|
37
|
+
const config_path = getConfigPath();
|
|
38
|
+
try {
|
|
39
|
+
const raw = await readFile(config_path, 'utf-8');
|
|
40
|
+
const parsed = JSON.parse(raw);
|
|
41
|
+
// Resolve any "file:<path>" secret references (e.g. passwords in ~/.ssh/tokens).
|
|
42
|
+
await resolveSecretRefs(parsed);
|
|
43
|
+
if (!parsed.connections || Object.keys(parsed.connections).length === 0) {
|
|
44
|
+
throw new Error('No connections defined in config');
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
connections: parsed.connections,
|
|
48
|
+
defaultConnection: parsed.defaultConnection ?? Object.keys(parsed.connections)[0],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
throw new Error(`Failed to load config from ${config_path}: ${message}\n` +
|
|
54
|
+
`Create ${config_path} — see config.example.json for format.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Normalize a name for tag matching: lowercase and strip every character
|
|
59
|
+
* that isn't a letter or digit. This makes "moko.live", "moko-live",
|
|
60
|
+
* "Moko Live" and "mokolive" all collapse to the same key.
|
|
61
|
+
*/
|
|
62
|
+
export function normalizeTag(value) {
|
|
63
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, '');
|
|
64
|
+
}
|
|
65
|
+
export function getConnection(config, name) {
|
|
66
|
+
const requested = name ?? config.defaultConnection;
|
|
67
|
+
// 1. Exact key match — fast path, preserves prior behavior exactly.
|
|
68
|
+
const direct = config.connections[requested];
|
|
69
|
+
if (direct)
|
|
70
|
+
return { key: requested, conn: direct };
|
|
71
|
+
// 2. Normalized match against connection keys and their tag shortcuts.
|
|
72
|
+
// Returns the canonical key, never the alias/tag the caller typed.
|
|
73
|
+
const target = normalizeTag(requested);
|
|
74
|
+
for (const [key, conn] of Object.entries(config.connections)) {
|
|
75
|
+
if (normalizeTag(key) === target)
|
|
76
|
+
return { key, conn };
|
|
77
|
+
if (conn.tags?.some((tag) => normalizeTag(tag) === target))
|
|
78
|
+
return { key, conn };
|
|
79
|
+
}
|
|
80
|
+
// 3. Not found — list keys plus their tags so the caller can self-correct.
|
|
81
|
+
const available = Object.entries(config.connections)
|
|
82
|
+
.map(([key, conn]) => (conn.tags?.length ? `${key} [${conn.tags.join(', ')}]` : key))
|
|
83
|
+
.join(', ');
|
|
84
|
+
throw new Error(`Connection "${requested}" not found. Available: ${available}`);
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../source/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":";AAqBA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,IAAI,MAAM,EAAE,WAAW,CAAC;AAC/B,eAAO,IAAI,MAAM,EAAE,WAAW,CAAC"}
|