kibi-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/kibi-mcp +59 -0
- package/dist/env.js +99 -0
- package/dist/mcpcat.js +129 -0
- package/dist/server.js +673 -0
- package/dist/tools/branch.js +208 -0
- package/dist/tools/check.js +349 -0
- package/dist/tools/context.js +280 -0
- package/dist/tools/coverage-report.js +91 -0
- package/dist/tools/delete.js +100 -0
- package/dist/tools/derive.js +311 -0
- package/dist/tools/impact.js +70 -0
- package/dist/tools/list-types.js +75 -0
- package/dist/tools/prolog-list.js +176 -0
- package/dist/tools/query-relationships.js +176 -0
- package/dist/tools/query.js +364 -0
- package/dist/tools/suggest-shared-facts.js +138 -0
- package/dist/tools/symbols.js +219 -0
- package/dist/tools/upsert.js +228 -0
- package/dist/tools-config.js +448 -0
- package/dist/workspace.js +126 -0
- package/package.json +43 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
/*
|
|
19
|
+
How to apply this header to source files (examples)
|
|
20
|
+
|
|
21
|
+
1) Prepend header to a single file (POSIX shells):
|
|
22
|
+
|
|
23
|
+
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
+
|
|
25
|
+
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
+
|
|
27
|
+
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
+
if [ -f "$f" ]; then
|
|
29
|
+
cp "$f" "$f".bak
|
|
30
|
+
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
+
|
|
36
|
+
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
+
if [ -f "$f" ]; then
|
|
38
|
+
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
+
cp "$f" "$f".bak
|
|
40
|
+
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
done
|
|
44
|
+
*/
|
|
45
|
+
export const TOOLS = [
|
|
46
|
+
{
|
|
47
|
+
name: "kb_query",
|
|
48
|
+
description: "Read entities from the KB with filters. Use for discovery and lookup before edits. Do not use for writes. No mutation side effects.",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
properties: {
|
|
52
|
+
type: {
|
|
53
|
+
type: "string",
|
|
54
|
+
enum: [
|
|
55
|
+
"req",
|
|
56
|
+
"scenario",
|
|
57
|
+
"test",
|
|
58
|
+
"adr",
|
|
59
|
+
"flag",
|
|
60
|
+
"event",
|
|
61
|
+
"symbol",
|
|
62
|
+
"fact",
|
|
63
|
+
],
|
|
64
|
+
description: "Optional entity type filter. Allowed: req, scenario, test, adr, flag, event, symbol, fact. Example: 'req'.",
|
|
65
|
+
},
|
|
66
|
+
id: {
|
|
67
|
+
type: "string",
|
|
68
|
+
description: "Optional exact entity ID. Example: 'REQ-001'. If omitted, returns matching entities by other filters.",
|
|
69
|
+
},
|
|
70
|
+
tags: {
|
|
71
|
+
type: "array",
|
|
72
|
+
items: { type: "string" },
|
|
73
|
+
description: "Optional tag filter. Matches entities that contain any provided tag. Example: ['security','billing'].",
|
|
74
|
+
},
|
|
75
|
+
sourceFile: {
|
|
76
|
+
type: "string",
|
|
77
|
+
description: "Optional source-file substring filter. Example: 'src/auth/login.ts'. Uses KB source linkage, not file-system scanning.",
|
|
78
|
+
},
|
|
79
|
+
limit: {
|
|
80
|
+
type: "number",
|
|
81
|
+
default: 100,
|
|
82
|
+
description: "Optional max rows to return after filtering. Default: 100 when omitted. Example: 25.",
|
|
83
|
+
},
|
|
84
|
+
offset: {
|
|
85
|
+
type: "number",
|
|
86
|
+
default: 0,
|
|
87
|
+
description: "Optional zero-based pagination offset. Default: 0. Example: 50 to skip first 50 rows.",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "kb_upsert",
|
|
94
|
+
description: "Create or update one entity and optional relationships. Use for KB mutations after validating intent. Use the `relationships` array for batch creation of multiple links in a single call (e.g., linking a requirement to multiple tests or facts). Prefer modeling requirements as reusable fact links (`constrains`, `requires_property`) so consistency and contradiction checks remain queryable. Do not use for read-only inspection. Side effects: writes KB, may refresh symbol coordinates.",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
required: ["type", "id", "properties"],
|
|
98
|
+
properties: {
|
|
99
|
+
type: {
|
|
100
|
+
type: "string",
|
|
101
|
+
enum: [
|
|
102
|
+
"req",
|
|
103
|
+
"scenario",
|
|
104
|
+
"test",
|
|
105
|
+
"adr",
|
|
106
|
+
"flag",
|
|
107
|
+
"event",
|
|
108
|
+
"symbol",
|
|
109
|
+
"fact",
|
|
110
|
+
],
|
|
111
|
+
description: "Entity type to create/update. Allowed: req, scenario, test, adr, flag, event, symbol, fact. Example: 'req'.",
|
|
112
|
+
},
|
|
113
|
+
id: {
|
|
114
|
+
type: "string",
|
|
115
|
+
description: "Unique entity ID (string). Example: 'REQ-123'. Existing ID updates the entity; new ID creates it.",
|
|
116
|
+
},
|
|
117
|
+
properties: {
|
|
118
|
+
type: "object",
|
|
119
|
+
description: "Entity fields to persist. Must include title and status. If created_at, updated_at, or source are omitted, server fills defaults.",
|
|
120
|
+
properties: {
|
|
121
|
+
title: {
|
|
122
|
+
type: "string",
|
|
123
|
+
description: "Required short title. Example: 'Protect account settings endpoint'.",
|
|
124
|
+
},
|
|
125
|
+
status: {
|
|
126
|
+
type: "string",
|
|
127
|
+
enum: [
|
|
128
|
+
"active",
|
|
129
|
+
"draft",
|
|
130
|
+
"archived",
|
|
131
|
+
"deleted",
|
|
132
|
+
"approved",
|
|
133
|
+
"rejected",
|
|
134
|
+
"pending",
|
|
135
|
+
"in_progress",
|
|
136
|
+
"superseded",
|
|
137
|
+
],
|
|
138
|
+
description: "Required lifecycle state. Allowed values are fixed enum options. Example: 'active'.",
|
|
139
|
+
},
|
|
140
|
+
source: {
|
|
141
|
+
type: "string",
|
|
142
|
+
description: "Optional provenance string. Example: 'docs/requirements/REQ-123.md'. Defaults to 'mcp://kibi/upsert'.",
|
|
143
|
+
},
|
|
144
|
+
tags: {
|
|
145
|
+
type: "array",
|
|
146
|
+
items: { type: "string" },
|
|
147
|
+
description: "Optional categorization tags. Example: ['security','api'].",
|
|
148
|
+
},
|
|
149
|
+
owner: {
|
|
150
|
+
type: "string",
|
|
151
|
+
description: "Optional owner name/team. Example: 'platform-team'.",
|
|
152
|
+
},
|
|
153
|
+
priority: {
|
|
154
|
+
type: "string",
|
|
155
|
+
description: "Optional priority label. Example: 'high'.",
|
|
156
|
+
},
|
|
157
|
+
severity: {
|
|
158
|
+
type: "string",
|
|
159
|
+
description: "Optional severity label. Example: 'critical'.",
|
|
160
|
+
},
|
|
161
|
+
links: {
|
|
162
|
+
type: "array",
|
|
163
|
+
items: { type: "string" },
|
|
164
|
+
description: "Optional references. Example: ['REQ-010','https://example.com/spec'].",
|
|
165
|
+
},
|
|
166
|
+
text_ref: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Optional text anchor/reference. Example: 'requirements.md#L40'.",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
required: ["title", "status"],
|
|
172
|
+
},
|
|
173
|
+
relationships: {
|
|
174
|
+
type: "array",
|
|
175
|
+
description: "Optional relationship rows to create in the same call. For requirement encoding, prefer `constrains` + `requires_property` edges from req IDs to shared fact IDs to maximize reuse and detect conflicts. Side effect: asserts edges in KB.",
|
|
176
|
+
items: {
|
|
177
|
+
type: "object",
|
|
178
|
+
required: ["type", "from", "to"],
|
|
179
|
+
properties: {
|
|
180
|
+
type: {
|
|
181
|
+
type: "string",
|
|
182
|
+
enum: [
|
|
183
|
+
"depends_on",
|
|
184
|
+
"specified_by",
|
|
185
|
+
"verified_by",
|
|
186
|
+
"validates",
|
|
187
|
+
"implements",
|
|
188
|
+
"covered_by",
|
|
189
|
+
"constrained_by",
|
|
190
|
+
"constrains",
|
|
191
|
+
"requires_property",
|
|
192
|
+
"guards",
|
|
193
|
+
"publishes",
|
|
194
|
+
"consumes",
|
|
195
|
+
"supersedes",
|
|
196
|
+
"relates_to",
|
|
197
|
+
],
|
|
198
|
+
description: "Relationship type enum. Use only supported values. Direction semantics follow KB model (e.g., implements symbol->req, verified_by req->test).",
|
|
199
|
+
},
|
|
200
|
+
from: {
|
|
201
|
+
type: "string",
|
|
202
|
+
description: "Source entity ID (must exist). Example: 'SYM-login-handler'.",
|
|
203
|
+
},
|
|
204
|
+
to: {
|
|
205
|
+
type: "string",
|
|
206
|
+
description: "Target entity ID (must exist). Example: 'REQ-001'.",
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "kb_delete",
|
|
216
|
+
description: "Delete entities by ID. Use only for intentional removals after dependency checks. Do not use as a bulk cleanup shortcut. Side effects: mutates and saves KB; skips entities with dependents.",
|
|
217
|
+
inputSchema: {
|
|
218
|
+
type: "object",
|
|
219
|
+
required: ["ids"],
|
|
220
|
+
properties: {
|
|
221
|
+
ids: {
|
|
222
|
+
type: "array",
|
|
223
|
+
items: { type: "string" },
|
|
224
|
+
description: "Required list of entity IDs to delete. Example: ['REQ-001','TEST-002']. At least one ID is required.",
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: "kb_check",
|
|
231
|
+
description: "Run KB validation rules and return violations. Use before or after mutations. Do not use for point lookups. No write side effects.",
|
|
232
|
+
inputSchema: {
|
|
233
|
+
type: "object",
|
|
234
|
+
properties: {
|
|
235
|
+
rules: {
|
|
236
|
+
type: "array",
|
|
237
|
+
items: { type: "string" },
|
|
238
|
+
description: "Optional rule subset. Allowed: must-priority-coverage, no-dangling-refs, no-cycles, required-fields, symbol-coverage. If omitted, server runs all.",
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: "kb_branch_ensure",
|
|
245
|
+
description: "Ensure a branch KB exists, creating it from develop when missing. Use when targeting non-develop branches. Do not use to switch git branches. Side effects: creates .kb/branches/<branch>.",
|
|
246
|
+
inputSchema: {
|
|
247
|
+
type: "object",
|
|
248
|
+
required: ["branch"],
|
|
249
|
+
properties: {
|
|
250
|
+
branch: {
|
|
251
|
+
type: "string",
|
|
252
|
+
description: "Required git branch name. Example: 'feature/auth-hardening'. Path traversal patterns are rejected.",
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "kb_branch_gc",
|
|
259
|
+
description: "Find or delete stale branch KB directories not present in git. Use for repository hygiene. Do not use if you need historical branch KBs. Side effects: can delete branch KB folders when dry_run is false.",
|
|
260
|
+
inputSchema: {
|
|
261
|
+
type: "object",
|
|
262
|
+
properties: {
|
|
263
|
+
dry_run: {
|
|
264
|
+
type: "boolean",
|
|
265
|
+
default: true,
|
|
266
|
+
description: "Optional safety flag. true = report only; false = delete stale branch KBs. Default: true.",
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: "kb_query_relationships",
|
|
273
|
+
description: "Read relationship edges with optional from/to/type filters. Use for traceability traversal. Do not use to create links. No mutation side effects.",
|
|
274
|
+
inputSchema: {
|
|
275
|
+
type: "object",
|
|
276
|
+
properties: {
|
|
277
|
+
from: {
|
|
278
|
+
type: "string",
|
|
279
|
+
description: "Optional source entity ID filter. Example: 'REQ-001'.",
|
|
280
|
+
},
|
|
281
|
+
to: {
|
|
282
|
+
type: "string",
|
|
283
|
+
description: "Optional target entity ID filter. Example: 'TEST-010'.",
|
|
284
|
+
},
|
|
285
|
+
type: {
|
|
286
|
+
type: "string",
|
|
287
|
+
enum: [
|
|
288
|
+
"depends_on",
|
|
289
|
+
"specified_by",
|
|
290
|
+
"verified_by",
|
|
291
|
+
"validates",
|
|
292
|
+
"implements",
|
|
293
|
+
"covered_by",
|
|
294
|
+
"constrained_by",
|
|
295
|
+
"constrains",
|
|
296
|
+
"requires_property",
|
|
297
|
+
"guards",
|
|
298
|
+
"publishes",
|
|
299
|
+
"consumes",
|
|
300
|
+
"supersedes",
|
|
301
|
+
"relates_to",
|
|
302
|
+
],
|
|
303
|
+
description: "Optional relationship type filter. Allowed enum values only. Example: 'implements'.",
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "kb_derive",
|
|
310
|
+
description: "Run deterministic inference predicates and return rows. Use for impact, coverage, and consistency analysis. Do not use for entity CRUD. No mutation side effects.",
|
|
311
|
+
inputSchema: {
|
|
312
|
+
type: "object",
|
|
313
|
+
required: ["rule"],
|
|
314
|
+
properties: {
|
|
315
|
+
rule: {
|
|
316
|
+
type: "string",
|
|
317
|
+
enum: [
|
|
318
|
+
"transitively_implements",
|
|
319
|
+
"transitively_depends",
|
|
320
|
+
"impacted_by_change",
|
|
321
|
+
"affected_symbols",
|
|
322
|
+
"coverage_gap",
|
|
323
|
+
"untested_symbols",
|
|
324
|
+
"stale",
|
|
325
|
+
"orphaned",
|
|
326
|
+
"conflicting",
|
|
327
|
+
"deprecated_still_used",
|
|
328
|
+
"current_adr",
|
|
329
|
+
"adr_chain",
|
|
330
|
+
"superseded_by",
|
|
331
|
+
"domain_contradictions",
|
|
332
|
+
],
|
|
333
|
+
description: "Required inference rule name. Allowed values are the enum options. Example: 'coverage_gap'.",
|
|
334
|
+
},
|
|
335
|
+
params: {
|
|
336
|
+
type: "object",
|
|
337
|
+
description: "Optional rule-specific parameters. Example: { changed: 'REQ-001' } for impacted_by_change.",
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: "kb_impact",
|
|
344
|
+
description: "Return entities impacted by a changed entity ID. Use for quick change blast radius checks. Do not use for general querying. No mutation side effects.",
|
|
345
|
+
inputSchema: {
|
|
346
|
+
type: "object",
|
|
347
|
+
required: ["entity"],
|
|
348
|
+
properties: {
|
|
349
|
+
entity: {
|
|
350
|
+
type: "string",
|
|
351
|
+
description: "Required changed entity ID. Example: 'REQ-001'.",
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: "kb_coverage_report",
|
|
358
|
+
description: "Compute aggregate traceability coverage for requirements and/or symbols. Use for health snapshots. Do not use for raw entity dumps. No mutation side effects.",
|
|
359
|
+
inputSchema: {
|
|
360
|
+
type: "object",
|
|
361
|
+
properties: {
|
|
362
|
+
type: {
|
|
363
|
+
type: "string",
|
|
364
|
+
enum: ["req", "symbol"],
|
|
365
|
+
description: "Optional focus scope: 'req' or 'symbol'. Omit to include both.",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "kb_symbols_refresh",
|
|
372
|
+
description: "Refresh generated symbol coordinates in the symbols manifest. Use after refactors that move symbols. Do not use for semantic edits. Side effects: may rewrite symbols.yaml unless dryRun is true.",
|
|
373
|
+
inputSchema: {
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
dryRun: {
|
|
377
|
+
type: "boolean",
|
|
378
|
+
default: false,
|
|
379
|
+
description: "Optional preview mode. true = report only, false = apply file updates. Default: false.",
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: "kb_list_entity_types",
|
|
386
|
+
description: "List supported entity type names. Use when building valid tool arguments. Do not use for entity data retrieval. No mutation side effects.",
|
|
387
|
+
inputSchema: { type: "object", properties: {} },
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
name: "kb_list_relationship_types",
|
|
391
|
+
description: "List supported relationship type names. Use before asserting or filtering relationships. Do not use for graph traversal. No mutation side effects.",
|
|
392
|
+
inputSchema: { type: "object", properties: {} },
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
name: "kbcontext",
|
|
396
|
+
description: "Return KB entities linked to a source file plus first-hop relationships. Use for file-centric traceability. Do not use for cross-repo search. No mutation side effects.",
|
|
397
|
+
inputSchema: {
|
|
398
|
+
type: "object",
|
|
399
|
+
required: ["sourceFile"],
|
|
400
|
+
properties: {
|
|
401
|
+
sourceFile: {
|
|
402
|
+
type: "string",
|
|
403
|
+
description: "Required source path substring. Example: 'src/auth/login.ts'.",
|
|
404
|
+
},
|
|
405
|
+
branch: {
|
|
406
|
+
type: "string",
|
|
407
|
+
description: "Optional branch hint for clients. Must match the server's active branch or will return an error.",
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
name: "get_help",
|
|
414
|
+
description: "Returns documentation for this MCP server. Call this first if you are unsure how to proceed or which tool to use. Available topics: overview, tools, workflow, constraints, examples, errors.",
|
|
415
|
+
inputSchema: {
|
|
416
|
+
type: "object",
|
|
417
|
+
properties: {
|
|
418
|
+
topic: {
|
|
419
|
+
type: "string",
|
|
420
|
+
enum: [
|
|
421
|
+
"overview",
|
|
422
|
+
"tools",
|
|
423
|
+
"workflow",
|
|
424
|
+
"constraints",
|
|
425
|
+
"examples",
|
|
426
|
+
"errors",
|
|
427
|
+
"branching",
|
|
428
|
+
],
|
|
429
|
+
description: "Optional documentation section. Omit to return overview. Example: 'workflow'.",
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "analyze_shared_facts",
|
|
436
|
+
description: "Analyze requirements and suggest shared domain facts for extraction. LLMs call this to identify missed semantic opportunities before upserting. Lightweight heuristic: finds overlapping capitalized terms and repeated phrases across requirements.",
|
|
437
|
+
inputSchema: {
|
|
438
|
+
type: "object",
|
|
439
|
+
properties: {
|
|
440
|
+
min_frequency: {
|
|
441
|
+
type: "number",
|
|
442
|
+
default: 2,
|
|
443
|
+
description: "Minimum frequency threshold for shared concepts. Default: 2. Example: 3 to only show concepts mentioned in 3+ requirements.",
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
];
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
/*
|
|
19
|
+
How to apply this header to source files (examples)
|
|
20
|
+
|
|
21
|
+
1) Prepend header to a single file (POSIX shells):
|
|
22
|
+
|
|
23
|
+
cat LICENSE_HEADER.txt "$FILE" > "$FILE".with-header && mv "$FILE".with-header "$FILE"
|
|
24
|
+
|
|
25
|
+
2) Apply to multiple files (example: the project's main entry files):
|
|
26
|
+
|
|
27
|
+
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp packages/cli/src/*.ts packages/mcp/src/*.ts; do
|
|
28
|
+
if [ -f "$f" ]; then
|
|
29
|
+
cp "$f" "$f".bak
|
|
30
|
+
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
3) Avoid duplicating the header: run a quick guard to only add if missing
|
|
35
|
+
|
|
36
|
+
for f in packages/cli/bin/kibi packages/mcp/bin/kibi-mcp; do
|
|
37
|
+
if [ -f "$f" ]; then
|
|
38
|
+
if ! head -n 5 "$f" | grep -q "Copyright (C) 2026 Piotr Franczyk"; then
|
|
39
|
+
cp "$f" "$f".bak
|
|
40
|
+
(cat LICENSE_HEADER.txt; echo; cat "$f" ) > "$f".new && mv "$f".new "$f"
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
done
|
|
44
|
+
*/
|
|
45
|
+
import fs from "node:fs";
|
|
46
|
+
import path from "node:path";
|
|
47
|
+
const WORKSPACE_ENV_KEYS = [
|
|
48
|
+
"KIBI_WORKSPACE",
|
|
49
|
+
"KIBI_PROJECT_ROOT",
|
|
50
|
+
"KIBI_ROOT",
|
|
51
|
+
];
|
|
52
|
+
const KB_PATH_ENV_KEYS = ["KIBI_KB_PATH", "KB_PATH"];
|
|
53
|
+
export function resolveWorkspaceRoot(startDir = process.cwd()) {
|
|
54
|
+
const envRoot = readFirstEnv(WORKSPACE_ENV_KEYS);
|
|
55
|
+
if (envRoot) {
|
|
56
|
+
return path.resolve(envRoot);
|
|
57
|
+
}
|
|
58
|
+
const kbRoot = findUpwards(startDir, ".kb");
|
|
59
|
+
if (kbRoot) {
|
|
60
|
+
return kbRoot;
|
|
61
|
+
}
|
|
62
|
+
const gitRoot = findUpwards(startDir, ".git");
|
|
63
|
+
if (gitRoot) {
|
|
64
|
+
return gitRoot;
|
|
65
|
+
}
|
|
66
|
+
return path.resolve(startDir);
|
|
67
|
+
}
|
|
68
|
+
export function resolveWorkspaceRootInfo(startDir = process.cwd()) {
|
|
69
|
+
const envRoot = readFirstEnv(WORKSPACE_ENV_KEYS);
|
|
70
|
+
if (envRoot) {
|
|
71
|
+
return { root: path.resolve(envRoot), reason: "env" };
|
|
72
|
+
}
|
|
73
|
+
const kbRoot = findUpwards(startDir, ".kb");
|
|
74
|
+
if (kbRoot) {
|
|
75
|
+
return { root: kbRoot, reason: "kb" };
|
|
76
|
+
}
|
|
77
|
+
const gitRoot = findUpwards(startDir, ".git");
|
|
78
|
+
if (gitRoot) {
|
|
79
|
+
return { root: gitRoot, reason: "git" };
|
|
80
|
+
}
|
|
81
|
+
return { root: path.resolve(startDir), reason: "cwd" };
|
|
82
|
+
}
|
|
83
|
+
export function resolveKbPath(workspaceRoot, branch) {
|
|
84
|
+
const envPath = readFirstEnv(KB_PATH_ENV_KEYS);
|
|
85
|
+
if (envPath) {
|
|
86
|
+
const resolved = path.resolve(envPath);
|
|
87
|
+
if (isBranchPath(resolved)) {
|
|
88
|
+
return resolved;
|
|
89
|
+
}
|
|
90
|
+
return path.join(resolved, "branches", branch);
|
|
91
|
+
}
|
|
92
|
+
return path.join(workspaceRoot, ".kb", "branches", branch);
|
|
93
|
+
}
|
|
94
|
+
export function resolveEnvFilePath(envFileName, workspaceRoot) {
|
|
95
|
+
if (path.isAbsolute(envFileName)) {
|
|
96
|
+
return envFileName;
|
|
97
|
+
}
|
|
98
|
+
return path.resolve(workspaceRoot, envFileName);
|
|
99
|
+
}
|
|
100
|
+
function readFirstEnv(keys) {
|
|
101
|
+
for (const key of keys) {
|
|
102
|
+
const value = process.env[key]?.trim();
|
|
103
|
+
if (value) {
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
function findUpwards(startDir, marker) {
|
|
110
|
+
let current = path.resolve(startDir);
|
|
111
|
+
while (true) {
|
|
112
|
+
const candidate = path.join(current, marker);
|
|
113
|
+
if (fs.existsSync(candidate)) {
|
|
114
|
+
return current;
|
|
115
|
+
}
|
|
116
|
+
const parent = path.dirname(current);
|
|
117
|
+
if (parent === current) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
current = parent;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function isBranchPath(p) {
|
|
124
|
+
const parent = path.basename(path.dirname(p));
|
|
125
|
+
return parent === "branches";
|
|
126
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kibi-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Model Context Protocol server for Kibi knowledge base",
|
|
6
|
+
"main": "./dist/server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"kibi-mcp": "./bin/kibi-mcp"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "bun test",
|
|
12
|
+
"dev": "bun run bin/kibi-mcp",
|
|
13
|
+
"build": "tsc -p tsconfig.json",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist", "bin"],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18",
|
|
19
|
+
"bun": ">=1.0"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./dist/server.js",
|
|
23
|
+
"./src/*": "./src/*.ts"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"kibi-cli": "^0.1.0",
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
28
|
+
"ajv": "^8.18.0",
|
|
29
|
+
"js-yaml": "^4.1.0",
|
|
30
|
+
"mcpcat": "^0.1.12",
|
|
31
|
+
"zod": "^4.3.6"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/bun": "latest",
|
|
35
|
+
"@types/node": "latest"
|
|
36
|
+
},
|
|
37
|
+
"license": "AGPL-3.0-or-later",
|
|
38
|
+
"author": "Piotr Franczyk",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/Looted/kibi.git"
|
|
42
|
+
}
|
|
43
|
+
}
|