dsh-db-mcp 0.6.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 +202 -0
- package/README.md +326 -0
- package/client.js +2939 -0
- package/cordis.patch.yml +6 -0
- package/docs/requirements.md +960 -0
- package/icon.svg +8 -0
- package/index.js +119 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +63 -0
- package/server/engines.py +617 -0
- package/server/main.py +260 -0
- package/server/requirements.txt +10 -0
- package/server/store.py +98 -0
- package/src/host.js +1507 -0
- package/src/mcp.js +264 -0
- package/src/tools.js +372 -0
package/icon.svg
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#247bbf" />
|
|
3
|
+
<g stroke="#ffffff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round">
|
|
4
|
+
<ellipse cx="32" cy="20" rx="13" ry="5" />
|
|
5
|
+
<path d="M19 20v9c0 2.8 5.8 5 13 5s13-2.2 13-5v-9" />
|
|
6
|
+
<path d="M19 33v9c0 2.8 5.8 5 13 5s13-2.2 13-5v-9" />
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
package/index.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-db-mcp — Host half entry.
|
|
3
|
+
*
|
|
4
|
+
* This file is deliberately tiny: the Cordis entry is imported once per process,
|
|
5
|
+
* so keeping the implementation out of it lets `POST /plugins/db-mcp/api/reload`
|
|
6
|
+
* swap in a fresh copy of ./src/host.js while DSH keeps running. During
|
|
7
|
+
* development that replaces a full app restart.
|
|
8
|
+
*
|
|
9
|
+
* Storage and API details live in src/host.js.
|
|
10
|
+
*/
|
|
11
|
+
import { join } from 'node:path'
|
|
12
|
+
import { homedir } from 'node:os'
|
|
13
|
+
|
|
14
|
+
const API_PREFIX = '/plugins/db-mcp/api'
|
|
15
|
+
const RELOAD_PATH = `${API_PREFIX}/reload`
|
|
16
|
+
|
|
17
|
+
export const inject = ['webServer']
|
|
18
|
+
|
|
19
|
+
function dshHome() {
|
|
20
|
+
return process.env.DSH_HOME || join(homedir(), '.dsh')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function apply(ctx, config = {}) {
|
|
24
|
+
const dir = (config && config.runtimeDir) || join(dshHome(), 'db-mcp')
|
|
25
|
+
let generation = 0
|
|
26
|
+
let hostPromise = null
|
|
27
|
+
let hostRef = null
|
|
28
|
+
|
|
29
|
+
function loadHost() {
|
|
30
|
+
if (!hostPromise) {
|
|
31
|
+
generation += 1
|
|
32
|
+
const specifier = new URL(`./src/host.js?v=${generation}`, import.meta.url)
|
|
33
|
+
hostPromise = import(specifier.href).then(async (module) => {
|
|
34
|
+
hostRef = await module.createHost({ dir, config, ctx })
|
|
35
|
+
return hostRef
|
|
36
|
+
})
|
|
37
|
+
hostPromise.catch(() => {
|
|
38
|
+
hostPromise = null
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
return hostPromise
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function unloadHost() {
|
|
45
|
+
const previous = hostRef
|
|
46
|
+
hostRef = null
|
|
47
|
+
hostPromise = null
|
|
48
|
+
if (previous && typeof previous.dispose === 'function') {
|
|
49
|
+
try {
|
|
50
|
+
await previous.dispose()
|
|
51
|
+
} catch {
|
|
52
|
+
/* nothing left to do at reload time */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Warm the implementation so a broken edit fails at mount time, not on the
|
|
58
|
+
// first request, but never block the loader on it.
|
|
59
|
+
loadHost().catch(() => {})
|
|
60
|
+
|
|
61
|
+
ctx.effect(() =>
|
|
62
|
+
ctx.webServer.register({
|
|
63
|
+
kind: 'exact',
|
|
64
|
+
path: RELOAD_PATH,
|
|
65
|
+
handler: async (request, response) => {
|
|
66
|
+
const send = (status, body) => {
|
|
67
|
+
const payload = JSON.stringify(body)
|
|
68
|
+
response.writeHead(status, {
|
|
69
|
+
'content-type': 'application/json; charset=utf-8',
|
|
70
|
+
'cache-control': 'no-store',
|
|
71
|
+
})
|
|
72
|
+
response.end(payload)
|
|
73
|
+
}
|
|
74
|
+
if ((request.method || 'GET').toUpperCase() !== 'POST') {
|
|
75
|
+
return send(405, { ok: false, error: 'POST required' })
|
|
76
|
+
}
|
|
77
|
+
const origin = request.headers.origin
|
|
78
|
+
if (origin) {
|
|
79
|
+
try {
|
|
80
|
+
if (new URL(origin).host !== request.headers.host) return send(403, { ok: false, error: 'cross-origin reload rejected' })
|
|
81
|
+
} catch {
|
|
82
|
+
return send(403, { ok: false, error: 'unreadable origin' })
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
hostPromise = null
|
|
86
|
+
await unloadHost()
|
|
87
|
+
try {
|
|
88
|
+
const host = await loadHost()
|
|
89
|
+
return send(200, { ok: true, generation, version: host.version, dir })
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return send(500, { ok: false, error: String((error && error.message) || error) })
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
ctx.effect(() =>
|
|
98
|
+
ctx.webServer.register({
|
|
99
|
+
kind: 'prefix',
|
|
100
|
+
path: API_PREFIX,
|
|
101
|
+
handler: async (request, response) => {
|
|
102
|
+
let host
|
|
103
|
+
try {
|
|
104
|
+
host = await loadHost()
|
|
105
|
+
} catch (error) {
|
|
106
|
+
response.writeHead(500, { 'content-type': 'application/json; charset=utf-8' })
|
|
107
|
+
response.end(JSON.stringify({ ok: false, error: `host module failed to load: ${(error && error.message) || error}` }))
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
await host.handle(request, response)
|
|
111
|
+
},
|
|
112
|
+
}),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
// Stop the Python child (and unregister its tools) when the plugin unloads.
|
|
116
|
+
ctx.effect(() => () => {
|
|
117
|
+
void unloadHost()
|
|
118
|
+
})
|
|
119
|
+
}
|
package/locale/en.json
ADDED
package/locale/zh.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-db-mcp",
|
|
3
|
+
"version": "0.6.4",
|
|
4
|
+
"description": "DSH database plugin: a data-source management panel plus a Python MCP server that exposes those sources to the agent.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"mcp",
|
|
9
|
+
"database",
|
|
10
|
+
"postgresql",
|
|
11
|
+
"mysql",
|
|
12
|
+
"oracle",
|
|
13
|
+
"sqlite"
|
|
14
|
+
],
|
|
15
|
+
"license": "Apache-2.0",
|
|
16
|
+
"author": "dsh-db-mcp contributors",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/halcyon6669/dsh-db-mcp.git"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/halcyon6669/dsh-db-mcp/issues"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/halcyon6669/dsh-db-mcp#readme",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"icon": "icon.svg",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./index.js",
|
|
29
|
+
"./client": "./client.js",
|
|
30
|
+
"./locale/*.json": "./locale/*.json",
|
|
31
|
+
"./icon": "./icon.svg"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"index.js",
|
|
35
|
+
"src/*.js",
|
|
36
|
+
"client.js",
|
|
37
|
+
"locale/*.json",
|
|
38
|
+
"icon.svg",
|
|
39
|
+
"cordis.patch.yml",
|
|
40
|
+
"server/*.py",
|
|
41
|
+
"server/requirements.txt",
|
|
42
|
+
"docs/*.md",
|
|
43
|
+
"LICENSE",
|
|
44
|
+
"README.md"
|
|
45
|
+
],
|
|
46
|
+
"scripts": {
|
|
47
|
+
"test": "node dev/selftest.mjs && node dev/shims.test.mjs && node dev/parse.test.mjs && node dev/render.test.mjs && node dev/i18n.test.mjs && node dev/p5.test.mjs",
|
|
48
|
+
"test:ci": "node dev/shims.test.mjs && node dev/parse.test.mjs && node dev/render.test.mjs && node dev/i18n.test.mjs && node dev/p5.test.mjs",
|
|
49
|
+
"test:mcp": "node dev/mcp.test.mjs"
|
|
50
|
+
},
|
|
51
|
+
"dsh": {
|
|
52
|
+
"bundle": {
|
|
53
|
+
"patch": "./cordis.patch.yml"
|
|
54
|
+
},
|
|
55
|
+
"client": {
|
|
56
|
+
"platform": "web",
|
|
57
|
+
"immediately": true,
|
|
58
|
+
"inject": [
|
|
59
|
+
"@deepseek-ai/dsh-client-locale"
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|