@modootoday/datalab-extension-mcp 1.4.3 → 1.5.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/README.en.md +4 -4
- package/README.md +4 -4
- package/dist/{chunk-CBHNMIS3.js → chunk-INQCEZGY.js} +82 -2
- package/dist/cli.js +8 -2
- package/dist/index.d.ts +24 -5
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -55,10 +55,10 @@ Avoid sharing a screenshot or the copied setup. If it may have leaked, press **[
|
|
|
55
55
|
One command finds **every** AI app on your computer and connects them automatically. Nothing to do per app.
|
|
56
56
|
|
|
57
57
|
1. **Open a terminal** — on Windows type `cmd` in the search box → "Command Prompt"; on Mac press `⌘+Space` and type `Terminal`; on Linux open your terminal app (often `Ctrl+Alt+T`).
|
|
58
|
-
2. **Paste this command and press Enter.** (`@1.
|
|
58
|
+
2. **Paste this command and press Enter.** (`@1.5.0` is the pinned version, so the connector never changes behind your back.)
|
|
59
59
|
|
|
60
60
|
```
|
|
61
|
-
npx -y @modootoday/datalab-extension-mcp@1.
|
|
61
|
+
npx -y @modootoday/datalab-extension-mcp@1.5.0 install
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
Lines of English scrolling by is normal. This only downloads and runs the connector — it touches nothing else.
|
|
@@ -206,7 +206,7 @@ Start it again after a full quit and it picks the tools up. If they still aren't
|
|
|
206
206
|
- **When the connection disappears** — run the very command you used at the start once more; it safely re-registers. (Some AI apps clean up their settings file and drop the connection.)
|
|
207
207
|
|
|
208
208
|
```
|
|
209
|
-
npx -y @modootoday/datalab-extension-mcp@1.
|
|
209
|
+
npx -y @modootoday/datalab-extension-mcp@1.5.0 install
|
|
210
210
|
```
|
|
211
211
|
|
|
212
212
|
- **`'npx' is not recognized...`** — Node.js isn't installed. The "No Node.js?" one-liner in Step 2 is the simplest fix.
|
|
@@ -236,7 +236,7 @@ Start it again after a full quit and it picks the tools up. If they still aren't
|
|
|
236
236
|
1. Run this in a terminal (it removes the entries registered in your AI apps).
|
|
237
237
|
|
|
238
238
|
```
|
|
239
|
-
npx -y @modootoday/datalab-extension-mcp@1.
|
|
239
|
+
npx -y @modootoday/datalab-extension-mcp@1.5.0 uninstall
|
|
240
240
|
```
|
|
241
241
|
|
|
242
242
|
2. Turn **MCP 연결** off in the extension settings. The panel is the bridge, so with it off a leftover config line can look nothing up.
|
package/README.md
CHANGED
|
@@ -49,10 +49,10 @@ Claude 같은 AI 앱을 데이터랩툴즈에 연결해 주는 작은 무료 프
|
|
|
49
49
|
명령 한 줄이면 컴퓨터에 있는 AI 앱을 **모두 자동으로** 찾아 연결해 줘요. 앱마다 따로 할 일은 없어요.
|
|
50
50
|
|
|
51
51
|
1. **터미널을 열어요** — Windows는 검색창에 `cmd` → "명령 프롬프트", Mac은 `⌘+스페이스`로 `터미널`, Linux는 터미널 앱(보통 `Ctrl+Alt+T`)이에요.
|
|
52
|
-
2. **아래 명령을 붙여넣고 Enter를 눌러요.** (`@1.
|
|
52
|
+
2. **아래 명령을 붙여넣고 Enter를 눌러요.** (`@1.5.0`은 커넥터가 나도 모르게 바뀌지 않도록 고정한 버전이에요.)
|
|
53
53
|
|
|
54
54
|
```
|
|
55
|
-
npx -y @modootoday/datalab-extension-mcp@1.
|
|
55
|
+
npx -y @modootoday/datalab-extension-mcp@1.5.0 install
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
영어 글자가 여러 줄 올라오는 건 정상이에요. 이 명령은 커넥터를 내려받아 실행할 뿐, 다른 건 건드리지 않아요.
|
|
@@ -180,7 +180,7 @@ AI가 "그런 기능은 없다" 고 답하면, **"도구 목록을 확인해 보
|
|
|
180
180
|
- **연결이 사라졌을 때** — 처음 실행했던 그 명령을 한 번 더 실행하면 안전하게 다시 등록돼요. (일부 AI 앱이 설정 파일을 정리하며 연결을 지우기도 해요.)
|
|
181
181
|
|
|
182
182
|
```
|
|
183
|
-
npx -y @modootoday/datalab-extension-mcp@1.
|
|
183
|
+
npx -y @modootoday/datalab-extension-mcp@1.5.0 install
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
- **`'npx'을(는) 내부 또는 외부 명령...`** — Node.js가 없는 거예요. 위 2단계의 "Node.js가 없다면" 한 줄 설치가 가장 간단해요.
|
|
@@ -210,7 +210,7 @@ AI가 "그런 기능은 없다" 고 답하면, **"도구 목록을 확인해 보
|
|
|
210
210
|
1. 터미널에서 아래 명령을 실행해요(AI 앱에 등록된 설정을 지워 줘요).
|
|
211
211
|
|
|
212
212
|
```
|
|
213
|
-
npx -y @modootoday/datalab-extension-mcp@1.
|
|
213
|
+
npx -y @modootoday/datalab-extension-mcp@1.5.0 uninstall
|
|
214
214
|
```
|
|
215
215
|
|
|
216
216
|
2. 확장 설정에서 **MCP 연결을 꺼요.** 패널이 브릿지라, 꺼 두면 어딘가 설정 줄이 남아 있어도 AI 앱이 아무것도 조회할 수 없어요.
|
|
@@ -16454,6 +16454,7 @@ function runDaemon(env, deps = {}) {
|
|
|
16454
16454
|
}
|
|
16455
16455
|
|
|
16456
16456
|
// src/adapter.ts
|
|
16457
|
+
import { spawnSync } from "child_process";
|
|
16457
16458
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
16458
16459
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
16459
16460
|
import {
|
|
@@ -31448,6 +31449,25 @@ ${BRIDGE_AGENT_HINT2.notConnected}`;
|
|
|
31448
31449
|
|
|
31449
31450
|
// src/adapter.ts
|
|
31450
31451
|
var NAME2 = "datalab-extension-mcp";
|
|
31452
|
+
var PACKAGE_NAME = "@modootoday/datalab-extension-mcp";
|
|
31453
|
+
var DEFAULT_WATCH_MS = 5 * 60 * 1e3;
|
|
31454
|
+
var CANONICAL_VERSION_URL = "https://app.datalab.tools/api/v1/mcp/version";
|
|
31455
|
+
var CANONICAL_TIMEOUT_MS = 4e3;
|
|
31456
|
+
var SEMVER = /^\d+\.\d+\.\d+$/;
|
|
31457
|
+
async function canonicalVersion(fetchImpl = fetch) {
|
|
31458
|
+
try {
|
|
31459
|
+
const ctl = new AbortController();
|
|
31460
|
+
const timer = setTimeout(() => ctl.abort(), CANONICAL_TIMEOUT_MS);
|
|
31461
|
+
const res = await fetchImpl(CANONICAL_VERSION_URL, {
|
|
31462
|
+
signal: ctl.signal
|
|
31463
|
+
}).finally(() => clearTimeout(timer));
|
|
31464
|
+
if (!res.ok) return null;
|
|
31465
|
+
const body = await res.json();
|
|
31466
|
+
return typeof body.version === "string" && SEMVER.test(body.version) ? body.version : null;
|
|
31467
|
+
} catch {
|
|
31468
|
+
return null;
|
|
31469
|
+
}
|
|
31470
|
+
}
|
|
31451
31471
|
var PROBE_TIMEOUT_MS = 300;
|
|
31452
31472
|
var READY_ATTEMPTS = 40;
|
|
31453
31473
|
var READY_INTERVAL_MS = 50;
|
|
@@ -31596,6 +31616,7 @@ function createAdapterServer(deps = {}) {
|
|
|
31596
31616
|
{ capabilities: { tools: { listChanged: true } } }
|
|
31597
31617
|
);
|
|
31598
31618
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
31619
|
+
deps.onActivity?.(1);
|
|
31599
31620
|
try {
|
|
31600
31621
|
const resp = await postMcp(fetchImpl, mcpUrl, "tools/list");
|
|
31601
31622
|
if (resp.error) {
|
|
@@ -31615,9 +31636,19 @@ function createAdapterServer(deps = {}) {
|
|
|
31615
31636
|
isTimeout(err) ? "connector_stuck" : "not_connected"
|
|
31616
31637
|
)
|
|
31617
31638
|
);
|
|
31639
|
+
} finally {
|
|
31640
|
+
deps.onActivity?.(-1);
|
|
31618
31641
|
}
|
|
31619
31642
|
});
|
|
31620
31643
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
31644
|
+
deps.onActivity?.(1);
|
|
31645
|
+
try {
|
|
31646
|
+
return await handleToolCall(request);
|
|
31647
|
+
} finally {
|
|
31648
|
+
deps.onActivity?.(-1);
|
|
31649
|
+
}
|
|
31650
|
+
});
|
|
31651
|
+
async function handleToolCall(request) {
|
|
31621
31652
|
const { name, arguments: args } = request.params;
|
|
31622
31653
|
let resp;
|
|
31623
31654
|
try {
|
|
@@ -31646,7 +31677,7 @@ function createAdapterServer(deps = {}) {
|
|
|
31646
31677
|
);
|
|
31647
31678
|
}
|
|
31648
31679
|
return resp.result ?? {};
|
|
31649
|
-
}
|
|
31680
|
+
}
|
|
31650
31681
|
return server;
|
|
31651
31682
|
}
|
|
31652
31683
|
var defaultSubscribe = async (url3, onEvent, signal) => {
|
|
@@ -31704,7 +31735,41 @@ async function pushToolChanges(deps) {
|
|
|
31704
31735
|
prev = wait;
|
|
31705
31736
|
}
|
|
31706
31737
|
}
|
|
31738
|
+
async function selfUpdateAndRestart(selfVersion, log, deps = {}) {
|
|
31739
|
+
if (!selfVersion) return false;
|
|
31740
|
+
const target = await (deps.resolve ?? canonicalVersion)();
|
|
31741
|
+
if (!target || !isOlderVersion(selfVersion, target)) return false;
|
|
31742
|
+
const args = deps.argv ?? process.argv.slice(2);
|
|
31743
|
+
log(
|
|
31744
|
+
`updating to the canonical connector ${target} (this build is ${selfVersion})`
|
|
31745
|
+
);
|
|
31746
|
+
const run = deps.spawn ?? spawnSync;
|
|
31747
|
+
const res = run("npx", ["-y", `${PACKAGE_NAME}@${target}`, ...args], {
|
|
31748
|
+
stdio: "inherit",
|
|
31749
|
+
shell: process.platform === "win32"
|
|
31750
|
+
});
|
|
31751
|
+
if (res.error) {
|
|
31752
|
+
log(
|
|
31753
|
+
`could not start ${target} (${res.error.message}); continuing as ${selfVersion}`
|
|
31754
|
+
);
|
|
31755
|
+
return false;
|
|
31756
|
+
}
|
|
31757
|
+
process.exit(res.status ?? 0);
|
|
31758
|
+
}
|
|
31759
|
+
function countRequests(flight, passthrough) {
|
|
31760
|
+
return (delta) => {
|
|
31761
|
+
flight.count += delta;
|
|
31762
|
+
passthrough?.(delta);
|
|
31763
|
+
};
|
|
31764
|
+
}
|
|
31707
31765
|
async function runAdapter(deps = {}) {
|
|
31766
|
+
if (deps.selfUpdate !== false) {
|
|
31767
|
+
await selfUpdateAndRestart(deps.version, deps.log ?? (() => {
|
|
31768
|
+
}), {
|
|
31769
|
+
resolve: deps.canonical,
|
|
31770
|
+
spawn: deps.spawnImpl
|
|
31771
|
+
});
|
|
31772
|
+
}
|
|
31708
31773
|
const ensure = deps.ensure ?? ensureDaemonRunning;
|
|
31709
31774
|
await ensure({
|
|
31710
31775
|
host: deps.host,
|
|
@@ -31712,7 +31777,21 @@ async function runAdapter(deps = {}) {
|
|
|
31712
31777
|
log: deps.log,
|
|
31713
31778
|
selfVersion: deps.version
|
|
31714
31779
|
});
|
|
31715
|
-
const
|
|
31780
|
+
const flight = { count: 0 };
|
|
31781
|
+
const watchMs = deps.watchIntervalMs ?? DEFAULT_WATCH_MS;
|
|
31782
|
+
const server = createAdapterServer({
|
|
31783
|
+
...deps,
|
|
31784
|
+
onActivity: countRequests(flight, deps.onActivity)
|
|
31785
|
+
});
|
|
31786
|
+
const watch = deps.selfUpdate === false ? null : setInterval(() => {
|
|
31787
|
+
if (flight.count > 0) return;
|
|
31788
|
+
void selfUpdateAndRestart(deps.version, deps.log ?? (() => {
|
|
31789
|
+
}), {
|
|
31790
|
+
resolve: deps.canonical,
|
|
31791
|
+
spawn: deps.spawnImpl
|
|
31792
|
+
});
|
|
31793
|
+
}, watchMs);
|
|
31794
|
+
watch?.unref?.();
|
|
31716
31795
|
let transport;
|
|
31717
31796
|
if (deps.transport) {
|
|
31718
31797
|
transport = deps.transport;
|
|
@@ -31725,6 +31804,7 @@ async function runAdapter(deps = {}) {
|
|
|
31725
31804
|
const controller = new AbortController();
|
|
31726
31805
|
const prevOnClose = transport.onclose;
|
|
31727
31806
|
transport.onclose = () => {
|
|
31807
|
+
if (watch) clearInterval(watch);
|
|
31728
31808
|
controller.abort();
|
|
31729
31809
|
prevOnClose?.();
|
|
31730
31810
|
};
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
dispatchCli,
|
|
4
4
|
runAdapter,
|
|
5
5
|
runDaemon
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-INQCEZGY.js";
|
|
7
7
|
import "./chunk-MLKGABMK.js";
|
|
8
8
|
|
|
9
9
|
// src/cli.ts
|
|
@@ -47,7 +47,13 @@ async function main() {
|
|
|
47
47
|
serve: () => {
|
|
48
48
|
runDaemon(process.env);
|
|
49
49
|
},
|
|
50
|
-
adapter: () => runAdapter({
|
|
50
|
+
adapter: () => runAdapter({
|
|
51
|
+
name: NAME,
|
|
52
|
+
version: VERSION,
|
|
53
|
+
// The host config pins an exact version, so without this a paired user
|
|
54
|
+
// never receives a release. `--no-self-update` keeps this build.
|
|
55
|
+
selfUpdate: !process.argv.slice(2).includes("--no-self-update")
|
|
56
|
+
})
|
|
51
57
|
});
|
|
52
58
|
}
|
|
53
59
|
main().catch((err) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
1
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
3
|
import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
3
4
|
|
|
@@ -11,6 +12,15 @@ import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
|
11
12
|
* what makes the proxy testable without a real socket or daemon.
|
|
12
13
|
*/
|
|
13
14
|
|
|
15
|
+
/**
|
|
16
|
+
* The version the operator currently publishes as canonical.
|
|
17
|
+
*
|
|
18
|
+
* 🔴 Asked of OUR gateway, never of npm directly. A floating `@latest` in the
|
|
19
|
+
* host config would let whoever controls the registry push code next to a
|
|
20
|
+
* logged-in browser session; this keeps the decision on a surface we own, with
|
|
21
|
+
* a rollback lever behind it. A failure returns null and changes nothing.
|
|
22
|
+
*/
|
|
23
|
+
declare function canonicalVersion(fetchImpl?: typeof fetch): Promise<string | null>;
|
|
14
24
|
/** The `fetch` shape this module needs — injectable so tests need no real HTTP. */
|
|
15
25
|
type FetchImpl = (url: string, init: {
|
|
16
26
|
method: string;
|
|
@@ -63,6 +73,12 @@ interface EnsureRunningDeps {
|
|
|
63
73
|
*/
|
|
64
74
|
declare function ensureDaemonRunning(deps?: EnsureRunningDeps): Promise<void>;
|
|
65
75
|
interface AdapterServerDeps {
|
|
76
|
+
/**
|
|
77
|
+
* Marks a request as started (+1) and finished (-1). The promotion watcher
|
|
78
|
+
* uses it to swap builds only while nothing is in flight — re-execing mid
|
|
79
|
+
* request would drop that call on the floor.
|
|
80
|
+
*/
|
|
81
|
+
onActivity?: (delta: 1 | -1) => void;
|
|
66
82
|
host?: string;
|
|
67
83
|
port?: number;
|
|
68
84
|
/** Injected in tests; defaults to the global `fetch`. */
|
|
@@ -85,18 +101,21 @@ declare function createAdapterServer(deps?: AdapterServerDeps): Server;
|
|
|
85
101
|
*/
|
|
86
102
|
type SubscribeImpl = (url: string, onEvent: (data: string) => void, signal: AbortSignal) => Promise<void>;
|
|
87
103
|
interface RunAdapterDeps extends AdapterServerDeps {
|
|
104
|
+
/** Injected in tests; how often the canonical version is re-checked. */
|
|
105
|
+
watchIntervalMs?: number;
|
|
106
|
+
/** Injected in tests; defaults to asking the gateway. */
|
|
107
|
+
canonical?: typeof canonicalVersion;
|
|
108
|
+
/** Injected in tests; defaults to the real spawn. */
|
|
109
|
+
spawnImpl?: typeof spawnSync;
|
|
88
110
|
/** Injected in tests; defaults to `ensureDaemonRunning`. */
|
|
89
111
|
ensure?: (deps: EnsureRunningDeps) => Promise<void>;
|
|
90
112
|
/** Injected in tests; defaults to a real stdio transport. */
|
|
91
113
|
transport?: Transport;
|
|
92
114
|
/** Injected in tests; defaults to the real SSE subscription. */
|
|
93
115
|
subscribe?: SubscribeImpl;
|
|
116
|
+
/** false pins this build — `--no-self-update`. Default promotes to canonical. */
|
|
117
|
+
selfUpdate?: boolean;
|
|
94
118
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Run the adapter: make sure a daemon exists, then serve MCP over stdio. The
|
|
97
|
-
* two legs stay separate so each is testable alone, and this is the only place
|
|
98
|
-
* that touches the real stdio transport.
|
|
99
|
-
*/
|
|
100
119
|
declare function runAdapter(deps?: RunAdapterDeps): Promise<void>;
|
|
101
120
|
interface CliHandlers {
|
|
102
121
|
install: (sub: "install" | "uninstall", argv: readonly string[]) => Promise<void>;
|
package/dist/index.js
CHANGED