taru-mcp 0.1.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.md ADDED
@@ -0,0 +1,81 @@
1
+ # taru-mcp
2
+
3
+ MCP server for [taru](https://taru.arupa.io) — connect Claude Code or Codex to your team's shared knowledge graph.
4
+
5
+ Zero dependencies. Pure Node.js. Works with any MCP client.
6
+
7
+ ## Install
8
+
9
+ ### Claude Code
10
+
11
+ ```bash
12
+ claude mcp add taru -- npx -y taru-mcp \
13
+ --url https://your-server.com \
14
+ --token xxv_your_token
15
+
16
+ # Copy the agent instructions to your project
17
+ cp node_modules/taru-mcp/samples/CLAUDE.md ./CLAUDE.md
18
+ ```
19
+
20
+ ### Codex (OpenAI)
21
+
22
+ ```bash
23
+ codex mcp add taru -- npx -y taru-mcp \
24
+ --url https://your-server.com \
25
+ --token xxv_your_token
26
+
27
+ # Copy the agent instructions to your project
28
+ cp node_modules/taru-mcp/samples/AGENTS.md ./AGENTS.md
29
+ ```
30
+
31
+ ### Agent instructions
32
+
33
+ The `samples/` directory contains ready-to-use instruction files:
34
+
35
+ | File | For | Description |
36
+ |------|-----|-------------|
37
+ | `samples/CLAUDE.md` | Claude Code | Drop into your project root |
38
+ | `samples/AGENTS.md` | Codex | Drop into your project root |
39
+
40
+ These files teach the AI how to use taru tools, classify documents vs opinions, handle conflicts, and set confidence scores. **Copy the appropriate file to your project root** after installing.
41
+
42
+ ## Options
43
+
44
+ | Flag | Env | Default | Description |
45
+ |------|-----|---------|-------------|
46
+ | `--url`, `-u` | `TARU_URL` | `http://localhost:9120` | Taru server URL |
47
+ | `--workspace-id`, `-w` | `TARU_WORKSPACE_ID` | `00000000-...0001` | Workspace UUID |
48
+ | `--token`, `-t` | `TARU_API_TOKEN` | — | API token (`xxv_...`) |
49
+
50
+ Get your API token from the taru web console: **Workspaces → Members → API Key**.
51
+
52
+ ## Tools
53
+
54
+ Once connected, these MCP tools are available to the AI:
55
+
56
+ | Tool | Description |
57
+ |------|-------------|
58
+ | `search_graph` | Search the knowledge base by natural language query |
59
+ | `read_full_document` | Read full document content by UUID |
60
+ | `store_document` | Store a document or opinion with auto-conflict detection |
61
+ | `list_documents` | List all documents in the workspace |
62
+ | `list_conflicts` | View pending knowledge conflicts |
63
+ | `web_search` | Search the web via DuckDuckGo |
64
+ | `web_fetch` | Fetch and extract text from a URL |
65
+ | `rebalance` | Merge similar keywords, clean up orphan nodes |
66
+
67
+ ## How it works
68
+
69
+ `taru-mcp` is a thin proxy: it reads JSON-RPC (MCP protocol) from stdin, forwards each request to the taru server over HTTP, and writes the response to stdout. No database, no AI calls — just I/O.
70
+
71
+ ```
72
+ MCP Client (Claude/Codex)
73
+ ↕ stdin/stdout (JSON-RPC)
74
+ taru-mcp (this package)
75
+ ↕ HTTP POST
76
+ Taru Server (knowledge graph + embeddings + graph DB)
77
+ ```
78
+
79
+ ## License
80
+
81
+ MIT
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createInterface } from "node:readline";
4
+ import { argv, env, stderr, stdout } from "node:process";
5
+ import { request as httpsRequest } from "node:https";
6
+ import { request as httpRequest } from "node:http";
7
+
8
+ // --- Parse args ---
9
+
10
+ const args = argv.slice(2);
11
+ let url = env.TARU_URL || "http://localhost:9120";
12
+ let workspaceId = env.TARU_WORKSPACE_ID || "00000000-0000-0000-0000-000000000001";
13
+ let token = env.TARU_API_TOKEN || "";
14
+
15
+ for (let i = 0; i < args.length; i++) {
16
+ if ((args[i] === "--url" || args[i] === "-u") && args[i + 1]) {
17
+ url = args[++i];
18
+ } else if ((args[i] === "--workspace-id" || args[i] === "-w") && args[i + 1]) {
19
+ workspaceId = args[++i];
20
+ } else if ((args[i] === "--token" || args[i] === "-t") && args[i + 1]) {
21
+ token = args[++i];
22
+ } else if (args[i] === "--help" || args[i] === "-h") {
23
+ stderr.write(`taru-mcp — MCP proxy for taru knowledge graph
24
+
25
+ Usage:
26
+ npx taru-mcp [options]
27
+
28
+ Options:
29
+ --url, -u Taru server URL (env: TARU_URL, default: http://localhost:9120)
30
+ --workspace-id, -w Workspace UUID (env: TARU_WORKSPACE_ID)
31
+ --token, -t API token (env: TARU_API_TOKEN)
32
+ --help, -h Show this help
33
+
34
+ Examples:
35
+ claude mcp add taru -- npx -y taru-mcp --url https://taru.example.com --token xxv_...
36
+ codex mcp add taru -- npx -y taru-mcp -u http://localhost:9120 -w <uuid>
37
+ `);
38
+ process.exit(0);
39
+ }
40
+ }
41
+
42
+ url = url.replace(/\/+$/, "");
43
+ const endpoint = `${url}/mcp/${workspaceId}`;
44
+ const isHttps = endpoint.startsWith("https://");
45
+
46
+ stderr.write(`[taru-mcp] endpoint: ${endpoint}\n`);
47
+
48
+ // --- JSON-RPC proxy: stdin → HTTP POST → stdout ---
49
+
50
+ const rl = createInterface({ input: process.stdin });
51
+
52
+ rl.on("line", async (line) => {
53
+ if (!line.trim()) return;
54
+
55
+ try {
56
+ const body = await post(endpoint, line);
57
+
58
+ // 202 Accepted = notification, no response needed
59
+ if (body === null) return;
60
+
61
+ stdout.write(body + "\n");
62
+ } catch (err) {
63
+ const parsed = safeParse(line);
64
+ const id = parsed?.id ?? null;
65
+ const errResp = JSON.stringify({
66
+ jsonrpc: "2.0",
67
+ id,
68
+ error: { code: -32603, message: `server unreachable: ${err.message}` },
69
+ });
70
+ stdout.write(errResp + "\n");
71
+ }
72
+ });
73
+
74
+ rl.on("close", () => process.exit(0));
75
+
76
+ // --- HTTP POST helper ---
77
+
78
+ function post(targetUrl, body) {
79
+ return new Promise((resolve, reject) => {
80
+ const parsed = new URL(targetUrl);
81
+ const requester = isHttps ? httpsRequest : httpRequest;
82
+
83
+ const headers = { "Content-Type": "application/json" };
84
+ if (token) headers["Authorization"] = `Bearer ${token}`;
85
+
86
+ const req = requester(
87
+ parsed,
88
+ { method: "POST", headers },
89
+ (res) => {
90
+ const chunks = [];
91
+ res.on("data", (chunk) => chunks.push(chunk));
92
+ res.on("end", () => {
93
+ if (res.statusCode === 202) {
94
+ resolve(null);
95
+ return;
96
+ }
97
+ resolve(Buffer.concat(chunks).toString());
98
+ });
99
+ }
100
+ );
101
+
102
+ req.on("error", reject);
103
+ req.write(body);
104
+ req.end();
105
+ });
106
+ }
107
+
108
+ function safeParse(s) {
109
+ try {
110
+ return JSON.parse(s);
111
+ } catch {
112
+ return null;
113
+ }
114
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "taru-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for taru knowledge graph — connect Claude Code or Codex to your team's shared brain",
5
+ "bin": {
6
+ "taru-mcp": "./bin/taru-mcp.mjs"
7
+ },
8
+ "type": "module",
9
+ "files": [
10
+ "bin/",
11
+ "samples/",
12
+ "README.md"
13
+ ],
14
+ "keywords": [
15
+ "mcp",
16
+ "knowledge-graph",
17
+ "taru",
18
+ "claude",
19
+ "codex",
20
+ "model-context-protocol"
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/carl/taru-mcp"
25
+ },
26
+ "license": "MIT",
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }
@@ -0,0 +1,54 @@
1
+ ## taru Knowledge Graph
2
+
3
+ You have access to the taru MCP server — a research knowledge graph with temporal knowledge management.
4
+
5
+ ### Tools
6
+
7
+ - search_graph: Search knowledge base by English query
8
+ - read_full_document: Read full document content by UUID
9
+ - store_document: Store extracted knowledge (handles embedding + graph)
10
+ - list_documents: List all documents with status and confidence
11
+ - list_conflicts: View pending knowledge conflicts
12
+ - web_search: Search the web (DuckDuckGo)
13
+ - web_fetch: Fetch text content from a URL
14
+ - rebalance: Clean up the knowledge graph (merge keywords, remove orphans)
15
+
16
+ ### Rules
17
+
18
+ 1. **Always search before storing.** Before store_document, call search_graph with the core claim to check for conflicts.
19
+
20
+ 2. **Document vs Opinion classification:**
21
+ - doc_type="document": Objective, research-backed facts, data, verified information.
22
+ - doc_type="opinion": Subjective insights, ideas, hypotheses, preferences, or conversational knowledge from humans.
23
+ - When a user shares a personal view, idea, preference, or experience → opinion.
24
+ - When referencing published research, official data, or verified facts → document.
25
+ - Opinions get lower default confidence (0.50) than documents (0.85).
26
+ - Store the original conversation/context in content field for traceability.
27
+
28
+ 3. **Conflict resolution:**
29
+ - supersedes_doc_id: Only when new info definitively invalidates old (retraction, correction). Marks old doc invalid.
30
+ - disputes_doc_id: Legitimate disagreement (competing theories). Both remain valid. USE THIS FOR COMPETING SCIENTIFIC CLAIMS.
31
+ - refines_doc_id: New info adds nuance to old. Both remain valid.
32
+ - Do NOT default to superseding. Competing claims must coexist.
33
+
34
+ 4. **Confidence scores:** 0.95 (meta-analysis) → 0.85 (peer-reviewed, default for documents) → 0.70 (preprint) → 0.50 (opinion, default) → 0.30 (unverified)
35
+
36
+ 5. **Extraction in English.** All titles, core_claims, keywords must be English for embedding consistency. Keywords lowercase and specific.
37
+
38
+ 6. **One claim per document.** Multiple independent claims from one source → separate store_document calls.
39
+
40
+ 7. **Source traceability.** Always set source_file: web://url, file://name, mcp://topic, or conversation://context. Set valid_from to current time for opinions.
41
+
42
+ 8. **Capturing conversational knowledge:**
43
+ - When a user expresses an opinion or idea during conversation, store it proactively.
44
+ - Include the full conversational context in the content field.
45
+ - Use source_file="conversation://session" to mark conversational origins.
46
+ - Extract the core insight as core_claim, even if the user expressed it casually.
47
+
48
+ 9. **Search result interpretation:**
49
+ - disputed_by present → present both perspectives
50
+ - confidence → note reliability level
51
+ - valid_until set → superseded, prefer newer but note history
52
+ - doc_type=opinion → present as "team insight" not "established fact"
53
+
54
+ 10. **Maintenance.** Run list_conflicts after bulk ingestion. Run rebalance after storing many documents.
@@ -0,0 +1,54 @@
1
+ ## taru Knowledge Graph
2
+
3
+ You have access to the taru MCP server — a research knowledge graph with temporal knowledge management.
4
+
5
+ ### Tools
6
+
7
+ - search_graph: Search knowledge base by English query
8
+ - read_full_document: Read full document content by UUID
9
+ - store_document: Store extracted knowledge (handles embedding + graph)
10
+ - list_documents: List all documents with status and confidence
11
+ - list_conflicts: View pending knowledge conflicts
12
+ - web_search: Search the web (DuckDuckGo)
13
+ - web_fetch: Fetch text content from a URL
14
+ - rebalance: Clean up the knowledge graph (merge keywords, remove orphans)
15
+
16
+ ### Rules
17
+
18
+ 1. **Always search before storing.** Before store_document, call search_graph with the core claim to check for conflicts.
19
+
20
+ 2. **Document vs Opinion classification:**
21
+ - doc_type="document": Objective, research-backed facts, data, verified information.
22
+ - doc_type="opinion": Subjective insights, ideas, hypotheses, preferences, or conversational knowledge from humans.
23
+ - When a user shares a personal view, idea, preference, or experience → opinion.
24
+ - When referencing published research, official data, or verified facts → document.
25
+ - Opinions get lower default confidence (0.50) than documents (0.85).
26
+ - Store the original conversation/context in content field for traceability.
27
+
28
+ 3. **Conflict resolution:**
29
+ - supersedes_doc_id: Only when new info definitively invalidates old (retraction, correction). Marks old doc invalid.
30
+ - disputes_doc_id: Legitimate disagreement (competing theories). Both remain valid. USE THIS FOR COMPETING SCIENTIFIC CLAIMS.
31
+ - refines_doc_id: New info adds nuance to old. Both remain valid.
32
+ - Do NOT default to superseding. Competing claims must coexist.
33
+
34
+ 4. **Confidence scores:** 0.95 (meta-analysis) → 0.85 (peer-reviewed, default for documents) → 0.70 (preprint) → 0.50 (opinion, default) → 0.30 (unverified)
35
+
36
+ 5. **Extraction in English.** All titles, core_claims, keywords must be English for embedding consistency. Keywords lowercase and specific.
37
+
38
+ 6. **One claim per document.** Multiple independent claims from one source → separate store_document calls.
39
+
40
+ 7. **Source traceability.** Always set source_file: web://url, file://name, mcp://topic, or conversation://context. Set valid_from to current time for opinions.
41
+
42
+ 8. **Capturing conversational knowledge:**
43
+ - When a user expresses an opinion or idea during conversation, store it proactively.
44
+ - Include the full conversational context in the content field.
45
+ - Use source_file="conversation://session" to mark conversational origins.
46
+ - Extract the core insight as core_claim, even if the user expressed it casually.
47
+
48
+ 9. **Search result interpretation:**
49
+ - disputed_by present → present both perspectives
50
+ - confidence → note reliability level
51
+ - valid_until set → superseded, prefer newer but note history
52
+ - doc_type=opinion → present as "team insight" not "established fact"
53
+
54
+ 10. **Maintenance.** Run list_conflicts after bulk ingestion. Run rebalance after storing many documents.