@novaeo/brain-connector 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/LICENSE +15 -0
- package/README.md +126 -0
- package/dist/brain-http-client.d.ts +99 -0
- package/dist/brain-http-client.js +89 -0
- package/dist/brain-http-client.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +37 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +186 -0
- package/dist/server.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Novaeo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
package/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# @novaeo/brain-connector
|
|
2
|
+
|
|
3
|
+
A standalone [Model Context Protocol](https://modelcontextprotocol.io) (MCP)
|
|
4
|
+
connector for the **Novaeo Brain** — your company's permission-aware memory.
|
|
5
|
+
It runs as a local **stdio** MCP server and exposes nine Brain tools to any MCP
|
|
6
|
+
client (Claude Desktop, Cursor, Codex, or a generic stdio host). Every call is
|
|
7
|
+
made over HTTPS to the Brain API, authenticated with your personal token. The
|
|
8
|
+
token **is** your identity: the server resolves who you are and only ever
|
|
9
|
+
returns what you are allowed to see.
|
|
10
|
+
|
|
11
|
+
This package is fully self-contained: no database, no workspace dependencies,
|
|
12
|
+
and no secrets. Its only runtime dependencies are
|
|
13
|
+
`@modelcontextprotocol/sdk` and `zod`.
|
|
14
|
+
|
|
15
|
+
## Tools
|
|
16
|
+
|
|
17
|
+
| Tool | What it does |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `search_brain` | Permission-filtered semantic search; returns ranked snippets with citations. |
|
|
20
|
+
| `answer_from_brain` | Grounded answer to a question, with source citations. |
|
|
21
|
+
| `write_brain_memory` | Write a draft note into the brain under a visibility policy. |
|
|
22
|
+
| `list_action_items` | List action items (defaults to your own). |
|
|
23
|
+
| `create_action_item` | Create an action item with owner, project, and due date. |
|
|
24
|
+
| `update_action_item` | Update an action item's status or fields. |
|
|
25
|
+
| `create_reminder` | Create a reminder that inherits its trigger message's visibility. |
|
|
26
|
+
| `summarize_thread` | Summarize a chat thread into a short, cited summary. |
|
|
27
|
+
| `promote_to_curated_note` | Promote a reviewed note into the curated `novaeo-brain` vault. |
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
Two environment variables are **required**. The connector exits with a clear
|
|
32
|
+
message if either is missing.
|
|
33
|
+
|
|
34
|
+
| Variable | Required | Description |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| `BRAIN_API_URL` | yes | Base URL of your Brain API, e.g. `https://brain.novaeo.com`. |
|
|
37
|
+
| `NOVAEO_BRAIN_TOKEN` | yes | Your personal Brain token (starts with `nbk_`). Sent as `Authorization: Bearer <token>`. |
|
|
38
|
+
|
|
39
|
+
### Getting your token
|
|
40
|
+
|
|
41
|
+
Your Brain token is issued from the **Connect-your-agent** page in the Novaeo
|
|
42
|
+
app (coming soon). It looks like `nbk_...`. Treat it like a password — it
|
|
43
|
+
grants exactly your access. Do not commit it; pass it via your MCP client's
|
|
44
|
+
environment block.
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
Run directly with `npx` (no install needed):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
BRAIN_API_URL=https://brain.novaeo.com \
|
|
52
|
+
NOVAEO_BRAIN_TOKEN=nbk_your_token \
|
|
53
|
+
npx @novaeo/brain-connector
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The process speaks the MCP protocol over stdio; diagnostics go to stderr.
|
|
57
|
+
|
|
58
|
+
## MCP client configuration
|
|
59
|
+
|
|
60
|
+
### Claude Desktop
|
|
61
|
+
|
|
62
|
+
Edit `claude_desktop_config.json` (Settings → Developer → Edit Config):
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"novaeo-brain": {
|
|
68
|
+
"command": "npx",
|
|
69
|
+
"args": ["-y", "@novaeo/brain-connector"],
|
|
70
|
+
"env": {
|
|
71
|
+
"BRAIN_API_URL": "https://brain.novaeo.com",
|
|
72
|
+
"NOVAEO_BRAIN_TOKEN": "nbk_your_token"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Cursor
|
|
80
|
+
|
|
81
|
+
Edit `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project):
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"mcpServers": {
|
|
86
|
+
"novaeo-brain": {
|
|
87
|
+
"command": "npx",
|
|
88
|
+
"args": ["-y", "@novaeo/brain-connector"],
|
|
89
|
+
"env": {
|
|
90
|
+
"BRAIN_API_URL": "https://brain.novaeo.com",
|
|
91
|
+
"NOVAEO_BRAIN_TOKEN": "nbk_your_token"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Codex
|
|
99
|
+
|
|
100
|
+
Add to `~/.codex/config.toml`:
|
|
101
|
+
|
|
102
|
+
```toml
|
|
103
|
+
[mcp_servers.novaeo-brain]
|
|
104
|
+
command = "npx"
|
|
105
|
+
args = ["-y", "@novaeo/brain-connector"]
|
|
106
|
+
env = { BRAIN_API_URL = "https://brain.novaeo.com", NOVAEO_BRAIN_TOKEN = "nbk_your_token" }
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Generic stdio MCP client
|
|
110
|
+
|
|
111
|
+
Any MCP host that launches a command can use:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["-y", "@novaeo/brain-connector"],
|
|
117
|
+
"env": {
|
|
118
|
+
"BRAIN_API_URL": "https://brain.novaeo.com",
|
|
119
|
+
"NOVAEO_BRAIN_TOKEN": "nbk_your_token"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type ConnectorConfig } from "./config.js";
|
|
2
|
+
/** Minimal fetch signature this client depends on (Node 18+ global `fetch`). */
|
|
3
|
+
export type FetchLike = (input: string, init: {
|
|
4
|
+
method: string;
|
|
5
|
+
headers: Record<string, string>;
|
|
6
|
+
body?: string;
|
|
7
|
+
}) => Promise<{
|
|
8
|
+
ok: boolean;
|
|
9
|
+
status: number;
|
|
10
|
+
json: () => Promise<unknown>;
|
|
11
|
+
text: () => Promise<string>;
|
|
12
|
+
}>;
|
|
13
|
+
/** Raised when the Brain API call fails (network or non-2xx response). */
|
|
14
|
+
export declare class BrainApiError extends Error {
|
|
15
|
+
readonly details: {
|
|
16
|
+
path: string;
|
|
17
|
+
status?: number;
|
|
18
|
+
correlationId: string;
|
|
19
|
+
cause?: string;
|
|
20
|
+
};
|
|
21
|
+
constructor(message: string, details: {
|
|
22
|
+
path: string;
|
|
23
|
+
status?: number;
|
|
24
|
+
correlationId: string;
|
|
25
|
+
cause?: string;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export interface SearchPayload {
|
|
29
|
+
query: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
answerMode?: "private" | "shared";
|
|
32
|
+
}
|
|
33
|
+
export interface AnswerPayload {
|
|
34
|
+
query: string;
|
|
35
|
+
limit?: number;
|
|
36
|
+
answerMode?: "private" | "shared";
|
|
37
|
+
}
|
|
38
|
+
export interface WriteMemoryPayload {
|
|
39
|
+
title: string;
|
|
40
|
+
body: string;
|
|
41
|
+
visibilityPolicyId: string;
|
|
42
|
+
noteType?: "decision" | "sop" | "summary" | "fact";
|
|
43
|
+
}
|
|
44
|
+
export interface ListActionItemsPayload {
|
|
45
|
+
ownerIdentityId?: string;
|
|
46
|
+
status?: "open" | "in_progress" | "blocked" | "done" | "cancelled";
|
|
47
|
+
limit?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface CreateActionItemPayload {
|
|
50
|
+
title: string;
|
|
51
|
+
details?: string;
|
|
52
|
+
ownerIdentityId?: string;
|
|
53
|
+
projectId?: string;
|
|
54
|
+
sourceMessageId?: string;
|
|
55
|
+
visibilityPolicyId?: string;
|
|
56
|
+
dueDate?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface UpdateActionItemPayload {
|
|
59
|
+
id: string;
|
|
60
|
+
status?: "open" | "in_progress" | "blocked" | "done" | "cancelled";
|
|
61
|
+
title?: string;
|
|
62
|
+
dueDate?: string;
|
|
63
|
+
ownerIdentityId?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface CreateReminderPayload {
|
|
66
|
+
remindAfter: string;
|
|
67
|
+
triggerMessageId: string;
|
|
68
|
+
spaceId?: string;
|
|
69
|
+
threadId?: string;
|
|
70
|
+
mentionedIdentityId?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface SummarizeThreadPayload {
|
|
73
|
+
threadId: string;
|
|
74
|
+
}
|
|
75
|
+
export interface PromoteNotePayload {
|
|
76
|
+
noteId: string;
|
|
77
|
+
dryRun?: boolean;
|
|
78
|
+
}
|
|
79
|
+
export interface BrainHttpClientOptions {
|
|
80
|
+
/** Injected for tests; defaults to the global `fetch`. */
|
|
81
|
+
fetchImpl?: FetchLike;
|
|
82
|
+
}
|
|
83
|
+
export declare class BrainHttpClient {
|
|
84
|
+
private readonly baseUrl;
|
|
85
|
+
private readonly token;
|
|
86
|
+
private readonly fetchImpl;
|
|
87
|
+
constructor(config: ConnectorConfig, options?: BrainHttpClientOptions);
|
|
88
|
+
/** Issue an authenticated JSON request. The token resolves the identity. */
|
|
89
|
+
private call;
|
|
90
|
+
search(payload: SearchPayload): Promise<unknown>;
|
|
91
|
+
answer(payload: AnswerPayload): Promise<unknown>;
|
|
92
|
+
writeMemory(payload: WriteMemoryPayload): Promise<unknown>;
|
|
93
|
+
listActionItems(payload: ListActionItemsPayload): Promise<unknown>;
|
|
94
|
+
createActionItem(payload: CreateActionItemPayload): Promise<unknown>;
|
|
95
|
+
updateActionItem(payload: UpdateActionItemPayload): Promise<unknown>;
|
|
96
|
+
createReminder(payload: CreateReminderPayload): Promise<unknown>;
|
|
97
|
+
summarizeThread(payload: SummarizeThreadPayload): Promise<unknown>;
|
|
98
|
+
promoteNote(payload: PromoteNotePayload): Promise<unknown>;
|
|
99
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { newCorrelationId } from "./config.js";
|
|
2
|
+
/** Raised when the Brain API call fails (network or non-2xx response). */
|
|
3
|
+
export class BrainApiError extends Error {
|
|
4
|
+
details;
|
|
5
|
+
constructor(message, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.details = details;
|
|
8
|
+
this.name = "BrainApiError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class BrainHttpClient {
|
|
12
|
+
baseUrl;
|
|
13
|
+
token;
|
|
14
|
+
fetchImpl;
|
|
15
|
+
constructor(config, options = {}) {
|
|
16
|
+
this.baseUrl = config.brainApiUrl.replace(/\/$/, "");
|
|
17
|
+
this.token = config.token;
|
|
18
|
+
const impl = options.fetchImpl ?? globalThis.fetch;
|
|
19
|
+
if (!impl) {
|
|
20
|
+
throw new Error("No fetch implementation available. Use Node 18+ or pass options.fetchImpl.");
|
|
21
|
+
}
|
|
22
|
+
this.fetchImpl = impl;
|
|
23
|
+
}
|
|
24
|
+
/** Issue an authenticated JSON request. The token resolves the identity. */
|
|
25
|
+
async call(method, path, body) {
|
|
26
|
+
const correlationId = newCorrelationId();
|
|
27
|
+
const url = `${this.baseUrl}${path}`;
|
|
28
|
+
let res;
|
|
29
|
+
try {
|
|
30
|
+
res = await this.fetchImpl(url, {
|
|
31
|
+
method,
|
|
32
|
+
headers: {
|
|
33
|
+
"content-type": "application/json",
|
|
34
|
+
authorization: `Bearer ${this.token}`,
|
|
35
|
+
"x-correlation-id": correlationId,
|
|
36
|
+
},
|
|
37
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
throw new BrainApiError("Brain API request failed", { path, correlationId, cause: String(err) });
|
|
42
|
+
}
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
let detail = "";
|
|
45
|
+
try {
|
|
46
|
+
detail = await res.text();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* ignore */
|
|
50
|
+
}
|
|
51
|
+
throw new BrainApiError(`Brain API returned ${res.status}${detail ? `: ${detail}` : ""}`, {
|
|
52
|
+
path,
|
|
53
|
+
status: res.status,
|
|
54
|
+
correlationId,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return (await res.json());
|
|
58
|
+
}
|
|
59
|
+
/* The 9 Brain tools → HTTP paths. requesterId is NEVER sent. */
|
|
60
|
+
search(payload) {
|
|
61
|
+
return this.call("POST", "/v1/search", { ...payload });
|
|
62
|
+
}
|
|
63
|
+
answer(payload) {
|
|
64
|
+
return this.call("POST", "/v1/answer", { ...payload });
|
|
65
|
+
}
|
|
66
|
+
writeMemory(payload) {
|
|
67
|
+
return this.call("POST", "/v1/notes", { ...payload });
|
|
68
|
+
}
|
|
69
|
+
listActionItems(payload) {
|
|
70
|
+
return this.call("POST", "/v1/action-items/query", { ...payload });
|
|
71
|
+
}
|
|
72
|
+
createActionItem(payload) {
|
|
73
|
+
return this.call("POST", "/v1/action-items", { ...payload });
|
|
74
|
+
}
|
|
75
|
+
updateActionItem(payload) {
|
|
76
|
+
const { id, ...rest } = payload;
|
|
77
|
+
return this.call("PATCH", `/v1/action-items/${id}`, { ...rest });
|
|
78
|
+
}
|
|
79
|
+
createReminder(payload) {
|
|
80
|
+
return this.call("POST", "/v1/reminders", { ...payload });
|
|
81
|
+
}
|
|
82
|
+
summarizeThread(payload) {
|
|
83
|
+
return this.call("POST", "/v1/summarize-thread", { ...payload });
|
|
84
|
+
}
|
|
85
|
+
promoteNote(payload) {
|
|
86
|
+
return this.call("POST", "/v1/notes/promote", { ...payload });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=brain-http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brain-http-client.js","sourceRoot":"","sources":["../src/brain-http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { createBrainConnectorServer } from "./server.js";
|
|
4
|
+
import { BrainHttpClient } from "./brain-http-client.js";
|
|
5
|
+
import { loadConfig, ConfigError } from "./config.js";
|
|
6
|
+
/* ---------------------------------------------------------------------------
|
|
7
|
+
* DER-274 — stdio entrypoint.
|
|
8
|
+
*
|
|
9
|
+
* `npx @novaeo/brain-connector` (bin: novaeo-brain-connector) starts a stdio
|
|
10
|
+
* MCP server. Config comes from BRAIN_API_URL + NOVAEO_BRAIN_TOKEN; a missing
|
|
11
|
+
* one prints a clear message to stderr and exits non-zero. All diagnostics go
|
|
12
|
+
* to stderr so stdout stays a clean MCP transport.
|
|
13
|
+
* ------------------------------------------------------------------------- */
|
|
14
|
+
async function main() {
|
|
15
|
+
let config;
|
|
16
|
+
try {
|
|
17
|
+
config = loadConfig();
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
if (e instanceof ConfigError) {
|
|
21
|
+
process.stderr.write(`[novaeo-brain-connector] ${e.message}\n`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
throw e;
|
|
25
|
+
}
|
|
26
|
+
const client = new BrainHttpClient(config);
|
|
27
|
+
const server = createBrainConnectorServer({ client });
|
|
28
|
+
const transport = new StdioServerTransport();
|
|
29
|
+
await server.connect(transport);
|
|
30
|
+
process.stderr.write("[novaeo-brain-connector] connected over stdio.\n");
|
|
31
|
+
}
|
|
32
|
+
main().catch((e) => {
|
|
33
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
34
|
+
process.stderr.write(`[novaeo-brain-connector] fatal: ${message}\n`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;;;+EAO+E;AAE/E,KAAK,UAAU,IAAI;IACjB,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,WAAW,EAAE,CAAC;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC;YAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,0BAA0B,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;AAC3E,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;IAC1B,MAAM,OAAO,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mCAAmC,OAAO,IAAI,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Resolved, validated connector configuration. */
|
|
2
|
+
export interface ConnectorConfig {
|
|
3
|
+
/** Base URL of the Brain API (e.g. https://brain.novaeo.com). */
|
|
4
|
+
brainApiUrl: string;
|
|
5
|
+
/** Per-user Brain token (an `nbk_` token). IS the caller identity. */
|
|
6
|
+
token: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Thrown when required configuration is missing. Carries a clear, actionable
|
|
10
|
+
* message that the CLI surfaces to the user before exiting.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ConfigError extends Error {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read connector config from the environment. Both variables are required;
|
|
17
|
+
* a missing one fails fast with an explicit, copy-pasteable hint.
|
|
18
|
+
*
|
|
19
|
+
* - `BRAIN_API_URL` — base URL of the Brain API.
|
|
20
|
+
* - `NOVAEO_BRAIN_TOKEN`— per-user token sent as `Authorization: Bearer <token>`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): ConnectorConfig;
|
|
23
|
+
/** Correlation id stamped on every tool call for end-to-end audit tracing. */
|
|
24
|
+
export declare function newCorrelationId(): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when required configuration is missing. Carries a clear, actionable
|
|
4
|
+
* message that the CLI surfaces to the user before exiting.
|
|
5
|
+
*/
|
|
6
|
+
export class ConfigError extends Error {
|
|
7
|
+
constructor(message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "ConfigError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Read connector config from the environment. Both variables are required;
|
|
14
|
+
* a missing one fails fast with an explicit, copy-pasteable hint.
|
|
15
|
+
*
|
|
16
|
+
* - `BRAIN_API_URL` — base URL of the Brain API.
|
|
17
|
+
* - `NOVAEO_BRAIN_TOKEN`— per-user token sent as `Authorization: Bearer <token>`.
|
|
18
|
+
*/
|
|
19
|
+
export function loadConfig(env = process.env) {
|
|
20
|
+
const brainApiUrl = env.BRAIN_API_URL?.trim();
|
|
21
|
+
const token = env.NOVAEO_BRAIN_TOKEN?.trim();
|
|
22
|
+
if (!brainApiUrl) {
|
|
23
|
+
throw new ConfigError("Missing required env var BRAIN_API_URL. Set it to your Brain API base URL, e.g. BRAIN_API_URL=https://brain.novaeo.com");
|
|
24
|
+
}
|
|
25
|
+
if (!token) {
|
|
26
|
+
throw new ConfigError("Missing required env var NOVAEO_BRAIN_TOKEN. Set it to your personal Brain token (starts with `nbk_`). Get one from the Connect-your-agent page.");
|
|
27
|
+
}
|
|
28
|
+
// Never send a bearer token over plaintext or to a credential-embedded URL.
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = new URL(brainApiUrl);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new ConfigError(`BRAIN_API_URL is not a valid URL: ${brainApiUrl}`);
|
|
35
|
+
}
|
|
36
|
+
const isLocal = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
37
|
+
if (parsed.protocol !== "https:" && !isLocal) {
|
|
38
|
+
throw new ConfigError("BRAIN_API_URL must use https:// (your token is a bearer credential).");
|
|
39
|
+
}
|
|
40
|
+
if (parsed.username || parsed.password) {
|
|
41
|
+
throw new ConfigError("BRAIN_API_URL must not embed credentials.");
|
|
42
|
+
}
|
|
43
|
+
return { brainApiUrl, token };
|
|
44
|
+
}
|
|
45
|
+
/** Correlation id stamped on every tool call for end-to-end audit tracing. */
|
|
46
|
+
export function newCorrelationId() {
|
|
47
|
+
return `corr_${randomUUID()}`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkBzC;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,WAAW,GAAG,GAAG,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IAE7C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,WAAW,CACnB,wHAAwH,CACzH,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,WAAW,CACnB,kJAAkJ,CACnJ,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,WAAW,CAAC,qCAAqC,WAAW,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,KAAK,WAAW,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW,CAAC;IACnF,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7C,MAAM,IAAI,WAAW,CAAC,sEAAsE,CAAC,CAAC;IAChG,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,WAAW,CAAC,2CAA2C,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB;IAC9B,OAAO,QAAQ,UAAU,EAAE,EAAE,CAAC;AAChC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createBrainConnectorServer, BRAIN_TOOL_NAMES, type CreateServerOptions } from "./server.js";
|
|
2
|
+
export { BrainHttpClient, BrainApiError, type FetchLike, type BrainHttpClientOptions } from "./brain-http-client.js";
|
|
3
|
+
export { loadConfig, ConfigError, newCorrelationId, type ConnectorConfig } from "./config.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,gBAAgB,EAA4B,MAAM,aAAa,CAAC;AACrG,OAAO,EAAE,eAAe,EAAE,aAAa,EAA+C,MAAM,wBAAwB,CAAC;AACrH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAwB,MAAM,aAAa,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { BrainHttpClient } from "./brain-http-client.js";
|
|
3
|
+
export interface CreateServerOptions {
|
|
4
|
+
/** HTTP client to the Brain API. Tests inject one with a mock fetch. */
|
|
5
|
+
client: BrainHttpClient;
|
|
6
|
+
}
|
|
7
|
+
/** The stable, ordered list of tool names this connector exposes. */
|
|
8
|
+
export declare const BRAIN_TOOL_NAMES: readonly ["search_brain", "answer_from_brain", "write_brain_memory", "list_action_items", "create_action_item", "update_action_item", "create_reminder", "summarize_thread", "promote_to_curated_note"];
|
|
9
|
+
/**
|
|
10
|
+
* Build the public Brain MCP server with all nine tools registered. Connect the
|
|
11
|
+
* returned server to a stdio (or any) transport.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createBrainConnectorServer(options: CreateServerOptions): McpServer;
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { BrainHttpClient } from "./brain-http-client.js";
|
|
4
|
+
function ok(data) {
|
|
5
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
6
|
+
}
|
|
7
|
+
function fail(e) {
|
|
8
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
9
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: message }) }], isError: true };
|
|
10
|
+
}
|
|
11
|
+
/** The stable, ordered list of tool names this connector exposes. */
|
|
12
|
+
export const BRAIN_TOOL_NAMES = [
|
|
13
|
+
"search_brain",
|
|
14
|
+
"answer_from_brain",
|
|
15
|
+
"write_brain_memory",
|
|
16
|
+
"list_action_items",
|
|
17
|
+
"create_action_item",
|
|
18
|
+
"update_action_item",
|
|
19
|
+
"create_reminder",
|
|
20
|
+
"summarize_thread",
|
|
21
|
+
"promote_to_curated_note",
|
|
22
|
+
];
|
|
23
|
+
const answerMode = z
|
|
24
|
+
.enum(["private", "shared"])
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("DM (private) vs group/channel (shared). Defaults server-side to private.");
|
|
27
|
+
/**
|
|
28
|
+
* Build the public Brain MCP server with all nine tools registered. Connect the
|
|
29
|
+
* returned server to a stdio (or any) transport.
|
|
30
|
+
*/
|
|
31
|
+
export function createBrainConnectorServer(options) {
|
|
32
|
+
const { client } = options;
|
|
33
|
+
const server = new McpServer({ name: "novaeo-brain-connector", version: "0.1.0" });
|
|
34
|
+
// 1. search_brain → POST /v1/search
|
|
35
|
+
server.registerTool("search_brain", {
|
|
36
|
+
description: "Search company memory for relevant snippets (permission-filtered to your access). Returns ranked results with citations.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
query: z.string().min(1).describe("What to search for."),
|
|
39
|
+
limit: z.number().int().positive().max(50).optional(),
|
|
40
|
+
answerMode,
|
|
41
|
+
},
|
|
42
|
+
}, async (args) => {
|
|
43
|
+
try {
|
|
44
|
+
return ok(await client.search(args));
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
return fail(e);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// 2. answer_from_brain → POST /v1/answer
|
|
51
|
+
server.registerTool("answer_from_brain", {
|
|
52
|
+
description: "Answer a question grounded in company memory, permission-filtered to your access, with source citations.",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
query: z.string().min(1).describe("The question to answer."),
|
|
55
|
+
limit: z.number().int().positive().max(50).optional(),
|
|
56
|
+
answerMode,
|
|
57
|
+
},
|
|
58
|
+
}, async (args) => {
|
|
59
|
+
try {
|
|
60
|
+
return ok(await client.answer(args));
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
return fail(e);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
// 3. write_brain_memory → POST /v1/notes
|
|
67
|
+
server.registerTool("write_brain_memory", {
|
|
68
|
+
description: "Write a memory (draft note) into the brain under a given visibility policy.",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
title: z.string().min(1),
|
|
71
|
+
body: z.string().min(1),
|
|
72
|
+
visibilityPolicyId: z.string().uuid().describe("Visibility policy the note inherits."),
|
|
73
|
+
noteType: z.enum(["decision", "sop", "summary", "fact"]).optional(),
|
|
74
|
+
},
|
|
75
|
+
}, async (args) => {
|
|
76
|
+
try {
|
|
77
|
+
return ok(await client.writeMemory(args));
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
return fail(e);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
// 4. list_action_items → POST /v1/action-items/query
|
|
84
|
+
server.registerTool("list_action_items", {
|
|
85
|
+
description: "List action items (permission-filtered). Defaults to your own items; an owner filter for another user requires admin.",
|
|
86
|
+
inputSchema: {
|
|
87
|
+
ownerIdentityId: z.string().uuid().optional(),
|
|
88
|
+
status: z.enum(["open", "in_progress", "blocked", "done", "cancelled"]).optional(),
|
|
89
|
+
limit: z.number().int().positive().max(100).optional(),
|
|
90
|
+
},
|
|
91
|
+
}, async (args) => {
|
|
92
|
+
try {
|
|
93
|
+
return ok(await client.listActionItems(args));
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
return fail(e);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// 5. create_action_item → POST /v1/action-items
|
|
100
|
+
server.registerTool("create_action_item", {
|
|
101
|
+
description: "Create an action item with an owner, optional project, source message, and due date.",
|
|
102
|
+
inputSchema: {
|
|
103
|
+
title: z.string().min(1),
|
|
104
|
+
details: z.string().optional(),
|
|
105
|
+
ownerIdentityId: z.string().uuid().optional(),
|
|
106
|
+
projectId: z.string().uuid().optional(),
|
|
107
|
+
sourceMessageId: z.string().uuid().optional().describe("Message the item derives visibility from."),
|
|
108
|
+
visibilityPolicyId: z.string().uuid().optional().describe("Explicit visibility policy if no source message."),
|
|
109
|
+
dueDate: z.string().optional(),
|
|
110
|
+
},
|
|
111
|
+
}, async (args) => {
|
|
112
|
+
try {
|
|
113
|
+
return ok(await client.createActionItem(args));
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
return fail(e);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// 6. update_action_item → PATCH /v1/action-items/:id
|
|
120
|
+
server.registerTool("update_action_item", {
|
|
121
|
+
description: "Update an action item's status or fields. Only the owner or an admin may modify it.",
|
|
122
|
+
inputSchema: {
|
|
123
|
+
id: z.string().uuid(),
|
|
124
|
+
status: z.enum(["open", "in_progress", "blocked", "done", "cancelled"]).optional(),
|
|
125
|
+
title: z.string().min(1).optional(),
|
|
126
|
+
dueDate: z.string().optional(),
|
|
127
|
+
ownerIdentityId: z.string().uuid().optional(),
|
|
128
|
+
},
|
|
129
|
+
}, async (args) => {
|
|
130
|
+
try {
|
|
131
|
+
return ok(await client.updateActionItem(args));
|
|
132
|
+
}
|
|
133
|
+
catch (e) {
|
|
134
|
+
return fail(e);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
// 7. create_reminder → POST /v1/reminders
|
|
138
|
+
server.registerTool("create_reminder", {
|
|
139
|
+
description: "Create a reminder that fires after a given time, inheriting the trigger message's visibility.",
|
|
140
|
+
inputSchema: {
|
|
141
|
+
remindAfter: z.string().describe("ISO timestamp to remind after."),
|
|
142
|
+
triggerMessageId: z.string().uuid().describe("Message the reminder derives visibility from."),
|
|
143
|
+
spaceId: z.string().uuid().optional(),
|
|
144
|
+
threadId: z.string().optional(),
|
|
145
|
+
mentionedIdentityId: z.string().uuid().optional(),
|
|
146
|
+
},
|
|
147
|
+
}, async (args) => {
|
|
148
|
+
try {
|
|
149
|
+
return ok(await client.createReminder(args));
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
return fail(e);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
// 8. summarize_thread → POST /v1/summarize-thread
|
|
156
|
+
server.registerTool("summarize_thread", {
|
|
157
|
+
description: "Summarize a chat thread (permission-filtered) into a short, cited summary.",
|
|
158
|
+
inputSchema: {
|
|
159
|
+
threadId: z.string().min(1),
|
|
160
|
+
},
|
|
161
|
+
}, async (args) => {
|
|
162
|
+
try {
|
|
163
|
+
return ok(await client.summarizeThread(args));
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
return fail(e);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
// 9. promote_to_curated_note → POST /v1/notes/promote
|
|
170
|
+
server.registerTool("promote_to_curated_note", {
|
|
171
|
+
description: "Promote a reviewed brain note into the curated novaeo-brain vault. Defaults to a dry run; sensitive promotions require admin.",
|
|
172
|
+
inputSchema: {
|
|
173
|
+
noteId: z.string().uuid(),
|
|
174
|
+
dryRun: z.boolean().optional().describe("Preview without writing. Defaults to true server-side."),
|
|
175
|
+
},
|
|
176
|
+
}, async (args) => {
|
|
177
|
+
try {
|
|
178
|
+
return ok(await client.promoteNote(args));
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
return fail(e);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
return server;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@novaeo/brain-connector",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Standalone stdio MCP connector for the Novaeo Brain. Exposes search, answer, memory, action-item, reminder, summarize, and promote tools over HTTPS using a per-user token.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"novaeo-brain-connector": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"prepublishOnly": "tsc",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"start": "node ./dist/cli.js"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mcp",
|
|
30
|
+
"model-context-protocol",
|
|
31
|
+
"novaeo",
|
|
32
|
+
"brain",
|
|
33
|
+
"connector"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
40
|
+
"zod": "^3.24.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.10.0",
|
|
44
|
+
"typescript": "^5.7.2",
|
|
45
|
+
"vitest": "^2.1.8"
|
|
46
|
+
}
|
|
47
|
+
}
|