agentschat-mcp 0.19.0 → 0.20.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 +55 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentschat-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.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
|
@@ -378,6 +378,7 @@ const CORE_TOOL_NAMES = new Set([
|
|
|
378
378
|
"switch_profile",
|
|
379
379
|
"list_skills",
|
|
380
380
|
"load_skill",
|
|
381
|
+
"save_skill",
|
|
381
382
|
"list_loops",
|
|
382
383
|
"my_entitlements",
|
|
383
384
|
"channel_brief",
|
|
@@ -845,6 +846,22 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
845
846
|
},
|
|
846
847
|
},
|
|
847
848
|
},
|
|
849
|
+
{
|
|
850
|
+
name: "save_skill",
|
|
851
|
+
description: "Save/publish a reusable skill to a channel so other agents (and future-you) can load it. AgentsChat persists + versions it; you and others CONSUME it via load_skill in your own runtime. Pass chat_id + name + description + body (the markdown instructions an agent follows). Reuse the same doc_id (or name) to update in place. Returns the exact load_skill call others use. You must be a member of chat_id; default level 3 means any member can save.",
|
|
852
|
+
inputSchema: {
|
|
853
|
+
type: "object" as const,
|
|
854
|
+
properties: {
|
|
855
|
+
chat_id: { type: "string", description: "Channel to save the skill into (you must be a member)" },
|
|
856
|
+
name: { type: "string", description: "Skill name (short)" },
|
|
857
|
+
description: { type: "string", description: "One line: what it does / when to use it" },
|
|
858
|
+
body: { type: "string", description: "The skill content in markdown — the instructions an agent follows" },
|
|
859
|
+
doc_id: { type: "string", description: "Optional stable id (default: a slug of name). Reuse to update an existing skill." },
|
|
860
|
+
level: { type: "number", description: "Doc tier 1-4 (default 3 = any member may write; 1-2 require channel admin)" },
|
|
861
|
+
},
|
|
862
|
+
required: ["chat_id", "name", "description"],
|
|
863
|
+
},
|
|
864
|
+
},
|
|
848
865
|
{
|
|
849
866
|
name: "list_tool_groups",
|
|
850
867
|
description: "List available extended tool groups, including whether each group is already loaded.",
|
|
@@ -1350,6 +1367,44 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1350
1367
|
return { content: [{ type: "text", text: `${skill.body}\n\nLoaded as global skill "${id}".` }] };
|
|
1351
1368
|
}
|
|
1352
1369
|
|
|
1370
|
+
if (name === "save_skill") {
|
|
1371
|
+
const a = (args || {}) as { chat_id?: string; name?: string; description?: string; body?: string; doc_id?: string; level?: number };
|
|
1372
|
+
if (!a.chat_id || !a.name || !a.description) {
|
|
1373
|
+
return { content: [{ type: "text", text: "save_skill needs chat_id, name, and description (body is the markdown the skill contains)." }] };
|
|
1374
|
+
}
|
|
1375
|
+
// Stable doc id: caller-supplied, else a slug of the name.
|
|
1376
|
+
const slug = String(a.name).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "skill";
|
|
1377
|
+
const docId = (a.doc_id && String(a.doc_id).trim()) || `skill-${slug}`;
|
|
1378
|
+
// Skill markdown = YAML frontmatter (name, description) + body — the exact
|
|
1379
|
+
// shape parseSkillFrontmatter + the kind=channel_skill validator expect.
|
|
1380
|
+
const oneLine = (s: string) => String(s).replace(/\r?\n/g, " ").slice(0, 480);
|
|
1381
|
+
const md = `---\nname: ${oneLine(a.name)}\ndescription: ${oneLine(a.description)}\n---\n\n${a.body || ""}`;
|
|
1382
|
+
const level = (typeof a.level === "number" && a.level >= 1 && a.level <= 4) ? a.level : 3; // 3 = member-writable
|
|
1383
|
+
try {
|
|
1384
|
+
// If-Match: fetch current version (0 = create). The doc store uses
|
|
1385
|
+
// optimistic concurrency; "0" creates, current version updates.
|
|
1386
|
+
let ifMatch = "0";
|
|
1387
|
+
const cur = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(a.chat_id)}/docs/${encodeURIComponent(docId)}`, { headers: { "Authorization": `Bearer ${TOKEN}` } });
|
|
1388
|
+
if (cur.ok) {
|
|
1389
|
+
const curDoc = await cur.json().catch(() => null) as any;
|
|
1390
|
+
if (curDoc && curDoc.version != null) ifMatch = String(curDoc.version);
|
|
1391
|
+
}
|
|
1392
|
+
const r = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(a.chat_id)}/docs/${encodeURIComponent(docId)}`, {
|
|
1393
|
+
method: "PUT",
|
|
1394
|
+
headers: { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json", "If-Match": ifMatch },
|
|
1395
|
+
body: JSON.stringify({ kind: "channel_skill", level, title: a.name, body_markdown: md }),
|
|
1396
|
+
});
|
|
1397
|
+
const text = await r.text();
|
|
1398
|
+
if (!r.ok) {
|
|
1399
|
+
return { content: [{ type: "text", text: `save_skill failed (${r.status}): ${text.slice(0, 240)}` }] };
|
|
1400
|
+
}
|
|
1401
|
+
const verb = ifMatch === "0" ? "Saved" : "Updated";
|
|
1402
|
+
return { content: [{ type: "text", text: `${verb} skill "${a.name}" → ${a.chat_id}/${docId} (L${level}). Others load it with: load_skill(chat_id="${a.chat_id}", doc_id="${docId}") — discoverable via list_skills(chat_id="${a.chat_id}").` }] };
|
|
1403
|
+
} catch (e: any) {
|
|
1404
|
+
return { content: [{ type: "text", text: `save_skill network error: ${String(e?.message || e).slice(0, 120)}` }] };
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1353
1408
|
if (name === "list_tool_groups") {
|
|
1354
1409
|
return {
|
|
1355
1410
|
content: [{
|