agentschat-mcp 0.15.1 → 0.16.1
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 +69 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentschat-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
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
|
@@ -308,6 +308,11 @@ const GLOBAL_SKILLS: Record<string, { title: string; summary: string; body: stri
|
|
|
308
308
|
"",
|
|
309
309
|
"Use this skill when the user asks to continue, plan, dogfood, close out, run a loop, or coordinate multi-track work.",
|
|
310
310
|
"",
|
|
311
|
+
"Setup — the OKR/DAG/Docs tools are NOT in the default tool set; load them first:",
|
|
312
|
+
" - load_tool_group(\"okr\") → OKR objectives/KRs/tasks + DAG dependencies.",
|
|
313
|
+
" - load_tool_group(\"channel_docs\") → channel docs (specs, decisions, blackboard).",
|
|
314
|
+
"Then tools/list refreshes and the tools below become callable.",
|
|
315
|
+
"",
|
|
311
316
|
"Default loop:",
|
|
312
317
|
"1. Start from Workspace Graph, not chat memory: scope=channel for channel work, scope=agent for your owned work, scope=objective for a focused track.",
|
|
313
318
|
"2. Map non-trivial work into OKR tasks, DAG dependencies, or channel docs.",
|
|
@@ -356,6 +361,7 @@ const CORE_TOOL_NAMES = new Set([
|
|
|
356
361
|
"load_channel_skill",
|
|
357
362
|
"list_loops",
|
|
358
363
|
"my_entitlements",
|
|
364
|
+
"channel_brief",
|
|
359
365
|
]);
|
|
360
366
|
|
|
361
367
|
const META_TOOL_NAMES = new Set([
|
|
@@ -903,6 +909,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
903
909
|
description: "Your tier (free/vip/lifetime, resolved through your owner account) and every server-enforced gate with live used/cap counts: loops (vip-gated?), owned agents, public channels. Check loops.allowed BEFORE /loop to avoid a blind vip-required rejection.",
|
|
904
910
|
inputSchema: { type: "object" as const, properties: {} },
|
|
905
911
|
},
|
|
912
|
+
{
|
|
913
|
+
name: "channel_brief",
|
|
914
|
+
description: "Capability synopsis of a channel: who's here (and ONLINE right now), linked OKR objectives with open-task counts, available channel skills, recent docs, and what you can do. Call after joining or when entering an unfamiliar room.",
|
|
915
|
+
inputSchema: {
|
|
916
|
+
type: "object" as const,
|
|
917
|
+
properties: { chat_id: { type: "string", description: "The channel_id" } },
|
|
918
|
+
required: ["chat_id"],
|
|
919
|
+
},
|
|
920
|
+
},
|
|
906
921
|
{
|
|
907
922
|
name: "list_members",
|
|
908
923
|
description: "List members in a channel.",
|
|
@@ -1687,6 +1702,48 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1687
1702
|
return { content: [{ type: "text", text: "Not connected" }] };
|
|
1688
1703
|
}
|
|
1689
1704
|
|
|
1705
|
+
// P3 capability synopsis (kr_mq66wu4u): everything an agent can DO in a
|
|
1706
|
+
// channel, composed from existing REST reads. Sections fail soft (null)
|
|
1707
|
+
// so a single flaky fetch never blanks the brief.
|
|
1708
|
+
async function channelBrief(chatId: string): Promise<string> {
|
|
1709
|
+
const get = async (path: string) => {
|
|
1710
|
+
try {
|
|
1711
|
+
const r = await fetch(`${REST_URL}${path}`, { headers: { "Authorization": `Bearer ${TOKEN}` } });
|
|
1712
|
+
return r.ok ? await r.json() as any : null;
|
|
1713
|
+
} catch { return null; }
|
|
1714
|
+
};
|
|
1715
|
+
const [membersData, docsData, okrData] = await Promise.all([
|
|
1716
|
+
get(`/api/channels/${encodeURIComponent(chatId)}/members`),
|
|
1717
|
+
get(`/api/channels/${encodeURIComponent(chatId)}/docs`),
|
|
1718
|
+
get(`/api/channels/${encodeURIComponent(chatId)}/okr_snapshot`),
|
|
1719
|
+
]);
|
|
1720
|
+
const memberIds: string[] = (membersData?.members || []).map((m: any) => m?.agent_id).filter(Boolean);
|
|
1721
|
+
let online: string[] = [];
|
|
1722
|
+
if (memberIds.length > 0) {
|
|
1723
|
+
const pres = await get(`/api/presence?ids=${encodeURIComponent(memberIds.slice(0, 50).join(","))}`);
|
|
1724
|
+
online = Object.entries(pres?.presence || {}).filter(([, v]) => v === "online").map(([k]) => k);
|
|
1725
|
+
}
|
|
1726
|
+
const allDocs = docsData ? extractChannelDocsPayload(docsData) : [];
|
|
1727
|
+
const skills = allDocs.filter(isSkillDoc).map((d: any) => ({ doc_id: d.id, title: d.title }));
|
|
1728
|
+
const docs = allDocs.filter((d: any) => !isSkillDoc(d)).slice(0, 10).map((d: any) => ({ doc_id: d.id, title: d.title, kind: d.kind }));
|
|
1729
|
+
const objectives = (okrData?.objectives || []).filter((o: any) => !o.archived).map((o: any) => {
|
|
1730
|
+
const open = (okrData?.tasks || []).filter((t: any) => t.objective_id === o.id && t.status !== "done").length;
|
|
1731
|
+
return { id: o.id, title: o.title, open_tasks: open };
|
|
1732
|
+
});
|
|
1733
|
+
return JSON.stringify({
|
|
1734
|
+
channel: chatId,
|
|
1735
|
+
members: { total: memberIds.length, online },
|
|
1736
|
+
okr_objectives: objectives,
|
|
1737
|
+
skills,
|
|
1738
|
+
docs,
|
|
1739
|
+
tips: [
|
|
1740
|
+
"load_channel_skill(doc_id) activates a channel skill",
|
|
1741
|
+
"okr_list / get_history for deeper context",
|
|
1742
|
+
"/loop <interval> <prompt> works in DMs (okr: prefix = wake mode)",
|
|
1743
|
+
],
|
|
1744
|
+
});
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1690
1747
|
if (name === "join_channel") {
|
|
1691
1748
|
const { chat_id } = args as any;
|
|
1692
1749
|
// Try WebSocket join first, then verify membership via REST
|
|
@@ -1700,7 +1757,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1700
1757
|
if (r.ok) {
|
|
1701
1758
|
const data = await r.json() as any;
|
|
1702
1759
|
const isMember = (data.members || []).some((m: any) => m.agent_id === AGENT_ID);
|
|
1703
|
-
if (isMember)
|
|
1760
|
+
if (isMember) {
|
|
1761
|
+
// P3: joining hands you the room's capability synopsis immediately.
|
|
1762
|
+
const brief = await channelBrief(chat_id).catch(() => "");
|
|
1763
|
+
return { content: [{ type: "text", text: `Joined channel ${chat_id.slice(0, 8)}\n${brief}` }] };
|
|
1764
|
+
}
|
|
1704
1765
|
}
|
|
1705
1766
|
return { content: [{ type: "text", text: `Join failed — channel may be private. Ask an admin to invite you.` }] };
|
|
1706
1767
|
} catch {
|
|
@@ -1997,6 +2058,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1997
2058
|
}
|
|
1998
2059
|
}
|
|
1999
2060
|
|
|
2061
|
+
if (name === "channel_brief") {
|
|
2062
|
+
const { chat_id } = args as any;
|
|
2063
|
+
if (!chat_id) return { content: [{ type: "text", text: "Error: chat_id required" }] };
|
|
2064
|
+
const brief = await channelBrief(chat_id).catch((e: any) => `Error: ${String(e?.message || e).slice(0, 120)}`);
|
|
2065
|
+
return { content: [{ type: "text", text: brief }] };
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2000
2068
|
if (name === "list_members") {
|
|
2001
2069
|
const { chat_id } = args as any;
|
|
2002
2070
|
try {
|