kibi-mcp 0.2.3 → 0.2.4

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.
@@ -68,13 +68,15 @@ export async function handleKbQuery(prolog, args) {
68
68
  goal = `findall(['${safeId}',Type,Props], kb_entity('${safeId}', Type, Props), Results)`;
69
69
  }
70
70
  else if (tags && tags.length > 0) {
71
- const tagList = `[${tags.map((t) => `'${escapeAtomContent(t)}'`).join(",")}]`;
71
+ // TODO: Reintroduce server-side (Prolog) tag filtering once normalization
72
+ // issues with tag list formats are resolved, to avoid fetching all entities
73
+ // before filtering in JS for large knowledge bases.
72
74
  if (type) {
73
75
  const safeType = escapeAtomContent(type);
74
- goal = `findall([Id,'${safeType}',Props], (kb_entity(Id, '${safeType}', Props), memberchk(tags=Tags, Props), member(Tag, Tags), member(Tag, ${tagList})), Results)`;
76
+ goal = `findall([Id,'${safeType}',Props], kb_entity(Id, '${safeType}', Props), Results)`;
75
77
  }
76
78
  else {
77
- goal = `findall([Id,Type,Props], (kb_entity(Id, Type, Props), memberchk(tags=Tags, Props), member(Tag, Tags), member(Tag, ${tagList})), Results)`;
79
+ goal = "findall([Id,Type,Props], kb_entity(Id, Type, Props), Results)";
78
80
  }
79
81
  }
80
82
  else if (type) {
@@ -101,6 +103,9 @@ export async function handleKbQuery(prolog, args) {
101
103
  else {
102
104
  throw new Error(queryResult.error || "Query failed with unknown error");
103
105
  }
106
+ if (tags && tags.length > 0) {
107
+ results = dedupeEntities(results.filter((entity) => hasAnyTag(entity, tags)));
108
+ }
104
109
  // Apply pagination
105
110
  const paginated = results.slice(offset, offset + limit);
106
111
  // Build human-readable text with entity IDs and titles
@@ -138,6 +143,37 @@ export async function handleKbQuery(prolog, args) {
138
143
  throw new Error(`Query execution failed: ${message}`);
139
144
  }
140
145
  }
146
+ function hasAnyTag(entity, requestedTags) {
147
+ const expected = new Set(requestedTags.map(normalizeTagValue));
148
+ const rawTags = entity.tags;
149
+ if (!Array.isArray(rawTags) || rawTags.length === 0) {
150
+ return false;
151
+ }
152
+ for (const tag of rawTags) {
153
+ if (expected.has(normalizeTagValue(tag))) {
154
+ return true;
155
+ }
156
+ }
157
+ return false;
158
+ }
159
+ function normalizeTagValue(tag) {
160
+ return String(tag).trim();
161
+ }
162
+ function dedupeEntities(entities) {
163
+ const seen = new Set();
164
+ const deduped = [];
165
+ for (const entity of entities) {
166
+ const id = String(entity.id ?? "");
167
+ const type = String(entity.type ?? "");
168
+ const key = `${type}::${id}`;
169
+ if (seen.has(key)) {
170
+ continue;
171
+ }
172
+ seen.add(key);
173
+ deduped.push(entity);
174
+ }
175
+ return deduped;
176
+ }
141
177
  /**
142
178
  * Parse a Prolog list of lists into a JavaScript array.
143
179
  * Input: "[[a,b,c],[d,e,f]]"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kibi-mcp",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "dependencies": {
5
5
  "@modelcontextprotocol/sdk": "^1.26.0",
6
6
  "ajv": "^8.18.0",
@@ -10,7 +10,7 @@
10
10
  "gray-matter": "^4.0.3",
11
11
  "js-yaml": "^4.1.0",
12
12
  "kibi-cli": "^0.2.3",
13
- "kibi-core": "^0.1.7",
13
+ "kibi-core": "^0.1.8",
14
14
  "mcpcat": "^0.1.12",
15
15
  "ts-morph": "^23.0.0",
16
16
  "zod": "^4.3.6"