@nodatachat/mcp 0.4.1 → 0.4.2
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.md +8 -0
- package/dist/index.js +42 -19
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -39,6 +39,14 @@ Add the server to Claude Code in one command:
|
|
|
39
39
|
claude mcp add nodata -- npx @nodatachat/mcp --api-key YOUR_API_KEY
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
On **Windows**, native (non-WSL) `npx` needs the `cmd /c` wrapper:
|
|
43
|
+
|
|
44
|
+
```cmd
|
|
45
|
+
claude mcp add nodata -- cmd /c npx @nodatachat/mcp --api-key YOUR_API_KEY
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
After changing the server's config (e.g. adding a credential), **restart Claude Code** — the running server process keeps its old arguments until the session restarts.
|
|
49
|
+
|
|
42
50
|
Or with a custom base URL (for self-hosted or staging):
|
|
43
51
|
|
|
44
52
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
32
32
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
33
33
|
import { z } from "zod";
|
|
34
|
-
const VERSION = "0.4.
|
|
34
|
+
const VERSION = "0.4.2";
|
|
35
35
|
const USAGE = `nodata-mcp v${VERSION} — NoData MCP server\n\n` +
|
|
36
36
|
" ADMIN mode: nodata-mcp --api-key sk_live_...\n" +
|
|
37
37
|
" AGENT mode: nodata-mcp --grant-token ndca-...\n" +
|
|
@@ -76,15 +76,26 @@ function parseArgs(argv) {
|
|
|
76
76
|
baseUrl = baseUrl.replace(/\/+$/, "");
|
|
77
77
|
return { apiKey, grantToken, baseUrl };
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
// Without a deadline a dead network turns a tool call into an indefinite hang
|
|
80
|
+
// inside the MCP client; 30s comfortably covers a slow decide/retrieve.
|
|
81
|
+
const REQUEST_TIMEOUT_MS = 30_000;
|
|
82
|
+
async function doFetch(url, init) {
|
|
83
|
+
let res;
|
|
84
|
+
try {
|
|
85
|
+
res = await fetch(url, { ...init, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS) });
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
const timedOut = err instanceof Error && err.name === "TimeoutError";
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
status: 0,
|
|
92
|
+
body: {
|
|
93
|
+
error: timedOut
|
|
94
|
+
? `Request timed out after ${REQUEST_TIMEOUT_MS / 1000}s: ${url}`
|
|
95
|
+
: `Network error reaching ${url}: ${err instanceof Error ? err.message : String(err)}`,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
88
99
|
let parsed;
|
|
89
100
|
try {
|
|
90
101
|
parsed = await res.json();
|
|
@@ -94,24 +105,26 @@ async function apiPost(baseUrl, bearer, path, body) {
|
|
|
94
105
|
}
|
|
95
106
|
return { ok: res.ok, status: res.status, body: parsed };
|
|
96
107
|
}
|
|
108
|
+
async function apiPost(baseUrl, bearer, path, body) {
|
|
109
|
+
return doFetch(`${baseUrl}${path}`, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: {
|
|
112
|
+
"Content-Type": "application/json",
|
|
113
|
+
Authorization: `Bearer ${bearer}`,
|
|
114
|
+
},
|
|
115
|
+
body: JSON.stringify(body),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
97
118
|
async function apiGet(baseUrl, bearer, path, params) {
|
|
98
119
|
const url = new URL(`${baseUrl}${path}`);
|
|
99
120
|
for (const [key, val] of Object.entries(params)) {
|
|
100
121
|
if (val !== undefined && val !== "")
|
|
101
122
|
url.searchParams.set(key, val);
|
|
102
123
|
}
|
|
103
|
-
|
|
124
|
+
return doFetch(url.toString(), {
|
|
104
125
|
method: "GET",
|
|
105
126
|
headers: { Authorization: `Bearer ${bearer}` },
|
|
106
127
|
});
|
|
107
|
-
let parsed;
|
|
108
|
-
try {
|
|
109
|
-
parsed = await res.json();
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
parsed = { error: `Non-JSON response (HTTP ${res.status})` };
|
|
113
|
-
}
|
|
114
|
-
return { ok: res.ok, status: res.status, body: parsed };
|
|
115
128
|
}
|
|
116
129
|
function formatResult(resp) {
|
|
117
130
|
const text = JSON.stringify(resp.body, null, 2);
|
|
@@ -261,6 +274,13 @@ function registerAdminTools(server, baseUrl, apiKey) {
|
|
|
261
274
|
}
|
|
262
275
|
function registerAgentTool(server, baseUrl, grantToken) {
|
|
263
276
|
const handle = handleFromGrant(grantToken);
|
|
277
|
+
if (!handle) {
|
|
278
|
+
// decide/retrieve are bearer-only and still work; read/use need the handle.
|
|
279
|
+
// Say so at startup instead of surprising the agent mid-conversation.
|
|
280
|
+
console.error("nodata-mcp: warning — could not derive an agent handle from the grant token " +
|
|
281
|
+
"(expected ndca-<jwt> with a 'handle' claim). nodata_decide/nodata_retrieve will work; " +
|
|
282
|
+
"nodata_read/nodata_use will fail until a valid grant token is provided.");
|
|
283
|
+
}
|
|
264
284
|
// ── Access Compute · the "may I?" oracle (P0) ───────────────────────
|
|
265
285
|
// Returns ONLY a decision + a signed proof, never any content. A planner
|
|
266
286
|
// calls this to learn what it can reach BEFORE moving data: allow, degrade
|
|
@@ -370,6 +390,9 @@ const SETUP_TEXT = "This NoData server is connected but has NO credential yet, s
|
|
|
370
390
|
" claude mcp add nodata -- npx @nodatachat/mcp --api-key sk_live_YOUR_KEY\n" +
|
|
371
391
|
" Or keep the command credential-free and set the env var instead:\n" +
|
|
372
392
|
" claude mcp add nodata --env NODATA_API_KEY=sk_live_YOUR_KEY -- npx @nodatachat/mcp\n\n" +
|
|
393
|
+
" IMPORTANT: after changing the config, RESTART the MCP client (e.g. exit and reopen\n" +
|
|
394
|
+
" Claude Code) — this server process was spawned with the old config and a config edit\n" +
|
|
395
|
+
" does not affect it. Until the restart it will keep answering in setup mode.\n\n" +
|
|
373
396
|
"3. (Agent mode) If you were handed a grant token (ndca-...), use --grant-token ndca-YOUR_GRANT\n" +
|
|
374
397
|
" (or NODATA_GRANT_TOKEN) instead of an API key — the server then exposes only the\n" +
|
|
375
398
|
" decide/retrieve/read/use tools scoped to that grant.\n\n" +
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nodatachat/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "NoData MCP Server — govern data for AI agents: decide (may I?) + retrieve (authorized context) + read + secret-blind invoke, plus admin governance/encrypt/decrypt/deliver",
|
|
5
5
|
"bin": {
|
|
6
|
-
"nodata-mcp": "
|
|
6
|
+
"nodata-mcp": "dist/index.js"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
9
|
"scripts": {
|