@naumu/mcp 0.3.1 → 0.4.1
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 +7 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +25 -5
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +32 -1
- package/dist/errors.js +44 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/tools/add-attribute.d.ts +3 -0
- package/dist/tools/add-attribute.js +43 -0
- package/dist/tools/add-attribute.js.map +1 -0
- package/dist/tools/add-connection.d.ts +3 -0
- package/dist/tools/add-connection.js +46 -0
- package/dist/tools/add-connection.js.map +1 -0
- package/dist/tools/add-edge.js +21 -13
- package/dist/tools/add-edge.js.map +1 -1
- package/dist/tools/add-node-type.d.ts +3 -0
- package/dist/tools/add-node-type.js +54 -0
- package/dist/tools/add-node-type.js.map +1 -0
- package/dist/tools/add-node.js +24 -13
- package/dist/tools/add-node.js.map +1 -1
- package/dist/tools/add-reaction.d.ts +3 -0
- package/dist/tools/add-reaction.js +34 -0
- package/dist/tools/add-reaction.js.map +1 -0
- package/dist/tools/ask-naumu.d.ts +3 -0
- package/dist/tools/ask-naumu.js +44 -0
- package/dist/tools/ask-naumu.js.map +1 -0
- package/dist/tools/canvas-add-element.d.ts +3 -0
- package/dist/tools/canvas-add-element.js +46 -0
- package/dist/tools/canvas-add-element.js.map +1 -0
- package/dist/tools/canvas-remove-element.d.ts +3 -0
- package/dist/tools/canvas-remove-element.js +17 -0
- package/dist/tools/canvas-remove-element.js.map +1 -0
- package/dist/tools/canvas-update-element.d.ts +3 -0
- package/dist/tools/canvas-update-element.js +20 -0
- package/dist/tools/canvas-update-element.js.map +1 -0
- package/dist/tools/create-canvas.d.ts +3 -0
- package/dist/tools/create-canvas.js +17 -0
- package/dist/tools/create-canvas.js.map +1 -0
- package/dist/tools/create-note.d.ts +3 -0
- package/dist/tools/create-note.js +17 -0
- package/dist/tools/create-note.js.map +1 -0
- package/dist/tools/create-thread.d.ts +3 -0
- package/dist/tools/create-thread.js +63 -0
- package/dist/tools/create-thread.js.map +1 -0
- package/dist/tools/get-canvas-elements.d.ts +3 -0
- package/dist/tools/get-canvas-elements.js +16 -0
- package/dist/tools/get-canvas-elements.js.map +1 -0
- package/dist/tools/get-canvas-image.d.ts +3 -0
- package/dist/tools/get-canvas-image.js +77 -0
- package/dist/tools/get-canvas-image.js.map +1 -0
- package/dist/tools/get-thread.d.ts +3 -0
- package/dist/tools/get-thread.js +25 -0
- package/dist/tools/get-thread.js.map +1 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +118 -16
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-canvases.d.ts +3 -0
- package/dist/tools/list-canvases.js +16 -0
- package/dist/tools/list-canvases.js.map +1 -0
- package/dist/tools/list-schema-violations.d.ts +3 -0
- package/dist/tools/list-schema-violations.js +16 -0
- package/dist/tools/list-schema-violations.js.map +1 -0
- package/dist/tools/list-threads.d.ts +3 -0
- package/dist/tools/list-threads.js +43 -0
- package/dist/tools/list-threads.js.map +1 -0
- package/dist/tools/naumu-typing.d.ts +3 -0
- package/dist/tools/naumu-typing.js +30 -0
- package/dist/tools/naumu-typing.js.map +1 -0
- package/dist/tools/note-append.d.ts +3 -0
- package/dist/tools/note-append.js +17 -0
- package/dist/tools/note-append.js.map +1 -0
- package/dist/tools/note-delete-section.d.ts +3 -0
- package/dist/tools/note-delete-section.js +22 -0
- package/dist/tools/note-delete-section.js.map +1 -0
- package/dist/tools/note-find-replace.d.ts +3 -0
- package/dist/tools/note-find-replace.js +26 -0
- package/dist/tools/note-find-replace.js.map +1 -0
- package/dist/tools/note-insert.d.ts +3 -0
- package/dist/tools/note-insert.js +24 -0
- package/dist/tools/note-insert.js.map +1 -0
- package/dist/tools/note-read.d.ts +3 -0
- package/dist/tools/note-read.js +16 -0
- package/dist/tools/note-read.js.map +1 -0
- package/dist/tools/note-replace-section.d.ts +3 -0
- package/dist/tools/note-replace-section.js +26 -0
- package/dist/tools/note-replace-section.js.map +1 -0
- package/dist/tools/note-replace.d.ts +3 -0
- package/dist/tools/note-replace.js +17 -0
- package/dist/tools/note-replace.js.map +1 -0
- package/dist/tools/post-message.d.ts +3 -0
- package/dist/tools/post-message.js +45 -0
- package/dist/tools/post-message.js.map +1 -0
- package/dist/tools/react-to-message.d.ts +3 -0
- package/dist/tools/react-to-message.js +34 -0
- package/dist/tools/react-to-message.js.map +1 -0
- package/dist/tools/read-thread.d.ts +3 -0
- package/dist/tools/read-thread.js +43 -0
- package/dist/tools/read-thread.js.map +1 -0
- package/dist/tools/remove-edge.js +14 -11
- package/dist/tools/remove-edge.js.map +1 -1
- package/dist/tools/remove-reaction.d.ts +3 -0
- package/dist/tools/remove-reaction.js +34 -0
- package/dist/tools/remove-reaction.js.map +1 -0
- package/dist/tools/request-attachment-upload.d.ts +3 -0
- package/dist/tools/request-attachment-upload.js +59 -0
- package/dist/tools/request-attachment-upload.js.map +1 -0
- package/dist/tools/update-schema.d.ts +3 -0
- package/dist/tools/update-schema.js +48 -0
- package/dist/tools/update-schema.js.map +1 -0
- package/dist/tools/whoami.d.ts +3 -0
- package/dist/tools/whoami.js +23 -0
- package/dist/tools/whoami.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,13 @@ Add to your Cursor MCP settings:
|
|
|
53
53
|
| `naumu_remove_edge` | Delete a relationship |
|
|
54
54
|
| `naumu_ask` | Ask the Naumu AI agent a question about your graph |
|
|
55
55
|
| `naumu_get_ai_thread` | Retrieve messages from a previous AI conversation |
|
|
56
|
+
| `naumu_whoami` | (Bot keys) Self-introspection — id, graphId, name, instructions, allowed tools |
|
|
57
|
+
| `naumu_list_threads` | (Bot keys) List threads in your graph with `isParticipant` flag |
|
|
58
|
+
| `naumu_get_thread` | (Bot keys) Fetch a thread plus its human + bot participant rosters |
|
|
59
|
+
| `naumu_create_thread` | (Bot keys) Start a new conversation, attach participants, post initial message |
|
|
60
|
+
| `naumu_request_attachment_upload` | (Bot keys) Get a presigned S3 URL to upload a file; pair with `naumu_post_message`'s `attachmentIds` |
|
|
61
|
+
| `naumu_add_reaction` | (Bot keys) Add an emoji reaction to a message in a thread you participate in (idempotent) |
|
|
62
|
+
| `naumu_remove_reaction` | (Bot keys) Remove your own reaction from a message |
|
|
56
63
|
|
|
57
64
|
## Environment variables
|
|
58
65
|
|
package/dist/client.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export declare class NaumuClient {
|
|
|
5
5
|
private headers;
|
|
6
6
|
private handleResponse;
|
|
7
7
|
get(path: string): Promise<unknown>;
|
|
8
|
+
getBinary(path: string): Promise<{
|
|
9
|
+
buffer: Uint8Array;
|
|
10
|
+
contentType: string;
|
|
11
|
+
}>;
|
|
8
12
|
post(path: string, body?: unknown): Promise<unknown>;
|
|
9
13
|
patch(path: string, body: unknown): Promise<unknown>;
|
|
10
14
|
del(path: string, body?: unknown): Promise<unknown>;
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NaumuApiError } from './errors.js';
|
|
1
|
+
import { NaumuApiError, safeErrorMessage } from './errors.js';
|
|
2
2
|
export class NaumuClient {
|
|
3
3
|
baseUrl;
|
|
4
4
|
apiKey;
|
|
@@ -15,15 +15,19 @@ export class NaumuClient {
|
|
|
15
15
|
async handleResponse(res) {
|
|
16
16
|
if (!res.ok) {
|
|
17
17
|
const text = await res.text().catch(() => 'Unknown error');
|
|
18
|
-
let
|
|
18
|
+
let upstream;
|
|
19
19
|
try {
|
|
20
20
|
const json = JSON.parse(text);
|
|
21
|
-
|
|
21
|
+
upstream = json.message || text;
|
|
22
22
|
}
|
|
23
23
|
catch {
|
|
24
|
-
|
|
24
|
+
upstream = text;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
// Log the raw upstream message server-side for debugging, but throw
|
|
27
|
+
// a safe-mapped one so 403/404 differentials don't leak through to
|
|
28
|
+
// the model.
|
|
29
|
+
console.error(`[mcp] upstream ${res.status}: ${upstream.slice(0, 500)}`);
|
|
30
|
+
throw new NaumuApiError(res.status, safeErrorMessage(res.status, upstream), upstream);
|
|
27
31
|
}
|
|
28
32
|
return res.json();
|
|
29
33
|
}
|
|
@@ -34,6 +38,22 @@ export class NaumuClient {
|
|
|
34
38
|
});
|
|
35
39
|
return this.handleResponse(res);
|
|
36
40
|
}
|
|
41
|
+
async getBinary(path) {
|
|
42
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
43
|
+
method: 'GET',
|
|
44
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const upstream = await res.text().catch(() => 'Unknown error');
|
|
48
|
+
console.error(`[mcp] upstream binary ${res.status}: ${upstream.slice(0, 500)}`);
|
|
49
|
+
throw new NaumuApiError(res.status, safeErrorMessage(res.status, upstream), upstream);
|
|
50
|
+
}
|
|
51
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
52
|
+
return {
|
|
53
|
+
buffer: new Uint8Array(arrayBuffer),
|
|
54
|
+
contentType: res.headers.get('content-type') ?? 'application/octet-stream',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
37
57
|
async post(path, body) {
|
|
38
58
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
39
59
|
method: 'POST',
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
export declare class NaumuApiError extends Error {
|
|
2
2
|
readonly status: number;
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Raw upstream message — captured for server-side logging only. Never
|
|
5
|
+
* pipe this to model output: it can carry 403/404 differential signal
|
|
6
|
+
* (e.g. "Thread not found" vs "Role 'X' cannot perform 'thread:post'")
|
|
7
|
+
* which lets a malicious caller enumerate resources they don't have
|
|
8
|
+
* access to. Tools should surface `error.message` (the safe-mapped
|
|
9
|
+
* version) instead.
|
|
10
|
+
*/
|
|
11
|
+
readonly upstreamMessage?: string | undefined;
|
|
12
|
+
constructor(status: number, message: string,
|
|
13
|
+
/**
|
|
14
|
+
* Raw upstream message — captured for server-side logging only. Never
|
|
15
|
+
* pipe this to model output: it can carry 403/404 differential signal
|
|
16
|
+
* (e.g. "Thread not found" vs "Role 'X' cannot perform 'thread:post'")
|
|
17
|
+
* which lets a malicious caller enumerate resources they don't have
|
|
18
|
+
* access to. Tools should surface `error.message` (the safe-mapped
|
|
19
|
+
* version) instead.
|
|
20
|
+
*/
|
|
21
|
+
upstreamMessage?: string | undefined);
|
|
4
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Map an HTTP status + raw upstream message to a model-safe error string.
|
|
25
|
+
*
|
|
26
|
+
* The 403/404 collapse is the security mitigation: bots can otherwise
|
|
27
|
+
* enumerate threads / attachments / nodes they don't own by reading the
|
|
28
|
+
* differential between "not found" and "forbidden" responses.
|
|
29
|
+
*
|
|
30
|
+
* 400/422 messages pass through verbatim because they describe what the
|
|
31
|
+
* caller did wrong (malformed input, validation failure) — the bot needs
|
|
32
|
+
* that detail to fix its own request, and the messages are derived from
|
|
33
|
+
* its own input rather than server-side state.
|
|
34
|
+
*/
|
|
35
|
+
export declare function safeErrorMessage(status: number, upstream: string): string;
|
package/dist/errors.js
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
export class NaumuApiError extends Error {
|
|
2
2
|
status;
|
|
3
|
-
|
|
3
|
+
upstreamMessage;
|
|
4
|
+
constructor(status, message,
|
|
5
|
+
/**
|
|
6
|
+
* Raw upstream message — captured for server-side logging only. Never
|
|
7
|
+
* pipe this to model output: it can carry 403/404 differential signal
|
|
8
|
+
* (e.g. "Thread not found" vs "Role 'X' cannot perform 'thread:post'")
|
|
9
|
+
* which lets a malicious caller enumerate resources they don't have
|
|
10
|
+
* access to. Tools should surface `error.message` (the safe-mapped
|
|
11
|
+
* version) instead.
|
|
12
|
+
*/
|
|
13
|
+
upstreamMessage) {
|
|
4
14
|
super(message);
|
|
5
15
|
this.status = status;
|
|
16
|
+
this.upstreamMessage = upstreamMessage;
|
|
6
17
|
this.name = 'NaumuApiError';
|
|
7
18
|
}
|
|
8
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Map an HTTP status + raw upstream message to a model-safe error string.
|
|
22
|
+
*
|
|
23
|
+
* The 403/404 collapse is the security mitigation: bots can otherwise
|
|
24
|
+
* enumerate threads / attachments / nodes they don't own by reading the
|
|
25
|
+
* differential between "not found" and "forbidden" responses.
|
|
26
|
+
*
|
|
27
|
+
* 400/422 messages pass through verbatim because they describe what the
|
|
28
|
+
* caller did wrong (malformed input, validation failure) — the bot needs
|
|
29
|
+
* that detail to fix its own request, and the messages are derived from
|
|
30
|
+
* its own input rather than server-side state.
|
|
31
|
+
*/
|
|
32
|
+
export function safeErrorMessage(status, upstream) {
|
|
33
|
+
if (status === 400 || status === 422)
|
|
34
|
+
return upstream;
|
|
35
|
+
if (status === 401)
|
|
36
|
+
return 'Unauthorized — check your API key.';
|
|
37
|
+
if (status === 403 || status === 404) {
|
|
38
|
+
return 'Resource not found, or you do not have access to it.';
|
|
39
|
+
}
|
|
40
|
+
if (status === 409)
|
|
41
|
+
return 'Conflict with current state.';
|
|
42
|
+
if (status === 410)
|
|
43
|
+
return 'Resource is no longer available.';
|
|
44
|
+
if (status === 413)
|
|
45
|
+
return 'Payload too large.';
|
|
46
|
+
if (status === 429)
|
|
47
|
+
return 'Rate limit exceeded — slow down and retry.';
|
|
48
|
+
if (status >= 500)
|
|
49
|
+
return 'Server error — try again shortly.';
|
|
50
|
+
return `Request failed with status ${status}.`;
|
|
51
|
+
}
|
|
9
52
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEtB;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,aAAc,SAAQ,KAAK;IAEtB;IAUA;IAXjB,YACiB,MAAc,EAC9B,OAAe;IACf;;;;;;;OAOG;IACa,eAAwB;QAExC,KAAK,CAAC,OAAO,CAAC,CAAC;QAZC,WAAM,GAAN,MAAM,CAAQ;QAUd,oBAAe,GAAf,eAAe,CAAS;QAGxC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC7B,CAAC;CACD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,QAAgB;IAChE,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC;IACtD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,oCAAoC,CAAC;IAChE,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACtC,OAAO,sDAAsD,CAAC;IAC/D,CAAC;IACD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,8BAA8B,CAAC;IAC1D,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,kCAAkC,CAAC;IAC9D,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,oBAAoB,CAAC;IAChD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,4CAA4C,CAAC;IACxE,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,mCAAmC,CAAC;IAC9D,OAAO,8BAA8B,MAAM,GAAG,CAAC;AAChD,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { NaumuClient } from './client.js';
|
|
5
|
-
import { registerAllTools } from './tools/index.js';
|
|
5
|
+
import { registerAllTools, registerNamedTools } from './tools/index.js';
|
|
6
6
|
const DEFAULT_API_URL = 'https://naumu.ai';
|
|
7
|
+
const BOT_KEY_PREFIX = 'nmu_bot_';
|
|
7
8
|
const apiUrl = (process.env.NAUMU_API_URL || DEFAULT_API_URL).replace(/\/api\/?$/, '');
|
|
8
9
|
const apiKey = process.env.NAUMU_API_KEY;
|
|
9
10
|
if (!apiKey) {
|
|
@@ -38,11 +39,30 @@ Localhost URLs (http://localhost:3000/spaces/{slug}/...) follow the same shape
|
|
|
38
39
|
const client = new NaumuClient(apiUrl, apiKey);
|
|
39
40
|
const server = new McpServer({
|
|
40
41
|
name: 'naumu',
|
|
41
|
-
version: '0.
|
|
42
|
+
version: '0.4.0',
|
|
42
43
|
}, {
|
|
43
44
|
instructions: NAUMU_INSTRUCTIONS,
|
|
44
45
|
});
|
|
45
|
-
|
|
46
|
+
// Bot keys (`nmu_bot_*`) get a filtered tool surface — the backend computes
|
|
47
|
+
// the allowed set from the Identity's `allowedTools`. User keys keep the full
|
|
48
|
+
// surface (no per-Identity scoping applies).
|
|
49
|
+
const isBotKey = apiKey.startsWith(BOT_KEY_PREFIX);
|
|
50
|
+
if (isBotKey) {
|
|
51
|
+
try {
|
|
52
|
+
const manifest = (await client.get('/api/identities/me/mcp-tool-manifest'));
|
|
53
|
+
registerNamedTools(server, client, manifest.mcpTools);
|
|
54
|
+
console.error(`[mcp] connected to ${apiUrl} as bot identity ${manifest.identityId} (${manifest.intelligenceKind}); ${manifest.mcpTools.length} tool(s) registered`);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
58
|
+
console.error(`[mcp] failed to fetch tool manifest: ${message}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
registerAllTools(server, client);
|
|
64
|
+
console.error(`[mcp] connected to ${apiUrl} as user key (${process.env.NAUMU_IDENTITY_ID ?? 'no identity id set'})`);
|
|
65
|
+
}
|
|
46
66
|
const transport = new StdioServerTransport();
|
|
47
67
|
await server.connect(transport);
|
|
48
68
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAExE,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAC3C,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,eAAe,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;AACvF,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;AAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,kBAAkB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;wOAwB6M,CAAC;AAEzO,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE/C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC3B;IACC,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;CAChB,EACD;IACC,YAAY,EAAE,kBAAkB;CAChC,CACD,CAAC;AAEF,4EAA4E;AAC5E,8EAA8E;AAC9E,6CAA6C;AAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnD,IAAI,QAAQ,EAAE,CAAC;IACd,IAAI,CAAC;QACJ,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAKzE,CAAC;QACF,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACtD,OAAO,CAAC,KAAK,CACZ,sBAAsB,MAAM,oBAAoB,QAAQ,CAAC,UAAU,KAAK,QAAQ,CAAC,gBAAgB,MAAM,QAAQ,CAAC,QAAQ,CAAC,MAAM,qBAAqB,CACpJ,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,wCAAwC,OAAO,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;AACF,CAAC;KAAM,CAAC;IACP,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,KAAK,CACZ,sBAAsB,MAAM,iBAAiB,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,oBAAoB,GAAG,CACrG,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerAddAttribute(server, client) {
|
|
3
|
+
server.registerTool('naumu_add_attribute', {
|
|
4
|
+
title: 'Add Attribute to Node Type',
|
|
5
|
+
description: 'Add or extend an attribute on an existing node type. If the attribute name doesn\'t exist, it is created. If it exists and is a select/multiselect, new values are merged in (existing values kept). Use type "select"/"multiselect" with values; "string"/"number"/"date" for free-form fields (pass values: []).',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
graphId: z.string(),
|
|
8
|
+
node_type: z.string().describe('Existing node type to add the attribute to.'),
|
|
9
|
+
name: z.string().describe('Attribute key (e.g. "stage", "status").'),
|
|
10
|
+
type: z.enum(['select', 'multiselect', 'string', 'number', 'date']).default('select'),
|
|
11
|
+
values: z.array(z.object({ label: z.string(), color: z.string().optional() })).default([]),
|
|
12
|
+
}),
|
|
13
|
+
}, async ({ graphId, node_type, name, type, values }) => {
|
|
14
|
+
const current = (await client.get(`/api/graphs/${graphId}/schema`));
|
|
15
|
+
const schema = current.definition ? JSON.parse(current.definition) : { nodes: [] };
|
|
16
|
+
const node = schema.nodes.find((n) => n.type === node_type);
|
|
17
|
+
if (!node) {
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Node type "${node_type}" not found. Add it first via naumu_add_node_type.` }, null, 2) }],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
node.attributes = node.attributes ?? [];
|
|
23
|
+
const existing = node.attributes.find((a) => a.name === name);
|
|
24
|
+
let action;
|
|
25
|
+
if (!existing) {
|
|
26
|
+
node.attributes.push({ name, type, values });
|
|
27
|
+
action = `Created attribute "${name}" (${type}) with ${values.length} value(s).`;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const existingLabels = new Set((existing.values ?? []).map((v) => v.label));
|
|
31
|
+
const added = values.filter((v) => !existingLabels.has(v.label));
|
|
32
|
+
existing.values = [...(existing.values ?? []), ...added];
|
|
33
|
+
action = added.length > 0
|
|
34
|
+
? `Extended attribute "${name}" with ${added.length} new value(s); kept ${existingLabels.size} existing.`
|
|
35
|
+
: `Attribute "${name}" already had all proposed values; no change.`;
|
|
36
|
+
}
|
|
37
|
+
await client.post(`/api/graphs/${graphId}/schema`, { definition: schema });
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: 'text', text: JSON.stringify({ message: action, node_type }, null, 2) }],
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=add-attribute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-attribute.js","sourceRoot":"","sources":["../../src/tools/add-attribute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerAddConnection(server, client) {
|
|
3
|
+
server.registerTool('naumu_add_connection', {
|
|
4
|
+
title: 'Add Connection to Node Type',
|
|
5
|
+
description: 'Add one connection from an existing node type to another. `kind`: "parent" (sets/replaces — every non-root type needs exactly one parent; only ONE type in the whole schema has no parent), "required" (must exist on instances), "suggested" (optional). Each connection is XOR: ONE concrete target_node OR polymorphic=true — never both. DEFAULT TO CONCRETE target_node. Polymorphic is the ESCAPE HATCH — reserve for genuinely cross-cutting relations (e.g. a Tag-style relation that validly applies to many distinct types). If you can\'t pick a concrete target, you may be missing a type — add it first instead of falling back to polymorphic. Same-type nesting (e.g. Topic under Topic) does NOT need a new connection — use the existing parent relation. Relation name UPPER_SNAKE_CASE.',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
graphId: z.string(),
|
|
8
|
+
source_type: z.string().describe('Existing node type to add the connection to.'),
|
|
9
|
+
relation: z.string().describe('UPPER_SNAKE_CASE relation name.'),
|
|
10
|
+
target_node: z.string().optional().describe('Target type. Omit when polymorphic=true.'),
|
|
11
|
+
polymorphic: z.boolean().optional(),
|
|
12
|
+
kind: z.enum(['required', 'suggested', 'parent']).default('suggested'),
|
|
13
|
+
}),
|
|
14
|
+
}, async ({ graphId, source_type, relation, target_node, polymorphic, kind }) => {
|
|
15
|
+
const current = (await client.get(`/api/graphs/${graphId}/schema`));
|
|
16
|
+
const schema = current.definition ? JSON.parse(current.definition) : { nodes: [] };
|
|
17
|
+
const node = schema.nodes.find((n) => n.type === source_type);
|
|
18
|
+
if (!node) {
|
|
19
|
+
return {
|
|
20
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Node type "${source_type}" not found. Add it first via naumu_add_node_type.` }, null, 2) }],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const conn = { relation, ...(polymorphic ? { polymorphic: true } : {}), ...(target_node ? { target_node } : {}) };
|
|
24
|
+
if (!node.connections)
|
|
25
|
+
node.connections = { required: [], suggested: [] };
|
|
26
|
+
if (kind === 'parent') {
|
|
27
|
+
node.connections.parent = conn;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const list = node.connections[kind] ?? [];
|
|
31
|
+
const exists = list.some((c) => c.relation === relation && c.target_node === target_node && Boolean(c.polymorphic) === Boolean(polymorphic));
|
|
32
|
+
if (exists) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: JSON.stringify({ message: `Connection already exists on "${source_type}", no change.` }, null, 2) }],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
list.push(conn);
|
|
38
|
+
node.connections[kind] = list;
|
|
39
|
+
}
|
|
40
|
+
await client.post(`/api/graphs/${graphId}/schema`, { definition: schema });
|
|
41
|
+
return {
|
|
42
|
+
content: [{ type: 'text', text: JSON.stringify({ message: `Added ${kind} connection ${relation}${target_node ? ` → ${target_node}` : ' (polymorphic)'} on "${source_type}".` }, null, 2) }],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=add-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-connection.js","sourceRoot":"","sources":["../../src/tools/add-connection.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/add-edge.js
CHANGED
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
const EdgeInput = z.object({
|
|
3
|
+
source: z.string().describe('Source node ID'),
|
|
4
|
+
target: z.string().describe('Target node ID'),
|
|
5
|
+
label: z.string().describe('Relationship type (e.g. RELATES_TO, SOLVES, TRACKS)'),
|
|
6
|
+
isParent: z.boolean().optional().describe('Whether this is a parent relationship'),
|
|
7
|
+
});
|
|
2
8
|
export function registerAddEdge(server, client) {
|
|
3
9
|
server.registerTool('naumu_add_edge', {
|
|
4
|
-
title: 'Add
|
|
5
|
-
description: '
|
|
10
|
+
title: 'Add Edges (bulk)',
|
|
11
|
+
description: 'Create 1–25 relationships (edges) between existing nodes in a single call. Keep batches small and atomic (5–25 edges) so failures stay contained. Typical workflow after a bulk import: create nodes with `naumu_add_node`, then wire them up with batched `naumu_add_edge` calls. **Direction matters and must match the schema.** Each edge\'s `(source.type, label, target.type)` tuple should appear in the schema\'s `connections` or `parent` for the source type. Wrong direction or wrong target type silently passes here but surfaces as `invalid_connection_target` / `parent_mismatch` violations later — check `naumu_get_schema` and flip / drop offending edges before calling. **Prefer `naumu_ask`** when you want the agent to discover the right connections itself.',
|
|
6
12
|
inputSchema: z.object({
|
|
7
13
|
graphId: z.string().describe('The graph ID'),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
edges: z
|
|
15
|
+
.array(EdgeInput)
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(25)
|
|
18
|
+
.describe('Batch of 1–25 edges to create. Keep batches small for atomicity.'),
|
|
12
19
|
}),
|
|
13
|
-
}, async ({ graphId,
|
|
14
|
-
const
|
|
15
|
-
source,
|
|
16
|
-
target,
|
|
17
|
-
label,
|
|
18
|
-
isParent: isParent || false,
|
|
19
|
-
});
|
|
20
|
+
}, async ({ graphId, edges }) => {
|
|
21
|
+
const payload = edges.map((e) => ({
|
|
22
|
+
source: e.source,
|
|
23
|
+
target: e.target,
|
|
24
|
+
label: e.label,
|
|
25
|
+
isParent: e.isParent || false,
|
|
26
|
+
}));
|
|
27
|
+
const data = await client.post(`/api/graphs/${graphId}/edges`, { edges: payload });
|
|
20
28
|
return {
|
|
21
29
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
22
30
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-edge.js","sourceRoot":"","sources":["../../src/tools/add-edge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,
|
|
1
|
+
{"version":3,"file":"add-edge.js","sourceRoot":"","sources":["../../src/tools/add-edge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAC7C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;IACjF,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;CAClF,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,MAAmB;IACrE,MAAM,CAAC,YAAY,CAClB,gBAAgB,EAChB;QACC,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACV,yvBAAyvB;QAC1vB,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACrB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;YAC5C,KAAK,EAAE,CAAC;iBACN,KAAK,CAAC,SAAS,CAAC;iBAChB,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,QAAQ,CAAC,kEAAkE,CAAC;SAC9E,CAAC;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;SAC7B,CAAC,CAAC,CAAC;QAEJ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,OAAO,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACnF,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACzE,CAAC;IACH,CAAC,CACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const ConnectionSchema = z.object({
|
|
3
|
+
relation: z.string().describe('UPPER_SNAKE_CASE relation name (WORKS_AT, BELONGS_TO).'),
|
|
4
|
+
target_node: z.string().optional().describe('Target type name. Omit when polymorphic=true.'),
|
|
5
|
+
polymorphic: z.boolean().optional().describe('True when this relation can target many types.'),
|
|
6
|
+
});
|
|
7
|
+
const AttributeValueSchema = z.object({
|
|
8
|
+
label: z.string(),
|
|
9
|
+
color: z.string().optional(),
|
|
10
|
+
});
|
|
11
|
+
const AttributeSchema = z.object({
|
|
12
|
+
name: z.string(),
|
|
13
|
+
type: z.enum(['select', 'multiselect', 'string', 'number', 'date']).optional(),
|
|
14
|
+
values: z.array(AttributeValueSchema).default([]),
|
|
15
|
+
});
|
|
16
|
+
export function registerAddNodeType(server, client) {
|
|
17
|
+
server.registerTool('naumu_add_node_type', {
|
|
18
|
+
title: 'Add Node Type to Schema',
|
|
19
|
+
description: 'Add one new node type to the schema. Cheaper than naumu_update_schema. STRUCTURAL RULES: (1) Schemas are hierarchical with a single root. If schema is empty, the first type IS the root — omit `parent`. Every subsequent type MUST set `parent`. (2) DEFAULT TO CONCRETE — pass {relation, target_node: <existing type>}. Polymorphic is the ESCAPE HATCH — use {relation, polymorphic: true} ONLY for genuinely cross-cutting concepts like Comment or Tag (types that validly attach to many distinct parents). If you can\'t pick a concrete parent, you may be missing a type — add the missing type first instead of falling back to polymorphic. (3) Required/suggested connections also each take ONE concrete target_node OR polymorphic — never a list. Default concrete there too. (4) Type name PascalCase (Company, Person, Feature). Relation names UPPER_SNAKE_CASE (BELONGS_TO, WORKS_AT). Returns an error if the type already exists — use naumu_add_attribute / naumu_add_connection to extend it.',
|
|
20
|
+
inputSchema: z.object({
|
|
21
|
+
graphId: z.string(),
|
|
22
|
+
type: z.string().describe('PascalCase type name'),
|
|
23
|
+
parent: ConnectionSchema.optional().describe('Optional parent connection — sets this type as a child of another type.'),
|
|
24
|
+
required: z.array(ConnectionSchema).optional(),
|
|
25
|
+
suggested: z.array(ConnectionSchema).optional(),
|
|
26
|
+
attributes: z.array(AttributeSchema).optional(),
|
|
27
|
+
color: z.string().optional(),
|
|
28
|
+
}),
|
|
29
|
+
}, async ({ graphId, type, parent, required, suggested, attributes, color }) => {
|
|
30
|
+
const current = (await client.get(`/api/graphs/${graphId}/schema`));
|
|
31
|
+
const schema = current.definition ? JSON.parse(current.definition) : { nodes: [] };
|
|
32
|
+
if (schema.nodes.some((n) => n.type === type)) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: 'text', text: JSON.stringify({ error: `Node type "${type}" already exists. Use naumu_add_attribute / naumu_add_connection to extend it.` }, null, 2) }],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const newNode = {
|
|
38
|
+
type,
|
|
39
|
+
connections: {
|
|
40
|
+
required: required ?? [],
|
|
41
|
+
suggested: suggested ?? [],
|
|
42
|
+
...(parent ? { parent } : {}),
|
|
43
|
+
},
|
|
44
|
+
...(attributes && attributes.length > 0 ? { attributes } : {}),
|
|
45
|
+
...(color ? { color } : {}),
|
|
46
|
+
};
|
|
47
|
+
schema.nodes.push(newNode);
|
|
48
|
+
await client.post(`/api/graphs/${graphId}/schema`, { definition: schema });
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: 'text', text: JSON.stringify({ message: `Added node type "${type}"`, total_types: schema.nodes.length }, null, 2) }],
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=add-node-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-node-type.js","sourceRoot":"","sources":["../../src/tools/add-node-type.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/add-node.js
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
const NodeInput = z.object({
|
|
3
|
+
label: z.string().describe('Display name of the node'),
|
|
4
|
+
type: z.string().describe('Node type from the graph schema (e.g. Feature, Pain, Metric)'),
|
|
5
|
+
content: z
|
|
6
|
+
.string()
|
|
7
|
+
.min(1)
|
|
8
|
+
.describe('Rich text content / description. REQUIRED — every node must explain what it is.'),
|
|
9
|
+
attributes: z.record(z.string(), z.unknown()).optional().describe('Additional key-value attributes'),
|
|
10
|
+
});
|
|
2
11
|
export function registerAddNode(server, client) {
|
|
3
12
|
server.registerTool('naumu_add_node', {
|
|
4
|
-
title: 'Add
|
|
5
|
-
description: '
|
|
13
|
+
title: 'Add Nodes (bulk)',
|
|
14
|
+
description: 'Create 1–25 nodes in the knowledge graph in a single call. Keep batches small and atomic (5–25 nodes) so failures stay contained. Each node MUST include a non-empty `content` describing what it is. Returns one entry per input node with `{id, label, type, status: "created"}` — there is NO server-side dedup, every input becomes a node. Dedup is the caller\'s responsibility: BEFORE calling this tool, run `naumu_semantic_search` on each candidate label and skip/route to update if a result has high similarity (≥0.78) and matching type. Warning: nodes are isolated until you connect them with `naumu_add_edge`. **Prefer `naumu_ask`** for general knowledge intake — it discovers and creates connections for you. Use this when you have a vetted, dedup-checked batch ready to insert.',
|
|
6
15
|
inputSchema: z.object({
|
|
7
16
|
graphId: z.string().describe('The graph ID'),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
nodes: z
|
|
18
|
+
.array(NodeInput)
|
|
19
|
+
.min(1)
|
|
20
|
+
.max(25)
|
|
21
|
+
.describe('Batch of 1–25 nodes to create. Keep batches small for atomicity.'),
|
|
12
22
|
}),
|
|
13
|
-
}, async ({ graphId,
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
}, async ({ graphId, nodes }) => {
|
|
24
|
+
const payload = nodes.map(({ label, type, content, attributes }) => {
|
|
25
|
+
const node = { label, type, content };
|
|
26
|
+
if (attributes)
|
|
27
|
+
Object.assign(node, attributes);
|
|
28
|
+
return node;
|
|
29
|
+
});
|
|
30
|
+
const data = await client.post(`/api/graphs/${graphId}/nodes`, { nodes: payload });
|
|
20
31
|
return {
|
|
21
32
|
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
22
33
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-node.js","sourceRoot":"","sources":["../../src/tools/add-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,
|
|
1
|
+
{"version":3,"file":"add-node.js","sourceRoot":"","sources":["../../src/tools/add-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IACtD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8DAA8D,CAAC;IACzF,OAAO,EAAE,CAAC;SACR,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,iFAAiF,CAAC;IAC7F,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;CACpG,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,MAAmB;IACrE,MAAM,CAAC,YAAY,CAClB,gBAAgB,EAChB;QACC,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACV,8wBAA8wB;QAC/wB,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACrB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;YAC5C,KAAK,EAAE,CAAC;iBACN,KAAK,CAAC,SAAS,CAAC;iBAChB,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,QAAQ,CAAC,kEAAkE,CAAC;SAC9E,CAAC;KACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE;YAClE,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC/D,IAAI,UAAU;gBAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;YAChD,OAAO,IAAI,CAAC;QACb,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,OAAO,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QACnF,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACzE,CAAC;IACH,CAAC,CACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerAddReaction(server, client) {
|
|
3
|
+
server.registerTool('naumu_add_reaction', {
|
|
4
|
+
title: 'Add Reaction',
|
|
5
|
+
description: 'Add an emoji reaction to a message in a thread you are participating in. Idempotent — calling twice with the same emoji is a no-op (use `naumu_remove_reaction` to undo). Returns `{ ok, messageId, emoji, alreadyExisted, reactionCount, reactions }` so you can confirm the state without re-reading the thread; `alreadyExisted: true` means the reaction was already on the message and the call was a no-op.\n\nWhen to react vs. when to post a message:\n• React (no message) for lightweight acknowledgement (👀, ✅, 👍), appreciation (❤️, 🙌), laughter (😂), or "I saw this".\n• Post a message for direct questions, clarification, important corrections, or final results — situations where words are required.\n• For long tasks: react 👀 first to acknowledge, optionally post a short "On it — I\'ll report back" if the work will take >20s, do the work, then post the final result.\n• Ignore casual human banter, side-conversations someone else already answered, or anything where you would only say "ok"/"nice"/"lol".\n\nUse at most one reaction per message unless explicitly useful. Reactions are social backpressure relief, not a sparkle-confetti channel.',
|
|
6
|
+
inputSchema: z.object({
|
|
7
|
+
threadId: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe('Thread containing the message. You must be a participant.'),
|
|
10
|
+
messageId: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe('The message to react to.'),
|
|
13
|
+
emoji: z
|
|
14
|
+
.string()
|
|
15
|
+
.min(1)
|
|
16
|
+
.describe('Emoji character (e.g. "👀", "✅", "❤️"). Custom-emoji shortcodes are NOT supported here — pass a real Unicode emoji.'),
|
|
17
|
+
}),
|
|
18
|
+
}, async ({ threadId, messageId, emoji }) => {
|
|
19
|
+
try {
|
|
20
|
+
const data = await client.post(`/api/threads/${threadId}/messages/${messageId}/reactions`, { emoji, action: 'add' });
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
27
|
+
return {
|
|
28
|
+
content: [{ type: 'text', text: `Error: ${message}` }],
|
|
29
|
+
isError: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=add-reaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-reaction.js","sourceRoot":"","sources":["../../src/tools/add-reaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,MAAmB;IACzE,MAAM,CAAC,YAAY,CAClB,oBAAoB,EACpB;QACC,KAAK,EAAE,cAAc;QACrB,WAAW,EACV,goCAAgoC;QACjoC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;YACrB,QAAQ,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,CAAC,2DAA2D,CAAC;YACvE,SAAS,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,CAAC,0BAA0B,CAAC;YACtC,KAAK,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,GAAG,CAAC,CAAC,CAAC;iBACN,QAAQ,CAAC,qHAAqH,CAAC;SACjI,CAAC;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE;QACxC,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAC7B,gBAAgB,QAAQ,aAAa,SAAS,YAAY,EAC1D,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CACxB,CAAC;YACF,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACzE,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;gBAC/D,OAAO,EAAE,IAAI;aACb,CAAC;QACH,CAAC;IACF,CAAC,CACD,CAAC;AACH,CAAC"}
|