@imenam/mcp-messenger 1.0.1 → 1.0.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/.env.example +1 -1
- package/README.md +11 -5
- package/dist/src/cli/generate-token.d.ts +7 -0
- package/dist/src/cli/generate-token.js +12 -0
- package/dist/src/index.js +17 -0
- package/dist/src/mcp/tools.js +1 -1
- package/dist/src/server/app.js +5 -6
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +3 -2
package/.env.example
CHANGED
|
@@ -15,7 +15,7 @@ MESSENGER_PORT=3600
|
|
|
15
15
|
|
|
16
16
|
# Jeton exigé sur TOUTE requête entrante (API, /health, console web).
|
|
17
17
|
# OBLIGATOIRE : sans MESSENGER_TOKEN ni MESSENGER_AGENT_TOKENS, le serveur refuse
|
|
18
|
-
# de démarrer. Générer
|
|
18
|
+
# de démarrer. Générer avec : npx @imenam/mcp-messenger --generate-token
|
|
19
19
|
MESSENGER_TOKEN=change-me
|
|
20
20
|
|
|
21
21
|
# Alternative plus stricte : un jeton par agent (prioritaire sur MESSENGER_TOKEN).
|
package/README.md
CHANGED
|
@@ -37,7 +37,10 @@ identifiée par une adresse opaque du type `box_9f2c4a01b3d7e5f8` — voir
|
|
|
37
37
|
### 1. Lancer la boîte aux lettres
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
|
|
40
|
+
# Un jeton, à conserver : il sera demandé au serveur, aux agents et à la console.
|
|
41
|
+
npx @imenam/mcp-messenger --generate-token
|
|
42
|
+
|
|
43
|
+
MESSENGER_TOKEN=<le-jeton> npx @imenam/mcp-messenger --server
|
|
41
44
|
# → listening on http://127.0.0.1:3600 (loopback only)
|
|
42
45
|
# → auth: shared token — required on every request
|
|
43
46
|
# → web console: http://127.0.0.1:3600/ui/?token=<MESSENGER_ADMIN_TOKEN>
|
|
@@ -93,7 +96,9 @@ la session MCP démarre quand même et l'enregistrement se fera au premier appel
|
|
|
93
96
|
|
|
94
97
|
L'agent A appelle `send_message` avec `to: ["coder"]`, l'agent B voit le message via
|
|
95
98
|
`list_messages` puis `read_message`, et répond avec `reply_to` pour rester dans le fil.
|
|
96
|
-
`wait_for_message` permet d'attendre une réponse sans faire tourner une boucle d'appels
|
|
99
|
+
`wait_for_message` permet d'attendre une réponse sans faire tourner une boucle d'appels : il ne
|
|
100
|
+
rend la main que sur un message arrivé *après* le début de l'attente, les non-lus déjà en boîte
|
|
101
|
+
ne l'interrompent pas.
|
|
97
102
|
|
|
98
103
|
---
|
|
99
104
|
|
|
@@ -114,7 +119,7 @@ L'agent A appelle `send_message` avec `to: ["coder"]`, l'agent B voit le message
|
|
|
114
119
|
| `delete_messages` | Corbeille, ou suppression définitive (`permanent: true`) |
|
|
115
120
|
| `list_folders` | Dossiers avec totaux et non-lus |
|
|
116
121
|
| `create_folder` / `delete_folder` | Organiser l'espace comme une messagerie |
|
|
117
|
-
| `wait_for_message` | Attente longue (jusqu'à 300 s) jusqu'à l'arrivée d'un message |
|
|
122
|
+
| `wait_for_message` | Attente longue (jusqu'à 300 s) jusqu'à l'arrivée d'un message *postérieur* à l'appel |
|
|
118
123
|
|
|
119
124
|
**Dossiers système** — toujours présents, non supprimables : `inbox`, `sent`, `archive`,
|
|
120
125
|
`trash`. Les dossiers personnalisés sont propres à chaque boîte.
|
|
@@ -203,7 +208,7 @@ Toutes les variables sont documentées dans [`.env.example`](.env.example). L'es
|
|
|
203
208
|
| `MESSENGER_PORT` | `3600` | Port d'écoute |
|
|
204
209
|
| `MESSENGER_HOST` | `127.0.0.1` (figé) | Non configurable ; une valeur non-loopback fait échouer le démarrage |
|
|
205
210
|
| `MESSENGER_DB_PATH` | `./data/messenger.db` | Fichier SQLite |
|
|
206
|
-
| `MESSENGER_TOKEN` | — | **Obligatoire** (sauf si `MESSENGER_AGENT_TOKENS`) : jeton exigé sur toute requête |
|
|
211
|
+
| `MESSENGER_TOKEN` | — | **Obligatoire** (sauf si `MESSENGER_AGENT_TOKENS`) : jeton exigé sur toute requête. `--generate-token` en produit un |
|
|
207
212
|
| `MESSENGER_AGENT_TOKENS` | — | Un jeton par agent : `planner:tok-a,coder:tok-b` |
|
|
208
213
|
| `MESSENGER_ADMIN_TOKEN` | `MESSENGER_TOKEN` | Jeton de la console ; obligatoire si seul `MESSENGER_AGENT_TOKENS` est défini |
|
|
209
214
|
| `MESSENGER_RATE_LIMIT_MAX` | `600` | Requêtes par IP et par fenêtre |
|
|
@@ -278,6 +283,7 @@ cet agent lorsque `MESSENGER_AGENT_TOKENS` est utilisé.
|
|
|
278
283
|
|
|
279
284
|
```bash
|
|
280
285
|
npm install
|
|
286
|
+
npm run generate-token # jeton aléatoire (32 octets, base64url)
|
|
281
287
|
npm run build # tsc + copie des fichiers de la console web
|
|
282
288
|
npm test # build puis suite Vitest complète
|
|
283
289
|
npm run test:watch
|
|
@@ -303,7 +309,7 @@ test/ # store, config, API HTTP, outils MCP, binaire réel
|
|
|
303
309
|
|
|
304
310
|
### Tests
|
|
305
311
|
|
|
306
|
-
|
|
312
|
+
86 tests couvrant : le stockage et l'isolation des boîtes, la validation de configuration,
|
|
307
313
|
l'API HTTP et son authentification (refus systématique sans jeton, jeton partagé, jetons par
|
|
308
314
|
agent, jeton de console distinct), les outils MCP de bout en bout (deux agents qui
|
|
309
315
|
conversent à travers un vrai serveur), l'allocation des boîtes par session — deux processus
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Génère un jeton aléatoire cryptographiquement sûr.
|
|
3
|
+
*
|
|
4
|
+
* L'encodage `base64url` est choisi pour que le jeton passe tel quel dans l'URL de la
|
|
5
|
+
* console web (`/ui/?token=…`) : ni `+`, ni `/`, ni `=` à échapper.
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateToken(bytes?: number): string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
/** 32 octets : hors de portée d'une attaque par force brute, même sans rate limiting. */
|
|
3
|
+
const DEFAULT_BYTES = 32;
|
|
4
|
+
/**
|
|
5
|
+
* Génère un jeton aléatoire cryptographiquement sûr.
|
|
6
|
+
*
|
|
7
|
+
* L'encodage `base64url` est choisi pour que le jeton passe tel quel dans l'URL de la
|
|
8
|
+
* console web (`/ui/?token=…`) : ni `+`, ni `/`, ni `=` à échapper.
|
|
9
|
+
*/
|
|
10
|
+
export function generateToken(bytes = DEFAULT_BYTES) {
|
|
11
|
+
return randomBytes(bytes).toString("base64url");
|
|
12
|
+
}
|
package/dist/src/index.js
CHANGED
|
@@ -10,6 +10,8 @@ Usage:
|
|
|
10
10
|
mcp-messenger --server Start the mailbox server (HTTP API + web console).
|
|
11
11
|
mcp-messenger --claude-setup-mcp [--force]
|
|
12
12
|
Write the messenger entry into ./.mcp.json.
|
|
13
|
+
mcp-messenger --generate-token
|
|
14
|
+
Print a fresh random token for MESSENGER_TOKEN.
|
|
13
15
|
mcp-messenger --version Print the version.
|
|
14
16
|
mcp-messenger --help Print this help.
|
|
15
17
|
|
|
@@ -28,6 +30,21 @@ async function main() {
|
|
|
28
30
|
process.stdout.write(`${APP_VERSION}\n`);
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
33
|
+
// Le jeton part seul sur stdout : la commande reste utilisable dans un pipe
|
|
34
|
+
// (`mcp-messenger --generate-token > token.txt`), les conseils vont sur stderr.
|
|
35
|
+
if (args.includes("--generate-token")) {
|
|
36
|
+
const { generateToken } = await import("./cli/generate-token.js");
|
|
37
|
+
process.stdout.write(`${generateToken()}\n`);
|
|
38
|
+
process.stderr.write([
|
|
39
|
+
"",
|
|
40
|
+
"Ce jeton doit être identique aux trois endroits suivants :",
|
|
41
|
+
" 1. le serveur : MESSENGER_TOKEN",
|
|
42
|
+
" 2. chaque agent : MESSENGER_TOKEN dans son .mcp.json",
|
|
43
|
+
" 3. la console web : http://127.0.0.1:3600/ui/?token=<jeton>",
|
|
44
|
+
"",
|
|
45
|
+
].join("\n"));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
31
48
|
// Traité avant toute initialisation : la commande écrit dans le répertoire de
|
|
32
49
|
// l'utilisateur, elle n'ouvre ni base ni serveur.
|
|
33
50
|
if (args.includes("--claude-setup-mcp")) {
|
package/dist/src/mcp/tools.js
CHANGED
|
@@ -168,7 +168,7 @@ export const TOOLS = [
|
|
|
168
168
|
},
|
|
169
169
|
{
|
|
170
170
|
name: "wait_for_message",
|
|
171
|
-
description: "Block until a
|
|
171
|
+
description: "Block until a message arrives AFTER this call starts, or until the timeout expires. Messages already in the mailbox — even unread ones — do not end the wait. Use it to wait for another agent's answer instead of polling list_messages.",
|
|
172
172
|
inputSchema: {
|
|
173
173
|
type: "object",
|
|
174
174
|
properties: {
|
package/dist/src/server/app.js
CHANGED
|
@@ -186,16 +186,15 @@ export function createApp({ store, config }) {
|
|
|
186
186
|
api.delete("/folders/:name", (req, res) => {
|
|
187
187
|
res.json({ moved: store.deleteFolder(req.agentId, String(req.params.name)) });
|
|
188
188
|
});
|
|
189
|
-
// Attente longue :
|
|
189
|
+
// Attente longue : seuls les messages arrivés APRÈS le début de l'attente réveillent
|
|
190
|
+
// l'appelant ; les non-lus déjà présents sont ignorés (sinon l'outil rendrait la main
|
|
191
|
+
// immédiatement tant que la boîte n'est pas vidée).
|
|
190
192
|
api.get("/wait", (req, res) => {
|
|
191
193
|
const { timeout_seconds, folder } = waitQuerySchema.parse(req.query);
|
|
192
194
|
const agentId = req.agentId;
|
|
193
195
|
const timeoutSeconds = Math.min(timeout_seconds ?? 30, config.maxWaitSeconds);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (first) {
|
|
197
|
-
res.json({ timed_out: false, message: store.getMessage(agentId, first.message_id, false) });
|
|
198
|
-
return;
|
|
196
|
+
if (folder && !store.listFolders(agentId).some((f) => f.name === folder)) {
|
|
197
|
+
throw new MessengerError(`unknown folder: ${folder}`, 404);
|
|
199
198
|
}
|
|
200
199
|
const done = (payload) => {
|
|
201
200
|
clearTimeout(timer);
|
package/dist/src/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const APP_VERSION = "1.0.
|
|
1
|
+
export declare const APP_VERSION = "1.0.2";
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Généré par scripts/generate-version.js — ne pas modifier à la main.
|
|
2
|
-
export const APP_VERSION = "1.0.
|
|
2
|
+
export const APP_VERSION = "1.0.2";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imenam/mcp-messenger",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"main": "dist/src/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "npm run build && vitest run",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"release": "npm version patch && npm publish && git push --follow-tags",
|
|
12
12
|
"typecheck": "tsc --noEmit",
|
|
13
13
|
"test:watch": "vitest",
|
|
14
|
-
"test:coverage": "vitest run --coverage"
|
|
14
|
+
"test:coverage": "vitest run --coverage",
|
|
15
|
+
"generate-token": "node dist/src/index.js --generate-token"
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|
|
17
18
|
"mcp",
|