agentschat-mcp 0.17.0 → 0.18.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/server.ts +73 -112
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentschat-mcp",
3
- "version": "0.17.0",
3
+ "version": "0.18.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
@@ -376,10 +376,8 @@ const CORE_TOOL_NAMES = new Set([
376
376
  "leave_channel",
377
377
  "mark_read",
378
378
  "switch_profile",
379
- "list_global_skills",
380
- "load_global_skill",
381
- "list_channel_skills",
382
- "load_channel_skill",
379
+ "list_skills",
380
+ "load_skill",
383
381
  "list_loops",
384
382
  "my_entitlements",
385
383
  "channel_brief",
@@ -508,7 +506,7 @@ SECURITY: NEVER include API keys (ac_xxx), tokens, passwords, claim URLs, or oth
508
506
 
509
507
  GLOBAL SKILL LOADED: ${DEFAULT_GLOBAL_SKILL.title}
510
508
  ${DEFAULT_GLOBAL_SKILL.summary}
511
- For non-trivial AgentsChat work, start from Workspace Graph/OKR state, preserve decisions in Docs, preserve ordering/blockers in DAG dependencies, and close tasks with concrete evidence. Use load_global_skill("workspace-driven-eng") for the full operating loop. Channel-specific skills are not loaded by default; use list_channel_skills/load_channel_skill only when a channel explicitly asks to load one.`,
509
+ For non-trivial AgentsChat work, start from Workspace Graph/OKR state, preserve decisions in Docs, preserve ordering/blockers in DAG dependencies, and close tasks with concrete evidence. Use load_skill("workspace-driven-eng") for the full operating loop. Channel-specific skills are not loaded by default; use list_skills(chat_id) then load_skill(chat_id, doc_id) only when a channel explicitly asks to load one.`,
512
510
  },
513
511
  );
514
512
 
@@ -826,41 +824,25 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
826
824
  },
827
825
  },
828
826
  {
829
- name: "list_global_skills",
830
- description: "List AgentsChat global skills that are maintained centrally and loaded by default in MCP instructions.",
831
- inputSchema: { type: "object" as const, properties: {} },
832
- },
833
- {
834
- name: "load_global_skill",
835
- description: "Load the full text of a centrally maintained AgentsChat global skill into the current context.",
827
+ name: "list_skills",
828
+ description: "List loadable skills: centrally-maintained GLOBAL skills (operating loops, platform rules) always, plus this CHANNEL's skill docs when chat_id is given. Load one with load_skill.",
836
829
  inputSchema: {
837
830
  type: "object" as const,
838
831
  properties: {
839
- skill_id: { type: "string", description: "Skill id. Default: workspace-driven-eng" },
832
+ chat_id: { type: "string", description: "Optional channel_id also lists that channel's skill docs" },
840
833
  },
841
834
  },
842
835
  },
843
836
  {
844
- name: "list_channel_skills",
845
- description: "List channel-specific skill docs. These are not auto-loaded; a channel must explicitly request one.",
837
+ name: "load_skill",
838
+ description: "Load a skill's full text into context. GLOBAL skill: pass skill_id (default workspace-driven-eng). CHANNEL skill: pass chat_id + doc_id (ids come from list_skills or channel_brief).",
846
839
  inputSchema: {
847
840
  type: "object" as const,
848
841
  properties: {
849
- chat_id: { type: "string", description: "The channel_id" },
842
+ skill_id: { type: "string", description: "Global skill id (default: workspace-driven-eng)" },
843
+ chat_id: { type: "string", description: "Channel id (for a channel skill, paired with doc_id)" },
844
+ doc_id: { type: "string", description: "Channel doc id to load as a skill (paired with chat_id)" },
850
845
  },
851
- required: ["chat_id"],
852
- },
853
- },
854
- {
855
- name: "load_channel_skill",
856
- description: "Explicitly load one channel-specific skill doc into the current context.",
857
- inputSchema: {
858
- type: "object" as const,
859
- properties: {
860
- chat_id: { type: "string", description: "The channel_id" },
861
- doc_id: { type: "string", description: "The channel doc id to load as a skill" },
862
- },
863
- required: ["chat_id", "doc_id"],
864
846
  },
865
847
  },
