@kinqs/brainrouter-mcp-server 0.3.4 → 0.3.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 +88 -15
- package/dist/env-loader.d.ts +1 -0
- package/dist/env-loader.js +47 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +12 -1
- package/dist/init.d.ts +1 -0
- package/dist/init.js +64 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@kinqs/brainrouter-mcp-server`
|
|
2
2
|
|
|
3
|
-
The cognitive memory engine behind [BrainRouter](https://github.com/kinqsradiollc/BrainRouter)
|
|
3
|
+
The cognitive memory engine behind [BrainRouter](https://github.com/kinqsradiollc/BrainRouter)
|
|
4
|
+
— exposed as a [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
5
|
+
server so any MCP-speaking agent (Claude Desktop, Cursor,
|
|
6
|
+
[`@kinqs/brainrouter-cli`](https://www.npmjs.com/package/@kinqs/brainrouter-cli),
|
|
7
|
+
custom clients) can recall, capture, and reason over long-term memory.
|
|
8
|
+
|
|
9
|
+
Ships the `brainrouter-mcp` binary.
|
|
10
|
+
|
|
11
|
+
---
|
|
4
12
|
|
|
5
13
|
## What it gives you
|
|
6
14
|
|
|
@@ -10,46 +18,111 @@ The cognitive memory engine behind [BrainRouter](https://github.com/kinqsradioll
|
|
|
10
18
|
- **Skill catalogue** — `list_skills`, `get_skill`, `search_skills`, `get_persona` — ships with 70+ canonical skills bundled at publish time.
|
|
11
19
|
- **HTTP and stdio transports** — run as a hosted service (HTTP/SSE) or spawn as a stdio child from any MCP client.
|
|
12
20
|
|
|
21
|
+
---
|
|
22
|
+
|
|
13
23
|
## Install
|
|
14
24
|
|
|
15
25
|
```bash
|
|
16
|
-
npm install @kinqs/brainrouter-mcp-server
|
|
26
|
+
npm install -g @kinqs/brainrouter-mcp-server
|
|
17
27
|
```
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
The `-g` flag is required so `brainrouter-mcp` lands on your `$PATH`.
|
|
30
|
+
See [`@kinqs/brainrouter-cli`'s README](https://www.npmjs.com/package/@kinqs/brainrouter-cli)
|
|
31
|
+
for the sudo / nvm caveats — the same rules apply.
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
# HTTP transport on :3747
|
|
23
|
-
npx brainrouter-mcp --http --port 3747
|
|
33
|
+
Verify:
|
|
24
34
|
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
```bash
|
|
36
|
+
which brainrouter-mcp
|
|
37
|
+
brainrouter-mcp --version # prints 0.3.5
|
|
27
38
|
```
|
|
28
39
|
|
|
40
|
+
---
|
|
41
|
+
|
|
29
42
|
## Configure
|
|
30
43
|
|
|
31
|
-
|
|
44
|
+
The server reads its config from a `.env` file. The challenge for a
|
|
45
|
+
globally-installed package is that you don't know where the package
|
|
46
|
+
lives, and even if you did, it's typically in a path you can't easily
|
|
47
|
+
edit (`/usr/local/lib/node_modules/...` or similar). To fix that, the
|
|
48
|
+
server looks for `.env` in three places, in order:
|
|
49
|
+
|
|
50
|
+
1. `$BRAINROUTER_ENV_FILE` — explicit override (set this when you want a
|
|
51
|
+
per-project or per-deployment config).
|
|
52
|
+
2. `~/.config/brainrouter/server.env` — the canonical user location.
|
|
53
|
+
3. `./.env` — current working directory (matches the classic dotenv
|
|
54
|
+
behavior; useful for monorepo dev).
|
|
55
|
+
|
|
56
|
+
At startup the server prints which path it loaded from, so there's never
|
|
57
|
+
any ambiguity:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
env: loaded 17 vars from /Users/you/.config/brainrouter/server.env
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### One-time setup
|
|
32
64
|
|
|
33
65
|
```bash
|
|
66
|
+
brainrouter-mcp init # scaffolds ~/.config/brainrouter/server.env
|
|
67
|
+
$EDITOR ~/.config/brainrouter/server.env
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`init` copies the package's bundled `.env.example` to
|
|
71
|
+
`~/.config/brainrouter/server.env` and chmods it to `0600`. It won't
|
|
72
|
+
overwrite an existing file.
|
|
73
|
+
|
|
74
|
+
### Minimum fields to set
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Cognitive extraction LLM (any OpenAI-compatible endpoint:
|
|
78
|
+
# OpenAI, OpenRouter, LM Studio, Ollama, vLLM…)
|
|
34
79
|
BRAINROUTER_LLM_API_KEY=sk-...
|
|
35
80
|
BRAINROUTER_LLM_ENDPOINT=https://api.openai.com/v1/chat/completions
|
|
36
81
|
BRAINROUTER_LLM_MODEL=gpt-4o-mini
|
|
37
82
|
|
|
83
|
+
# Embeddings — required for vector recall. Key falls back to BRAINROUTER_LLM_API_KEY.
|
|
38
84
|
BRAINROUTER_EMBEDDING_ENDPOINT=https://api.openai.com/v1/embeddings
|
|
39
85
|
BRAINROUTER_EMBEDDING_MODEL=text-embedding-3-small
|
|
40
86
|
BRAINROUTER_EMBEDDING_DIMENSIONS=1536
|
|
41
87
|
|
|
88
|
+
# Server auth — change before exposing the server
|
|
42
89
|
BRAINROUTER_ADMIN_PASSWORD=change_me_before_use
|
|
43
|
-
BRAINROUTER_JWT_SECRET=replace_with_a_long_random_secret
|
|
90
|
+
BRAINROUTER_JWT_SECRET=replace_with_a_long_random_secret # `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Full knob list (reranker, prewarming, focus-scene triggers, sweep
|
|
94
|
+
intervals, JWT, CORS) lives in the bundled `.env.example` — view it
|
|
95
|
+
after `init` ran, or directly with:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cat "$(npm root -g)/@kinqs/brainrouter-mcp-server/.env.example"
|
|
44
99
|
```
|
|
45
100
|
|
|
46
|
-
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Run
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# HTTP transport on :3747 — what the CLI connects to via login
|
|
107
|
+
brainrouter-mcp --http --port 3747
|
|
108
|
+
|
|
109
|
+
# stdio transport — for clients that spawn the server themselves
|
|
110
|
+
brainrouter-mcp
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The server writes logs to stderr. To leave it running detached, use a
|
|
114
|
+
process manager (launchd / systemd / tmux / `nohup`) of your choice.
|
|
115
|
+
|
|
116
|
+
---
|
|
47
117
|
|
|
48
118
|
## Docs
|
|
49
119
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
- [
|
|
120
|
+
- **Repo**: <https://github.com/kinqsradiollc/BrainRouter>
|
|
121
|
+
- **Memory engine deep-dive**: [BRAINROUTER.md](https://github.com/kinqsradiollc/BrainRouter/blob/main/BRAINROUTER.md)
|
|
122
|
+
- **Maintainer runbook**: [SETUP.md](https://github.com/kinqsradiollc/BrainRouter/blob/main/SETUP.md)
|
|
123
|
+
- **Bugs / requests**: <https://github.com/kinqsradiollc/BrainRouter/issues>
|
|
124
|
+
|
|
125
|
+
---
|
|
53
126
|
|
|
54
127
|
## License
|
|
55
128
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Side-effect module: imported FIRST in src/index.ts so it sets process.env
|
|
2
|
+
// from the right .env file BEFORE any other module evaluates and tries to
|
|
3
|
+
// read those vars.
|
|
4
|
+
//
|
|
5
|
+
// Priority order (first hit wins):
|
|
6
|
+
// 1. $BRAINROUTER_ENV_FILE (explicit user override)
|
|
7
|
+
// 2. ~/.config/brainrouter/server.env (canonical user location — the
|
|
8
|
+
// one a globally-installed
|
|
9
|
+
// `npm i -g @kinqs/brainrouter-mcp-server`
|
|
10
|
+
// user should write to)
|
|
11
|
+
// 3. ./.env (cwd — matches dotenv default,
|
|
12
|
+
// keeps monorepo dev working)
|
|
13
|
+
//
|
|
14
|
+
// The third entry matches dotenv's classic behavior, so existing
|
|
15
|
+
// `cd brainrouter/ && npm run start:http` workflows keep loading
|
|
16
|
+
// `brainrouter/.env` exactly as before. The first two are the additions
|
|
17
|
+
// that fix the global-install UX (users no longer need to cd anywhere
|
|
18
|
+
// special).
|
|
19
|
+
import dotenv from 'dotenv';
|
|
20
|
+
import fs from 'node:fs';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import os from 'node:os';
|
|
23
|
+
function resolveEnvFile() {
|
|
24
|
+
const candidates = [
|
|
25
|
+
process.env.BRAINROUTER_ENV_FILE,
|
|
26
|
+
path.join(os.homedir(), '.config', 'brainrouter', 'server.env'),
|
|
27
|
+
path.join(process.cwd(), '.env'),
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
for (const file of candidates) {
|
|
30
|
+
if (fs.existsSync(file))
|
|
31
|
+
return file;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const envFile = resolveEnvFile();
|
|
36
|
+
if (envFile) {
|
|
37
|
+
const result = dotenv.config({ path: envFile });
|
|
38
|
+
const count = Object.keys(result.parsed ?? {}).length;
|
|
39
|
+
process.stderr.write(`env: loaded ${count} var${count === 1 ? '' : 's'} from ${envFile}\n`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
process.stderr.write(`env: no .env file found — looked at:\n` +
|
|
43
|
+
` $BRAINROUTER_ENV_FILE (${process.env.BRAINROUTER_ENV_FILE ? 'set, but missing' : 'unset'})\n` +
|
|
44
|
+
` ~/.config/brainrouter/server.env\n` +
|
|
45
|
+
` ${path.join(process.cwd(), '.env')}\n` +
|
|
46
|
+
`Run 'brainrouter-mcp init' to scaffold one (or set BRAINROUTER_LLM_API_KEY and friends in your shell).\n`);
|
|
47
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
// Runs an Express HTTP server. Connect via serverUrl in tool config.
|
|
15
15
|
// Usage: node dist/index.js --root /path/to/project --http --port 3747
|
|
16
16
|
//
|
|
17
|
+
// init subcommand
|
|
18
|
+
// Scaffold ~/.config/brainrouter/server.env from the bundled
|
|
19
|
+
// .env.example and exit. Run this once after a global install.
|
|
20
|
+
// Usage: brainrouter-mcp init
|
|
21
|
+
//
|
|
22
|
+
// CRITICAL: import order matters. `init` may exit the process before
|
|
23
|
+
// anything else loads (for `brainrouter-mcp init`). `env-loader` runs next
|
|
24
|
+
// and sets process.env from the right .env file before any module body
|
|
25
|
+
// reads env vars (sqlite/embedding/extractor all do at load time).
|
|
26
|
+
import './init.js';
|
|
27
|
+
import './env-loader.js';
|
|
17
28
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
18
29
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
19
30
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
@@ -91,7 +102,7 @@ const PORT = parseInt(parseFlag('--port') ?? '3747', 10);
|
|
|
91
102
|
function buildMcpServer(registry, options) {
|
|
92
103
|
const defaultUserId = options?.defaultUserId ?? STDIO_DEFAULT_USER_ID;
|
|
93
104
|
const isAdmin = options?.isAdmin ?? false;
|
|
94
|
-
const server = new Server({ name: 'brainrouter-mcp-server', version: '0.3.
|
|
105
|
+
const server = new Server({ name: 'brainrouter-mcp-server', version: '0.3.5' }, { capabilities: { tools: {} } });
|
|
95
106
|
// ── Tool list ──────────────────────────────────────────────────────────────
|
|
96
107
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
97
108
|
tools: [
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Side-effect module: imported FIRST in src/index.ts (before env-loader).
|
|
2
|
+
//
|
|
3
|
+
// Handles the `brainrouter-mcp init` subcommand by scaffolding a user-editable
|
|
4
|
+
// .env file at ~/.config/brainrouter/server.env from the package's bundled
|
|
5
|
+
// .env.example, then exiting. Never returns control when invoked.
|
|
6
|
+
//
|
|
7
|
+
// This solves the global-install UX gap: a user who runs
|
|
8
|
+
// `npm install -g @kinqs/brainrouter-mcp-server` has no obvious place to put
|
|
9
|
+
// their LLM credentials. `brainrouter-mcp init` creates the file in a known
|
|
10
|
+
// user-writable location that env-loader.ts then auto-finds.
|
|
11
|
+
//
|
|
12
|
+
// If the file already exists, init prints the path so the user knows where
|
|
13
|
+
// to edit it — but does NOT overwrite (don't clobber a user's real config).
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import url from 'node:url';
|
|
18
|
+
function runInit() {
|
|
19
|
+
const userConfigDir = path.join(os.homedir(), '.config', 'brainrouter');
|
|
20
|
+
const userEnvFile = path.join(userConfigDir, 'server.env');
|
|
21
|
+
// .env.example sits at the package root (one level above src/ in source,
|
|
22
|
+
// one level above dist/ after build, both layouts work in the installed
|
|
23
|
+
// tarball because the `files` allowlist in package.json includes it).
|
|
24
|
+
const here = path.dirname(url.fileURLToPath(import.meta.url));
|
|
25
|
+
const exampleCandidates = [
|
|
26
|
+
path.resolve(here, '..', '.env.example'), // dist/init.js → ../.env.example
|
|
27
|
+
path.resolve(here, '..', '..', '.env.example'), // src/init.ts (dev) → ../../.env.example
|
|
28
|
+
];
|
|
29
|
+
const examplePath = exampleCandidates.find((p) => fs.existsSync(p));
|
|
30
|
+
if (!examplePath) {
|
|
31
|
+
process.stderr.write(`init: couldn't find .env.example bundled with the package.\n` +
|
|
32
|
+
`Checked:\n${exampleCandidates.map((p) => ` ${p}`).join('\n')}\n` +
|
|
33
|
+
`This is a packaging bug — please file an issue at ` +
|
|
34
|
+
`https://github.com/kinqsradiollc/BrainRouter/issues\n`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
if (fs.existsSync(userEnvFile)) {
|
|
38
|
+
process.stdout.write(`init: ${userEnvFile} already exists — not overwriting.\n` +
|
|
39
|
+
`Edit it with: $EDITOR ${userEnvFile}\n` +
|
|
40
|
+
`(Or compare against the latest template at ${examplePath})\n`);
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
fs.mkdirSync(userConfigDir, { recursive: true });
|
|
44
|
+
fs.copyFileSync(examplePath, userEnvFile);
|
|
45
|
+
// Tighten perms — this file will hold API keys + a JWT secret.
|
|
46
|
+
try {
|
|
47
|
+
fs.chmodSync(userEnvFile, 0o600);
|
|
48
|
+
}
|
|
49
|
+
catch { /* best effort */ }
|
|
50
|
+
process.stdout.write(`init: created ${userEnvFile}\n` +
|
|
51
|
+
`\n` +
|
|
52
|
+
`Next steps:\n` +
|
|
53
|
+
` 1. Edit it: $EDITOR ${userEnvFile}\n` +
|
|
54
|
+
` 2. Set BRAINROUTER_LLM_API_KEY (required for cognitive extraction)\n` +
|
|
55
|
+
` 3. Change BRAINROUTER_ADMIN_PASSWORD and BRAINROUTER_JWT_SECRET\n` +
|
|
56
|
+
` 4. Start the server: brainrouter-mcp --http --port 3747\n` +
|
|
57
|
+
`\n` +
|
|
58
|
+
`The server auto-finds this file via ~/.config/brainrouter/server.env\n` +
|
|
59
|
+
`(or set BRAINROUTER_ENV_FILE=/some/other/path to override).\n`);
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
if (process.argv.includes('init')) {
|
|
63
|
+
runInit();
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kinqs/brainrouter-mcp-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "BrainRouter MCP server — the cognitive memory engine. Exposes recall, capture, focus scenes, persona, contradictions, skills, and graph queries as MCP tools for any MCP-speaking agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"gray-matter": "^4.0.3",
|
|
46
46
|
"sqlite-vec": "^0.1.9",
|
|
47
47
|
"zod": "^3.22.4",
|
|
48
|
-
"@kinqs/brainrouter-types": "^0.3.
|
|
48
|
+
"@kinqs/brainrouter-types": "^0.3.5"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=22.0.0"
|