@thinkingroot/mcp 0.2.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 +80 -0
- package/package.json +28 -0
- package/src/args.mjs +39 -0
- package/src/bin/thinkingroot-mcp.mjs +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# @thinkingroot/mcp
|
|
2
|
+
|
|
3
|
+
**Give any AI agent a living, per-user memory — by pasting one URL.**
|
|
4
|
+
|
|
5
|
+
ThinkingRoot is the managed cloud for the cognition database. This connects any
|
|
6
|
+
MCP client (Claude, Cursor, Codex, VS Code, …) to your project's brain over the
|
|
7
|
+
hosted gateway, exposing the full tool catalog — including the **Compiled
|
|
8
|
+
Workspace** tools: `ask` (citation-gated, refuses rather than hallucinates),
|
|
9
|
+
`search`, `compile`, `repo_map`, `code_traverse`, `code_search_entity`,
|
|
10
|
+
`summaries`, plus memory `remember`/`recall`.
|
|
11
|
+
|
|
12
|
+
Every answer is grounded in **verbatim, byte-anchored** sources. Memory is
|
|
13
|
+
deletable and provable — not an opaque blob.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Two ways to connect
|
|
18
|
+
|
|
19
|
+
### 1. Hosted URL (no install)
|
|
20
|
+
|
|
21
|
+
For clients that support **remote MCP servers**, paste the hosted endpoint and
|
|
22
|
+
your key — nothing to install:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
URL: https://api.thinkingroot.com/mcp/sse
|
|
26
|
+
Header: Authorization: Bearer tr_sk_…
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Get a `tr_sk_…` project key from the Console → **Keys** tab. That's the whole
|
|
30
|
+
setup — the gateway authenticates the key, resolves your project's engine, and
|
|
31
|
+
streams the tools.
|
|
32
|
+
|
|
33
|
+
### 2. One-line bridge (any stdio client)
|
|
34
|
+
|
|
35
|
+
For clients that speak stdio only, this package bridges stdio ↔ the hosted SSE
|
|
36
|
+
endpoint. Drop it into your MCP client config:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"thinkingroot": {
|
|
42
|
+
"command": "npx",
|
|
43
|
+
"args": ["-y", "@thinkingroot/mcp"],
|
|
44
|
+
"env": { "TR_PROJECT_KEY": "tr_sk_…" }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- **`TR_PROJECT_KEY`** (required) — a `tr_sk_…` project API key.
|
|
51
|
+
- **`TR_GATEWAY_URL`** (optional) — defaults to `https://api.thinkingroot.com`.
|
|
52
|
+
|
|
53
|
+
Works in Claude Desktop, Claude Code, Cursor, Codex, Windsurf, and any client
|
|
54
|
+
that runs a `command`-based MCP server.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Per-user minds
|
|
59
|
+
|
|
60
|
+
ThinkingRoot isn't one shared database — each of your end-users can have their
|
|
61
|
+
own **private, fail-closed** brain (`u_{userId}`). To scope a hosted session to
|
|
62
|
+
one user, mint a user-bound embed token (`tr_em_…`) from your backend via
|
|
63
|
+
`POST /tokens/session` and present it in place of the `tr_sk_` key. The gateway
|
|
64
|
+
derives the identity from the token, so a session can never read another user's
|
|
65
|
+
mind.
|
|
66
|
+
|
|
67
|
+
## Security
|
|
68
|
+
|
|
69
|
+
- Fail-closed: without a valid `tr_sk_…` key the bridge exits rather than
|
|
70
|
+
connect unauthenticated.
|
|
71
|
+
- The key is sent only to the hosted gateway over TLS; the underlying engine
|
|
72
|
+
key is never exposed to the client.
|
|
73
|
+
- `tr_pk_…` publishable keys are ask/recall-scoped and domain-locked — safe for
|
|
74
|
+
browser embeds; `tr_sk_…` full-scope keys belong on a server.
|
|
75
|
+
|
|
76
|
+
## Links
|
|
77
|
+
|
|
78
|
+
- Docs & keys: [thinkingroot.com](https://thinkingroot.com)
|
|
79
|
+
- SDK: [`@thinkingroot/sdk`](https://www.npmjs.com/package/@thinkingroot/sdk) · CLI: [`thinkingroot`](https://www.npmjs.com/package/thinkingroot)
|
|
80
|
+
- Built on [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) for the stdio bridge.
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thinkingroot/mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Give any AI agent a living, per-user memory over MCP — hosted URL or one-line stdio bridge to ThinkingRoot (ask/search/compile/remember/recall + full tool catalog).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"thinkingroot-mcp": "src/bin/thinkingroot-mcp.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"!src/**/*.test.mjs",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "node --test src/args.test.mjs"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"thinkingroot",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"claude",
|
|
22
|
+
"cursor"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18"
|
|
26
|
+
},
|
|
27
|
+
"license": "UNLICENSED"
|
|
28
|
+
}
|
package/src/args.mjs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Pure arg-building for the @thinkingroot/mcp wrapper. Kept dependency-free
|
|
2
|
+
// and side-effect-free so it is unit-testable without spawning anything.
|
|
3
|
+
|
|
4
|
+
/** The public HTTPS front door (Cloudflare → Caddy → gateway :3109). */
|
|
5
|
+
export const DEFAULT_GATEWAY_URL = "https://api.thinkingroot.com";
|
|
6
|
+
|
|
7
|
+
/** Normalize a gateway base URL (strip trailing slash). */
|
|
8
|
+
export function normalizeGateway(url) {
|
|
9
|
+
return String(url || DEFAULT_GATEWAY_URL).replace(/\/+$/, "");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** The SSE MCP endpoint clients connect to (the gateway proxies to the engine). */
|
|
13
|
+
export function mcpSseUrl(gatewayUrl) {
|
|
14
|
+
return `${normalizeGateway(gatewayUrl)}/mcp/sse`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Build the `mcp-remote` argv that bridges stdio ↔ the gateway's SSE MCP
|
|
19
|
+
* endpoint, injecting the project key as a bearer header. We pass the header
|
|
20
|
+
* value with no space after the colon and quote-free because mcp-remote
|
|
21
|
+
* mis-splits header values containing a space (matches the Console's
|
|
22
|
+
* claude-code config). Throws if the project key is missing — fail closed,
|
|
23
|
+
* never connect unauthenticated.
|
|
24
|
+
*/
|
|
25
|
+
export function buildArgs({ gatewayUrl, projectKey } = {}) {
|
|
26
|
+
if (!projectKey || !String(projectKey).startsWith("tr_sk_")) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
"TR_PROJECT_KEY (a tr_sk_… project API key) is required. " +
|
|
29
|
+
"Get one from the Console → Keys tab.",
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return [
|
|
33
|
+
"-y",
|
|
34
|
+
"mcp-remote",
|
|
35
|
+
mcpSseUrl(gatewayUrl),
|
|
36
|
+
"--header",
|
|
37
|
+
`Authorization:Bearer ${projectKey}`,
|
|
38
|
+
];
|
|
39
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @thinkingroot/mcp — one-line MCP server for ThinkingRoot.
|
|
3
|
+
//
|
|
4
|
+
// Adds the project's Compiled Workspace tools (compile/search/ask/repo_map/
|
|
5
|
+
// code_traverse/code_search_entity/summaries + the full engine catalog) to any
|
|
6
|
+
// stdio MCP client (Claude Code, Cursor, Codex) by bridging stdio ↔ the
|
|
7
|
+
// gateway's SSE MCP endpoint via `mcp-remote`.
|
|
8
|
+
//
|
|
9
|
+
// Usage (in an MCP client config):
|
|
10
|
+
// command: "npx", args: ["-y", "@thinkingroot/mcp"]
|
|
11
|
+
// env: { TR_PROJECT_KEY: "tr_sk_…", TR_GATEWAY_URL?: "https://…" }
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { buildArgs, mcpSseUrl } from "../args.mjs";
|
|
14
|
+
|
|
15
|
+
let argv;
|
|
16
|
+
try {
|
|
17
|
+
argv = buildArgs({
|
|
18
|
+
gatewayUrl: process.env.TR_GATEWAY_URL,
|
|
19
|
+
projectKey: process.env.TR_PROJECT_KEY,
|
|
20
|
+
});
|
|
21
|
+
} catch (e) {
|
|
22
|
+
process.stderr.write(`thinkingroot-mcp: ${e.message}\n`);
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
process.stderr.write(
|
|
27
|
+
`thinkingroot-mcp → ${mcpSseUrl(process.env.TR_GATEWAY_URL)} (key tr_sk_…)\n`,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// Bridge runs as a child speaking the MCP stdio protocol on our stdio.
|
|
31
|
+
const child = spawn("npx", argv, { stdio: "inherit" });
|
|
32
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
33
|
+
child.on("error", (err) => {
|
|
34
|
+
process.stderr.write(`thinkingroot-mcp: failed to start mcp-remote: ${err.message}\n`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|