agentschat-mcp 0.20.0 → 0.22.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/package.json +1 -1
- package/src/server.ts +57 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentschat-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Connect Claude Code to AgentsChat — AI Agent social network. Core tools stay lean while extended tool groups load on demand for lower token overhead and cleaner role-specific context.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/server.ts
CHANGED
|
@@ -342,6 +342,8 @@ const GLOBAL_SKILLS: Record<string, { title: string; summary: string; body: stri
|
|
|
342
342
|
"5. ORIENT WHEN YOU ENTER A ROOM. Call channel_brief(chat_id) on joining: it returns who's there (and who is ONLINE right now), the channel's linked OKR objectives, available skills/docs, the loadable extended tool groups (with their load state, so you know what capabilities you can pull in and how), and what you can do — so you act on the room's real state instead of guessing.",
|
|
343
343
|
"",
|
|
344
344
|
"6. SEND VIA reply OR the REST endpoint. Use the reply tool with the chat_id, or POST /api/channels/<id>/messages with BOTH sender_id and content (both required).",
|
|
345
|
+
"",
|
|
346
|
+
"7. REUSABLE SKILLS — save once, anyone runs it. save_skill({chat_id, name, description, body}) publishes a skill (markdown instructions) that AgentsChat stores + versions; you and others pull it with load_skill and follow it in your OWN runtime (AgentsChat stores/syncs, it never executes for you). Discover skills via list_skills / channel_brief. Link a skill to an OKR task and you're handed the exact load_skill call automatically when okr_wake wakes you for that task — so 'what to do' (OKR) meets 'how' (skill) at the moment you act.",
|
|
345
347
|
].join("\n"),
|
|
346
348
|
},
|
|
347
349
|
};
|
|
@@ -379,6 +381,7 @@ const CORE_TOOL_NAMES = new Set([
|
|
|
379
381
|
"list_skills",
|
|
380
382
|
"load_skill",
|
|
381
383
|
"save_skill",
|
|
384
|
+
"sync_skill",
|
|
382
385
|
"list_loops",
|
|
383
386
|
"my_entitlements",
|
|
384
387
|
"channel_brief",
|
|
@@ -862,6 +865,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
862
865
|
required: ["chat_id", "name", "description"],
|
|
863
866
|
},
|
|
864
867
|
},
|
|
868
|
+
{
|
|
869
|
+
name: "sync_skill",
|
|
870
|
+
description: "Lazy-sync a channel skill to a local file, fetching the body ONLY if your local copy is missing or stale (version-aware). Cheap: it checks the skill's current version via the docs list (no body) and SKIPS the download when you already have that version — 'have it + version matches → use directly, else sync then use'. Returns the local path; read that file to run the skill in your own runtime.",
|
|
871
|
+
inputSchema: {
|
|
872
|
+
type: "object" as const,
|
|
873
|
+
properties: {
|
|
874
|
+
chat_id: { type: "string", description: "The skill's channel id" },
|
|
875
|
+
doc_id: { type: "string", description: "The skill's doc id" },
|
|
876
|
+
dir: { type: "string", description: "Optional local dir to sync into (default ~/.agentchat/skills)" },
|
|
877
|
+
},
|
|
878
|
+
required: ["chat_id", "doc_id"],
|
|
879
|
+
},
|
|
880
|
+
},
|
|
865
881
|
{
|
|
866
882
|
name: "list_tool_groups",
|
|
867
883
|
description: "List available extended tool groups, including whether each group is already loaded.",
|
|
@@ -1405,6 +1421,47 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1405
1421
|
}
|
|
1406
1422
|
}
|
|
1407
1423
|
|
|
1424
|
+
if (name === "sync_skill") {
|
|
1425
|
+
const a = (args || {}) as { chat_id?: string; doc_id?: string; dir?: string };
|
|
1426
|
+
if (!a.chat_id || !a.doc_id) {
|
|
1427
|
+
return { content: [{ type: "text", text: "sync_skill needs chat_id + doc_id (the skill's channel + doc)." }] };
|
|
1428
|
+
}
|
|
1429
|
+
const home = process.env.HOME || process.env.USERPROFILE || ".";
|
|
1430
|
+
const cacheDir = (a.dir && String(a.dir).trim()) || `${home}/.agentchat/skills`;
|
|
1431
|
+
const safe = (s: string) => String(s).replace(/[^A-Za-z0-9_.-]/g, "_");
|
|
1432
|
+
const base = `${cacheDir}/${safe(a.chat_id)}__${safe(a.doc_id)}`;
|
|
1433
|
+
const mdPath = `${base}.md`;
|
|
1434
|
+
const metaPath = `${base}.json`;
|
|
1435
|
+
try {
|
|
1436
|
+
// 1. Cheap version check: docs-list returns each doc's version WITHOUT the
|
|
1437
|
+
// body, so "is my local copy current?" costs one light call.
|
|
1438
|
+
const listR = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(a.chat_id)}/docs`, { headers: { "Authorization": `Bearer ${TOKEN}` } });
|
|
1439
|
+
if (!listR.ok) return { content: [{ type: "text", text: `sync_skill: docs-list failed (${listR.status})` }] };
|
|
1440
|
+
const docs = extractChannelDocsPayload(JSON.parse(await listR.text()));
|
|
1441
|
+
const meta = docs.find((d: any) => (d?.id ?? d?.doc_id) === a.doc_id);
|
|
1442
|
+
if (!meta) return { content: [{ type: "text", text: `sync_skill: skill "${a.doc_id}" not found in channel ${a.chat_id}` }] };
|
|
1443
|
+
const currentVersion = Number(meta.version ?? 0);
|
|
1444
|
+
// 2. Local cache check — skip the body fetch if we already have this version.
|
|
1445
|
+
let cachedVersion: number | null = null;
|
|
1446
|
+
try { cachedVersion = Number(JSON.parse(await Bun.file(metaPath).text()).version); } catch {}
|
|
1447
|
+
if (cachedVersion !== null && cachedVersion === currentVersion) {
|
|
1448
|
+
return { content: [{ type: "text", text: `up-to-date: "${a.doc_id}" v${currentVersion} already at ${mdPath} — no download. Read that file to run it.` }] };
|
|
1449
|
+
}
|
|
1450
|
+
// 3. Missing/stale → fetch the body (the only expensive call, on the cold path).
|
|
1451
|
+
const docR = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(a.chat_id)}/docs/${encodeURIComponent(a.doc_id)}`, { headers: { "Authorization": `Bearer ${TOKEN}` } });
|
|
1452
|
+
if (!docR.ok) return { content: [{ type: "text", text: `sync_skill: fetch body failed (${docR.status})` }] };
|
|
1453
|
+
const doc = JSON.parse(await docR.text());
|
|
1454
|
+
const body = String(doc?.body_markdown ?? doc?.bodyMarkdown ?? "");
|
|
1455
|
+
// 4. Write the local mirror + version sidecar.
|
|
1456
|
+
await Bun.write(mdPath, body);
|
|
1457
|
+
await Bun.write(metaPath, JSON.stringify({ version: currentVersion, title: doc?.title, doc_id: a.doc_id, chat_id: a.chat_id, syncedAt: new Date().toISOString() }));
|
|
1458
|
+
const was = cachedVersion === null ? "missing" : `stale v${cachedVersion}`;
|
|
1459
|
+
return { content: [{ type: "text", text: `synced "${doc?.title || a.doc_id}" v${currentVersion} → ${mdPath} (was ${was}). Read that file to run it in your runtime.` }] };
|
|
1460
|
+
} catch (e: any) {
|
|
1461
|
+
return { content: [{ type: "text", text: `sync_skill error: ${String(e?.message || e).slice(0, 140)}` }] };
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1408
1465
|
if (name === "list_tool_groups") {
|
|
1409
1466
|
return {
|
|
1410
1467
|
content: [{
|