taru-mcp 0.1.8 → 0.1.9

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 CHANGED
@@ -53,10 +53,10 @@ cp node_modules/taru-mcp/samples/AGENTS.md ./AGENTS.md
53
53
 
54
54
  ```bash
55
55
  # Claude Code
56
- claude mcp add taru -- ./node_modules/.bin/taru-mcp --token xxv_your_token
56
+ claude mcp add taru -- node node_modules/taru-mcp/bin/taru-mcp.mjs --token xxv_your_token
57
57
 
58
58
  # Codex
59
- codex mcp add taru -- ./node_modules/.bin/taru-mcp --token xxv_your_token
59
+ codex mcp add taru -- node node_modules/taru-mcp/bin/taru-mcp.mjs --token xxv_your_token
60
60
  ```
61
61
 
62
62
  ### 4. Or configure MCP manually
@@ -67,7 +67,7 @@ If `claude mcp add` doesn't work, create `.mcp.json` in your project root:
67
67
  {
68
68
  "mcpServers": {
69
69
  "taru": {
70
- "command": "./node_modules/.bin/taru-mcp",
70
+ "command": "node node_modules/taru-mcp/bin/taru-mcp.mjs",
71
71
  "args": ["--token", "xxv_your_token"]
72
72
  }
73
73
  }
@@ -80,7 +80,7 @@ For Claude Code global config (`~/.claude.json`):
80
80
  {
81
81
  "mcpServers": {
82
82
  "taru": {
83
- "command": "./node_modules/.bin/taru-mcp",
83
+ "command": "node node_modules/taru-mcp/bin/taru-mcp.mjs",
84
84
  "args": ["--token", "xxv_your_token"]
85
85
  }
86
86
  }
package/bin/taru-mcp.mjs CHANGED
@@ -1,9 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // Suppress all stderr output to prevent Codex MCP transport from closing.
4
+ // Codex monitors stderr and kills the transport if anything is written to it.
5
+ if (!process.env.TARU_DEBUG) {
6
+ process.stderr.write = () => true;
7
+ }
8
+ process.on('warning', () => {});
9
+ process.on('uncaughtException', () => {});
10
+ process.on('unhandledRejection', () => {});
11
+
3
12
  import { createInterface } from "node:readline";
4
- import { argv, env, stderr, stdout } from "node:process";
13
+ import { argv, env, stdout } from "node:process";
5
14
  import { request as httpsRequest } from "node:https";
6
15
  import { request as httpRequest } from "node:http";
16
+ import { appendFileSync } from "node:fs";
17
+
18
+ const LOG_FILE = process.env.TARU_LOG || "";
19
+ function log(msg) {
20
+ if (LOG_FILE) {
21
+ try { appendFileSync(LOG_FILE, `[${new Date().toISOString()}] ${msg}\n`); } catch {}
22
+ }
23
+ }
7
24
 
8
25
  // --- Parse args ---
9
26
 
@@ -20,10 +37,10 @@ for (let i = 0; i < args.length; i++) {
20
37
  } else if ((args[i] === "--token" || args[i] === "-t") && args[i + 1]) {
21
38
  token = args[++i];
22
39
  } else if (args[i] === "--help" || args[i] === "-h") {
23
- stderr.write(`taru-mcp — MCP proxy for taru knowledge graph
40
+ console.error(`taru-mcp — MCP proxy for taru knowledge graph
24
41
 
25
42
  Usage:
26
- npx taru-mcp [options]
43
+ node node_modules/taru-mcp/bin/taru-mcp.mjs [options]
27
44
 
28
45
  Options:
29
46
  --workspace-id, -w Workspace UUID (env: TARU_WORKSPACE_ID)
@@ -31,39 +48,72 @@ Options:
31
48
  --help, -h Show this help
32
49
 
33
50
  Examples:
34
- claude mcp add taru -- npx -y taru-mcp --token tru_...
35
- codex mcp add taru -- npx -y taru-mcp --token tru_...
51
+ claude mcp add taru -- node node_modules/taru-mcp/bin/taru-mcp.mjs --token tru_...
52
+ codex mcp add taru -- node node_modules/taru-mcp/bin/taru-mcp.mjs --token tru_...
36
53
  `);
37
54
  process.exit(0);
38
55
  }
39
56
  }
40
57
 
41
58
  url = url.replace(/\/+$/, "");
42
- // If workspace ID was explicitly provided, use the scoped endpoint; otherwise use token-based auto endpoint
43
59
  const hasExplicitWorkspace = args.some(a => a === "--workspace-id" || a === "-w") || env.TARU_WORKSPACE_ID;
44
60
  const endpoint = hasExplicitWorkspace ? `${url}/mcp/${workspaceId}` : `${url}/mcp`;
45
61
  const isHttps = endpoint.startsWith("https://");
46
62
 
47
- // Only log to stderr when debug is enabled (Codex kills transport on stderr output)
48
- if (env.TARU_DEBUG) stderr.write(`[taru-mcp] endpoint: ${endpoint}\n`);
49
-
50
63
  // --- JSON-RPC proxy: stdin → HTTP POST → stdout ---
51
64
 
65
+ let pendingRequests = 0;
66
+ let stdinClosed = false;
67
+
52
68
  const rl = createInterface({ input: process.stdin });
53
69
 
54
70
  rl.on("line", async (line) => {
55
71
  if (!line.trim()) return;
56
72
 
73
+ pendingRequests++;
74
+ const parsed = safeParse(line);
75
+ const id = parsed?.id ?? null;
76
+ const method = parsed?.method || parsed?.params?.name || "unknown";
77
+ log(`REQ id=${id} method=${method}`);
78
+
57
79
  try {
58
- const body = await post(endpoint, line);
80
+ const { status, body } = await post(endpoint, line);
81
+ log(`RES id=${id} status=${status} len=${body?.length || 0}`);
59
82
 
60
83
  // 202 Accepted = notification, no response needed
61
- if (body === null) return;
62
-
63
- stdout.write(body + "\n");
84
+ if (status === 202) {
85
+ pendingRequests--;
86
+ maybeExit();
87
+ return;
88
+ }
89
+
90
+ // Server returned non-200: wrap in JSON-RPC error
91
+ if (status < 200 || status >= 300) {
92
+ const errResp = JSON.stringify({
93
+ jsonrpc: "2.0",
94
+ id,
95
+ error: { code: -32603, message: `server error (${status}): ${body}` },
96
+ });
97
+ stdout.write(errResp + "\n");
98
+ pendingRequests--;
99
+ maybeExit();
100
+ return;
101
+ }
102
+
103
+ // Verify response is valid JSON before forwarding
104
+ const responseJson = safeParse(body);
105
+ if (responseJson) {
106
+ stdout.write(body + "\n");
107
+ } else {
108
+ const errResp = JSON.stringify({
109
+ jsonrpc: "2.0",
110
+ id,
111
+ error: { code: -32603, message: `invalid server response` },
112
+ });
113
+ stdout.write(errResp + "\n");
114
+ }
64
115
  } catch (err) {
65
- const parsed = safeParse(line);
66
- const id = parsed?.id ?? null;
116
+ log(`ERR id=${id} ${err.message}`);
67
117
  const errResp = JSON.stringify({
68
118
  jsonrpc: "2.0",
69
119
  id,
@@ -71,39 +121,52 @@ rl.on("line", async (line) => {
71
121
  });
72
122
  stdout.write(errResp + "\n");
73
123
  }
124
+
125
+ pendingRequests--;
126
+ maybeExit();
127
+ });
128
+
129
+ rl.on("close", () => {
130
+ stdinClosed = true;
131
+ maybeExit();
74
132
  });
75
133
 
76
- rl.on("close", () => process.exit(0));
134
+ // Only exit after stdin closes AND all pending HTTP requests are done
135
+ function maybeExit() {
136
+ if (stdinClosed && pendingRequests === 0) {
137
+ process.exit(0);
138
+ }
139
+ }
77
140
 
78
141
  // --- HTTP POST helper ---
79
142
 
80
143
  function post(targetUrl, body) {
81
144
  return new Promise((resolve, reject) => {
82
- const parsed = new URL(targetUrl);
83
- const requester = isHttps ? httpsRequest : httpRequest;
84
-
85
- const headers = { "Content-Type": "application/json" };
86
- if (token) headers["Authorization"] = `Bearer ${token}`;
87
-
88
- const req = requester(
89
- parsed,
90
- { method: "POST", headers },
91
- (res) => {
92
- const chunks = [];
93
- res.on("data", (chunk) => chunks.push(chunk));
94
- res.on("end", () => {
95
- if (res.statusCode === 202) {
96
- resolve(null);
97
- return;
98
- }
99
- resolve(Buffer.concat(chunks).toString());
100
- });
101
- }
102
- );
103
-
104
- req.on("error", reject);
105
- req.write(body);
106
- req.end();
145
+ try {
146
+ const parsed = new URL(targetUrl);
147
+ const requester = isHttps ? httpsRequest : httpRequest;
148
+
149
+ const headers = { "Content-Type": "application/json" };
150
+ if (token) headers["Authorization"] = `Bearer ${token}`;
151
+
152
+ const req = requester(
153
+ parsed,
154
+ { method: "POST", headers },
155
+ (res) => {
156
+ const chunks = [];
157
+ res.on("data", (chunk) => chunks.push(chunk));
158
+ res.on("end", () => {
159
+ resolve({ status: res.statusCode, body: Buffer.concat(chunks).toString() });
160
+ });
161
+ }
162
+ );
163
+
164
+ req.on("error", (err) => reject(err));
165
+ req.write(body);
166
+ req.end();
167
+ } catch (err) {
168
+ reject(err);
169
+ }
107
170
  });
108
171
  }
109
172
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taru-mcp",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "MCP server for taru knowledge graph — connect Claude Code or Codex to your team's shared brain",
5
5
  "bin": {
6
6
  "taru-mcp": "./bin/taru-mcp.mjs"
package/setup.sh CHANGED
@@ -90,14 +90,14 @@ register_mcp() {
90
90
  token_args=" --token $TOKEN"
91
91
  fi
92
92
 
93
- local mcp_bin="$(pwd)/node_modules/.bin/taru-mcp"
93
+ local mcp_bin="$(pwd)/node_modules/taru-mcp/bin/taru-mcp.mjs"
94
94
 
95
95
  if command -v "$cli" &>/dev/null; then
96
96
  echo "==> Registering MCP server with $cli..."
97
- $cli mcp add taru -- "$mcp_bin" --url "$URL"$token_args
97
+ $cli mcp add taru -- node "$mcp_bin" --url "$URL"$token_args
98
98
  else
99
99
  echo "==> '$cli' not found, skipping MCP registration."
100
- echo " Run this later: $cli mcp add taru -- $mcp_bin --url $URL$token_args"
100
+ echo " Run this later: $cli mcp add taru -- node $mcp_bin --url $URL$token_args"
101
101
  fi
102
102
  }
103
103