@apart-tech/intelligence-mcp 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +349 -0
- package/dist/index.js.map +1 -0
- package/package.json +27 -0
- package/src/index.ts +466 -0
- package/tsconfig.json +8 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { loadConfig, getTenantDb, NodeService, EdgeService, SearchService, ContextService, DomainService, WorkspaceService, createEmbeddingProvider, SINGLE_TENANT_ORG_ID, } from "@apart-tech/intelligence-core";
|
|
6
|
+
const config = loadConfig();
|
|
7
|
+
const tenant = {
|
|
8
|
+
organizationId: config.tenancy.organizationId ?? SINGLE_TENANT_ORG_ID,
|
|
9
|
+
};
|
|
10
|
+
const db = getTenantDb(config.database.url, tenant);
|
|
11
|
+
const embeddings = createEmbeddingProvider(config, { db });
|
|
12
|
+
const nodeService = new NodeService(db, embeddings, tenant);
|
|
13
|
+
const edgeService = new EdgeService(db);
|
|
14
|
+
const searchService = new SearchService(db, embeddings, config, tenant);
|
|
15
|
+
const domainService = new DomainService(db, tenant);
|
|
16
|
+
const workspaceService = new WorkspaceService(db, tenant);
|
|
17
|
+
const contextService = new ContextService(nodeService, edgeService, searchService, config, workspaceService, domainService);
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: "apart-intelligence",
|
|
20
|
+
version: "0.1.0",
|
|
21
|
+
});
|
|
22
|
+
// ── Read Tools ─────────────────────────────────────────────────────────────
|
|
23
|
+
server.tool("search_knowledge", "Hybrid semantic + keyword search across all knowledge nodes", {
|
|
24
|
+
query: z.string().describe("Search query"),
|
|
25
|
+
limit: z.number().optional().describe("Max results (default 10)"),
|
|
26
|
+
types: z
|
|
27
|
+
.array(z.string())
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Filter by node types"),
|
|
30
|
+
include_drafts: z
|
|
31
|
+
.boolean()
|
|
32
|
+
.optional()
|
|
33
|
+
.describe("Include draft nodes in results"),
|
|
34
|
+
domain_slugs: z
|
|
35
|
+
.array(z.string())
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Filter by domain slugs"),
|
|
38
|
+
workspace: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("Workspace slug — auto-applies domain/type/tag filters"),
|
|
42
|
+
}, async ({ query, limit, types, include_drafts, domain_slugs, workspace }) => {
|
|
43
|
+
let domainIds;
|
|
44
|
+
let resolvedTypes = types;
|
|
45
|
+
// Apply workspace filters (explicit params override workspace defaults)
|
|
46
|
+
if (workspace) {
|
|
47
|
+
const filter = await workspaceService.resolveFilter(workspace, (slugs) => domainService.resolveSlugs(slugs));
|
|
48
|
+
if (filter) {
|
|
49
|
+
if (!domainIds && filter.domainIds)
|
|
50
|
+
domainIds = filter.domainIds;
|
|
51
|
+
if (!resolvedTypes && filter.types)
|
|
52
|
+
resolvedTypes = filter.types;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (domain_slugs?.length) {
|
|
56
|
+
domainIds = await domainService.resolveSlugs(domain_slugs);
|
|
57
|
+
}
|
|
58
|
+
const results = await searchService.search({
|
|
59
|
+
query,
|
|
60
|
+
limit,
|
|
61
|
+
types: resolvedTypes,
|
|
62
|
+
includeDrafts: include_drafts,
|
|
63
|
+
domainIds,
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: JSON.stringify(results, null, 2),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
server.tool("get_node", "Retrieve a specific knowledge node by ID with its edges", {
|
|
75
|
+
id: z.string().describe("Node UUID"),
|
|
76
|
+
}, async ({ id }) => {
|
|
77
|
+
const node = await nodeService.getById(id);
|
|
78
|
+
if (!node) {
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: "text", text: "Node not found" }],
|
|
81
|
+
isError: true,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const edges = await edgeService.getByNodeId(id);
|
|
85
|
+
return {
|
|
86
|
+
content: [
|
|
87
|
+
{
|
|
88
|
+
type: "text",
|
|
89
|
+
text: JSON.stringify({ node, edges }, null, 2),
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
server.tool("get_context", "Assemble a context package for a topic — returns related nodes with their relationships", {
|
|
95
|
+
query: z.string().describe("Topic or question for context assembly"),
|
|
96
|
+
max_depth: z.number().optional().describe("Graph traversal depth (default 1)"),
|
|
97
|
+
max_nodes: z.number().optional().describe("Max nodes to return (default 20)"),
|
|
98
|
+
include_drafts: z.boolean().optional().describe("Include draft nodes"),
|
|
99
|
+
types: z.array(z.string()).optional().describe("Filter by node types"),
|
|
100
|
+
domain_slugs: z
|
|
101
|
+
.array(z.string())
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("Filter by domain slugs"),
|
|
104
|
+
workspace: z
|
|
105
|
+
.string()
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Workspace slug — auto-applies all workspace filters"),
|
|
108
|
+
}, async ({ query, max_depth, max_nodes, include_drafts, types, domain_slugs, workspace }) => {
|
|
109
|
+
let domainIds;
|
|
110
|
+
if (domain_slugs?.length) {
|
|
111
|
+
domainIds = await domainService.resolveSlugs(domain_slugs);
|
|
112
|
+
}
|
|
113
|
+
const ctx = await contextService.assemble({
|
|
114
|
+
query,
|
|
115
|
+
maxDepth: max_depth,
|
|
116
|
+
maxNodes: max_nodes,
|
|
117
|
+
includeDrafts: include_drafts,
|
|
118
|
+
types,
|
|
119
|
+
domainIds,
|
|
120
|
+
workspace,
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
content: [
|
|
124
|
+
{ type: "text", text: JSON.stringify(ctx, null, 2) },
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
server.tool("get_neighborhood", "Return a node and its N-hop graph neighborhood", {
|
|
129
|
+
id: z.string().describe("Node UUID"),
|
|
130
|
+
depth: z.number().optional().describe("Hops to traverse (default 1)"),
|
|
131
|
+
}, async ({ id, depth }) => {
|
|
132
|
+
const node = await nodeService.getById(id);
|
|
133
|
+
if (!node) {
|
|
134
|
+
return {
|
|
135
|
+
content: [{ type: "text", text: "Node not found" }],
|
|
136
|
+
isError: true,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const neighborIds = await edgeService.getNeighborIds(id, depth ?? 1);
|
|
140
|
+
const neighbors = [];
|
|
141
|
+
for (const nId of neighborIds) {
|
|
142
|
+
const n = await nodeService.getById(nId);
|
|
143
|
+
if (n)
|
|
144
|
+
neighbors.push(n);
|
|
145
|
+
}
|
|
146
|
+
const edges = await edgeService.getByNodeId(id);
|
|
147
|
+
return {
|
|
148
|
+
content: [
|
|
149
|
+
{
|
|
150
|
+
type: "text",
|
|
151
|
+
text: JSON.stringify({ node, neighbors, edges }, null, 2),
|
|
152
|
+
},
|
|
153
|
+
],
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
server.tool("list_drafts", "List all draft nodes pending curation", {
|
|
157
|
+
limit: z.number().optional().describe("Max results (default 50)"),
|
|
158
|
+
}, async ({ limit }) => {
|
|
159
|
+
const drafts = await nodeService.listDrafts(limit);
|
|
160
|
+
return {
|
|
161
|
+
content: [
|
|
162
|
+
{ type: "text", text: JSON.stringify(drafts, null, 2) },
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
server.tool("list_types", "List all node types and relationship types currently in use", {}, async () => {
|
|
167
|
+
const [nodeTypes, edgeTypes] = await Promise.all([
|
|
168
|
+
nodeService.listTypes(),
|
|
169
|
+
edgeService.listRelationshipTypes(),
|
|
170
|
+
]);
|
|
171
|
+
return {
|
|
172
|
+
content: [
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
text: JSON.stringify({ nodeTypes, edgeTypes }, null, 2),
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
server.tool("list_domains", "List the full domain taxonomy tree", {}, async () => {
|
|
181
|
+
const tree = await domainService.getTree();
|
|
182
|
+
return {
|
|
183
|
+
content: [
|
|
184
|
+
{ type: "text", text: JSON.stringify(tree, null, 2) },
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
});
|
|
188
|
+
server.tool("seed_domains", "Seed the default domain taxonomy", {}, async () => {
|
|
189
|
+
const result = await domainService.seed();
|
|
190
|
+
return {
|
|
191
|
+
content: [
|
|
192
|
+
{
|
|
193
|
+
type: "text",
|
|
194
|
+
text: JSON.stringify(result, null, 2),
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
// ── Workspace Tools ───────────────────────────────────────────────────────
|
|
200
|
+
server.tool("list_workspaces", "List all workspaces — each defines a filtered view of the knowledge graph for a specific kind of work", {}, async () => {
|
|
201
|
+
const list = await workspaceService.list();
|
|
202
|
+
return {
|
|
203
|
+
content: [
|
|
204
|
+
{ type: "text", text: JSON.stringify(list, null, 2) },
|
|
205
|
+
],
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
server.tool("get_workspace", "Get full workspace definition including filter rules and system prompt", {
|
|
209
|
+
slug: z.string().describe("Workspace slug"),
|
|
210
|
+
}, async ({ slug }) => {
|
|
211
|
+
const ws = await workspaceService.getBySlug(slug);
|
|
212
|
+
if (!ws) {
|
|
213
|
+
return {
|
|
214
|
+
content: [{ type: "text", text: "Workspace not found" }],
|
|
215
|
+
isError: true,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{ type: "text", text: JSON.stringify(ws, null, 2) },
|
|
221
|
+
],
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
server.tool("export_workspace", "Export a workspace as a CLAUDE.md-formatted markdown document", {
|
|
225
|
+
slug: z.string().describe("Workspace slug"),
|
|
226
|
+
}, async ({ slug }) => {
|
|
227
|
+
const md = await workspaceService.exportAsMarkdown(slug);
|
|
228
|
+
if (!md) {
|
|
229
|
+
return {
|
|
230
|
+
content: [{ type: "text", text: "Workspace not found" }],
|
|
231
|
+
isError: true,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
content: [{ type: "text", text: md }],
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
// ── Write Tools ────────────────────────────────────────────────────────────
|
|
239
|
+
server.tool("add_node", "Create a new knowledge node (defaults to draft status)", {
|
|
240
|
+
type: z
|
|
241
|
+
.string()
|
|
242
|
+
.describe("Node type (policy, process, decision, customer, etc.)"),
|
|
243
|
+
title: z.string().describe("Human-readable title"),
|
|
244
|
+
content: z.string().describe("Markdown content body"),
|
|
245
|
+
metadata: z
|
|
246
|
+
.record(z.unknown())
|
|
247
|
+
.optional()
|
|
248
|
+
.describe("Optional key-value metadata"),
|
|
249
|
+
created_by: z
|
|
250
|
+
.string()
|
|
251
|
+
.optional()
|
|
252
|
+
.describe("Creator identifier (default: mcp)"),
|
|
253
|
+
domain_slug: z
|
|
254
|
+
.string()
|
|
255
|
+
.optional()
|
|
256
|
+
.describe("Domain slug to assign to the node"),
|
|
257
|
+
}, async ({ type, title, content, metadata, created_by, domain_slug }) => {
|
|
258
|
+
let domainId;
|
|
259
|
+
if (domain_slug) {
|
|
260
|
+
const domain = await domainService.getBySlug(domain_slug);
|
|
261
|
+
if (domain)
|
|
262
|
+
domainId = domain.id;
|
|
263
|
+
}
|
|
264
|
+
const node = await nodeService.create({
|
|
265
|
+
type,
|
|
266
|
+
title,
|
|
267
|
+
content,
|
|
268
|
+
metadata,
|
|
269
|
+
createdBy: created_by ?? "mcp",
|
|
270
|
+
domainId,
|
|
271
|
+
});
|
|
272
|
+
return {
|
|
273
|
+
content: [
|
|
274
|
+
{ type: "text", text: JSON.stringify(node, null, 2) },
|
|
275
|
+
],
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
server.tool("update_node", "Update content or metadata of an existing knowledge node", {
|
|
279
|
+
id: z.string().describe("Node UUID"),
|
|
280
|
+
title: z.string().optional().describe("New title"),
|
|
281
|
+
content: z.string().optional().describe("New markdown content"),
|
|
282
|
+
metadata: z.record(z.unknown()).optional().describe("New metadata"),
|
|
283
|
+
type: z.string().optional().describe("New node type"),
|
|
284
|
+
}, async ({ id, title, content, metadata, type }) => {
|
|
285
|
+
const node = await nodeService.update(id, { title, content, metadata, type });
|
|
286
|
+
if (!node) {
|
|
287
|
+
return {
|
|
288
|
+
content: [{ type: "text", text: "Node not found" }],
|
|
289
|
+
isError: true,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
content: [
|
|
294
|
+
{ type: "text", text: JSON.stringify(node, null, 2) },
|
|
295
|
+
],
|
|
296
|
+
};
|
|
297
|
+
});
|
|
298
|
+
server.tool("link_nodes", "Create an edge between two knowledge nodes", {
|
|
299
|
+
source_node_id: z.string().describe("Source node UUID"),
|
|
300
|
+
target_node_id: z.string().describe("Target node UUID"),
|
|
301
|
+
relationship_type: z
|
|
302
|
+
.string()
|
|
303
|
+
.describe("Edge type (relates-to, part-of, supersedes, etc.)"),
|
|
304
|
+
weight: z.number().optional().describe("Relevance weight (default 1.0)"),
|
|
305
|
+
created_by: z.string().optional().describe("Creator identifier"),
|
|
306
|
+
}, async ({ source_node_id, target_node_id, relationship_type, weight, created_by }) => {
|
|
307
|
+
const edge = await edgeService.create({
|
|
308
|
+
sourceNodeId: source_node_id,
|
|
309
|
+
targetNodeId: target_node_id,
|
|
310
|
+
relationshipType: relationship_type,
|
|
311
|
+
weight,
|
|
312
|
+
createdBy: created_by ?? "mcp",
|
|
313
|
+
});
|
|
314
|
+
return {
|
|
315
|
+
content: [
|
|
316
|
+
{ type: "text", text: JSON.stringify(edge, null, 2) },
|
|
317
|
+
],
|
|
318
|
+
};
|
|
319
|
+
});
|
|
320
|
+
server.tool("set_status", "Change node status (draft/reviewed/approved/archived)", {
|
|
321
|
+
id: z.string().describe("Node UUID"),
|
|
322
|
+
status: z
|
|
323
|
+
.enum(["draft", "reviewed", "approved", "archived"])
|
|
324
|
+
.describe("New status"),
|
|
325
|
+
}, async ({ id, status }) => {
|
|
326
|
+
const node = await nodeService.setStatus(id, status);
|
|
327
|
+
if (!node) {
|
|
328
|
+
return {
|
|
329
|
+
content: [{ type: "text", text: "Node not found" }],
|
|
330
|
+
isError: true,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
content: [
|
|
335
|
+
{ type: "text", text: JSON.stringify(node, null, 2) },
|
|
336
|
+
],
|
|
337
|
+
};
|
|
338
|
+
});
|
|
339
|
+
// ── Start Server ───────────────────────────────────────────────────────────
|
|
340
|
+
async function main() {
|
|
341
|
+
const transport = new StdioServerTransport();
|
|
342
|
+
await server.connect(transport);
|
|
343
|
+
console.error("Apart Intelligence MCP server running on stdio");
|
|
344
|
+
}
|
|
345
|
+
main().catch((err) => {
|
|
346
|
+
console.error("Failed to start MCP server:", err);
|
|
347
|
+
process.exit(1);
|
|
348
|
+
});
|
|
349
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@apart-tech/intelligence-mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server for Apart Intelligence knowledge graph",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"tc-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@modelcontextprotocol/sdk": "^1.8.0",
|
|
12
|
+
"zod": "^3.24.0",
|
|
13
|
+
"@apart-tech/intelligence-core": "1.0.3"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^25.5.0",
|
|
17
|
+
"typescript": "^5.7.0",
|
|
18
|
+
"vitest": "^3.0.0"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"start": "node dist/index.js",
|
|
24
|
+
"lint": "tsc --noEmit",
|
|
25
|
+
"test": "vitest run"
|
|
26
|
+
}
|
|
27
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import {
|
|
7
|
+
loadConfig,
|
|
8
|
+
getTenantDb,
|
|
9
|
+
NodeService,
|
|
10
|
+
EdgeService,
|
|
11
|
+
SearchService,
|
|
12
|
+
ContextService,
|
|
13
|
+
DomainService,
|
|
14
|
+
WorkspaceService,
|
|
15
|
+
createEmbeddingProvider,
|
|
16
|
+
SINGLE_TENANT_ORG_ID,
|
|
17
|
+
} from "@apart-tech/intelligence-core";
|
|
18
|
+
import type { NodeStatus, TenantContext } from "@apart-tech/intelligence-core";
|
|
19
|
+
|
|
20
|
+
const config = loadConfig();
|
|
21
|
+
const tenant: TenantContext = {
|
|
22
|
+
organizationId: config.tenancy.organizationId ?? SINGLE_TENANT_ORG_ID,
|
|
23
|
+
};
|
|
24
|
+
const db = getTenantDb(config.database.url, tenant);
|
|
25
|
+
const embeddings = createEmbeddingProvider(config, { db });
|
|
26
|
+
const nodeService = new NodeService(db, embeddings, tenant);
|
|
27
|
+
const edgeService = new EdgeService(db);
|
|
28
|
+
const searchService = new SearchService(db, embeddings, config, tenant);
|
|
29
|
+
const domainService = new DomainService(db, tenant);
|
|
30
|
+
const workspaceService = new WorkspaceService(db, tenant);
|
|
31
|
+
const contextService = new ContextService(
|
|
32
|
+
nodeService,
|
|
33
|
+
edgeService,
|
|
34
|
+
searchService,
|
|
35
|
+
config,
|
|
36
|
+
workspaceService,
|
|
37
|
+
domainService,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const server = new McpServer({
|
|
41
|
+
name: "apart-intelligence",
|
|
42
|
+
version: "0.1.0",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// ── Read Tools ─────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
server.tool(
|
|
48
|
+
"search_knowledge",
|
|
49
|
+
"Hybrid semantic + keyword search across all knowledge nodes",
|
|
50
|
+
{
|
|
51
|
+
query: z.string().describe("Search query"),
|
|
52
|
+
limit: z.number().optional().describe("Max results (default 10)"),
|
|
53
|
+
types: z
|
|
54
|
+
.array(z.string())
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("Filter by node types"),
|
|
57
|
+
include_drafts: z
|
|
58
|
+
.boolean()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe("Include draft nodes in results"),
|
|
61
|
+
domain_slugs: z
|
|
62
|
+
.array(z.string())
|
|
63
|
+
.optional()
|
|
64
|
+
.describe("Filter by domain slugs"),
|
|
65
|
+
workspace: z
|
|
66
|
+
.string()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Workspace slug — auto-applies domain/type/tag filters"),
|
|
69
|
+
},
|
|
70
|
+
async ({ query, limit, types, include_drafts, domain_slugs, workspace }) => {
|
|
71
|
+
let domainIds: string[] | undefined;
|
|
72
|
+
let resolvedTypes = types;
|
|
73
|
+
|
|
74
|
+
// Apply workspace filters (explicit params override workspace defaults)
|
|
75
|
+
if (workspace) {
|
|
76
|
+
const filter = await workspaceService.resolveFilter(workspace, (slugs) =>
|
|
77
|
+
domainService.resolveSlugs(slugs),
|
|
78
|
+
);
|
|
79
|
+
if (filter) {
|
|
80
|
+
if (!domainIds && filter.domainIds) domainIds = filter.domainIds;
|
|
81
|
+
if (!resolvedTypes && filter.types) resolvedTypes = filter.types;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (domain_slugs?.length) {
|
|
86
|
+
domainIds = await domainService.resolveSlugs(domain_slugs);
|
|
87
|
+
}
|
|
88
|
+
const results = await searchService.search({
|
|
89
|
+
query,
|
|
90
|
+
limit,
|
|
91
|
+
types: resolvedTypes,
|
|
92
|
+
includeDrafts: include_drafts,
|
|
93
|
+
domainIds,
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
content: [
|
|
97
|
+
{
|
|
98
|
+
type: "text" as const,
|
|
99
|
+
text: JSON.stringify(results, null, 2),
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
server.tool(
|
|
107
|
+
"get_node",
|
|
108
|
+
"Retrieve a specific knowledge node by ID with its edges",
|
|
109
|
+
{
|
|
110
|
+
id: z.string().describe("Node UUID"),
|
|
111
|
+
},
|
|
112
|
+
async ({ id }) => {
|
|
113
|
+
const node = await nodeService.getById(id);
|
|
114
|
+
if (!node) {
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: "text" as const, text: "Node not found" }],
|
|
117
|
+
isError: true,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const edges = await edgeService.getByNodeId(id);
|
|
121
|
+
return {
|
|
122
|
+
content: [
|
|
123
|
+
{
|
|
124
|
+
type: "text" as const,
|
|
125
|
+
text: JSON.stringify({ node, edges }, null, 2),
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
server.tool(
|
|
133
|
+
"get_context",
|
|
134
|
+
"Assemble a context package for a topic — returns related nodes with their relationships",
|
|
135
|
+
{
|
|
136
|
+
query: z.string().describe("Topic or question for context assembly"),
|
|
137
|
+
max_depth: z.number().optional().describe("Graph traversal depth (default 1)"),
|
|
138
|
+
max_nodes: z.number().optional().describe("Max nodes to return (default 20)"),
|
|
139
|
+
include_drafts: z.boolean().optional().describe("Include draft nodes"),
|
|
140
|
+
types: z.array(z.string()).optional().describe("Filter by node types"),
|
|
141
|
+
domain_slugs: z
|
|
142
|
+
.array(z.string())
|
|
143
|
+
.optional()
|
|
144
|
+
.describe("Filter by domain slugs"),
|
|
145
|
+
workspace: z
|
|
146
|
+
.string()
|
|
147
|
+
.optional()
|
|
148
|
+
.describe("Workspace slug — auto-applies all workspace filters"),
|
|
149
|
+
},
|
|
150
|
+
async ({ query, max_depth, max_nodes, include_drafts, types, domain_slugs, workspace }) => {
|
|
151
|
+
let domainIds: string[] | undefined;
|
|
152
|
+
if (domain_slugs?.length) {
|
|
153
|
+
domainIds = await domainService.resolveSlugs(domain_slugs);
|
|
154
|
+
}
|
|
155
|
+
const ctx = await contextService.assemble({
|
|
156
|
+
query,
|
|
157
|
+
maxDepth: max_depth,
|
|
158
|
+
maxNodes: max_nodes,
|
|
159
|
+
includeDrafts: include_drafts,
|
|
160
|
+
types,
|
|
161
|
+
domainIds,
|
|
162
|
+
workspace,
|
|
163
|
+
});
|
|
164
|
+
return {
|
|
165
|
+
content: [
|
|
166
|
+
{ type: "text" as const, text: JSON.stringify(ctx, null, 2) },
|
|
167
|
+
],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
server.tool(
|
|
173
|
+
"get_neighborhood",
|
|
174
|
+
"Return a node and its N-hop graph neighborhood",
|
|
175
|
+
{
|
|
176
|
+
id: z.string().describe("Node UUID"),
|
|
177
|
+
depth: z.number().optional().describe("Hops to traverse (default 1)"),
|
|
178
|
+
},
|
|
179
|
+
async ({ id, depth }) => {
|
|
180
|
+
const node = await nodeService.getById(id);
|
|
181
|
+
if (!node) {
|
|
182
|
+
return {
|
|
183
|
+
content: [{ type: "text" as const, text: "Node not found" }],
|
|
184
|
+
isError: true,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const neighborIds = await edgeService.getNeighborIds(id, depth ?? 1);
|
|
188
|
+
const neighbors = [];
|
|
189
|
+
for (const nId of neighborIds) {
|
|
190
|
+
const n = await nodeService.getById(nId);
|
|
191
|
+
if (n) neighbors.push(n);
|
|
192
|
+
}
|
|
193
|
+
const edges = await edgeService.getByNodeId(id);
|
|
194
|
+
return {
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: "text" as const,
|
|
198
|
+
text: JSON.stringify({ node, neighbors, edges }, null, 2),
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
server.tool(
|
|
206
|
+
"list_drafts",
|
|
207
|
+
"List all draft nodes pending curation",
|
|
208
|
+
{
|
|
209
|
+
limit: z.number().optional().describe("Max results (default 50)"),
|
|
210
|
+
},
|
|
211
|
+
async ({ limit }) => {
|
|
212
|
+
const drafts = await nodeService.listDrafts(limit);
|
|
213
|
+
return {
|
|
214
|
+
content: [
|
|
215
|
+
{ type: "text" as const, text: JSON.stringify(drafts, null, 2) },
|
|
216
|
+
],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
server.tool(
|
|
222
|
+
"list_types",
|
|
223
|
+
"List all node types and relationship types currently in use",
|
|
224
|
+
{},
|
|
225
|
+
async () => {
|
|
226
|
+
const [nodeTypes, edgeTypes] = await Promise.all([
|
|
227
|
+
nodeService.listTypes(),
|
|
228
|
+
edgeService.listRelationshipTypes(),
|
|
229
|
+
]);
|
|
230
|
+
return {
|
|
231
|
+
content: [
|
|
232
|
+
{
|
|
233
|
+
type: "text" as const,
|
|
234
|
+
text: JSON.stringify({ nodeTypes, edgeTypes }, null, 2),
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
server.tool(
|
|
242
|
+
"list_domains",
|
|
243
|
+
"List the full domain taxonomy tree",
|
|
244
|
+
{},
|
|
245
|
+
async () => {
|
|
246
|
+
const tree = await domainService.getTree();
|
|
247
|
+
return {
|
|
248
|
+
content: [
|
|
249
|
+
{ type: "text" as const, text: JSON.stringify(tree, null, 2) },
|
|
250
|
+
],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
server.tool(
|
|
256
|
+
"seed_domains",
|
|
257
|
+
"Seed the default domain taxonomy",
|
|
258
|
+
{},
|
|
259
|
+
async () => {
|
|
260
|
+
const result = await domainService.seed();
|
|
261
|
+
return {
|
|
262
|
+
content: [
|
|
263
|
+
{
|
|
264
|
+
type: "text" as const,
|
|
265
|
+
text: JSON.stringify(result, null, 2),
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// ── Workspace Tools ───────────────────────────────────────────────────────
|
|
273
|
+
|
|
274
|
+
server.tool(
|
|
275
|
+
"list_workspaces",
|
|
276
|
+
"List all workspaces — each defines a filtered view of the knowledge graph for a specific kind of work",
|
|
277
|
+
{},
|
|
278
|
+
async () => {
|
|
279
|
+
const list = await workspaceService.list();
|
|
280
|
+
return {
|
|
281
|
+
content: [
|
|
282
|
+
{ type: "text" as const, text: JSON.stringify(list, null, 2) },
|
|
283
|
+
],
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
server.tool(
|
|
289
|
+
"get_workspace",
|
|
290
|
+
"Get full workspace definition including filter rules and system prompt",
|
|
291
|
+
{
|
|
292
|
+
slug: z.string().describe("Workspace slug"),
|
|
293
|
+
},
|
|
294
|
+
async ({ slug }) => {
|
|
295
|
+
const ws = await workspaceService.getBySlug(slug);
|
|
296
|
+
if (!ws) {
|
|
297
|
+
return {
|
|
298
|
+
content: [{ type: "text" as const, text: "Workspace not found" }],
|
|
299
|
+
isError: true,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
content: [
|
|
304
|
+
{ type: "text" as const, text: JSON.stringify(ws, null, 2) },
|
|
305
|
+
],
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
server.tool(
|
|
311
|
+
"export_workspace",
|
|
312
|
+
"Export a workspace as a CLAUDE.md-formatted markdown document",
|
|
313
|
+
{
|
|
314
|
+
slug: z.string().describe("Workspace slug"),
|
|
315
|
+
},
|
|
316
|
+
async ({ slug }) => {
|
|
317
|
+
const md = await workspaceService.exportAsMarkdown(slug);
|
|
318
|
+
if (!md) {
|
|
319
|
+
return {
|
|
320
|
+
content: [{ type: "text" as const, text: "Workspace not found" }],
|
|
321
|
+
isError: true,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
content: [{ type: "text" as const, text: md }],
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
// ── Write Tools ────────────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
server.tool(
|
|
333
|
+
"add_node",
|
|
334
|
+
"Create a new knowledge node (defaults to draft status)",
|
|
335
|
+
{
|
|
336
|
+
type: z
|
|
337
|
+
.string()
|
|
338
|
+
.describe("Node type (policy, process, decision, customer, etc.)"),
|
|
339
|
+
title: z.string().describe("Human-readable title"),
|
|
340
|
+
content: z.string().describe("Markdown content body"),
|
|
341
|
+
metadata: z
|
|
342
|
+
.record(z.unknown())
|
|
343
|
+
.optional()
|
|
344
|
+
.describe("Optional key-value metadata"),
|
|
345
|
+
created_by: z
|
|
346
|
+
.string()
|
|
347
|
+
.optional()
|
|
348
|
+
.describe("Creator identifier (default: mcp)"),
|
|
349
|
+
domain_slug: z
|
|
350
|
+
.string()
|
|
351
|
+
.optional()
|
|
352
|
+
.describe("Domain slug to assign to the node"),
|
|
353
|
+
},
|
|
354
|
+
async ({ type, title, content, metadata, created_by, domain_slug }) => {
|
|
355
|
+
let domainId: string | undefined;
|
|
356
|
+
if (domain_slug) {
|
|
357
|
+
const domain = await domainService.getBySlug(domain_slug);
|
|
358
|
+
if (domain) domainId = domain.id;
|
|
359
|
+
}
|
|
360
|
+
const node = await nodeService.create({
|
|
361
|
+
type,
|
|
362
|
+
title,
|
|
363
|
+
content,
|
|
364
|
+
metadata,
|
|
365
|
+
createdBy: created_by ?? "mcp",
|
|
366
|
+
domainId,
|
|
367
|
+
});
|
|
368
|
+
return {
|
|
369
|
+
content: [
|
|
370
|
+
{ type: "text" as const, text: JSON.stringify(node, null, 2) },
|
|
371
|
+
],
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
server.tool(
|
|
377
|
+
"update_node",
|
|
378
|
+
"Update content or metadata of an existing knowledge node",
|
|
379
|
+
{
|
|
380
|
+
id: z.string().describe("Node UUID"),
|
|
381
|
+
title: z.string().optional().describe("New title"),
|
|
382
|
+
content: z.string().optional().describe("New markdown content"),
|
|
383
|
+
metadata: z.record(z.unknown()).optional().describe("New metadata"),
|
|
384
|
+
type: z.string().optional().describe("New node type"),
|
|
385
|
+
},
|
|
386
|
+
async ({ id, title, content, metadata, type }) => {
|
|
387
|
+
const node = await nodeService.update(id, { title, content, metadata, type });
|
|
388
|
+
if (!node) {
|
|
389
|
+
return {
|
|
390
|
+
content: [{ type: "text" as const, text: "Node not found" }],
|
|
391
|
+
isError: true,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
content: [
|
|
396
|
+
{ type: "text" as const, text: JSON.stringify(node, null, 2) },
|
|
397
|
+
],
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
server.tool(
|
|
403
|
+
"link_nodes",
|
|
404
|
+
"Create an edge between two knowledge nodes",
|
|
405
|
+
{
|
|
406
|
+
source_node_id: z.string().describe("Source node UUID"),
|
|
407
|
+
target_node_id: z.string().describe("Target node UUID"),
|
|
408
|
+
relationship_type: z
|
|
409
|
+
.string()
|
|
410
|
+
.describe("Edge type (relates-to, part-of, supersedes, etc.)"),
|
|
411
|
+
weight: z.number().optional().describe("Relevance weight (default 1.0)"),
|
|
412
|
+
created_by: z.string().optional().describe("Creator identifier"),
|
|
413
|
+
},
|
|
414
|
+
async ({ source_node_id, target_node_id, relationship_type, weight, created_by }) => {
|
|
415
|
+
const edge = await edgeService.create({
|
|
416
|
+
sourceNodeId: source_node_id,
|
|
417
|
+
targetNodeId: target_node_id,
|
|
418
|
+
relationshipType: relationship_type,
|
|
419
|
+
weight,
|
|
420
|
+
createdBy: created_by ?? "mcp",
|
|
421
|
+
});
|
|
422
|
+
return {
|
|
423
|
+
content: [
|
|
424
|
+
{ type: "text" as const, text: JSON.stringify(edge, null, 2) },
|
|
425
|
+
],
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
server.tool(
|
|
431
|
+
"set_status",
|
|
432
|
+
"Change node status (draft/reviewed/approved/archived)",
|
|
433
|
+
{
|
|
434
|
+
id: z.string().describe("Node UUID"),
|
|
435
|
+
status: z
|
|
436
|
+
.enum(["draft", "reviewed", "approved", "archived"])
|
|
437
|
+
.describe("New status"),
|
|
438
|
+
},
|
|
439
|
+
async ({ id, status }) => {
|
|
440
|
+
const node = await nodeService.setStatus(id, status as NodeStatus);
|
|
441
|
+
if (!node) {
|
|
442
|
+
return {
|
|
443
|
+
content: [{ type: "text" as const, text: "Node not found" }],
|
|
444
|
+
isError: true,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
return {
|
|
448
|
+
content: [
|
|
449
|
+
{ type: "text" as const, text: JSON.stringify(node, null, 2) },
|
|
450
|
+
],
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
// ── Start Server ───────────────────────────────────────────────────────────
|
|
456
|
+
|
|
457
|
+
async function main() {
|
|
458
|
+
const transport = new StdioServerTransport();
|
|
459
|
+
await server.connect(transport);
|
|
460
|
+
console.error("Apart Intelligence MCP server running on stdio");
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
main().catch((err) => {
|
|
464
|
+
console.error("Failed to start MCP server:", err);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
});
|