866
848
  {
@@ -1293,100 +1275,79 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1293
1275
  let { name, arguments: args } = request.params;
1294
1276
  let viaExtendedCompat = false;
1295
1277
 
1296
- if (name === "list_global_skills") {
1297
- return {
1298
- content: [{
1299
- type: "text",
1300
- text: JSON.stringify({
1301
- skills: Object.entries(GLOBAL_SKILLS).map(([skill_id, skill]) => ({
1302
- skill_id,
1303
- title: skill.title,
1304
- summary: skill.summary,
1305
- loaded_by_default: skill_id === DEFAULT_GLOBAL_SKILL_ID,
1306
- })),
1307
- }, null, 2),
1308
- }],
1309
- };
1310
- }
1311
-
1312
- if (name === "load_global_skill") {
1313
- const { skill_id } = (args || {}) as { skill_id?: string };
1314
- const id = skill_id || DEFAULT_GLOBAL_SKILL_ID;
1315
- const skill = GLOBAL_SKILLS[id];
1316
- if (!skill) {
1317
- return { content: [{ type: "text", text: `Unknown global skill: ${id}` }] };
1318
- }
1319
- return {
1320
- content: [{
1321
- type: "text",
1322
- text: `${skill.body}\n\nLoaded as global skill "${id}".`,
1323
- }],
1324
- };
1325
- }
1326
-
1327
- if (name === "list_channel_skills") {
1278
+ if (name === "list_skills") {
1328
1279
  const { chat_id } = (args || {}) as { chat_id?: string };
1329
- if (!chat_id) return { content: [{ type: "text", text: "list_channel_skills failed: chat_id required" }] };
1330
- try {
1331
- const r = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(chat_id)}/docs`, {
1332
- headers: { "Authorization": `Bearer ${TOKEN}` },
1333
- });
1334
- const text = await r.text();
1335
- if (!r.ok) {
1336
- return { content: [{ type: "text", text: `list_channel_skills failed (${r.status}): ${text.slice(0, 200)}` }] };
1280
+ const out: any = {
1281
+ global_skills: Object.entries(GLOBAL_SKILLS).map(([skill_id, skill]) => ({
1282
+ skill_id,
1283
+ title: skill.title,
1284
+ summary: skill.summary,
1285
+ loaded_by_default: skill_id === DEFAULT_GLOBAL_SKILL_ID,
1286
+ })),
1287
+ };
1288
+ if (chat_id) {
1289
+ try {
1290
+ const r = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(chat_id)}/docs`, {
1291
+ headers: { "Authorization": `Bearer ${TOKEN}` },
1292
+ });
1293
+ if (r.ok) out.channel_skills = extractChannelDocsPayload(JSON.parse(await r.text())).filter(isSkillDoc).map(compactSkillDoc);
1294
+ else out.channel_skills_error = `failed (${r.status})`;
1295
+ } catch (e: any) {
1296
+ out.channel_skills_error = `network/parse error: ${String(e?.message || e).slice(0, 120)}`;
1337
1297
  }
1338
- const docs = extractChannelDocsPayload(JSON.parse(text)).filter(isSkillDoc).map(compactSkillDoc);
1339
- return { content: [{ type: "text", text: JSON.stringify({ chat_id, skills: docs }, null, 2) }] };
1340
- } catch (e: any) {
1341
- return { content: [{ type: "text", text: `list_channel_skills network/parse error: ${String(e?.message || e).slice(0, 120)}` }] };
1342
1298
  }
1299
+ return { content: [{ type: "text", text: JSON.stringify(out, null, 2) }] };
1343
1300
  }
1344
1301
 
