Add /unregister endpoint and document Claude Code hooks for graceful shutdown
This commit is contained in:
parent
66e5c677ea
commit
99cc1853aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,5 +2,6 @@ node_modules/
|
||||
.state/
|
||||
conversations/
|
||||
data/
|
||||
drafts/
|
||||
*.log
|
||||
*.db
|
||||
|
||||
37
README.md
37
README.md
@ -169,6 +169,7 @@ mcp-claude-duo/
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/register` | POST | Register a partner |
|
||||
| `/unregister` | POST | Unregister / go offline |
|
||||
| `/talk` | POST | Send a message |
|
||||
| `/listen/:partnerId` | GET | Long-poll for messages |
|
||||
| `/conversations` | POST | Create group conversation |
|
||||
@ -197,6 +198,42 @@ See [docs/db-schema.md](docs/db-schema.md) for full schema documentation.
|
||||
| `BROKER_PORT` | `3210` | Broker listen port |
|
||||
| `PARTNER_NAME` | `Claude` | Display name for the partner |
|
||||
|
||||
### Graceful Shutdown with Hooks
|
||||
|
||||
To properly mark your Claude instance as offline when the MCP stops, configure a Claude Code hook.
|
||||
|
||||
**1. Create a settings file (if not exists):**
|
||||
|
||||
Create or edit `~/.claude/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"Stop": [
|
||||
{
|
||||
"matcher": "duo-partner",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "curl -X POST http://localhost:3210/unregister -H \"Content-Type: application/json\" -d \"{\\\"partnerId\\\": \\\"$PARTNER_ID\\\"}\""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**2. Or use the Claude CLI:**
|
||||
|
||||
```bash
|
||||
claude config set hooks.Stop '[{"matcher": "duo-partner", "hooks": [{"type": "command", "command": "curl -X POST http://localhost:3210/unregister -H \"Content-Type: application/json\" -d \"{\\\"partnerId\\\": \\\"YOUR_PROJECT_NAME\\\"}\""}]}]'
|
||||
```
|
||||
|
||||
Replace `YOUR_PROJECT_NAME` with your actual partner ID (usually derived from your project folder name).
|
||||
|
||||
**Note:** Without this hook, partners will remain marked as "online" until the broker restarts or they reconnect.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
||||
|
||||
@ -434,6 +434,35 @@ app.post("/partners/:partnerId/notifications", (req, res) => {
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* Se désenregistrer / passer offline
|
||||
* POST /unregister
|
||||
* Body: { partnerId }
|
||||
*/
|
||||
app.post("/unregister", (req, res) => {
|
||||
const { partnerId } = req.body;
|
||||
|
||||
if (!partnerId) {
|
||||
return res.status(400).json({ error: "partnerId required" });
|
||||
}
|
||||
|
||||
// Fermer la connexion long-polling si active
|
||||
if (waitingPartners.has(partnerId)) {
|
||||
const { res: waitingRes, heartbeat, timeout } = waitingPartners.get(partnerId);
|
||||
clearInterval(heartbeat);
|
||||
if (timeout) clearTimeout(timeout);
|
||||
waitingPartners.delete(partnerId);
|
||||
try {
|
||||
waitingRes.json({ hasMessages: false, messages: [], reason: "unregistered" });
|
||||
} catch {}
|
||||
}
|
||||
|
||||
DB.setPartnerOffline(partnerId);
|
||||
console.log(`[BROKER] Unregistered: ${partnerId}`);
|
||||
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
/**
|
||||
* Health check
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user