syncromsp-mcp 1.4.0 → 1.4.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/README.md +201 -120
- package/dist/index.js +24 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,24 +1,45 @@
|
|
|
1
1
|
# SyncroMSP MCP Server
|
|
2
2
|
|
|
3
|
-
A fully-featured [Model Context Protocol](https://modelcontextprotocol.io) server for the [SyncroMSP](https://syncromsp.com) IT/MSP platform.
|
|
3
|
+
A fully-featured [Model Context Protocol](https://modelcontextprotocol.io) server for the [SyncroMSP](https://syncromsp.com) IT/MSP platform. Gives AI assistants full access to tickets, customers, assets, invoices, and 30+ resource types.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **170 API endpoints** across 15 domains
|
|
8
|
-
- **Flat mode** (default) — all tools available immediately, works with Claude Desktop and Claude Code
|
|
9
|
-
- **Navigation mode** (optional) — lazy-loaded domains for lower token usage
|
|
10
8
|
- **Full CRUD** for tickets, customers, invoices, estimates, appointments, contracts, products, and more
|
|
11
9
|
- **Ticket comments** — email replies, public notes, and private/internal notes
|
|
12
10
|
- **Line items** — add products from catalog or manual entries to tickets, invoices, estimates, schedules
|
|
13
11
|
- **RMM alerts** — create, read, mute, resolve alerts on assets
|
|
14
12
|
- **Rate limiting** — built-in 180 req/min token bucket (Syncro API limit)
|
|
15
13
|
- **Confirmation required** for all destructive operations (DELETE, etc.)
|
|
16
|
-
- **Docker deployment** with native MCP OAuth 2.1 for Claude.ai remote connection
|
|
17
14
|
- **Auto-update check** — warns on startup if a newer version is available
|
|
18
15
|
|
|
19
|
-
|
|
16
|
+
### Deployment Options
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
| Method | Best For | Auto-Updates |
|
|
19
|
+
|--------|----------|-------------|
|
|
20
|
+
| [**Claude Code**](#claude-code) | Developers using Claude Code CLI | Yes (npx) |
|
|
21
|
+
| [**Claude Desktop**](#claude-desktop) | Local desktop app users | Yes (npx) |
|
|
22
|
+
| [**Docker + Claude.ai**](#docker-deployment-remote-mcp) | Teams, remote access, Claude.ai web | Yes (Watchtower) |
|
|
23
|
+
| [**From Source**](#from-source) | Development and customization | Manual |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
### Getting Your Syncro API Key
|
|
30
|
+
|
|
31
|
+
1. Log in to your Syncro account
|
|
32
|
+
2. Go to **Admin** > **API Tokens**
|
|
33
|
+
3. Click **+ New Token**
|
|
34
|
+
4. Select the **Custom Permissions** tab
|
|
35
|
+
5. Name your token and set permissions for the resources you need
|
|
36
|
+
6. Click **Create** and copy the token (it cannot be retrieved later)
|
|
37
|
+
|
|
38
|
+
Your **subdomain** is the part before `.syncromsp.com` in your Syncro URL (e.g., `mycompany` from `mycompany.syncromsp.com`).
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Claude Code
|
|
22
43
|
|
|
23
44
|
```bash
|
|
24
45
|
claude mcp add syncromsp \
|
|
@@ -27,13 +48,17 @@ claude mcp add syncromsp \
|
|
|
27
48
|
-- npx syncromsp-mcp
|
|
28
49
|
```
|
|
29
50
|
|
|
30
|
-
|
|
51
|
+
That's it. Claude Code will download and run the latest version automatically.
|
|
52
|
+
|
|
53
|
+
---
|
|
31
54
|
|
|
32
|
-
|
|
55
|
+
## Claude Desktop
|
|
56
|
+
|
|
57
|
+
### Option 1: MCPB Extension
|
|
33
58
|
|
|
34
59
|
Download the latest `.mcpb` file from [Releases](https://github.com/advenimus/syncromsp-mcp/releases) and double-click to install. Claude Desktop will prompt you for your API key and subdomain.
|
|
35
60
|
|
|
36
|
-
|
|
61
|
+
### Option 2: Manual Configuration
|
|
37
62
|
|
|
38
63
|
Add to your `claude_desktop_config.json`:
|
|
39
64
|
|
|
@@ -42,7 +67,7 @@ Add to your `claude_desktop_config.json`:
|
|
|
42
67
|
"mcpServers": {
|
|
43
68
|
"syncromsp": {
|
|
44
69
|
"command": "npx",
|
|
45
|
-
"args": ["syncromsp-mcp"],
|
|
70
|
+
"args": ["-y", "syncromsp-mcp"],
|
|
46
71
|
"env": {
|
|
47
72
|
"SYNCRO_API_KEY": "your-api-key",
|
|
48
73
|
"SYNCRO_SUBDOMAIN": "your-subdomain"
|
|
@@ -56,159 +81,198 @@ Config file location:
|
|
|
56
81
|
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
57
82
|
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
58
83
|
|
|
59
|
-
|
|
84
|
+
Restart Claude Desktop after saving. The server updates automatically via npx on each restart.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Docker Deployment (Remote MCP)
|
|
89
|
+
|
|
90
|
+
Deploy as a Docker container for remote access from Claude.ai, shared team usage, or running on a server. Includes built-in OAuth 2.1 authentication so only authorized users can connect.
|
|
91
|
+
|
|
92
|
+
### Step 1: Clone and Configure
|
|
60
93
|
|
|
61
94
|
```bash
|
|
62
95
|
git clone https://github.com/advenimus/syncromsp-mcp.git
|
|
63
96
|
cd syncromsp-mcp
|
|
64
|
-
|
|
65
|
-
npm run build
|
|
66
|
-
|
|
67
|
-
# Set environment variables
|
|
68
|
-
export SYNCRO_API_KEY=your-api-key
|
|
69
|
-
export SYNCRO_SUBDOMAIN=your-subdomain
|
|
70
|
-
|
|
71
|
-
# Run
|
|
72
|
-
npm start
|
|
97
|
+
cp .env.example .env
|
|
73
98
|
```
|
|
74
99
|
|
|
75
|
-
|
|
100
|
+
Edit `.env` with your settings:
|
|
76
101
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
5. Name your token and set permissions for the resources you need
|
|
82
|
-
6. Click **Create** and copy the token (it cannot be retrieved later)
|
|
102
|
+
```bash
|
|
103
|
+
# Required: Syncro credentials
|
|
104
|
+
SYNCRO_API_KEY=your-api-key
|
|
105
|
+
SYNCRO_SUBDOMAIN=your-subdomain
|
|
83
106
|
|
|
84
|
-
|
|
107
|
+
# Required: The public URL where this server will be reachable
|
|
108
|
+
# Must be HTTPS for production (put behind Traefik, Caddy, nginx, etc.)
|
|
109
|
+
MCP_BASE_URL=https://mcp.yourcompany.com
|
|
85
110
|
|
|
86
|
-
|
|
111
|
+
# Required: Access key that users must enter to authorize connections
|
|
112
|
+
# Generate one with: openssl rand -hex 32
|
|
113
|
+
MCP_AUTH_SECRET=your-strong-secret-here
|
|
114
|
+
```
|
|
87
115
|
|
|
88
|
-
###
|
|
116
|
+
### Step 2: Deploy
|
|
89
117
|
|
|
90
|
-
|
|
118
|
+
```bash
|
|
119
|
+
docker compose up -d
|
|
120
|
+
```
|
|
91
121
|
|
|
92
|
-
|
|
122
|
+
The container runs on port 8080 by default. You need a reverse proxy (Traefik, Caddy, nginx) in front to provide HTTPS.
|
|
93
123
|
|
|
94
|
-
###
|
|
124
|
+
### Step 3: Connect from Claude.ai
|
|
95
125
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
| **contacts** | Customer contacts | CRUD |
|
|
102
|
-
| **invoices** | Invoices | CRUD, line items (manual + product catalog), print, email |
|
|
103
|
-
| **estimates** | Estimates/quotes | CRUD, line items, print, email, convert to invoice |
|
|
104
|
-
| **appointments** | Calendar appointments | CRUD, appointment types, ticket linking |
|
|
105
|
-
| **products** | Inventory/products | CRUD, serials, SKUs, categories, images |
|
|
106
|
-
| **payments** | Payment records | Create, read, multi-invoice distribution |
|
|
107
|
-
| **leads** | Leads/opportunities | Create, read, update |
|
|
108
|
-
| **contracts** | Service contracts | CRUD |
|
|
109
|
-
| **rmm** | RMM alerts | Create, read, mute, resolve |
|
|
110
|
-
| **scheduling** | Recurring invoices | CRUD, schedule line items |
|
|
111
|
-
| **time** | Timers and time logs | List, update |
|
|
112
|
-
| **admin** | Search, users, vendors, wiki, portal, settings, purchase orders, and more | Various |
|
|
126
|
+
1. In Claude.ai, go to **Settings** > **MCP Servers** > **Add Remote Server**
|
|
127
|
+
2. Enter your MCP URL: `https://mcp.yourcompany.com/mcp`
|
|
128
|
+
3. Claude.ai will auto-discover the OAuth endpoints
|
|
129
|
+
4. A login page appears — enter the `MCP_AUTH_SECRET` you configured in Step 1
|
|
130
|
+
5. Once authenticated, Claude.ai connects and all 170 tools become available
|
|
113
131
|
|
|
114
|
-
|
|
132
|
+
### How Authentication Works
|
|
115
133
|
|
|
116
|
-
|
|
134
|
+
The server implements the [MCP OAuth 2.1 + PKCE](https://spec.modelcontextprotocol.io) spec with an access key gate:
|
|
117
135
|
|
|
118
|
-
```bash
|
|
119
|
-
cp .env.example .env
|
|
120
|
-
# Edit .env with your Syncro credentials and base URL
|
|
121
136
|
```
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
MCP_AUTH_SECRET=your-strong-secret-here # Required! Users must know this to connect
|
|
137
|
+
Client connects → 401 Unauthorized
|
|
138
|
+
→ Client discovers /.well-known/oauth-authorization-server
|
|
139
|
+
→ Client dynamically registers (RFC 7591)
|
|
140
|
+
→ Client redirects user to /authorize
|
|
141
|
+
→ User sees login page, enters MCP_AUTH_SECRET
|
|
142
|
+
→ Correct key: auth code issued → token granted → MCP access
|
|
143
|
+
→ Wrong key: 403 Access Denied, connection rejected
|
|
130
144
|
```
|
|
131
145
|
|
|
132
|
-
|
|
146
|
+
- Tokens are validated on every MCP request via bearer auth
|
|
147
|
+
- Access tokens expire after 24 hours (refresh tokens last 30 days)
|
|
148
|
+
- Timing-safe secret comparison prevents side-channel attacks
|
|
149
|
+
- Server **refuses to start** if `MCP_AUTH_SECRET` is not set
|
|
133
150
|
|
|
134
|
-
|
|
151
|
+
### Example: Docker with Traefik
|
|
135
152
|
|
|
136
|
-
```
|
|
137
|
-
|
|
153
|
+
```yaml
|
|
154
|
+
services:
|
|
155
|
+
syncro-mcp:
|
|
156
|
+
image: ghcr.io/advenimus/syncromsp-mcp:latest
|
|
157
|
+
container_name: syncromsp-mcp
|
|
158
|
+
restart: unless-stopped
|
|
159
|
+
environment:
|
|
160
|
+
- SYNCRO_API_KEY=${SYNCRO_API_KEY}
|
|
161
|
+
- SYNCRO_SUBDOMAIN=${SYNCRO_SUBDOMAIN}
|
|
162
|
+
- MCP_TRANSPORT=http
|
|
163
|
+
- MCP_PORT=8080
|
|
164
|
+
- MCP_BASE_URL=https://mcp.yourcompany.com
|
|
165
|
+
- MCP_AUTH_SECRET=${MCP_AUTH_SECRET}
|
|
166
|
+
labels:
|
|
167
|
+
- "traefik.enable=true"
|
|
168
|
+
- "traefik.http.routers.mcp.rule=Host(`mcp.yourcompany.com`)"
|
|
169
|
+
- "traefik.http.routers.mcp.entrypoints=websecure"
|
|
170
|
+
- "traefik.http.routers.mcp.tls.certresolver=letsencrypt"
|
|
171
|
+
- "traefik.http.services.mcp.loadbalancer.server.port=8080"
|
|
138
172
|
```
|
|
139
173
|
|
|
140
|
-
###
|
|
174
|
+
### Example: Docker with Caddy
|
|
141
175
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
176
|
+
```yaml
|
|
177
|
+
services:
|
|
178
|
+
syncro-mcp:
|
|
179
|
+
image: ghcr.io/advenimus/syncromsp-mcp:latest
|
|
180
|
+
container_name: syncromsp-mcp
|
|
181
|
+
restart: unless-stopped
|
|
182
|
+
environment:
|
|
183
|
+
- SYNCRO_API_KEY=${SYNCRO_API_KEY}
|
|
184
|
+
- SYNCRO_SUBDOMAIN=${SYNCRO_SUBDOMAIN}
|
|
185
|
+
- MCP_TRANSPORT=http
|
|
186
|
+
- MCP_BASE_URL=https://mcp.yourcompany.com
|
|
187
|
+
- MCP_AUTH_SECRET=${MCP_AUTH_SECRET}
|
|
188
|
+
expose:
|
|
189
|
+
- "8080"
|
|
190
|
+
|
|
191
|
+
caddy:
|
|
192
|
+
image: caddy:2
|
|
193
|
+
restart: unless-stopped
|
|
194
|
+
ports:
|
|
195
|
+
- "80:80"
|
|
196
|
+
- "443:443"
|
|
197
|
+
volumes:
|
|
198
|
+
- ./Caddyfile:/etc/caddy/Caddyfile
|
|
199
|
+
- caddy_data:/data
|
|
148
200
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
201
|
+
volumes:
|
|
202
|
+
caddy_data:
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`Caddyfile`:
|
|
206
|
+
```
|
|
207
|
+
mcp.yourcompany.com {
|
|
208
|
+
reverse_proxy syncro-mcp:8080
|
|
209
|
+
}
|
|
210
|
+
```
|
|
156
211
|
|
|
157
|
-
### Disabling Auth
|
|
212
|
+
### Disabling Auth (Not Recommended)
|
|
158
213
|
|
|
159
|
-
For testing
|
|
214
|
+
For testing on private networks only:
|
|
160
215
|
|
|
161
216
|
```bash
|
|
162
217
|
MCP_AUTH=false docker compose up -d
|
|
163
218
|
```
|
|
164
219
|
|
|
220
|
+
**Warning:** Without auth, anyone who can reach the URL gets full access to your Syncro account.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
165
224
|
## Environment Variables
|
|
166
225
|
|
|
167
|
-
| Variable | Required | Description |
|
|
168
|
-
|
|
169
|
-
| `SYNCRO_API_KEY` | Yes | Your Syncro API token |
|
|
170
|
-
| `SYNCRO_SUBDOMAIN` | Yes | Your Syncro subdomain |
|
|
171
|
-
| `MCP_TRANSPORT` | No | `stdio` (
|
|
172
|
-
| `MCP_PORT` | No |
|
|
173
|
-
| `MCP_BASE_URL` | For
|
|
174
|
-
| `MCP_AUTH` | No | `true`
|
|
175
|
-
| `MCP_AUTH_SECRET` | For
|
|
176
|
-
| `MCP_TOOL_MODE` | No | `flat` (
|
|
226
|
+
| Variable | Required | Default | Description |
|
|
227
|
+
|----------|----------|---------|-------------|
|
|
228
|
+
| `SYNCRO_API_KEY` | Yes | — | Your Syncro API token |
|
|
229
|
+
| `SYNCRO_SUBDOMAIN` | Yes | — | Your Syncro subdomain |
|
|
230
|
+
| `MCP_TRANSPORT` | No | `stdio` | `stdio` (local) or `http` (Docker/remote) |
|
|
231
|
+
| `MCP_PORT` | No | `8080` | HTTP listen port |
|
|
232
|
+
| `MCP_BASE_URL` | For Docker | — | Public HTTPS URL (e.g., `https://mcp.yourcompany.com`) |
|
|
233
|
+
| `MCP_AUTH` | No | `true` | `true` or `false` to disable OAuth |
|
|
234
|
+
| `MCP_AUTH_SECRET` | For Docker | — | Access key users enter to authorize (min 8 chars) |
|
|
235
|
+
| `MCP_TOOL_MODE` | No | `flat` | `flat` (all tools) or `navigation` (lazy domains) |
|
|
177
236
|
|
|
178
|
-
|
|
237
|
+
---
|
|
179
238
|
|
|
180
|
-
|
|
239
|
+
## Available Domains
|
|
181
240
|
|
|
182
|
-
|
|
241
|
+
| Domain | Description | Key Operations |
|
|
242
|
+
|--------|-------------|---------------|
|
|
243
|
+
| **tickets** | Service tickets | CRUD, comments (email/public/private), line items, timers, attachments |
|
|
244
|
+
| **customers** | Customer records | CRUD, phone numbers, autocomplete |
|
|
245
|
+
| **assets** | Customer assets | CRUD, patches, properties (OS, RAM, HDD, etc.) |
|
|
246
|
+
| **contacts** | Customer contacts | CRUD |
|
|
247
|
+
| **invoices** | Invoices | CRUD, line items (manual + product catalog), print, email |
|
|
248
|
+
| **estimates** | Estimates/quotes | CRUD, line items, print, email, convert to invoice |
|
|
249
|
+
| **appointments** | Calendar appointments | CRUD, appointment types, ticket linking |
|
|
250
|
+
| **products** | Inventory/products | CRUD, serials, SKUs, categories, images |
|
|
251
|
+
| **payments** | Payment records | Create, read, multi-invoice distribution |
|
|
252
|
+
| **leads** | Leads/opportunities | Create, read, update |
|
|
253
|
+
| **contracts** | Service contracts | CRUD |
|
|
254
|
+
| **rmm** | RMM alerts | Create, read, mute, resolve |
|
|
255
|
+
| **scheduling** | Recurring invoices | CRUD, schedule line items |
|
|
256
|
+
| **time** | Timers and time logs | List, update |
|
|
257
|
+
| **admin** | Search, users, vendors, wiki, portal, settings, purchase orders, and more | Various |
|
|
183
258
|
|
|
184
|
-
|
|
185
|
-
- **Line items** cannot be added inline during resource creation — always add them via separate API calls after creating the parent resource
|
|
186
|
-
- **Ticket comments** have 3 modes: email reply, public note, and private/internal note
|
|
187
|
-
- Some resources have no DELETE endpoint (vendors, leads, products, assets) — use `disabled: true` via update instead
|
|
259
|
+
---
|
|
188
260
|
|
|
189
261
|
## Staying Up to Date
|
|
190
262
|
|
|
191
263
|
The server checks for updates on startup and logs a warning if a newer version is available.
|
|
192
264
|
|
|
193
|
-
|
|
265
|
+
| Method | How to Update |
|
|
266
|
+
|--------|--------------|
|
|
267
|
+
| **npx / Claude Desktop** | Automatic — npx pulls latest on each run |
|
|
268
|
+
| **Docker** | `docker compose pull && docker compose up -d` |
|
|
269
|
+
| **Docker (auto)** | Add [Watchtower](https://containrrr.dev/watchtower/) for automatic daily updates |
|
|
270
|
+
| **MCPB** | Download latest `.mcpb` from [Releases](https://github.com/advenimus/syncromsp-mcp/releases) |
|
|
271
|
+
| **From Source** | `git pull && npm install && npm run build` |
|
|
194
272
|
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
npx syncromsp-mcp@latest
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Claude Desktop (MCPB)
|
|
201
|
-
|
|
202
|
-
Download the latest `.mcpb` from [Releases](https://github.com/advenimus/syncromsp-mcp/releases) and reinstall.
|
|
273
|
+
### Auto-Update with Watchtower
|
|
203
274
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
```bash
|
|
207
|
-
docker compose pull
|
|
208
|
-
docker compose up -d
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
For **automatic updates**, add [Watchtower](https://containrrr.dev/watchtower/):
|
|
275
|
+
Add to your `docker-compose.yml`:
|
|
212
276
|
|
|
213
277
|
```yaml
|
|
214
278
|
services:
|
|
@@ -217,16 +281,33 @@ services:
|
|
|
217
281
|
volumes:
|
|
218
282
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
219
283
|
environment:
|
|
220
|
-
- WATCHTOWER_POLL_INTERVAL=86400 # Check
|
|
284
|
+
- WATCHTOWER_POLL_INTERVAL=86400 # Check every 24 hours
|
|
221
285
|
- WATCHTOWER_CLEANUP=true
|
|
222
286
|
```
|
|
223
287
|
|
|
224
|
-
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Important Notes
|
|
291
|
+
|
|
292
|
+
- **Destructive operations** (DELETE, remove line item, etc.) require explicit confirmation
|
|
293
|
+
- **Line items** cannot be added inline during resource creation — always add them via separate API calls after creating the parent resource
|
|
294
|
+
- **Ticket comments** have 3 modes: email reply (`do_not_email: false`), public note (`do_not_email: true, hidden: false`), and private note (`hidden: true`)
|
|
295
|
+
- Some resources have no DELETE endpoint (vendors, leads, products, assets) — use `disabled: true` via update instead
|
|
296
|
+
- **Rate limit**: 180 requests per minute per IP (enforced by Syncro, managed by built-in rate limiter)
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## From Source
|
|
225
301
|
|
|
226
302
|
```bash
|
|
227
|
-
git
|
|
303
|
+
git clone https://github.com/advenimus/syncromsp-mcp.git
|
|
304
|
+
cd syncromsp-mcp
|
|
228
305
|
npm install
|
|
229
306
|
npm run build
|
|
307
|
+
|
|
308
|
+
export SYNCRO_API_KEY=your-api-key
|
|
309
|
+
export SYNCRO_SUBDOMAIN=your-subdomain
|
|
310
|
+
npm start
|
|
230
311
|
```
|
|
231
312
|
|
|
232
313
|
## Development
|
package/dist/index.js
CHANGED
|
@@ -76,34 +76,35 @@ if (transport === "http") {
|
|
|
76
76
|
else {
|
|
77
77
|
console.error("Auth disabled (MCP_AUTH=false). WARNING: Server is unprotected.");
|
|
78
78
|
}
|
|
79
|
-
// Session management
|
|
80
|
-
|
|
79
|
+
// Session management — each session gets its own Server + Transport pair
|
|
80
|
+
// because the MCP SDK Server can only bind to one transport at a time
|
|
81
|
+
const sessions = {};
|
|
81
82
|
const mcpHandler = async (req, res) => {
|
|
82
83
|
const sessionId = req.headers["mcp-session-id"];
|
|
83
84
|
try {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
if (sessionId && sessions[sessionId]) {
|
|
86
|
+
await sessions[sessionId].transport.handleRequest(req, res, req.body);
|
|
87
|
+
return;
|
|
87
88
|
}
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
if (!sessionId && isInitializeRequest(req.body)) {
|
|
90
|
+
// Create a fresh Server + Transport for this session
|
|
91
|
+
const sessionServer = createServer(client, toolMode);
|
|
92
|
+
const sessionTransport = new StreamableHTTPServerTransport({
|
|
90
93
|
sessionIdGenerator: () => randomUUID(),
|
|
91
94
|
onsessioninitialized: (sid) => {
|
|
92
|
-
|
|
95
|
+
sessions[sid] = { transport: sessionTransport, server: sessionServer };
|
|
93
96
|
},
|
|
94
97
|
});
|
|
95
98
|
sessionTransport.onclose = () => {
|
|
96
99
|
const sid = sessionTransport.sessionId;
|
|
97
100
|
if (sid)
|
|
98
|
-
delete
|
|
101
|
+
delete sessions[sid];
|
|
99
102
|
};
|
|
100
|
-
await
|
|
101
|
-
|
|
102
|
-
else {
|
|
103
|
-
res.status(400).json({ error: "Bad request: missing session ID or not an init request" });
|
|
103
|
+
await sessionServer.connect(sessionTransport);
|
|
104
|
+
await sessionTransport.handleRequest(req, res, req.body);
|
|
104
105
|
return;
|
|
105
106
|
}
|
|
106
|
-
|
|
107
|
+
res.status(400).json({ error: "Bad request: missing session ID or not an init request" });
|
|
107
108
|
}
|
|
108
109
|
catch (error) {
|
|
109
110
|
console.error("MCP handler error:", error);
|
|
@@ -123,6 +124,13 @@ if (transport === "http") {
|
|
|
123
124
|
app.get("/mcp", mcpHandler);
|
|
124
125
|
app.delete("/mcp", mcpHandler);
|
|
125
126
|
}
|
|
127
|
+
// Log active session count periodically
|
|
128
|
+
setInterval(() => {
|
|
129
|
+
const count = Object.keys(sessions).length;
|
|
130
|
+
if (count > 0) {
|
|
131
|
+
console.error(`Active MCP sessions: ${count}`);
|
|
132
|
+
}
|
|
133
|
+
}, 60000);
|
|
126
134
|
app.listen(port, () => {
|
|
127
135
|
console.error(`SyncroMSP MCP server listening on http://0.0.0.0:${port}`);
|
|
128
136
|
console.error(`Health: http://0.0.0.0:${port}/health`);
|
|
@@ -132,8 +140,8 @@ if (transport === "http") {
|
|
|
132
140
|
}
|
|
133
141
|
});
|
|
134
142
|
const shutdown = () => {
|
|
135
|
-
for (const
|
|
136
|
-
|
|
143
|
+
for (const s of Object.values(sessions)) {
|
|
144
|
+
s.transport.close();
|
|
137
145
|
}
|
|
138
146
|
process.exit(0);
|
|
139
147
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED