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 +6 -1
- package/package.json +1 -1
- package/src/server.ts +41 -2
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.
|
|
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.
|
|
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:
|
|
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
|