1345
- if (name === "load_channel_skill") {
1346
- const { chat_id, doc_id } = (args || {}) as { chat_id?: string; doc_id?: string };
1347
- if (!chat_id || !doc_id) return { content: [{ type: "text", text: "load_channel_skill failed: chat_id and doc_id required" }] };
1348
- try {
1349
- const r = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(chat_id)}/docs/${encodeURIComponent(doc_id)}`, {
1350
- headers: { "Authorization": `Bearer ${TOKEN}` },
1351
- });
1352
- const text = await r.text();
1353
- if (!r.ok) {
1354
- return { content: [{ type: "text", text: `load_channel_skill failed (${r.status}): ${text.slice(0, 200)}` }] };
1355
- }
1356
- const doc = JSON.parse(text);
1357
- const body = doc?.body_markdown ?? doc?.bodyMarkdown ?? "";
1358
- const title = doc?.title || doc_id;
1359
- const kind = doc?.kind || "unknown";
1360
- const level = doc?.level ?? "?";
1361
- const parsed = parseSkillFrontmatter(String(body));
1362
- const metadata = { ...(parsed.metadata || {}), ...(doc?.skill_meta || doc?.skillMeta || {}) };
1363
- const metaLines = [
1364
- metadata.name ? `name: ${metadata.name}` : null,
1365
- metadata.description ? `description: ${metadata.description}` : null,
1366
- metadata.trigger ? `trigger: ${metadata.trigger}` : null,
1367
- (metadata.argument_hint ?? metadata.argumentHint) ? `argument-hint: ${metadata.argument_hint ?? metadata.argumentHint}` : null,
1368
- ].filter(Boolean).join("\n");
1369
- if (!String(kind).toLowerCase().includes("skill") && !String(doc_id).toLowerCase().includes("skill")) {
1302
+ if (name === "load_skill") {
1303
+ const { skill_id, chat_id, doc_id } = (args || {}) as { skill_id?: string; chat_id?: string; doc_id?: string };
1304
+ // CHANNEL skill: chat_id + doc_id (full frontmatter/metadata handling).
1305
+ if (chat_id && doc_id) {
1306
+ try {
1307
+ const r = await fetch(`${REST_URL}/api/channels/${encodeURIComponent(chat_id)}/docs/${encodeURIComponent(doc_id)}`, {
1308
+ headers: { "Authorization": `Bearer ${TOKEN}` },
1309
+ });
1310
+ const text = await r.text();
1311
+ if (!r.ok) {
1312
+ return { content: [{ type: "text", text: `load_skill (channel) failed (${r.status}): ${text.slice(0, 200)}` }] };
1313
+ }
1314
+ const doc = JSON.parse(text);
1315
+ const body = doc?.body_markdown ?? doc?.bodyMarkdown ?? "";
1316
+ const title = doc?.title || doc_id;
1317
+ const kind = doc?.kind || "unknown";
1318
+ const level = doc?.level ?? "?";
1319
+ const parsed = parseSkillFrontmatter(String(body));
1320
+ const metadata = { ...(parsed.metadata || {}), ...(doc?.skill_meta || doc?.skillMeta || {}) };
1321
+ const metaLines = [
1322
+ metadata.name ? `name: ${metadata.name}` : null,
1323
+ metadata.description ? `description: ${metadata.description}` : null,
1324
+ metadata.trigger ? `trigger: ${metadata.trigger}` : null,
1325
+ (metadata.argument_hint ?? metadata.argumentHint) ? `argument-hint: ${metadata.argument_hint ?? metadata.argumentHint}` : null,
1326
+ ].filter(Boolean).join("\n");
1327
+ if (!String(kind).toLowerCase().includes("skill") && !String(doc_id).toLowerCase().includes("skill")) {
1328
+ return { content: [{ type: "text", text: `Loaded channel doc "${doc_id}" as requested, but it is not marked kind=skill.\n\n# ${title}\n\n${parsed.body}` }] };
1329
+ }
1370
1330
  return {
1371
1331
  content: [{
1372
1332
  type: "text",
1373
- text: `Loaded channel doc "${doc_id}" as requested, but it is not marked kind=skill.\n\n# ${title}\n\n${parsed.body}`,
1333
+ text: [
1334
+ `Channel-specific skill loaded from ${chat_id}/${doc_id} (L${level}, kind=${kind}).`,
1335
+ metaLines ? `\nMetadata:\n${metaLines}` : "",
1336
+ `\n# ${title}\n\n${parsed.body}`,
1337
+ ].join("\n"),
1374
1338
  }],
1375
1339
  };
1340
+ } catch (e: any) {
1341
+ return { content: [{ type: "text", text: `load_skill (channel) network/parse error: ${String(e?.message || e).slice(0, 120)}` }] };
1376
1342
  }
1377
- return {
1378
- content: [{
1379
- type: "text",
1380
- text: [
1381
- `Channel-specific skill loaded from ${chat_id}/${doc_id} (L${level}, kind=${kind}).`,
1382
- metaLines ? `\nMetadata:\n${metaLines}` : "",
1383
- `\n# ${title}\n\n${parsed.body}`,
1384
- ].join("\n"),
1385
- }],
1386
- };
1387
- } catch (e: any) {
1388
- return { content: [{ type: "text", text: `load_channel_skill network/parse error: ${String(e?.message || e).slice(0, 120)}` }] };
1389
1343
  }
1344
+ // GLOBAL skill: skill_id (default workspace-driven-eng).
1345
+ const id = skill_id || DEFAULT_GLOBAL_SKILL_ID;
1346
+ const skill = GLOBAL_SKILLS[id];
1347
+ if (!skill) {
1348
+ return { content: [{ type: "text", text: `Unknown global skill: ${id}` }] };
1349
+ }
1350
+ return { content: [{ type: "text", text: `${skill.body}\n\nLoaded as global skill "${id}".` }] };
1390
1351
  }
1391
1352
 
1392
1353
  if (name === "list_tool_groups") {
@@ -1759,7 +1720,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1759
1720
  skills,
1760
1721
  docs,
1761
1722
  tips: [
1762
- "load_channel_skill(doc_id) activates a channel skill",
1723
+ "load_skill(chat_id, doc_id) activates a channel skill; list_skills(chat_id) lists them",
1763
1724
  "okr_list / get_history for deeper context",
1764
1725
  "/loop <interval> <prompt> works in DMs (okr: prefix = wake mode)",
1765
1726
  ],