agentschat-mcp 0.28.0 → 0.29.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 +60 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentschat-mcp",
|
|
3
3
|
"mcpName": "io.github.swswordholy-tech/agentschat-mcp",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.29.0",
|
|
5
5
|
"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.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
package/src/server.ts
CHANGED
|
@@ -566,7 +566,7 @@ const TOOL_GROUPS: ToolGroupMeta[] = [
|
|
|
566
566
|
summary: "Send images and voice/audio clips into channels (upload a local file or attach an already-hosted url).",
|
|
567
567
|
tags: ["chat", "media"],
|
|
568
568
|
estimated_tokens: 700,
|
|
569
|
-
tools: ["send_image", "send_voice", "set_voice", "list_voices"],
|
|
569
|
+
tools: ["send_image", "send_voice", "set_voice", "list_voices", "transcribe"],
|
|
570
570
|
},
|
|
571
571
|
];
|
|
572
572
|
|
|
@@ -680,6 +680,17 @@ const ALL_TOOL_DEFS = [
|
|
|
680
680
|
required: ["voice"],
|
|
681
681
|
},
|
|
682
682
|
},
|
|
683
|
+
{
|
|
684
|
+
name: "transcribe",
|
|
685
|
+
description: "Transcribe a voice/audio attachment to text via the server's speech-to-text, so you can \"hear\" a voice message. Pass the audio `url` from get_history (an /api/file/uploads/* proxy path). Returns the spoken text. (If get_history already shows a transcript for that clip, just read it — no need to call this.)",
|
|
686
|
+
inputSchema: {
|
|
687
|
+
type: "object" as const,
|
|
688
|
+
properties: {
|
|
689
|
+
url: { type: "string", description: "Audio attachment url from get_history (/api/file/uploads/<name>)" },
|
|
690
|
+
},
|
|
691
|
+
required: ["url"],
|
|
692
|
+
},
|
|
693
|
+
},
|
|
683
694
|
{
|
|
684
695
|
name: "send_typing",
|
|
685
696
|
description: "Send a typing indicator to an AgentsChat channel.",
|
|
@@ -1735,6 +1746,33 @@ HANDLERS.set("set_voice", async (args) => {
|
|
|
1735
1746
|
}
|
|
1736
1747
|
});
|
|
1737
1748
|
|
|
1749
|
+
// transcribe — POST /api/stt {audio_url} so an agent can "hear" a voice attachment
|
|
1750
|
+
// (the LLM can't consume audio; STT turns it into readable text). Closes the
|
|
1751
|
+
// "voice is perceivable to humans but not to agents" gap (plan B). Server already
|
|
1752
|
+
// returns attachment URLs in get_history; this is the transcribe entrypoint.
|
|
1753
|
+
HANDLERS.set("transcribe", async (args) => {
|
|
1754
|
+
const { url } = (args || {}) as { url?: string };
|
|
1755
|
+
if (!url) return { content: [{ type: "text", text: "Error: url required (an audio attachment url from get_history)" }], isError: true };
|
|
1756
|
+
try {
|
|
1757
|
+
const r = await apiFetch(`${REST_URL}/api/stt`, {
|
|
1758
|
+
method: "POST",
|
|
1759
|
+
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${TOKEN}` },
|
|
1760
|
+
body: JSON.stringify({ audio_url: url }),
|
|
1761
|
+
});
|
|
1762
|
+
const t = await r.text();
|
|
1763
|
+
if (r.status === 429 && /MEDIA_BUDGET_EXCEEDED/i.test(t)) return { content: [{ type: "text", text: "Voice budget exhausted for today (MEDIA_BUDGET_EXCEEDED) — try again tomorrow." }], isError: true };
|
|
1764
|
+
if (r.status === 415 && /UNSUPPORTED_AUDIO_ENCODING/i.test(t)) return { content: [{ type: "text", text: "That audio format can't be transcribed (m4a/AAC aren't supported by the STT engine; wav/mp3/ogg/opus/webm are)." }], isError: true };
|
|
1765
|
+
if (!r.ok) return { content: [{ type: "text", text: `Transcription failed (${r.status}): ${t.slice(0, 140)}` }], isError: true };
|
|
1766
|
+
let d: any;
|
|
1767
|
+
try { d = JSON.parse(t); } catch { return { content: [{ type: "text", text: `STT returned non-JSON: ${t.slice(0, 120)}` }], isError: true }; }
|
|
1768
|
+
const transcript = d?.transcript;
|
|
1769
|
+
if (!transcript) return { content: [{ type: "text", text: "No speech detected in that audio." }] };
|
|
1770
|
+
return { content: [{ type: "text", text: `Transcript${d?.language ? ` (${d.language})` : ""}: ${transcript}` }] };
|
|
1771
|
+
} catch (e: any) {
|
|
1772
|
+
return { content: [{ type: "text", text: `Error transcribing: ${String(e?.message || e).slice(0, 120)}` }], isError: true };
|
|
1773
|
+
}
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1738
1776
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1739
1777
|
let { name, arguments: args } = request.params;
|
|
1740
1778
|
let viaExtendedCompat = false;
|
|
@@ -2801,7 +2839,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2801
2839
|
if (msgs.length === 0) return { content: [{ type: "text", text: "No messages in this channel." }] };
|
|
2802
2840
|
const list = msgs.map((m: any) => {
|
|
2803
2841
|
const time = m.timestamp ? new Date(m.timestamp).toLocaleString() : "?";
|
|
2804
|
-
|
|
2842
|
+
let line = `[${time}] ${m.sender_id?.slice(0, 12)}: ${m.content?.slice(0, 200) ?? ""}`;
|
|
2843
|
+
// Surface media attachments so an agent can perceive voice/image messages,
|
|
2844
|
+
// not just their text caption. Audio: show any server transcript inline
|
|
2845
|
+
// (agent reads it directly); otherwise point at transcribe(url).
|
|
2846
|
+
const atts = Array.isArray(m.attachments) ? m.attachments : [];
|
|
2847
|
+
for (const a of atts) {
|
|
2848
|
+
if (!a?.url) continue;
|
|
2849
|
+
if (a.type === "audio") {
|
|
2850
|
+
const dur = typeof a.duration_ms === "number" ? ` ${(a.duration_ms / 1000).toFixed(1)}s` : "";
|
|
2851
|
+
line += `\n 🔊 audio${dur}: ${a.url}`;
|
|
2852
|
+
line += a.transcript
|
|
2853
|
+
? `\n transcript: "${String(a.transcript).slice(0, 400)}"`
|
|
2854
|
+
: `\n (no transcript — call transcribe(url) to read what was said)`;
|
|
2855
|
+
} else if (a.type === "image") {
|
|
2856
|
+
const dim = a.width && a.height ? ` ${a.width}×${a.height}` : "";
|
|
2857
|
+
line += `\n 🖼 image${dim}: ${a.url}`;
|
|
2858
|
+
} else {
|
|
2859
|
+
line += `\n 📎 ${a.type || "file"}: ${a.url}`;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2862
|
+
return line;
|
|
2805
2863
|
}).join("\n");
|
|
2806
2864
|
return { content: [{ type: "text", text: `${msgs.length} messages:\n${list}` }] };
|
|
2807
2865
|
}
|