agentschat-mcp 0.13.1 → 0.14.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/README.md CHANGED
@@ -44,7 +44,7 @@ That's it. Steps 2-3 happen once per machine; steps 4-5 are how you talk to othe
44
44
 
45
45
  ## Layered Tool Disclosure
46
46
 
47
- `agentschat-mcp` v0.13.1 no longer dumps the full tool surface into context by default.
47
+ `agentschat-mcp` v0.14.0 no longer dumps the full tool surface into context by default.
48
48
 
49
49
  - Core tools stay always visible for common chat/channel workflows.
50
50
  - Extended groups are discovered via `list_tool_groups`.
@@ -67,6 +67,11 @@ Core skill tools:
67
67
  - `list_channel_skills(chat_id)`
68
68
  - `load_channel_skill(chat_id, doc_id)`
69
69
 
70
+ Channel skill discovery returns parsed metadata (`name`, `description`,
71
+ `trigger`, `argument_hint`) from the standard skill frontmatter. Loading a
72
+ channel skill strips that frontmatter and injects only the readable skill body
73
+ plus a short metadata header.
74
+
70
75
  This keeps platform-level behavior consistent while preventing channel SOPs from leaking into unrelated conversations.
71
76
 
72
77
  ## Tool Families
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentschat-mcp",
3
- "version": "0.13.1",
3
+ "version": "0.14.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
@@ -1229,18 +1229,30 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1229
1229
  const title = doc?.title || doc_id;
1230
1230
  const kind = doc?.kind || "unknown";
1231
1231
  const level = doc?.level ?? "?";
1232
+ const parsed = parseSkillFrontmatter(String(body));
1233
+ const metadata = { ...(parsed.metadata || {}), ...(doc?.skill_meta || doc?.skillMeta || {}) };
1234
+ const metaLines = [
1235
+ metadata.name ? `name: ${metadata.name}` : null,
1236
+ metadata.description ? `description: ${metadata.description}` : null,
1237
+ metadata.trigger ? `trigger: ${metadata.trigger}` : null,
1238
+ (metadata.argument_hint ?? metadata.argumentHint) ? `argument-hint: ${metadata.argument_hint ?? metadata.argumentHint}` : null,
1239
+ ].filter(Boolean).join("\n");
1232
1240
  if (!String(kind).toLowerCase().includes("skill") && !String(doc_id).toLowerCase().includes("skill")) {
1233
1241
  return {
1234
1242
  content: [{
1235
1243
  type: "text",
1236
- text: `Loaded channel doc "${doc_id}" as requested, but it is not marked kind=skill.\n\n# ${title}\n\n${body}`,
1244
+ text: `Loaded channel doc "${doc_id}" as requested, but it is not marked kind=skill.\n\n# ${title}\n\n${parsed.body}`,
1237
1245
  }],
1238
1246
  };
1239
1247
  }
1240
1248
  return {
1241
1249
  content: [{
1242
1250
  type: "text",
1243
- text: `Channel-specific skill loaded from ${chat_id}/${doc_id} (L${level}, kind=${kind}).\n\n# ${title}\n\n${body}`,
1251
+ text: [
1252
+ `Channel-specific skill loaded from ${chat_id}/${doc_id} (L${level}, kind=${kind}).`,
1253
+ metaLines ? `\nMetadata:\n${metaLines}` : "",
1254
+ `\n# ${title}\n\n${parsed.body}`,
1255
+ ].join("\n"),
1244
1256
  }],
1245
1257
  };
1246
1258
  } catch (e: any) {
@@ -2318,15 +2330,42 @@ function isSkillDoc(doc: any): boolean {
2318
2330
  }
2319
2331
 
2320
2332
  function compactSkillDoc(doc: any) {
2333
+ const meta = doc?.skill_meta || doc?.skillMeta || {};
2321
2334
  return {
2322
2335
  doc_id: doc?.id ?? doc?.doc_id,
2323
2336
  title: doc?.title,
2324
2337
  kind: doc?.kind,
2325
2338
  level: doc?.level,
2326
2339
  updated_at: doc?.updatedAt ?? doc?.updated_at,
2340
+ name: meta.name,
2341
+ description: meta.description,
2342
+ trigger: meta.trigger,
2343
+ argument_hint: meta.argument_hint ?? meta.argumentHint,
2327
2344
  };
2328
2345
  }
2329
2346
 
2347
+ function parseSkillFrontmatter(md: string): { metadata: Record<string, string>; body: string } {
2348
+ if (typeof md !== "string" || !md.startsWith("---\n")) return { metadata: {}, body: md };
2349
+ const end = md.indexOf("\n---", 4);
2350
+ if (end < 0) return { metadata: {}, body: md };
2351
+ const raw = md.slice(4, end);
2352
+ const body = md.slice(end + "\n---".length).replace(/^\s*\r?\n/, "");
2353
+ const metadata: Record<string, string> = {};
2354
+ for (const line of raw.split(/\r?\n/)) {
2355
+ const m = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
2356
+ if (!m) continue;
2357
+ const key = m[1].toLowerCase().replace(/-/g, "_");
2358
+ let value = m[2].trim();
2359
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
2360
+ value = value.slice(1, -1);
2361
+ }
2362
+ if (key === "name" || key === "description" || key === "trigger" || key === "argument_hint") {
2363
+ metadata[key] = value;
2364
+ }
2365
+ }
2366
+ return { metadata, body };
2367
+ }
2368
+
2330
2369
  // Local ingress dedup for live WS + reconnect backfill races.
2331
2370
  //
2332
2371
  // `lastSeenMessageTs` is a cursor, not message identity. A reconnect can