@cachly-dev/mcp-server 0.10.93 β 0.10.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/src/handlers/brain.js +117 -2
- package/dist/src/handlers/brain.js.map +1 -1
- package/dist/src/handlers/syndicate.js +120 -0
- package/dist/src/handlers/syndicate.js.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/src/tools.d.ts +59 -0
- package/dist/src/tools.js +52 -0
- package/dist/src/tools.js.map +1 -1
- package/dist/src/toolspecs.d.ts +1 -1
- package/dist/src/toolspecs.js +1 -1
- package/package.json +2 -2
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
<img src="https://img.shields.io/badge/GDPR-EU%20servers-green" alt="GDPR: EU servers" />
|
|
23
23
|
</a>
|
|
24
24
|
|
|
25
|
-
<img src="https://img.shields.io/badge/
|
|
25
|
+
<img src="https://img.shields.io/badge/118%20MCP%20tools-violet" alt="118 MCP tools" />
|
|
26
26
|
|
|
27
27
|
<img src="https://img.shields.io/badge/License-Apache--2.0-yellow" alt="License: Apache-2.0" />
|
|
28
28
|
</p>
|
|
@@ -190,6 +190,7 @@ close without breaking its own lock-in. **That gap is where cachly wins.**
|
|
|
190
190
|
| **`brain_who_knows`** | *"Who on my team knows about Kubernetes deploys?"* β ranked experts π₯π₯π₯, built automatically from authorship. |
|
|
191
191
|
| **`brain_file_map`** | Before you touch a file: who's worked on it and which lessons reference it. |
|
|
192
192
|
| **`team_expertise_map`** | The whole team's skills matrix in one table β onboarding and bus-factor insurance. |
|
|
193
|
+
| **`brain_collab_pairs`** | PersonβPerson Collaboration Graph β *"Frag X und Y, die haben das zusammen gelΓΆst."* Bus-factor alerts included. |
|
|
193
194
|
| **`brain_from_git`** | Reads your entire git history and populates the team knowledge graph (people + files + lessons) β zero setup, retroactively. |
|
|
194
195
|
| **`brain_coverage` / `skill_gaps`** | A 0β100 health score for your knowledge + a ranked list of blind spots to fix. |
|
|
195
196
|
| **`brain_predict`** | Predicts likely failures *before* they happen, from past incident patterns. |
|
|
@@ -244,7 +245,7 @@ npx @cachly-dev/mcp-server@latest learn-git # Auto-learn lessons from recent git
|
|
|
244
245
|
|
|
245
246
|
---
|
|
246
247
|
|
|
247
|
-
## MCP Tools (
|
|
248
|
+
## MCP Tools (118 total)
|
|
248
249
|
|
|
249
250
|
### π§ Session & Memory (most used)
|
|
250
251
|
|
|
@@ -267,6 +268,7 @@ npx @cachly-dev/mcp-server@latest learn-git # Auto-learn lessons from recent git
|
|
|
267
268
|
| **`brain_who_knows`** | Find your team's experts on any topic β ranked π₯π₯π₯ |
|
|
268
269
|
| **`brain_file_map`** | Experts + lessons per file, before you touch it |
|
|
269
270
|
| **`team_expertise_map`** | Full team skills matrix in one table |
|
|
271
|
+
| **`brain_collab_pairs`** | PersonβPerson Collaboration Graph β who collaborates with whom, bus-factor alerts |
|
|
270
272
|
| **`skill_gaps`** | Knowledge blind spots: unresolved failures, missing attribution |
|
|
271
273
|
| **`brain_coverage`** | 0β100 knowledge-health score for your codebase |
|
|
272
274
|
| `madc_deliberate` | Specialist AI agents vote to resolve contradictory lessons |
|
|
@@ -297,6 +299,7 @@ npx @cachly-dev/mcp-server@latest learn-git # Auto-learn lessons from recent git
|
|
|
297
299
|
| Tool | What it does |
|
|
298
300
|
|------|-------------|
|
|
299
301
|
| `syndicate` / `fedbrain_search` | Contribute to / search the global Knowledge Commons |
|
|
302
|
+
| `brain_marketplace` / `brain_install` | Browse + install curated Domain Brains (Kubernetes, Auth, DBβ¦) into your Brain |
|
|
300
303
|
| `cache_get` / `cache_set` / `semantic_search` / `index_project` | Cache + semantic ops |
|
|
301
304
|
| `list_instances` / `create_instance` / `delete_instance` | Manage Brain instances |
|
|
302
305
|
| `roadmap_add` / `roadmap_next` | Persistent project roadmap stored in the Brain |
|
|
@@ -7,8 +7,23 @@ import { keywordSearch, tokenize, splitMultiQuery, levenshtein, indexVocab as _i
|
|
|
7
7
|
import { rerankByQuality } from '../rerank.js';
|
|
8
8
|
import { computeEmbedding, hasEmbedProvider } from '../embeddings.js';
|
|
9
9
|
// ββ Changelog (shown once per version in session_start) ββββββββββββββββββββββ
|
|
10
|
-
const MCP_VERSION = '0.10.
|
|
10
|
+
const MCP_VERSION = '0.10.95';
|
|
11
11
|
const WHATS_NEW = {
|
|
12
|
+
'0.10.95': [
|
|
13
|
+
`π§ **Domain Brain Marketplace (W10) β bootstrap your Brain with curated community knowledge**`,
|
|
14
|
+
` π \`brain_marketplace()\` β browse installable packs of high-trust lessons by domain: βΈοΈ Kubernetes, π Auth, ποΈ Database, βοΈ React, π³ Payments & more`,
|
|
15
|
+
` π¦ \`brain_install(slug="k8s")\` β merges a domain's verified lessons into your Brain; live in \`smart_recall\` instantly, even offline`,
|
|
16
|
+
` π‘οΈ Idempotent + non-destructive: installed lessons are tagged \`source:"marketplace:<slug>"\` and NEVER override your own`,
|
|
17
|
+
` π New gRPC \`Subscribe\` RPC β agents get new lessons streamed live the moment they're learned (completes the M2M loop with \`Learn\`)`,
|
|
18
|
+
` π 118 MCP tools (new: \`brain_marketplace\`, \`brain_install\`)`,
|
|
19
|
+
],
|
|
20
|
+
'0.10.94': [
|
|
21
|
+
`π€ **PersonβPerson Collaboration Graph (W5) β "Frag X und Y, die haben das zusammen gelΓΆst"**`,
|
|
22
|
+
` πΈοΈ New \`brain_collab_pairs()\` tool: shows every contributor pair who've touched the same files or recalled each other's lessons β ideal for onboarding and bus-factor analysis`,
|
|
23
|
+
` π‘ \`smart_recall\` now wires CKG \`collaborates\` edges live when cross-author reuse fires β collaboration graph grows with every team recall`,
|
|
24
|
+
` β οΈ Bus-factor section: flags solo contributors whose knowledge no teammate has yet recalled`,
|
|
25
|
+
` π 116 MCP tools (new: \`brain_collab_pairs\`)`,
|
|
26
|
+
],
|
|
12
27
|
'0.10.93': [
|
|
13
28
|
`πΊοΈ **\`brain_plan\` β your Brain goes from "what did we learn?" to "what should I do?"**`,
|
|
14
29
|
` π§ Give it a task you're about to start ("upgrade Postgres 14β16") and it returns an ordered, grounded action plan: ranked failure modes to avoid, proven fix steps (dependency-aware, with commands), and a pre-flight checklist β all from your own lessons`,
|
|
@@ -78,7 +93,7 @@ const WHATS_NEW = {
|
|
|
78
93
|
'0.10.84': [
|
|
79
94
|
`π€ **M2M & agent-ecosystem reach β cachly for every caller, human or machine**`,
|
|
80
95
|
` π OAuth2 \`client_credentials\` grant β set CACHLY_CLIENT_ID + CACHLY_CLIENT_SECRET for fully headless auth (CI, agents, AI-to-AI)`,
|
|
81
|
-
` ποΈ \`npx ... tool-specs --format=openai|anthropic|langchain\` β export all
|
|
96
|
+
` ποΈ \`npx ... tool-specs --format=openai|anthropic|langchain\` β export all 118 tools in any framework's dialect`,
|
|
82
97
|
` π \`npx ... openapi\` β OpenAPI 3.1 doc (1 POST path per tool) for Assistants / codegen / Postman`,
|
|
83
98
|
` π§ͺ 14 new tests: client_credentials helpers, all four spec dialects, OpenAPI required-body inference`,
|
|
84
99
|
],
|
|
@@ -773,6 +788,12 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
|
|
|
773
788
|
crossAuthorThisCall++;
|
|
774
789
|
redis.incr(`cachly:stats:cross_author_recalls:${instance_id}`).catch(() => { });
|
|
775
790
|
redis.sadd(`cachly:stats:reuse_pairs:${instance_id}`, `${requester}<-${lesson.author}`).catch(() => { });
|
|
791
|
+
// W5: wire personβperson CKG collaborates edges from knowledge-reuse events.
|
|
792
|
+
// This feeds brain_collab_pairs and enriches brain_who_knows with reuse-based edges.
|
|
793
|
+
const reqPersonId = `person:${ckgSlug(requester)}`;
|
|
794
|
+
const authPersonId = `person:${ckgSlug(lesson.author)}`;
|
|
795
|
+
ckgUpdateEdge(redis, reqPersonId, 'collaborates', authPersonId, true).catch(() => { });
|
|
796
|
+
ckgUpdateEdge(redis, authPersonId, 'collaborates', reqPersonId, true).catch(() => { });
|
|
776
797
|
}
|
|
777
798
|
// Surface banner for proven successes (recall_count >= 1 means it's been validated)
|
|
778
799
|
if (lesson.outcome === 'success' && (lesson.recall_count ?? 0) >= 1) {
|
|
@@ -2796,6 +2817,100 @@ export async function handleBrainTool(name, args, getConnection, apiFetch) {
|
|
|
2796
2817
|
lines.push(`---`, `_Tag lessons with \`service="${service}"\` to keep this map current. For infra, pass \`service_kind="system"\`._`);
|
|
2797
2818
|
return lines.join('\n');
|
|
2798
2819
|
}
|
|
2820
|
+
// ββ brain_collab_pairs βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
2821
|
+
// W5: PersonβPerson Collaboration Graph. Shows who works with whom on the
|
|
2822
|
+
// team β built from (a) shared file-touches during learn_from_attempts and
|
|
2823
|
+
// (b) cross-author knowledge-reuse events from smart_recall. Answers the
|
|
2824
|
+
// onboarding question: "Frag X und Y β they solved that together."
|
|
2825
|
+
case 'brain_collab_pairs': {
|
|
2826
|
+
const { instance_id, min_weight = 1 } = args;
|
|
2827
|
+
const redis = await getConnection(instance_id);
|
|
2828
|
+
const minW = typeof min_weight === 'number' && min_weight >= 1 ? Math.floor(min_weight) : 1;
|
|
2829
|
+
// Collect all person nodes.
|
|
2830
|
+
const personKeys = await scanKeys(redis, 'cachly:ckg:node:person:*', { max: 500 });
|
|
2831
|
+
const persons = new Map();
|
|
2832
|
+
for (const k of personKeys) {
|
|
2833
|
+
const raw = await redis.get(k);
|
|
2834
|
+
if (!raw)
|
|
2835
|
+
continue;
|
|
2836
|
+
const pn = safeJsonParse(raw, null);
|
|
2837
|
+
if (!pn || pn.type !== 'person')
|
|
2838
|
+
continue;
|
|
2839
|
+
persons.set(pn.id, { id: pn.id, handle: pn.handle, domain: pn.domain, count: pn.count });
|
|
2840
|
+
}
|
|
2841
|
+
if (persons.size === 0) {
|
|
2842
|
+
return [
|
|
2843
|
+
`## π€ Team Collaboration Graph`,
|
|
2844
|
+
``,
|
|
2845
|
+
`No contributors found yet.`,
|
|
2846
|
+
``,
|
|
2847
|
+
`The graph builds automatically as teammates store lessons with \`author="name"\`:`,
|
|
2848
|
+
`\`learn_from_attempts(topic="...", author="alice", file_paths=["src/auth.ts"], ...)\``,
|
|
2849
|
+
].join('\n');
|
|
2850
|
+
}
|
|
2851
|
+
const pairMap = new Map();
|
|
2852
|
+
for (const [personId, pInfo] of persons) {
|
|
2853
|
+
const edgeKeys = await redis.smembers(`cachly:ckg:idx:from:${personId}`);
|
|
2854
|
+
for (const ek of edgeKeys) {
|
|
2855
|
+
const er = await redis.get(ek);
|
|
2856
|
+
if (!er)
|
|
2857
|
+
continue;
|
|
2858
|
+
const edge = safeJsonParse(er, null);
|
|
2859
|
+
if (!edge || edge.edgeType !== 'collaborates')
|
|
2860
|
+
continue;
|
|
2861
|
+
const otherInfo = persons.get(edge.to);
|
|
2862
|
+
if (!otherInfo)
|
|
2863
|
+
continue;
|
|
2864
|
+
// Canonical pair key: alphabetically smaller id first.
|
|
2865
|
+
const [idA, idB] = personId < edge.to ? [personId, edge.to] : [edge.to, personId];
|
|
2866
|
+
const pairKey = `${idA}||${idB}`;
|
|
2867
|
+
const existing = pairMap.get(pairKey);
|
|
2868
|
+
if (existing) {
|
|
2869
|
+
existing.trials += edge.trials;
|
|
2870
|
+
}
|
|
2871
|
+
else {
|
|
2872
|
+
const [pA, pB] = personId < edge.to ? [pInfo, otherInfo] : [otherInfo, pInfo];
|
|
2873
|
+
pairMap.set(pairKey, { a: pA, b: pB, trials: edge.trials, confidence: edge.confidence });
|
|
2874
|
+
}
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
const pairs = [...pairMap.values()]
|
|
2878
|
+
.filter(p => p.trials >= minW)
|
|
2879
|
+
.sort((a, b) => b.trials - a.trials);
|
|
2880
|
+
// Find solo contributors (no collaborators).
|
|
2881
|
+
const connectedIds = new Set();
|
|
2882
|
+
for (const p of pairs) {
|
|
2883
|
+
connectedIds.add(p.a.id);
|
|
2884
|
+
connectedIds.add(p.b.id);
|
|
2885
|
+
}
|
|
2886
|
+
const soloPersons = [...persons.values()].filter(p => !connectedIds.has(p.id));
|
|
2887
|
+
const lines = [
|
|
2888
|
+
`## π€ Team Collaboration Graph`,
|
|
2889
|
+
``,
|
|
2890
|
+
];
|
|
2891
|
+
if (pairs.length === 0) {
|
|
2892
|
+
lines.push(`No collaboration pairs yet (min weight: ${minW}).`, ``, `Pairs appear when two contributors touch the same file in \`learn_from_attempts\``, `or when someone recalls a teammate's lesson via \`smart_recall(requester="...")\`.`);
|
|
2893
|
+
}
|
|
2894
|
+
else {
|
|
2895
|
+
lines.push(`**${pairs.length} collaboration pair${pairs.length !== 1 ? 's' : ''}** across ${connectedIds.size} contributor${connectedIds.size !== 1 ? 's' : ''}:`, ``);
|
|
2896
|
+
for (const p of pairs.slice(0, 20)) {
|
|
2897
|
+
const conf = (p.confidence * 100).toFixed(0);
|
|
2898
|
+
const sharedDomains = [p.a.domain, p.b.domain]
|
|
2899
|
+
.filter((d, i, arr) => d && arr.indexOf(d) === i)
|
|
2900
|
+
.map(d => `\`${d}\``)
|
|
2901
|
+
.join(', ');
|
|
2902
|
+
lines.push(`### @${p.a.handle} β @${p.b.handle}`, `- **${p.trials} collaboration event${p.trials !== 1 ? 's' : ''}** Β· ${conf}% confidence`, `- Domains: ${sharedDomains || '_unknown_'}`, `> π¬ _"Frag **@${p.a.handle}** und **@${p.b.handle}** β they've solved problems together in these areas."_`, ``);
|
|
2903
|
+
}
|
|
2904
|
+
if (pairs.length > 20) {
|
|
2905
|
+
lines.push(`_...and ${pairs.length - 20} more pairs. Use \`min_weight\` to filter._`, ``);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
if (soloPersons.length > 0) {
|
|
2909
|
+
lines.push(`---`, `### β οΈ Bus Factor Alert β No Collaborators Yet`, ``, `${soloPersons.length} contributor${soloPersons.length !== 1 ? 's have' : ' has'} knowledge that no teammate has recalled or co-touched:`, ``, ...soloPersons.slice(0, 10).map(p => `- **@${p.handle}** β ${p.count} lesson${p.count !== 1 ? 's' : ''} Β· domain: \`${p.domain}\``), ``, `_Tip: pair these contributors with teammates on shared files to reduce bus factor._`);
|
|
2910
|
+
}
|
|
2911
|
+
lines.push(``, `---`, `_Collaboration edges build from \`learn_from_attempts(author=..., file_paths=[...])\` and \`smart_recall(requester=...)\` cross-author reuse._`);
|
|
2912
|
+
return lines.join('\n');
|
|
2913
|
+
}
|
|
2799
2914
|
// ββ sync_file_changes βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
2800
2915
|
default:
|
|
2801
2916
|
return null;
|