@cognistore/mcp-server 0.9.13 → 1.0.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.js +335 -53
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var KnowledgeType;
|
|
|
21
21
|
KnowledgeType2["FIX"] = "fix";
|
|
22
22
|
KnowledgeType2["CONSTRAINT"] = "constraint";
|
|
23
23
|
KnowledgeType2["GOTCHA"] = "gotcha";
|
|
24
|
+
KnowledgeType2["SYSTEM"] = "system";
|
|
24
25
|
})(KnowledgeType || (KnowledgeType = {}));
|
|
25
26
|
var KnowledgeStatus;
|
|
26
27
|
(function(KnowledgeStatus2) {
|
|
@@ -134,7 +135,7 @@ __export(schema_exports, {
|
|
|
134
135
|
|
|
135
136
|
// ../../packages/core/dist/db/schema/knowledge.js
|
|
136
137
|
import { sqliteTable, text, integer, real, index } from "drizzle-orm/sqlite-core";
|
|
137
|
-
var knowledgeTypeEnum = ["decision", "pattern", "fix", "constraint", "gotcha"];
|
|
138
|
+
var knowledgeTypeEnum = ["decision", "pattern", "fix", "constraint", "gotcha", "system"];
|
|
138
139
|
var knowledgeEntries = sqliteTable("knowledge_entries", {
|
|
139
140
|
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
140
141
|
title: text("title").notNull().default(""),
|
|
@@ -376,7 +377,7 @@ function createPlansEmbeddingsTable(sqlite) {
|
|
|
376
377
|
}
|
|
377
378
|
|
|
378
379
|
// ../../packages/core/dist/repositories/knowledge.repository.js
|
|
379
|
-
import { eq, sql, and, or, isNull } from "drizzle-orm";
|
|
380
|
+
import { eq, ne, sql, and, or, isNull } from "drizzle-orm";
|
|
380
381
|
var KnowledgeRepository = class {
|
|
381
382
|
db;
|
|
382
383
|
sqlite;
|
|
@@ -461,6 +462,7 @@ var KnowledgeRepository = class {
|
|
|
461
462
|
if (options?.type) {
|
|
462
463
|
conditions.push(eq(knowledgeEntries.type, options.type));
|
|
463
464
|
}
|
|
465
|
+
conditions.push(ne(knowledgeEntries.type, "system"));
|
|
464
466
|
conditions.push(or(isNull(knowledgeEntries.expiresAt), sql`${knowledgeEntries.expiresAt} > ${(/* @__PURE__ */ new Date()).toISOString()}`));
|
|
465
467
|
const whereClause = and(...conditions);
|
|
466
468
|
const entries = await this.db.select().from(knowledgeEntries).where(whereClause);
|
|
@@ -470,27 +472,23 @@ var KnowledgeRepository = class {
|
|
|
470
472
|
})).filter((r) => r.similarity >= threshold).sort((a, b) => b.similarity - a.similarity).slice(0, limit);
|
|
471
473
|
}
|
|
472
474
|
async listRecent(limit = 20, filters) {
|
|
473
|
-
const conditions = [];
|
|
475
|
+
const conditions = [ne(knowledgeEntries.type, "system")];
|
|
474
476
|
if (filters?.type)
|
|
475
477
|
conditions.push(sql`${knowledgeEntries.type} = ${filters.type}`);
|
|
476
478
|
if (filters?.scope)
|
|
477
479
|
conditions.push(sql`${knowledgeEntries.scope} = ${filters.scope}`);
|
|
478
|
-
|
|
479
|
-
return this.db.select().from(knowledgeEntries).orderBy(sql`${knowledgeEntries.createdAt} DESC`).limit(limit);
|
|
480
|
-
}
|
|
481
|
-
const where = conditions.length === 1 ? conditions[0] : sql`${conditions[0]} AND ${conditions[1]}`;
|
|
482
|
-
return this.db.select().from(knowledgeEntries).where(where).orderBy(sql`${knowledgeEntries.createdAt} DESC`).limit(limit);
|
|
480
|
+
return this.db.select().from(knowledgeEntries).where(and(...conditions)).orderBy(sql`${knowledgeEntries.createdAt} DESC`).limit(limit);
|
|
483
481
|
}
|
|
484
482
|
async listTags() {
|
|
485
|
-
const result = await this.db.all(sql`SELECT DISTINCT value FROM knowledge_entries, json_each(knowledge_entries.tags)`);
|
|
483
|
+
const result = await this.db.all(sql`SELECT DISTINCT value FROM knowledge_entries, json_each(knowledge_entries.tags) WHERE knowledge_entries.type != 'system'`);
|
|
486
484
|
return result.map((r) => r.value);
|
|
487
485
|
}
|
|
488
486
|
async topTags(limit = 10) {
|
|
489
|
-
const result = await this.db.all(sql`SELECT value as tag, COUNT(*) as count FROM knowledge_entries, json_each(knowledge_entries.tags) GROUP BY value ORDER BY count DESC LIMIT ${limit}`);
|
|
487
|
+
const result = await this.db.all(sql`SELECT value as tag, COUNT(*) as count FROM knowledge_entries, json_each(knowledge_entries.tags) WHERE knowledge_entries.type != 'system' GROUP BY value ORDER BY count DESC LIMIT ${limit}`);
|
|
490
488
|
return result;
|
|
491
489
|
}
|
|
492
490
|
async count() {
|
|
493
|
-
const [result] = await this.db.select({ count: sql`count(*)` }).from(knowledgeEntries);
|
|
491
|
+
const [result] = await this.db.select({ count: sql`count(*)` }).from(knowledgeEntries).where(ne(knowledgeEntries.type, "system"));
|
|
494
492
|
return Number(result.count);
|
|
495
493
|
}
|
|
496
494
|
async lastUpdatedAt() {
|
|
@@ -501,18 +499,18 @@ var KnowledgeRepository = class {
|
|
|
501
499
|
const results = await this.db.select({
|
|
502
500
|
type: knowledgeEntries.type,
|
|
503
501
|
count: sql`count(*)`
|
|
504
|
-
}).from(knowledgeEntries).groupBy(knowledgeEntries.type);
|
|
502
|
+
}).from(knowledgeEntries).where(ne(knowledgeEntries.type, "system")).groupBy(knowledgeEntries.type);
|
|
505
503
|
return results.map((r) => ({ type: r.type, count: Number(r.count) }));
|
|
506
504
|
}
|
|
507
505
|
async countByScope() {
|
|
508
506
|
const results = await this.db.select({
|
|
509
507
|
scope: knowledgeEntries.scope,
|
|
510
508
|
count: sql`count(*)`
|
|
511
|
-
}).from(knowledgeEntries).groupBy(knowledgeEntries.scope);
|
|
509
|
+
}).from(knowledgeEntries).where(ne(knowledgeEntries.type, "system")).groupBy(knowledgeEntries.scope);
|
|
512
510
|
return results.map((r) => ({ scope: r.scope, count: Number(r.count) }));
|
|
513
511
|
}
|
|
514
512
|
async listAll() {
|
|
515
|
-
return this.db.select().from(knowledgeEntries).orderBy(sql`${knowledgeEntries.createdAt} DESC`);
|
|
513
|
+
return this.db.select().from(knowledgeEntries).where(ne(knowledgeEntries.type, "system")).orderBy(sql`${knowledgeEntries.createdAt} DESC`);
|
|
516
514
|
}
|
|
517
515
|
async listScopes() {
|
|
518
516
|
const rows = this.sqlite.prepare(`SELECT DISTINCT scope FROM knowledge_entries
|
|
@@ -638,6 +636,14 @@ var KnowledgeRepository = class {
|
|
|
638
636
|
getPlanTaskById(id) {
|
|
639
637
|
return this.sqlite.prepare("SELECT * FROM plan_tasks WHERE id = ?").get(id) ?? null;
|
|
640
638
|
}
|
|
639
|
+
getTaskPlanId(taskId) {
|
|
640
|
+
const row = this.sqlite.prepare("SELECT plan_id FROM plan_tasks WHERE id = ?").get(taskId);
|
|
641
|
+
return row?.plan_id ?? null;
|
|
642
|
+
}
|
|
643
|
+
countIncompleteTasks(planId) {
|
|
644
|
+
const row = this.sqlite.prepare("SELECT COUNT(*) as cnt FROM plan_tasks WHERE plan_id = ? AND status != 'completed'").get(planId);
|
|
645
|
+
return row?.cnt ?? 0;
|
|
646
|
+
}
|
|
641
647
|
getPlanTaskStats() {
|
|
642
648
|
const result = this.sqlite.prepare(`
|
|
643
649
|
SELECT
|
|
@@ -766,6 +772,11 @@ var KnowledgeService = class {
|
|
|
766
772
|
const errors = [];
|
|
767
773
|
for (const id of ids) {
|
|
768
774
|
try {
|
|
775
|
+
const entry = await this.repository.findById(id);
|
|
776
|
+
if (entry?.type === "system") {
|
|
777
|
+
errors.push(`Skipped ${id}: system knowledge cannot be deleted`);
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
769
780
|
const result = await this.repository.delete(id);
|
|
770
781
|
if (result) {
|
|
771
782
|
deleted++;
|
|
@@ -858,7 +869,17 @@ var KnowledgeService = class {
|
|
|
858
869
|
}
|
|
859
870
|
updatePlan(id, updates) {
|
|
860
871
|
const row = this.repository.updatePlan(id, updates);
|
|
861
|
-
|
|
872
|
+
if (!row)
|
|
873
|
+
return null;
|
|
874
|
+
if (updates.status === "completed") {
|
|
875
|
+
const tasks = this.repository.listPlanTasks(id);
|
|
876
|
+
for (const t of tasks) {
|
|
877
|
+
if (t.status !== "completed") {
|
|
878
|
+
this.repository.updatePlanTask(t.id, { status: "completed" });
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
return this.toPlan(row);
|
|
862
883
|
}
|
|
863
884
|
deletePlan(id) {
|
|
864
885
|
return this.repository.deletePlan(id);
|
|
@@ -934,7 +955,38 @@ var KnowledgeService = class {
|
|
|
934
955
|
}
|
|
935
956
|
updatePlanTask(id, updates) {
|
|
936
957
|
const row = this.repository.updatePlanTask(id, updates);
|
|
937
|
-
|
|
958
|
+
if (!row)
|
|
959
|
+
return null;
|
|
960
|
+
const task = this.toPlanTask(row);
|
|
961
|
+
const planId = this.repository.getTaskPlanId(id);
|
|
962
|
+
const autoActions = [];
|
|
963
|
+
if (planId) {
|
|
964
|
+
if (updates.status === "in_progress") {
|
|
965
|
+
const plan = this.repository.getPlanById(planId);
|
|
966
|
+
if (plan && (plan.status === "draft" || plan.status === "completed")) {
|
|
967
|
+
this.repository.updatePlan(planId, { status: "active" });
|
|
968
|
+
autoActions.push(`Plan auto-activated from ${plan.status} to active`);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
if (updates.status === "completed") {
|
|
972
|
+
const incomplete = this.repository.countIncompleteTasks(planId);
|
|
973
|
+
if (incomplete === 0) {
|
|
974
|
+
this.repository.updatePlan(planId, { status: "completed" });
|
|
975
|
+
autoActions.push("Plan auto-completed \u2014 all tasks done");
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
const currentPlan = planId ? this.repository.getPlanById(planId) : null;
|
|
980
|
+
const allTasks = planId ? this.repository.listPlanTasks(planId) : [];
|
|
981
|
+
const completedCount = allTasks.filter((t) => t.status === "completed").length;
|
|
982
|
+
const progress = `${completedCount}/${allTasks.length} completed`;
|
|
983
|
+
return {
|
|
984
|
+
task,
|
|
985
|
+
planId: planId ?? "",
|
|
986
|
+
planStatus: currentPlan?.status ?? "unknown",
|
|
987
|
+
progress,
|
|
988
|
+
autoActions
|
|
989
|
+
};
|
|
938
990
|
}
|
|
939
991
|
deletePlanTask(id) {
|
|
940
992
|
return this.repository.deletePlanTask(id);
|
|
@@ -1262,16 +1314,28 @@ var KnowledgeSDK = class {
|
|
|
1262
1314
|
throw new ValidationError(`Invalid updates: ${parsed.error.message}`);
|
|
1263
1315
|
}
|
|
1264
1316
|
try {
|
|
1317
|
+
const existing = await this.service.getById(id);
|
|
1318
|
+
if (existing?.type === "system" && updates.type && updates.type !== "system") {
|
|
1319
|
+
throw new ValidationError("System knowledge type cannot be changed");
|
|
1320
|
+
}
|
|
1265
1321
|
return await this.service.update(id, parsed.data);
|
|
1266
1322
|
} catch (error) {
|
|
1323
|
+
if (error instanceof ValidationError)
|
|
1324
|
+
throw error;
|
|
1267
1325
|
throw this.wrapError(error, "Failed to update knowledge");
|
|
1268
1326
|
}
|
|
1269
1327
|
}
|
|
1270
1328
|
async deleteKnowledge(id) {
|
|
1271
1329
|
this.ensureInitialized();
|
|
1272
1330
|
try {
|
|
1331
|
+
const existing = await this.service.getById(id);
|
|
1332
|
+
if (existing?.type === "system") {
|
|
1333
|
+
throw new ValidationError("System knowledge cannot be deleted");
|
|
1334
|
+
}
|
|
1273
1335
|
return await this.service.delete(id);
|
|
1274
1336
|
} catch (error) {
|
|
1337
|
+
if (error instanceof ValidationError)
|
|
1338
|
+
throw error;
|
|
1275
1339
|
throw this.wrapError(error, "Failed to delete knowledge");
|
|
1276
1340
|
}
|
|
1277
1341
|
}
|
|
@@ -1390,8 +1454,12 @@ var KnowledgeSDK = class {
|
|
|
1390
1454
|
this.ensureInitialized();
|
|
1391
1455
|
return this.service.listPlans(limit, status);
|
|
1392
1456
|
}
|
|
1393
|
-
addPlanRelation(planId, knowledgeId, relationType) {
|
|
1457
|
+
async addPlanRelation(planId, knowledgeId, relationType) {
|
|
1394
1458
|
this.ensureInitialized();
|
|
1459
|
+
const entry = await this.service.getById(knowledgeId);
|
|
1460
|
+
if (entry?.type === "system") {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1395
1463
|
this.service.addPlanRelation(planId, knowledgeId, relationType);
|
|
1396
1464
|
}
|
|
1397
1465
|
async getPlanRelations(planId) {
|
|
@@ -1411,6 +1479,16 @@ var KnowledgeSDK = class {
|
|
|
1411
1479
|
this.ensureInitialized();
|
|
1412
1480
|
return this.service.updatePlanTask(id, updates);
|
|
1413
1481
|
}
|
|
1482
|
+
updatePlanTasks(updates) {
|
|
1483
|
+
this.ensureInitialized();
|
|
1484
|
+
const results = [];
|
|
1485
|
+
for (const u of updates) {
|
|
1486
|
+
const result = this.service.updatePlanTask(u.taskId, { status: u.status, notes: u.notes });
|
|
1487
|
+
if (result)
|
|
1488
|
+
results.push(result);
|
|
1489
|
+
}
|
|
1490
|
+
return results;
|
|
1491
|
+
}
|
|
1414
1492
|
deletePlanTask(id) {
|
|
1415
1493
|
this.ensureInitialized();
|
|
1416
1494
|
return this.service.deletePlanTask(id);
|
|
@@ -1510,28 +1588,34 @@ var KnowledgeSDK = class {
|
|
|
1510
1588
|
};
|
|
1511
1589
|
|
|
1512
1590
|
// src/server.ts
|
|
1513
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1591
|
+
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1514
1592
|
import { z as z2 } from "zod";
|
|
1515
1593
|
var knowledgeTypeValues = ["decision", "pattern", "fix", "constraint", "gotcha"];
|
|
1516
1594
|
var knowledgeStatusValues = ["draft", "active", "completed", "archived"];
|
|
1595
|
+
var READ_ONLY = { readOnlyHint: true, destructiveHint: false };
|
|
1596
|
+
var WRITE = { readOnlyHint: false, destructiveHint: false };
|
|
1597
|
+
var DESTRUCTIVE = { readOnlyHint: false, destructiveHint: true };
|
|
1517
1598
|
function createServer(sdk) {
|
|
1518
1599
|
const server = new McpServer({
|
|
1519
1600
|
name: "cognistore",
|
|
1520
|
-
version: "
|
|
1601
|
+
version: "1.0.0"
|
|
1521
1602
|
});
|
|
1603
|
+
let lastSearchResultIds = [];
|
|
1522
1604
|
server.tool(
|
|
1523
1605
|
"addKnowledge",
|
|
1524
|
-
"Store a
|
|
1606
|
+
"Store a knowledge entry. If you have an active plan, ALWAYS pass planId to auto-link as output.",
|
|
1525
1607
|
{
|
|
1526
|
-
title: z2.string().describe("Short descriptive title
|
|
1527
|
-
content: z2.string().describe("The knowledge content text
|
|
1528
|
-
tags: z2.array(z2.string()).describe("
|
|
1529
|
-
type: z2.enum(knowledgeTypeValues).describe("Type
|
|
1608
|
+
title: z2.string().describe("Short descriptive title"),
|
|
1609
|
+
content: z2.string().describe("The knowledge content text"),
|
|
1610
|
+
tags: z2.array(z2.string()).describe("Categorical tags for filtering"),
|
|
1611
|
+
type: z2.enum(knowledgeTypeValues).describe("Type: decision, pattern, fix, constraint, or gotcha"),
|
|
1530
1612
|
scope: z2.string().describe('Scope: "global" or "workspace:<project-name>"'),
|
|
1531
1613
|
source: z2.string().describe("Source of the knowledge"),
|
|
1532
1614
|
confidenceScore: z2.number().min(0).max(1).optional().describe("Confidence score 0-1"),
|
|
1533
|
-
agentId: z2.string().optional().describe("ID of the agent that created this")
|
|
1615
|
+
agentId: z2.string().optional().describe("ID of the agent that created this"),
|
|
1616
|
+
planId: z2.string().optional().describe("Plan ID to auto-link this knowledge as output. ALWAYS pass this if you have an active plan.")
|
|
1534
1617
|
},
|
|
1618
|
+
WRITE,
|
|
1535
1619
|
async (params) => {
|
|
1536
1620
|
const result = await sdk.addKnowledge({
|
|
1537
1621
|
title: params.title,
|
|
@@ -1543,12 +1627,69 @@ function createServer(sdk) {
|
|
|
1543
1627
|
confidenceScore: params.confidenceScore,
|
|
1544
1628
|
agentId: params.agentId
|
|
1545
1629
|
});
|
|
1546
|
-
|
|
1630
|
+
let linked = false;
|
|
1631
|
+
let linkWarning = "";
|
|
1632
|
+
if (params.planId && result.type !== "system") {
|
|
1633
|
+
try {
|
|
1634
|
+
await sdk.addPlanRelation(params.planId, result.id, "output");
|
|
1635
|
+
linked = true;
|
|
1636
|
+
} catch (e) {
|
|
1637
|
+
linkWarning = e instanceof Error ? e.message : "Unknown linking error";
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
const response = { entry: result };
|
|
1641
|
+
if (params.planId) {
|
|
1642
|
+
response.linked = linked;
|
|
1643
|
+
response.planId = params.planId;
|
|
1644
|
+
if (linkWarning) response.linkWarning = linkWarning;
|
|
1645
|
+
}
|
|
1646
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1647
|
+
}
|
|
1648
|
+
);
|
|
1649
|
+
server.tool(
|
|
1650
|
+
"addKnowledgeBatch",
|
|
1651
|
+
"Create multiple knowledge entries at once. Pass planId per entry for output linking. Reduces tool calls.",
|
|
1652
|
+
{
|
|
1653
|
+
entries: z2.array(z2.object({
|
|
1654
|
+
title: z2.string(),
|
|
1655
|
+
content: z2.string(),
|
|
1656
|
+
tags: z2.array(z2.string()),
|
|
1657
|
+
type: z2.enum(knowledgeTypeValues),
|
|
1658
|
+
scope: z2.string(),
|
|
1659
|
+
source: z2.string(),
|
|
1660
|
+
planId: z2.string().optional()
|
|
1661
|
+
})).describe("Array of knowledge entries to create")
|
|
1662
|
+
},
|
|
1663
|
+
WRITE,
|
|
1664
|
+
async (params) => {
|
|
1665
|
+
const results = [];
|
|
1666
|
+
for (const e of params.entries) {
|
|
1667
|
+
const entry = await sdk.addKnowledge({
|
|
1668
|
+
title: e.title,
|
|
1669
|
+
content: e.content,
|
|
1670
|
+
tags: e.tags,
|
|
1671
|
+
type: e.type,
|
|
1672
|
+
scope: e.scope,
|
|
1673
|
+
source: e.source
|
|
1674
|
+
});
|
|
1675
|
+
let linked = false;
|
|
1676
|
+
let linkWarning = "";
|
|
1677
|
+
if (e.planId && entry.type !== "system") {
|
|
1678
|
+
try {
|
|
1679
|
+
await sdk.addPlanRelation(e.planId, entry.id, "output");
|
|
1680
|
+
linked = true;
|
|
1681
|
+
} catch (err) {
|
|
1682
|
+
linkWarning = err instanceof Error ? err.message : "Unknown linking error";
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
results.push({ entry, linked, ...e.planId ? { planId: e.planId } : {}, ...linkWarning ? { linkWarning } : {} });
|
|
1686
|
+
}
|
|
1687
|
+
return { content: [{ type: "text", text: JSON.stringify({ created: results.length, entries: results }, null, 2) }] };
|
|
1547
1688
|
}
|
|
1548
1689
|
);
|
|
1549
1690
|
server.tool(
|
|
1550
1691
|
"getKnowledge",
|
|
1551
|
-
"Search knowledge semantically.
|
|
1692
|
+
"Search knowledge semantically. SAVE returned entry IDs \u2014 pass them as relatedKnowledgeIds when calling createPlan.",
|
|
1552
1693
|
{
|
|
1553
1694
|
query: z2.string().describe("Natural language query to search for"),
|
|
1554
1695
|
tags: z2.array(z2.string()).optional().describe("Optional tag filters"),
|
|
@@ -1557,6 +1698,7 @@ function createServer(sdk) {
|
|
|
1557
1698
|
limit: z2.number().optional().describe("Max results (default: 10)"),
|
|
1558
1699
|
threshold: z2.number().optional().describe("Min similarity 0-1 (default: 0.3)")
|
|
1559
1700
|
},
|
|
1701
|
+
READ_ONLY,
|
|
1560
1702
|
async (params) => {
|
|
1561
1703
|
const results = await sdk.getKnowledge(params.query, {
|
|
1562
1704
|
tags: params.tags,
|
|
@@ -1565,7 +1707,23 @@ function createServer(sdk) {
|
|
|
1565
1707
|
limit: params.limit,
|
|
1566
1708
|
threshold: params.threshold
|
|
1567
1709
|
});
|
|
1568
|
-
|
|
1710
|
+
lastSearchResultIds = results.map((r) => r.entry.id);
|
|
1711
|
+
const response = { results };
|
|
1712
|
+
try {
|
|
1713
|
+
const activePlans = sdk.listPlans(1, "active");
|
|
1714
|
+
const draftPlans = sdk.listPlans(1, "draft");
|
|
1715
|
+
const currentPlan = activePlans[0] || draftPlans[0];
|
|
1716
|
+
if (currentPlan) {
|
|
1717
|
+
response.activePlan = {
|
|
1718
|
+
id: currentPlan.id,
|
|
1719
|
+
title: currentPlan.title,
|
|
1720
|
+
status: currentPlan.status,
|
|
1721
|
+
hint: "Pass this planId to addKnowledge calls for output linking."
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
} catch {
|
|
1725
|
+
}
|
|
1726
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1569
1727
|
}
|
|
1570
1728
|
);
|
|
1571
1729
|
server.tool(
|
|
@@ -1581,6 +1739,7 @@ function createServer(sdk) {
|
|
|
1581
1739
|
source: z2.string().optional().describe("New source"),
|
|
1582
1740
|
confidenceScore: z2.number().min(0).max(1).optional().describe("New confidence score")
|
|
1583
1741
|
},
|
|
1742
|
+
WRITE,
|
|
1584
1743
|
async (params) => {
|
|
1585
1744
|
const { id, ...updates } = params;
|
|
1586
1745
|
const result = await sdk.updateKnowledge(id, {
|
|
@@ -1592,8 +1751,8 @@ function createServer(sdk) {
|
|
|
1592
1751
|
source: updates.source,
|
|
1593
1752
|
confidenceScore: updates.confidenceScore
|
|
1594
1753
|
});
|
|
1595
|
-
|
|
1596
|
-
return { content: [{ type: "text", text:
|
|
1754
|
+
if (!result) return { content: [{ type: "text", text: JSON.stringify({ error: "not_found", type: "knowledge_entry", id }) }] };
|
|
1755
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1597
1756
|
}
|
|
1598
1757
|
);
|
|
1599
1758
|
server.tool(
|
|
@@ -1602,17 +1761,18 @@ function createServer(sdk) {
|
|
|
1602
1761
|
{
|
|
1603
1762
|
id: z2.string().describe("UUID of the knowledge entry to delete")
|
|
1604
1763
|
},
|
|
1764
|
+
DESTRUCTIVE,
|
|
1605
1765
|
async (params) => {
|
|
1606
1766
|
const deleted = await sdk.deleteKnowledge(params.id);
|
|
1607
|
-
return {
|
|
1608
|
-
|
|
1609
|
-
};
|
|
1767
|
+
if (!deleted) return { content: [{ type: "text", text: JSON.stringify({ error: "not_found", type: "knowledge_entry", id: params.id }) }] };
|
|
1768
|
+
return { content: [{ type: "text", text: JSON.stringify({ deleted: true, id: params.id }) }] };
|
|
1610
1769
|
}
|
|
1611
1770
|
);
|
|
1612
1771
|
server.tool(
|
|
1613
1772
|
"listTags",
|
|
1614
1773
|
"List all unique tags across all knowledge entries.",
|
|
1615
1774
|
{},
|
|
1775
|
+
READ_ONLY,
|
|
1616
1776
|
async () => {
|
|
1617
1777
|
const tags = await sdk.listTags();
|
|
1618
1778
|
return { content: [{ type: "text", text: JSON.stringify(tags) }] };
|
|
@@ -1622,6 +1782,7 @@ function createServer(sdk) {
|
|
|
1622
1782
|
"healthCheck",
|
|
1623
1783
|
"Check health of the knowledge base infrastructure (database, Ollama).",
|
|
1624
1784
|
{},
|
|
1785
|
+
READ_ONLY,
|
|
1625
1786
|
async () => {
|
|
1626
1787
|
const health = await sdk.healthCheck();
|
|
1627
1788
|
return { content: [{ type: "text", text: JSON.stringify(health, null, 2) }] };
|
|
@@ -1629,73 +1790,90 @@ function createServer(sdk) {
|
|
|
1629
1790
|
);
|
|
1630
1791
|
server.tool(
|
|
1631
1792
|
"createPlan",
|
|
1632
|
-
"Create a
|
|
1793
|
+
"Create a plan with tasks. Plan auto-activates when the first task starts. Returns planId \u2014 SAVE IT and pass to addKnowledge calls.",
|
|
1633
1794
|
{
|
|
1634
1795
|
title: z2.string().describe("Plan title (short, descriptive)"),
|
|
1635
1796
|
content: z2.string().describe("Full plan content (steps, approach, considerations)"),
|
|
1636
1797
|
tags: z2.array(z2.string()).describe("Tags for categorization"),
|
|
1637
1798
|
scope: z2.string().describe('Scope: "global" or "workspace:<project-name>"'),
|
|
1638
1799
|
source: z2.string().describe("Source/context of the plan"),
|
|
1639
|
-
relatedKnowledgeIds: z2.array(z2.string()).optional().describe("IDs of knowledge entries consulted during planning (input
|
|
1800
|
+
relatedKnowledgeIds: z2.array(z2.string()).optional().describe("IDs of knowledge entries consulted during planning (auto-linked as input)"),
|
|
1640
1801
|
tasks: z2.array(z2.object({
|
|
1641
1802
|
description: z2.string(),
|
|
1642
1803
|
priority: z2.enum(["low", "medium", "high"]).optional()
|
|
1643
|
-
})).optional().describe("
|
|
1804
|
+
})).optional().describe("Tasks for the plan. ALWAYS include tasks for multi-step work.")
|
|
1644
1805
|
},
|
|
1806
|
+
WRITE,
|
|
1645
1807
|
async (params) => {
|
|
1808
|
+
const inputIds = /* @__PURE__ */ new Set([
|
|
1809
|
+
...params.relatedKnowledgeIds || [],
|
|
1810
|
+
...lastSearchResultIds
|
|
1811
|
+
]);
|
|
1646
1812
|
const result = await sdk.createPlan({
|
|
1647
1813
|
title: params.title,
|
|
1648
1814
|
content: params.content,
|
|
1649
1815
|
tags: params.tags,
|
|
1650
1816
|
scope: params.scope,
|
|
1651
1817
|
source: params.source,
|
|
1652
|
-
relatedKnowledgeIds:
|
|
1818
|
+
relatedKnowledgeIds: inputIds.size > 0 ? [...inputIds] : void 0,
|
|
1653
1819
|
tasks: params.tasks
|
|
1654
1820
|
});
|
|
1655
|
-
|
|
1821
|
+
lastSearchResultIds = [];
|
|
1822
|
+
const response = {
|
|
1823
|
+
...result,
|
|
1824
|
+
reminder: `Your plan ID is "${result.id}". Pass planId: "${result.id}" to every addKnowledge call for output linking. Plan auto-activates when you start the first task.`
|
|
1825
|
+
};
|
|
1826
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1656
1827
|
}
|
|
1657
1828
|
);
|
|
1658
1829
|
server.tool(
|
|
1659
1830
|
"updatePlan",
|
|
1660
|
-
"Update
|
|
1831
|
+
"Update a plan. Status lifecycle: draft \u2192 active \u2192 completed. Plan auto-activates and auto-completes via task updates \u2014 usually you do not need to call this manually.",
|
|
1661
1832
|
{
|
|
1662
1833
|
planId: z2.string().describe("UUID of the plan to update"),
|
|
1663
1834
|
title: z2.string().optional().describe("New title"),
|
|
1664
1835
|
content: z2.string().optional().describe("New content"),
|
|
1665
1836
|
tags: z2.array(z2.string()).optional().describe("New tags"),
|
|
1666
1837
|
scope: z2.string().optional().describe("New scope"),
|
|
1667
|
-
status: z2.enum(knowledgeStatusValues).optional().describe("New status"),
|
|
1838
|
+
status: z2.enum(knowledgeStatusValues).optional().describe("New status (usually auto-managed)"),
|
|
1668
1839
|
source: z2.string().optional().describe("New source")
|
|
1669
1840
|
},
|
|
1841
|
+
WRITE,
|
|
1670
1842
|
async (params) => {
|
|
1671
1843
|
const { planId, ...updates } = params;
|
|
1672
1844
|
const result = sdk.updatePlan(planId, updates);
|
|
1673
|
-
|
|
1674
|
-
return { content: [{ type: "text", text:
|
|
1845
|
+
if (!result) return { content: [{ type: "text", text: JSON.stringify({ error: "not_found", type: "plan", id: planId }) }] };
|
|
1846
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1675
1847
|
}
|
|
1676
1848
|
);
|
|
1677
1849
|
server.tool(
|
|
1678
1850
|
"addPlanRelation",
|
|
1679
|
-
|
|
1851
|
+
"Link a knowledge entry to a plan. Input = consulted during planning, output = created during execution. Usually auto-handled \u2014 use only for manual linking.",
|
|
1680
1852
|
{
|
|
1681
1853
|
planId: z2.string().describe("UUID of the plan"),
|
|
1682
1854
|
knowledgeId: z2.string().describe("UUID of the knowledge entry to link"),
|
|
1683
|
-
relationType: z2.enum(["input", "output"]).describe('"input" = consulted
|
|
1855
|
+
relationType: z2.enum(["input", "output"]).describe('"input" = consulted, "output" = produced')
|
|
1684
1856
|
},
|
|
1857
|
+
WRITE,
|
|
1685
1858
|
async (params) => {
|
|
1686
|
-
|
|
1687
|
-
|
|
1859
|
+
try {
|
|
1860
|
+
sdk.addPlanRelation(params.planId, params.knowledgeId, params.relationType);
|
|
1861
|
+
return { content: [{ type: "text", text: JSON.stringify({ success: true, ...params }) }] };
|
|
1862
|
+
} catch (e) {
|
|
1863
|
+
return { content: [{ type: "text", text: JSON.stringify({ error: "link_failed", message: e instanceof Error ? e.message : "Unknown error", ...params }) }] };
|
|
1864
|
+
}
|
|
1688
1865
|
}
|
|
1689
1866
|
);
|
|
1690
1867
|
server.tool(
|
|
1691
1868
|
"addPlanTask",
|
|
1692
|
-
"Add a task to a plan
|
|
1869
|
+
"Add a task to a plan. Position is auto-calculated.",
|
|
1693
1870
|
{
|
|
1694
1871
|
planId: z2.string().describe("UUID of the plan"),
|
|
1695
1872
|
description: z2.string().describe("Task description"),
|
|
1696
1873
|
priority: z2.enum(["low", "medium", "high"]).optional().describe("Priority (default: medium)"),
|
|
1697
1874
|
notes: z2.string().optional().describe("Optional notes")
|
|
1698
1875
|
},
|
|
1876
|
+
WRITE,
|
|
1699
1877
|
async (params) => {
|
|
1700
1878
|
const task = sdk.createPlanTask(params);
|
|
1701
1879
|
return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
|
|
@@ -1703,7 +1881,7 @@ function createServer(sdk) {
|
|
|
1703
1881
|
);
|
|
1704
1882
|
server.tool(
|
|
1705
1883
|
"updatePlanTask",
|
|
1706
|
-
"Update a
|
|
1884
|
+
"Update a task status. Plan auto-activates on first in_progress and auto-completes when all tasks are done.",
|
|
1707
1885
|
{
|
|
1708
1886
|
taskId: z2.string().describe("UUID of the task"),
|
|
1709
1887
|
status: z2.enum(["pending", "in_progress", "completed"]).optional().describe("New status"),
|
|
@@ -1711,22 +1889,126 @@ function createServer(sdk) {
|
|
|
1711
1889
|
priority: z2.enum(["low", "medium", "high"]).optional().describe("New priority"),
|
|
1712
1890
|
notes: z2.string().nullable().optional().describe("Notes about progress or blockers")
|
|
1713
1891
|
},
|
|
1892
|
+
WRITE,
|
|
1714
1893
|
async (params) => {
|
|
1715
1894
|
const { taskId, ...updates } = params;
|
|
1716
|
-
const
|
|
1717
|
-
|
|
1718
|
-
|
|
1895
|
+
const result = sdk.updatePlanTask(taskId, updates);
|
|
1896
|
+
if (!result) return { content: [{ type: "text", text: JSON.stringify({ error: "not_found", type: "plan_task", id: taskId }) }] };
|
|
1897
|
+
const response = {
|
|
1898
|
+
task: result.task,
|
|
1899
|
+
plan: { id: result.planId, status: result.planStatus, progress: result.progress },
|
|
1900
|
+
...result.autoActions.length > 0 ? { autoActions: result.autoActions } : {},
|
|
1901
|
+
reminder: `Plan ID: "${result.planId}". Pass this planId to addKnowledge calls for output linking.`
|
|
1902
|
+
};
|
|
1903
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1904
|
+
}
|
|
1905
|
+
);
|
|
1906
|
+
server.tool(
|
|
1907
|
+
"updatePlanTasks",
|
|
1908
|
+
"Update multiple tasks at once. Reduces tool calls. Plan auto-activates and auto-completes automatically.",
|
|
1909
|
+
{
|
|
1910
|
+
updates: z2.array(z2.object({
|
|
1911
|
+
taskId: z2.string().describe("UUID of the task"),
|
|
1912
|
+
status: z2.enum(["pending", "in_progress", "completed"]).optional(),
|
|
1913
|
+
notes: z2.string().nullable().optional()
|
|
1914
|
+
})).describe("Array of task updates")
|
|
1915
|
+
},
|
|
1916
|
+
WRITE,
|
|
1917
|
+
async (params) => {
|
|
1918
|
+
const results = sdk.updatePlanTasks(params.updates);
|
|
1919
|
+
const allAutoActions = results.flatMap((r) => r.autoActions);
|
|
1920
|
+
const lastResult = results[results.length - 1];
|
|
1921
|
+
const response = {
|
|
1922
|
+
updated: results.length,
|
|
1923
|
+
tasks: results.map((r) => ({ id: r.task.id, status: r.task.status, description: r.task.description })),
|
|
1924
|
+
plan: lastResult ? { id: lastResult.planId, status: lastResult.planStatus, progress: lastResult.progress } : void 0,
|
|
1925
|
+
...allAutoActions.length > 0 ? { autoActions: allAutoActions } : {},
|
|
1926
|
+
reminder: lastResult ? `Plan ID: "${lastResult.planId}". Pass this planId to addKnowledge calls.` : void 0
|
|
1927
|
+
};
|
|
1928
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1719
1929
|
}
|
|
1720
1930
|
);
|
|
1721
1931
|
server.tool(
|
|
1722
1932
|
"listPlanTasks",
|
|
1723
|
-
"List all tasks for a plan, ordered by position.
|
|
1933
|
+
"List all tasks for a plan, ordered by position. Shows progress.",
|
|
1724
1934
|
{
|
|
1725
1935
|
planId: z2.string().describe("UUID of the plan")
|
|
1726
1936
|
},
|
|
1937
|
+
READ_ONLY,
|
|
1727
1938
|
async (params) => {
|
|
1728
1939
|
const tasks = sdk.listPlanTasks(params.planId);
|
|
1729
|
-
|
|
1940
|
+
const completed = tasks.filter((t) => t.status === "completed").length;
|
|
1941
|
+
const response = {
|
|
1942
|
+
tasks,
|
|
1943
|
+
progress: `${completed}/${tasks.length} completed`,
|
|
1944
|
+
reminder: `Plan ID: "${params.planId}". Pass this planId to addKnowledge calls for output linking.`
|
|
1945
|
+
};
|
|
1946
|
+
return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] };
|
|
1947
|
+
}
|
|
1948
|
+
);
|
|
1949
|
+
server.resource(
|
|
1950
|
+
"knowledge-context",
|
|
1951
|
+
new ResourceTemplate("cognistore://context/{scope}", { list: void 0 }),
|
|
1952
|
+
{ description: "Workspace-scoped knowledge base context with recent entries and active plans" },
|
|
1953
|
+
async (uri, variables) => {
|
|
1954
|
+
const scope = variables.scope || "global";
|
|
1955
|
+
const scopeFilter = scope === "global" ? void 0 : `workspace:${scope}`;
|
|
1956
|
+
let knowledgeSection = "";
|
|
1957
|
+
try {
|
|
1958
|
+
const results = await sdk.getKnowledge("*", { scope: scopeFilter, limit: 10, threshold: 0 });
|
|
1959
|
+
if (results.length > 0) {
|
|
1960
|
+
knowledgeSection = "## Recent Knowledge\n\n" + results.map(
|
|
1961
|
+
(r) => `- **${r.entry.title}** (${r.entry.type}, ${r.entry.scope})
|
|
1962
|
+
${r.entry.content.slice(0, 200)}${r.entry.content.length > 200 ? "..." : ""}`
|
|
1963
|
+
).join("\n\n");
|
|
1964
|
+
} else {
|
|
1965
|
+
knowledgeSection = "## Recent Knowledge\n\nNo entries found for this scope.";
|
|
1966
|
+
}
|
|
1967
|
+
} catch {
|
|
1968
|
+
knowledgeSection = "## Recent Knowledge\n\nUnable to fetch entries.";
|
|
1969
|
+
}
|
|
1970
|
+
let plansSection = "";
|
|
1971
|
+
try {
|
|
1972
|
+
const plans = sdk.listPlans(10, "active");
|
|
1973
|
+
const scopedPlans = scopeFilter ? plans.filter((p) => p.scope === scopeFilter || p.scope === "global") : plans;
|
|
1974
|
+
if (scopedPlans.length > 0) {
|
|
1975
|
+
const planEntries = scopedPlans.map((p) => {
|
|
1976
|
+
const tasks = sdk.listPlanTasks(p.id);
|
|
1977
|
+
const completed = tasks.filter((t) => t.status === "completed").length;
|
|
1978
|
+
return `- **${p.title}** (${p.status}, ${completed}/${tasks.length} tasks done)
|
|
1979
|
+
${p.content.slice(0, 150)}${p.content.length > 150 ? "..." : ""}`;
|
|
1980
|
+
});
|
|
1981
|
+
plansSection = "## Active Plans\n\n" + planEntries.join("\n\n");
|
|
1982
|
+
} else {
|
|
1983
|
+
plansSection = "## Active Plans\n\nNo active plans for this scope.";
|
|
1984
|
+
}
|
|
1985
|
+
} catch {
|
|
1986
|
+
plansSection = "## Active Plans\n\nUnable to fetch plans.";
|
|
1987
|
+
}
|
|
1988
|
+
let tagsSection = "";
|
|
1989
|
+
try {
|
|
1990
|
+
const tags = await sdk.listTags();
|
|
1991
|
+
if (tags.length > 0) {
|
|
1992
|
+
tagsSection = `## Tags
|
|
1993
|
+
|
|
1994
|
+
${tags.slice(0, 20).join(", ")}`;
|
|
1995
|
+
}
|
|
1996
|
+
} catch {
|
|
1997
|
+
}
|
|
1998
|
+
const content = `# CogniStore Context \u2014 ${scope}
|
|
1999
|
+
|
|
2000
|
+
${knowledgeSection}
|
|
2001
|
+
|
|
2002
|
+
${plansSection}
|
|
2003
|
+
|
|
2004
|
+
${tagsSection}`.trim();
|
|
2005
|
+
return {
|
|
2006
|
+
contents: [{
|
|
2007
|
+
uri: uri.href,
|
|
2008
|
+
text: content,
|
|
2009
|
+
mimeType: "text/markdown"
|
|
2010
|
+
}]
|
|
2011
|
+
};
|
|
1730
2012
|
}
|
|
1731
2013
|
);
|
|
1732
2014
|
return server;
|