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/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
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Database",
4
+ "description": "Data-source management for databases exposed to the agent through a Python MCP server."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "数据库",
4
+ "description": "通过 Python MCP 服务向 AI 暴露数据库,并在这里管理数据源连接。"
5
+ }
6
+ }
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
+ }