@tjamescouch/agentchat-mcp 0.8.1 → 0.8.2
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 +2 -2
- package/state.js +44 -1
- package/tools/connect.js +18 -3
- package/tools/listen.js +10 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tjamescouch/agentchat-mcp",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "MCP server for AgentChat - real-time AI agent communication",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
30
|
-
"@tjamescouch/agentchat": "^0.22.
|
|
30
|
+
"@tjamescouch/agentchat": "^0.22.1",
|
|
31
31
|
"zod": "^3.25.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
package/state.js
CHANGED
|
@@ -12,8 +12,25 @@ export let keepaliveInterval = null;
|
|
|
12
12
|
// Message tracking - timestamp of last message we returned to the caller
|
|
13
13
|
export let lastSeenTimestamp = 0;
|
|
14
14
|
|
|
15
|
+
// Message buffer - captures messages between listen() calls
|
|
16
|
+
const MAX_BUFFER_SIZE = 200;
|
|
17
|
+
let messageBuffer = [];
|
|
18
|
+
|
|
15
19
|
// Default server
|
|
16
|
-
export const DEFAULT_SERVER_URL =
|
|
20
|
+
export const DEFAULT_SERVER_URL = (() => {
|
|
21
|
+
const explicit = process.env.AGENTCHAT_URL;
|
|
22
|
+
if (explicit) {
|
|
23
|
+
const parsed = new URL(explicit);
|
|
24
|
+
const isLocal = parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1' || parsed.hostname === '::1';
|
|
25
|
+
if (!isLocal && process.env.AGENTCHAT_PUBLIC !== 'true') {
|
|
26
|
+
console.error(`ERROR: AGENTCHAT_URL points to remote host "${parsed.hostname}" but AGENTCHAT_PUBLIC is not set.`);
|
|
27
|
+
console.error('Set AGENTCHAT_PUBLIC=true to allow connections to non-localhost servers.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
return explicit;
|
|
31
|
+
}
|
|
32
|
+
return process.env.AGENTCHAT_PUBLIC === 'true' ? 'wss://agentchat-server.fly.dev' : 'ws://localhost:6667';
|
|
33
|
+
})();
|
|
17
34
|
|
|
18
35
|
// Keepalive settings
|
|
19
36
|
export const KEEPALIVE_INTERVAL_MS = 30000;
|
|
@@ -69,3 +86,29 @@ export function resetLastSeen() {
|
|
|
69
86
|
export function getLastSeen() {
|
|
70
87
|
return lastSeenTimestamp;
|
|
71
88
|
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Push a message into the buffer (called by persistent handler on client)
|
|
92
|
+
*/
|
|
93
|
+
export function bufferMessage(msg) {
|
|
94
|
+
messageBuffer.push(msg);
|
|
95
|
+
if (messageBuffer.length > MAX_BUFFER_SIZE) {
|
|
96
|
+
messageBuffer = messageBuffer.slice(-MAX_BUFFER_SIZE);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Drain all buffered messages and clear the buffer
|
|
102
|
+
*/
|
|
103
|
+
export function drainMessageBuffer() {
|
|
104
|
+
const messages = messageBuffer;
|
|
105
|
+
messageBuffer = [];
|
|
106
|
+
return messages;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Clear the message buffer (e.g., on reconnect)
|
|
111
|
+
*/
|
|
112
|
+
export function clearMessageBuffer() {
|
|
113
|
+
messageBuffer = [];
|
|
114
|
+
}
|
package/tools/connect.js
CHANGED
|
@@ -10,7 +10,7 @@ import path from 'path';
|
|
|
10
10
|
import {
|
|
11
11
|
client, keepaliveInterval,
|
|
12
12
|
setClient, setServerUrl, setKeepaliveInterval,
|
|
13
|
-
resetLastSeen,
|
|
13
|
+
resetLastSeen, clearMessageBuffer, bufferMessage,
|
|
14
14
|
DEFAULT_SERVER_URL, KEEPALIVE_INTERVAL_MS
|
|
15
15
|
} from '../state.js';
|
|
16
16
|
|
|
@@ -55,7 +55,7 @@ export function registerConnectTool(server) {
|
|
|
55
55
|
'agentchat_connect',
|
|
56
56
|
'Connect to an AgentChat server for real-time agent communication',
|
|
57
57
|
{
|
|
58
|
-
server_url: z.string().optional().describe('WebSocket URL (default: wss://agentchat-server.fly.dev)'),
|
|
58
|
+
server_url: z.string().optional().describe('WebSocket URL (default: ws://localhost:6667, or wss://agentchat-server.fly.dev if AGENTCHAT_PUBLIC=true)'),
|
|
59
59
|
name: z.string().optional().describe('Agent name for persistent identity. Creates .agentchat/identities/<name>.json. Omit for ephemeral identity.'),
|
|
60
60
|
identity_path: z.string().optional().describe('Custom path to identity file (overrides name)'),
|
|
61
61
|
},
|
|
@@ -132,8 +132,23 @@ export function registerConnectTool(server) {
|
|
|
132
132
|
setClient(newClient);
|
|
133
133
|
setServerUrl(actualServerUrl);
|
|
134
134
|
|
|
135
|
-
// Reset last seen timestamp on new connection
|
|
135
|
+
// Reset last seen timestamp and message buffer on new connection
|
|
136
136
|
resetLastSeen();
|
|
137
|
+
clearMessageBuffer();
|
|
138
|
+
|
|
139
|
+
// Persistent message handler - buffers ALL messages between listen() calls
|
|
140
|
+
// This is the fix for the listen() message drop bug: messages that arrive
|
|
141
|
+
// while the agent is busy with other tools are captured here instead of lost.
|
|
142
|
+
newClient.on('message', (msg) => {
|
|
143
|
+
// Skip own messages, server noise, and replays
|
|
144
|
+
if (msg.from === newClient.agentId || msg.from === '@server' || msg.replay) return;
|
|
145
|
+
bufferMessage({
|
|
146
|
+
from: msg.from,
|
|
147
|
+
to: msg.to,
|
|
148
|
+
content: msg.content,
|
|
149
|
+
ts: msg.ts,
|
|
150
|
+
});
|
|
151
|
+
});
|
|
137
152
|
|
|
138
153
|
// Start keepalive ping to prevent connection timeout
|
|
139
154
|
const interval = setInterval(() => {
|
package/tools/listen.js
CHANGED
|
@@ -8,7 +8,7 @@ import fs from 'fs';
|
|
|
8
8
|
import { getDaemonPaths } from '@tjamescouch/agentchat/lib/daemon.js';
|
|
9
9
|
import { addJitter } from '@tjamescouch/agentchat/lib/jitter.js';
|
|
10
10
|
import { ClientMessageType } from '@tjamescouch/agentchat/lib/protocol.js';
|
|
11
|
-
import { client, getLastSeen, updateLastSeen } from '../state.js';
|
|
11
|
+
import { client, getLastSeen, updateLastSeen, drainMessageBuffer } from '../state.js';
|
|
12
12
|
|
|
13
13
|
// Timeouts - agent cannot override these
|
|
14
14
|
const ENFORCED_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour when alone
|
|
@@ -87,9 +87,16 @@ export function registerListenTool(server) {
|
|
|
87
87
|
};
|
|
88
88
|
setPresence('listening');
|
|
89
89
|
|
|
90
|
-
//
|
|
90
|
+
// Drain the persistent message buffer (messages captured between listen calls)
|
|
91
|
+
const buffered = drainMessageBuffer().filter(m => {
|
|
92
|
+
// Filter to relevant channels/DMs, skip already-seen messages
|
|
93
|
+
const isRelevant = channels.includes(m.to) || m.to === client.agentId;
|
|
94
|
+
return isRelevant && (!m.ts || m.ts > lastSeen);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Start with buffered messages + replay messages captured during join
|
|
91
98
|
const paths = getDaemonPaths('default');
|
|
92
|
-
let missedMessages = [...replayMessages];
|
|
99
|
+
let missedMessages = [...buffered, ...replayMessages];
|
|
93
100
|
|
|
94
101
|
if (fs.existsSync(paths.inbox)) {
|
|
95
102
|
try {
|