@littlebigbrain/mcp 0.2.3 → 0.2.5
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 +19 -18
- package/dist/http-server.d.ts +3 -2
- package/dist/http-server.js +5 -2
- package/dist/http.js +5 -1
- package/dist/stdio.js +59 -11
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
# @littlebigbrain/mcp
|
|
2
2
|
|
|
3
|
-
Eleven task-shaped MCP tools
|
|
4
|
-
brain graph from Claude, Cursor, Codex, or another MCP client.
|
|
3
|
+
Eleven task-shaped [MCP](https://modelcontextprotocol.io) tools that let Claude, Cursor, Codex, or any MCP client search, query, and write a [Little Big Brain](https://littlebigbrain.com) graph. Ships two ways: a hosted endpoint with OAuth sign-in, and a local stdio server.
|
|
5
4
|
|
|
6
|
-
## Hosted OAuth
|
|
5
|
+
## Hosted (OAuth) — recommended
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
stores a little big brain stack key:
|
|
7
|
+
The client opens WorkOS sign-in; your machine never stores a Little Big Brain key. Point it at your stack:
|
|
10
8
|
|
|
11
9
|
```json
|
|
12
10
|
{
|
|
@@ -18,7 +16,7 @@ stores a little big brain stack key:
|
|
|
18
16
|
}
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
Codex
|
|
19
|
+
Codex sends the URL as an OAuth `resource`, so use the origin plus a stack header instead:
|
|
22
20
|
|
|
23
21
|
```json
|
|
24
22
|
{
|
|
@@ -32,7 +30,9 @@ Codex Desktop should use the origin plus a stack header:
|
|
|
32
30
|
}
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
## Local stdio
|
|
33
|
+
## Local (stdio)
|
|
34
|
+
|
|
35
|
+
Run against any data-plane endpoint with a stack API key:
|
|
36
36
|
|
|
37
37
|
```json
|
|
38
38
|
{
|
|
@@ -41,7 +41,7 @@ Codex Desktop should use the origin plus a stack header:
|
|
|
41
41
|
"command": "npx",
|
|
42
42
|
"args": ["-y", "@littlebigbrain/mcp"],
|
|
43
43
|
"env": {
|
|
44
|
-
"LBB_BASE_URL": "https://db.eu.littlebigbrain.com",
|
|
44
|
+
"LBB_BASE_URL": "https://0abc1def--production.db.eu.littlebigbrain.com",
|
|
45
45
|
"LBB_API_KEY": "lbb_sk_live_..."
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -49,7 +49,10 @@ Codex Desktop should use the origin plus a stack header:
|
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Set `LBB_GRAPH` or `LBB_BRANCH`
|
|
52
|
+
Set `LBB_GRAPH` or `LBB_BRANCH` to target a scope other than `main`.
|
|
53
|
+
`LBB_BASE_URL` has no hosted default: copy `endpoint_url` from the stack's
|
|
54
|
+
Connect page. The MCP process exits with a configuration error when it is
|
|
55
|
+
missing.
|
|
53
56
|
|
|
54
57
|
## Tools
|
|
55
58
|
|
|
@@ -67,24 +70,22 @@ Set `LBB_GRAPH` or `LBB_BRANCH` when the scope is not `main`.
|
|
|
67
70
|
| `lbb_configure` | ontology, schema, and inference rules |
|
|
68
71
|
| `lbb_index` | BM25, vector, and adjacency refresh |
|
|
69
72
|
|
|
70
|
-
Read tools return compact structured envelopes by default
|
|
71
|
-
`row_limit`, and returned cursors to page without silently truncating results.
|
|
72
|
-
Write tools derive idempotency keys unless you provide one.
|
|
73
|
+
Read tools return compact structured envelopes by default — use `detail`, `row_limit`, and returned cursors to page without silently truncating. Write tools derive an idempotency key unless you provide one.
|
|
73
74
|
|
|
74
75
|
## Embed the server
|
|
75
76
|
|
|
77
|
+
For self-hosting behind your own auth, the package also serves the tools over HTTP:
|
|
78
|
+
|
|
76
79
|
```ts
|
|
77
80
|
import { createMcpHttpServer } from "@littlebigbrain/mcp";
|
|
78
81
|
|
|
79
82
|
createMcpHttpServer({
|
|
80
|
-
baseUrl: "https://db.eu.littlebigbrain.com",
|
|
83
|
+
baseUrl: "https://0abc1def--production.db.eu.littlebigbrain.com",
|
|
81
84
|
mcpPath: "/mcp",
|
|
82
|
-
allowedHosts: ["127.0.0.1", "localhost", "::1"
|
|
85
|
+
allowedHosts: ["127.0.0.1", "localhost", "::1"],
|
|
83
86
|
}).listen(8080, "127.0.0.1");
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
The embedded
|
|
87
|
-
self-hosting behind your own auth. The hosted endpoint's OAuth/ownership layer
|
|
88
|
-
is served by the little big brain API.
|
|
89
|
+
The embedded server passes a key bearer to the data plane; the hosted endpoint's OAuth and ownership layer is served separately by the Little Big Brain API.
|
|
89
90
|
|
|
90
|
-
Full tool schemas and examples: [
|
|
91
|
+
Full tool schemas and examples: [docs.littlebigbrain.com/sdks/mcp](https://docs.littlebigbrain.com/sdks/mcp/).
|
package/dist/http-server.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type IncomingMessage, type Server } from "node:http";
|
|
2
2
|
import { LbbClient } from "@littlebigbrain/client";
|
|
3
3
|
export interface McpHttpServerOptions {
|
|
4
|
-
|
|
4
|
+
/** Required Little Big Brain stack endpoint (`endpoint_url` from Connect). */
|
|
5
|
+
baseUrl: string;
|
|
5
6
|
mcpPath?: string;
|
|
6
7
|
maxBodyBytes?: number;
|
|
7
8
|
requestTimeoutMs?: number;
|
|
@@ -30,4 +31,4 @@ export declare function readJsonBody(req: IncomingMessage, maxBodyBytes?: number
|
|
|
30
31
|
* Build the key-bearer streamable-HTTP MCP edge without starting a listener.
|
|
31
32
|
* The hosted multi-tenant OAuth endpoint remains in the SaaS API.
|
|
32
33
|
*/
|
|
33
|
-
export declare function createMcpHttpServer(options
|
|
34
|
+
export declare function createMcpHttpServer(options: McpHttpServerOptions): Server;
|
package/dist/http-server.js
CHANGED
|
@@ -96,13 +96,16 @@ export function readJsonBody(req, maxBodyBytes = DEFAULT_MAX_BODY_BYTES) {
|
|
|
96
96
|
* Build the key-bearer streamable-HTTP MCP edge without starting a listener.
|
|
97
97
|
* The hosted multi-tenant OAuth endpoint remains in the SaaS API.
|
|
98
98
|
*/
|
|
99
|
-
export function createMcpHttpServer(options
|
|
100
|
-
const baseUrl = options.baseUrl
|
|
99
|
+
export function createMcpHttpServer(options) {
|
|
100
|
+
const baseUrl = options.baseUrl.trim();
|
|
101
101
|
const mcpPath = options.mcpPath ?? "/mcp";
|
|
102
102
|
const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
103
103
|
const requestTimeoutMs = options.requestTimeoutMs ?? 30_000;
|
|
104
104
|
const allowedHosts = options.allowedHosts;
|
|
105
105
|
const allowedOrigins = options.allowedOrigins ?? [];
|
|
106
|
+
if (!baseUrl) {
|
|
107
|
+
throw new Error("baseUrl is required; copy endpoint_url from the stack's Connect page");
|
|
108
|
+
}
|
|
106
109
|
if (!mcpPath.startsWith("/"))
|
|
107
110
|
throw new Error("mcpPath must start with /");
|
|
108
111
|
if (!Number.isInteger(maxBodyBytes) || maxBodyBytes <= 0) {
|
package/dist/http.js
CHANGED
|
@@ -20,8 +20,12 @@ function csv(value) {
|
|
|
20
20
|
return items && items.length > 0 ? items : undefined;
|
|
21
21
|
}
|
|
22
22
|
const mcpPath = process.env.LBB_MCP_PATH ?? "/mcp";
|
|
23
|
+
const baseUrl = process.env.LBB_BASE_URL?.trim();
|
|
24
|
+
if (!baseUrl) {
|
|
25
|
+
throw new Error("LBB_BASE_URL is required. Copy endpoint_url from your stack's Connect page, for example https://<tenant-short-id>--<stack-slug>.db.eu.littlebigbrain.com");
|
|
26
|
+
}
|
|
23
27
|
const httpServer = createMcpHttpServer({
|
|
24
|
-
baseUrl
|
|
28
|
+
baseUrl,
|
|
25
29
|
mcpPath,
|
|
26
30
|
allowedHosts: csv(process.env.LBB_MCP_ALLOWED_HOSTS) ??
|
|
27
31
|
(isLoopback ? LOOPBACK_HOSTS : undefined),
|
package/dist/stdio.js
CHANGED
|
@@ -1,27 +1,75 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
2
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
5
|
import { LbbClient } from "@littlebigbrain/client";
|
|
4
6
|
import { buildLbbServer } from "./server.js";
|
|
7
|
+
const BASE_URL_HELP = "LBB_BASE_URL is required. Copy endpoint_url from your Little Big Brain stack's Connect page.";
|
|
5
8
|
/**
|
|
6
9
|
* Local stdio entrypoint (`npx @littlebigbrain/mcp`). Reads the connection from the
|
|
7
10
|
* environment and serves the little big brain tools over stdio, the transport every
|
|
8
11
|
* editor (Claude Code, Cursor, Codex) supports.
|
|
9
12
|
*
|
|
10
|
-
* LBB_BASE_URL (
|
|
13
|
+
* LBB_BASE_URL (required for tool calls; copy endpoint_url from the stack Connect page)
|
|
11
14
|
* LBB_API_KEY stack API key (lbb_sk_live_…) or single-mode token
|
|
12
15
|
* LBB_GRAPH / LBB_BRANCH (optional; server defaults to main/main)
|
|
16
|
+
*
|
|
17
|
+
* The base URL is required lazily, at the first tool invocation, not at
|
|
18
|
+
* process start: MCP hosts launch servers to complete the initialize
|
|
19
|
+
* handshake and list tools before the user has finished configuring them,
|
|
20
|
+
* and a startup crash surfaces as an opaque "server failed to start" in
|
|
21
|
+
* every editor. An unconfigured server therefore boots, handshakes, and
|
|
22
|
+
* lists tools normally — and every tool call fails with the actionable
|
|
23
|
+
* message above until LBB_BASE_URL is set. (There is deliberately no
|
|
24
|
+
* localhost default: pointing production tool calls at 127.0.0.1 silently
|
|
25
|
+
* was worse than failing loudly.)
|
|
13
26
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
export function unconfiguredClient() {
|
|
28
|
+
return new Proxy({}, {
|
|
29
|
+
get(_target, property) {
|
|
30
|
+
// Allow the runtime's duck-typing probes without exploding.
|
|
31
|
+
if (property === "then" || typeof property === "symbol")
|
|
32
|
+
return undefined;
|
|
33
|
+
throw new Error(BASE_URL_HELP);
|
|
34
|
+
},
|
|
20
35
|
});
|
|
36
|
+
}
|
|
37
|
+
async function main() {
|
|
38
|
+
const baseUrl = process.env.LBB_BASE_URL?.trim();
|
|
39
|
+
if (!baseUrl) {
|
|
40
|
+
console.error(`warning: ${BASE_URL_HELP} Tool calls will fail until it is set.`);
|
|
41
|
+
}
|
|
42
|
+
const client = baseUrl
|
|
43
|
+
? new LbbClient({
|
|
44
|
+
baseUrl,
|
|
45
|
+
apiKey: process.env.LBB_API_KEY,
|
|
46
|
+
graph: process.env.LBB_GRAPH,
|
|
47
|
+
branch: process.env.LBB_BRANCH,
|
|
48
|
+
})
|
|
49
|
+
: unconfiguredClient();
|
|
21
50
|
const server = buildLbbServer(client);
|
|
22
51
|
await server.connect(new StdioServerTransport());
|
|
23
52
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
53
|
+
// Only start the server when executed as the bin entrypoint — importing this
|
|
54
|
+
// module (e.g. the unconfiguredClient unit tests) must not attach a stdio
|
|
55
|
+
// transport to the host process, which would hold its stdin open forever.
|
|
56
|
+
// npm installs bins as symlinks, so argv[1] must be realpath'd before
|
|
57
|
+
// comparing against import.meta.url (which is always the resolved file).
|
|
58
|
+
function entrypointHref() {
|
|
59
|
+
const argv1 = process.argv[1];
|
|
60
|
+
if (argv1 === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
try {
|
|
63
|
+
return pathToFileURL(realpathSync(argv1)).href;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return pathToFileURL(argv1).href;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const invokedAsBin = import.meta.url === entrypointHref();
|
|
70
|
+
if (invokedAsBin) {
|
|
71
|
+
main().catch((error) => {
|
|
72
|
+
console.error(error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
|
75
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@littlebigbrain/mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "MCP server for little big brain — graph and hybrid search tools for agents",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"test:coverage": "npm run clean:test && tsc -p tsconfig.test.json && node --test --experimental-test-coverage --test-coverage-include=test-dist/*.js --test-coverage-exclude=test-dist/*.test.js --test-coverage-exclude=test-dist/stdio.js --test-coverage-exclude=test-dist/test-support.js --test-coverage-lines=90 --test-coverage-branches=70 --test-coverage-functions=85 \"test-dist/**/*.test.js\""
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@littlebigbrain/client": "^0.
|
|
55
|
+
"@littlebigbrain/client": "^0.6.0",
|
|
56
56
|
"@modelcontextprotocol/sdk": "^1",
|
|
57
57
|
"zod": "^3"
|
|
58
58
|
},
|