syncromsp-mcp 1.3.2 → 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 CHANGED
@@ -1,22 +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. Provides AI assistants with access to tickets, customers, assets, invoices, and 30+ resource types through a domain-navigation architecture that keeps token usage efficient.
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
- - **170 API endpoints** across 15 lazy-loaded domains
8
- - **Domain navigation** — only 3-8 tools visible at a time, not 170
7
+ - **170 API endpoints** across 15 domains
9
8
  - **Full CRUD** for tickets, customers, invoices, estimates, appointments, contracts, products, and more
10
9
  - **Ticket comments** — email replies, public notes, and private/internal notes
11
10
  - **Line items** — add products from catalog or manual entries to tickets, invoices, estimates, schedules
12
11
  - **RMM alerts** — create, read, mute, resolve alerts on assets
13
12
  - **Rate limiting** — built-in 180 req/min token bucket (Syncro API limit)
14
13
  - **Confirmation required** for all destructive operations (DELETE, etc.)
15
- - **Docker deployment** with OAuth2 proxy for remote/team access
14
+ - **Auto-update check** warns on startup if a newer version is available
16
15
 
17
- ## Quick Start
16
+ ### Deployment Options
18
17
 
19
- ### Claude Code
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
20
43
 
21
44
  ```bash
22
45
  claude mcp add syncromsp \
@@ -25,13 +48,17 @@ claude mcp add syncromsp \
25
48
  -- npx syncromsp-mcp
26
49
  ```
27
50
 
28
- ### Claude Desktop
51
+ That's it. Claude Code will download and run the latest version automatically.
29
52
 
30
- #### Option 1: MCPB Extension (Recommended)
53
+ ---
54
+
55
+ ## Claude Desktop
56
+
57
+ ### Option 1: MCPB Extension
31
58
 
32
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.
33
60
 
34
- #### Option 2: Manual Configuration
61
+ ### Option 2: Manual Configuration
35
62
 
36
63
  Add to your `claude_desktop_config.json`:
37
64
 
@@ -40,7 +67,7 @@ Add to your `claude_desktop_config.json`:
40
67
  "mcpServers": {
41
68
  "syncromsp": {
42
69
  "command": "npx",
43
- "args": ["syncromsp-mcp"],
70
+ "args": ["-y", "syncromsp-mcp"],
44
71
  "env": {
45
72
  "SYNCRO_API_KEY": "your-api-key",
46
73
  "SYNCRO_SUBDOMAIN": "your-subdomain"
@@ -54,162 +81,198 @@ Config file location:
54
81
  - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
55
82
  - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
56
83
 
57
- ### From Source
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
58
93
 
59
94
  ```bash
60
95
  git clone https://github.com/advenimus/syncromsp-mcp.git
61
96
  cd syncromsp-mcp
62
- npm install
63
- npm run build
64
-
65
- # Set environment variables
66
- export SYNCRO_API_KEY=your-api-key
67
- export SYNCRO_SUBDOMAIN=your-subdomain
68
-
69
- # Run
70
- npm start
97
+ cp .env.example .env
71
98
  ```
72
99
 
73
- ## Getting Your API Key
100
+ Edit `.env` with your settings:
74
101
 
75
- 1. Log in to your Syncro account
76
- 2. Go to **Admin** > **API Tokens**
77
- 3. Click **+ New Token**
78
- 4. Select the **Custom Permissions** tab
79
- 5. Name your token and set permissions for the resources you need
80
- 6. Click **Create** and copy the token (it cannot be retrieved later)
81
-
82
- Your subdomain is the part before `.syncromsp.com` in your Syncro URL (e.g., `mycompany` from `mycompany.syncromsp.com`).
102
+ ```bash
103
+ # Required: Syncro credentials
104
+ SYNCRO_API_KEY=your-api-key
105
+ SYNCRO_SUBDOMAIN=your-subdomain
83
106
 
84
- ## How It Works
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
- ### Domain Navigation
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
- Instead of loading 170+ tools at once (which would overwhelm any AI), the server uses a **navigation pattern**:
116
+ ### Step 2: Deploy
89
117
 
118
+ ```bash
119
+ docker compose up -d
90
120
  ```
91
- Startup → 3 tools visible:
92
- syncro_navigate("tickets") → loads ticket tools
93
- syncro_status() → shows current domain
94
- syncro_back() → returns to root
95
-
96
- After navigating to "tickets" → domain tools visible:
97
- tickets_list, tickets_get, tickets_create, tickets_update,
98
- tickets_delete, tickets_comment, tickets_add_line_item, ...
99
- syncro_back()
100
- ```
101
-
102
- ### Available Domains
103
121
 
104
- | Domain | Description | Key Operations |
105
- |--------|-------------|---------------|
106
- | **tickets** | Service tickets | CRUD, comments (email/public/private), line items, timers, attachments |
107
- | **customers** | Customer records | CRUD, phone numbers, autocomplete |
108
- | **assets** | Customer assets | CRUD, patches, properties (OS, RAM, HDD, etc.) |
109
- | **contacts** | Customer contacts | CRUD |
110
- | **invoices** | Invoices | CRUD, line items (manual + product catalog), print, email |
111
- | **estimates** | Estimates/quotes | CRUD, line items, print, email, convert to invoice |
112
- | **appointments** | Calendar appointments | CRUD, appointment types, ticket linking |
113
- | **products** | Inventory/products | CRUD, serials, SKUs, categories, images |
114
- | **payments** | Payment records | Create, read, multi-invoice distribution |
115
- | **leads** | Leads/opportunities | Create, read, update |
116
- | **contracts** | Service contracts | CRUD |
117
- | **rmm** | RMM alerts | Create, read, mute, resolve |
118
- | **scheduling** | Recurring invoices | CRUD, schedule line items |
119
- | **time** | Timers and time logs | List, update |
120
- | **admin** | Search, users, vendors, wiki, portal, settings, purchase orders, and more | Various |
122
+ The container runs on port 8080 by default. You need a reverse proxy (Traefik, Caddy, nginx) in front to provide HTTPS.
121
123
 
122
- ## Docker Deployment (Remote MCP with OAuth)
124
+ ### Step 3: Connect from Claude.ai
123
125
 
124
- For connecting Claude.ai or other remote MCP clients with built-in OAuth 2.1 authentication:
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
125
131
 
126
- ```bash
127
- cp .env.example .env
128
- # Edit .env with your Syncro credentials and base URL
129
- ```
132
+ ### How Authentication Works
130
133
 
131
- Set `MCP_BASE_URL` to your public HTTPS URL (required for OAuth):
134
+ The server implements the [MCP OAuth 2.1 + PKCE](https://spec.modelcontextprotocol.io) spec with an access key gate:
132
135
 
133
- ```bash
134
- SYNCRO_API_KEY=your-api-key
135
- SYNCRO_SUBDOMAIN=your-subdomain
136
- MCP_BASE_URL=https://mcp.yourcompany.com
136
+ ```
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
137
144
  ```
138
145
 
139
- Then deploy:
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
140
150
 
141
- ```bash
142
- docker compose up -d
151
+ ### Example: Docker with Traefik
152
+
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"
143
172
  ```
144
173
 
145
- ### Connecting Claude.ai
174
+ ### Example: Docker with Caddy
175
+
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
146
200
 
147
- 1. Deploy the server with HTTPS (via reverse proxy like Traefik, Caddy, or nginx)
148
- 2. In Claude.ai, go to **Settings** > **MCP Servers** > **Add Remote Server**
149
- 3. Enter your MCP URL: `https://mcp.yourcompany.com/mcp`
150
- 4. Claude.ai will auto-discover the OAuth endpoints and authenticate
201
+ volumes:
202
+ caddy_data:
203
+ ```
151
204
 
152
- The server implements the full MCP OAuth 2.1 + PKCE spec:
153
- - `/.well-known/oauth-authorization-server` — discovery metadata
154
- - `/authorize` — authorization endpoint (auto-approves since you control the server)
155
- - `/token` — token endpoint with PKCE S256 validation
156
- - `/register` — dynamic client registration (RFC 7591)
157
- - Bearer token validation on all MCP requests
205
+ `Caddyfile`:
206
+ ```
207
+ mcp.yourcompany.com {
208
+ reverse_proxy syncro-mcp:8080
209
+ }
210
+ ```
158
211
 
159
- ### Disabling Auth
212
+ ### Disabling Auth (Not Recommended)
160
213
 
161
- For testing or private networks, disable OAuth:
214
+ For testing on private networks only:
162
215
 
163
216
  ```bash
164
217
  MCP_AUTH=false docker compose up -d
165
218
  ```
166
219
 
220
+ **Warning:** Without auth, anyone who can reach the URL gets full access to your Syncro account.
221
+
222
+ ---
223
+
167
224
  ## Environment Variables
168
225
 
169
- | Variable | Required | Description |
170
- |----------|----------|-------------|
171
- | `SYNCRO_API_KEY` | Yes | Your Syncro API token |
172
- | `SYNCRO_SUBDOMAIN` | Yes | Your Syncro subdomain |
173
- | `MCP_TRANSPORT` | No | `stdio` (default) or `http` |
174
- | `MCP_PORT` | No | HTTP port (default: `8080`) |
175
- | `MCP_BASE_URL` | For OAuth | Public HTTPS URL (e.g., `https://mcp.yourcompany.com`) |
176
- | `MCP_AUTH` | No | `true` (default) or `false` to disable OAuth |
177
- | `MCP_TOOL_MODE` | No | `flat` (default, all tools) or `navigation` (lazy domains) |
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) |
178
236
 
179
- ## API Rate Limits
237
+ ---
180
238
 
181
- Syncro enforces a rate limit of **180 requests per minute per IP**. The server includes a built-in token bucket rate limiter that automatically queues requests when approaching the limit.
239
+ ## Available Domains
182
240
 
183
- ## Important Notes
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 |
184
258
 
185
- - **Destructive operations** (DELETE, remove line item, etc.) require explicit confirmation
186
- - **Line items** cannot be added inline during resource creation — always add them via separate API calls after creating the parent resource
187
- - **Ticket comments** have 3 modes: email reply, public note, and private/internal note
188
- - Some resources have no DELETE endpoint (vendors, leads, products, assets) — use `disabled: true` via update instead
259
+ ---
189
260
 
190
261
  ## Staying Up to Date
191
262
 
192
263
  The server checks for updates on startup and logs a warning if a newer version is available.
193
264
 
194
- ### npx
195
-
196
- Always uses the latest published version automatically:
197
- ```bash
198
- npx syncromsp-mcp@latest
199
- ```
200
-
201
- ### Claude Desktop (MCPB)
202
-
203
- Download the latest `.mcpb` from [Releases](https://github.com/advenimus/syncromsp-mcp/releases) and reinstall.
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` |
204
272
 
205
- ### Docker
206
-
207
- ```bash
208
- docker compose pull
209
- docker compose up -d
210
- ```
273
+ ### Auto-Update with Watchtower
211
274
 
212
- For **automatic updates**, add [Watchtower](https://containrrr.dev/watchtower/):
275
+ Add to your `docker-compose.yml`:
213
276
 
214
277
  ```yaml
215
278
  services:
@@ -218,16 +281,33 @@ services:
218
281
  volumes:
219
282
  - /var/run/docker.sock:/var/run/docker.sock
220
283
  environment:
221
- - WATCHTOWER_POLL_INTERVAL=86400 # Check daily
284
+ - WATCHTOWER_POLL_INTERVAL=86400 # Check every 24 hours
222
285
  - WATCHTOWER_CLEANUP=true
223
286
  ```
224
287
 
225
- ### From Source
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
226
301
 
227
302
  ```bash
228
- git pull
303
+ git clone https://github.com/advenimus/syncromsp-mcp.git
304
+ cd syncromsp-mcp
229
305
  npm install
230
306
  npm run build
307
+
308
+ export SYNCRO_API_KEY=your-api-key
309
+ export SYNCRO_SUBDOMAIN=your-subdomain
310
+ npm start
231
311
  ```
232
312
 
233
313
  ## Development
package/dist/auth.d.ts CHANGED
@@ -9,22 +9,28 @@ declare class InMemoryClientsStore implements OAuthRegisteredClientsStore {
9
9
  registerClient(clientMetadata: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
10
10
  }
11
11
  /**
12
- * OAuth provider for MCP server authentication.
12
+ * Secure OAuth provider for MCP server authentication.
13
13
  *
14
- * Implements the MCP OAuth 2.1 + PKCE spec so that Claude.ai and other
15
- * remote MCP clients can authenticate against this server.
14
+ * When MCP_AUTH_SECRET is set, the authorize flow presents a login page
15
+ * requiring the secret before granting access. This prevents unauthorized
16
+ * clients from completing the OAuth flow even if they discover the server URL.
16
17
  *
17
- * The authorize flow auto-approves requests since the server operator
18
- * deployed this themselves with their Syncro API key, any client that
19
- * can reach the server and complete the OAuth flow is authorized.
18
+ * Without MCP_AUTH_SECRET, the server refuses to start in auth mode.
20
19
  */
21
20
  export declare class McpOAuthProvider implements OAuthServerProvider {
22
21
  readonly clientsStore: InMemoryClientsStore;
23
22
  private readonly codes;
24
23
  private readonly tokens;
24
+ private readonly pendingAuths;
25
25
  private readonly tokenLifetimeMs;
26
- constructor(tokenLifetimeHours?: number);
26
+ private readonly authSecret;
27
+ constructor(authSecret: string, tokenLifetimeHours?: number);
27
28
  authorize(client: OAuthClientInformationFull, params: AuthorizationParams, res: Response): Promise<void>;
29
+ /**
30
+ * Called from the /authorize/callback POST handler.
31
+ * Validates the secret and either redirects with an auth code or shows an error.
32
+ */
33
+ handleAuthCallback(pendingId: string, secret: string, res: Response): Promise<void>;
28
34
  challengeForAuthorizationCode(_client: OAuthClientInformationFull, authorizationCode: string): Promise<string>;
29
35
  exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string, _codeVerifier?: string): Promise<OAuthTokens>;
30
36
  exchangeRefreshToken(client: OAuthClientInformationFull, refreshToken: string, _scopes?: string[], _resource?: URL): Promise<OAuthTokens>;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AACpG,OAAO,KAAK,EACV,0BAA0B,EAC1B,WAAW,EACZ,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAexC,cAAM,oBAAqB,YAAW,2BAA2B;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IAEnE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAI5E,cAAc,CAClB,cAAc,EAAE,0BAA0B,GACzC,OAAO,CAAC,0BAA0B,CAAC;CAIvC;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,YAAW,mBAAmB;IAC1D,QAAQ,CAAC,YAAY,uBAA8B;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;gBAE7B,kBAAkB,GAAE,MAAW;IAIrC,SAAS,CACb,MAAM,EAAE,0BAA0B,EAClC,MAAM,EAAE,mBAAmB,EAC3B,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,IAAI,CAAC;IAyBV,6BAA6B,CACjC,OAAO,EAAE,0BAA0B,EACnC,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,CAAC;IAQZ,yBAAyB,CAC7B,MAAM,EAAE,0BAA0B,EAClC,iBAAiB,EAAE,MAAM,EACzB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,CAAC;IAwCjB,oBAAoB,CACxB,MAAM,EAAE,0BAA0B,EAClC,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,EAAE,EAClB,SAAS,CAAC,EAAE,GAAG,GACd,OAAO,CAAC,WAAW,CAAC;IA4BjB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAcnD,WAAW,CACf,OAAO,EAAE,0BAA0B,EACnC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC,IAAI,CAAC;CAGjB"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAC;AACpG,OAAO,KAAK,EACV,0BAA0B,EAC1B,WAAW,EACZ,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AA4BxC,cAAM,oBAAqB,YAAW,2BAA2B;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiD;IAEnE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC;IAI5E,cAAc,CAClB,cAAc,EAAE,0BAA0B,GACzC,OAAO,CAAC,0BAA0B,CAAC;CAIvC;AAED;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,YAAW,mBAAmB;IAC1D,QAAQ,CAAC,YAAY,uBAA8B;IACnD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IACvD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,UAAU,EAAE,MAAM,EAAE,kBAAkB,GAAE,MAAW;IAUzD,SAAS,CACb,MAAM,EAAE,0BAA0B,EAClC,MAAM,EAAE,mBAAmB,EAC3B,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,IAAI,CAAC;IAqDhB;;;OAGG;IACG,kBAAkB,CACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,QAAQ,GACZ,OAAO,CAAC,IAAI,CAAC;IAmDV,6BAA6B,CACjC,OAAO,EAAE,0BAA0B,EACnC,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,CAAC;IAQZ,yBAAyB,CAC7B,MAAM,EAAE,0BAA0B,EAClC,iBAAiB,EAAE,MAAM,EACzB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,WAAW,CAAC;IA6CjB,oBAAoB,CACxB,MAAM,EAAE,0BAA0B,EAClC,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,EAAE,EAClB,SAAS,CAAC,EAAE,GAAG,GACd,OAAO,CAAC,WAAW,CAAC;IA2BjB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAcnD,WAAW,CACf,OAAO,EAAE,0BAA0B,EACnC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC,IAAI,CAAC;CAGjB"}
package/dist/auth.js CHANGED
@@ -1,4 +1,9 @@
1
- import { randomUUID } from "node:crypto";
1
+ import { randomUUID, createHash, timingSafeEqual } from "node:crypto";
2
+ function safeCompare(a, b) {
3
+ const hashA = createHash("sha256").update(a).digest();
4
+ const hashB = createHash("sha256").update(b).digest();
5
+ return timingSafeEqual(hashA, hashB);
6
+ }
2
7
  class InMemoryClientsStore {
3
8
  clients = new Map();
4
9
  async getClient(clientId) {
@@ -10,40 +15,126 @@ class InMemoryClientsStore {
10
15
  }
11
16
  }
12
17
  /**
13
- * OAuth provider for MCP server authentication.
18
+ * Secure OAuth provider for MCP server authentication.
14
19
  *
15
- * Implements the MCP OAuth 2.1 + PKCE spec so that Claude.ai and other
16
- * remote MCP clients can authenticate against this server.
20
+ * When MCP_AUTH_SECRET is set, the authorize flow presents a login page
21
+ * requiring the secret before granting access. This prevents unauthorized
22
+ * clients from completing the OAuth flow even if they discover the server URL.
17
23
  *
18
- * The authorize flow auto-approves requests since the server operator
19
- * deployed this themselves with their Syncro API key, any client that
20
- * can reach the server and complete the OAuth flow is authorized.
24
+ * Without MCP_AUTH_SECRET, the server refuses to start in auth mode.
21
25
  */
22
26
  export class McpOAuthProvider {
23
27
  clientsStore = new InMemoryClientsStore();
24
28
  codes = new Map();
25
29
  tokens = new Map();
30
+ pendingAuths = new Map();
26
31
  tokenLifetimeMs;
27
- constructor(tokenLifetimeHours = 24) {
32
+ authSecret;
33
+ constructor(authSecret, tokenLifetimeHours = 24) {
34
+ if (!authSecret || authSecret.length < 8) {
35
+ throw new Error("MCP_AUTH_SECRET must be set and at least 8 characters for secure operation");
36
+ }
37
+ this.authSecret = authSecret;
28
38
  this.tokenLifetimeMs = tokenLifetimeHours * 60 * 60 * 1000;
29
39
  }
30
40
  async authorize(client, params, res) {
31
- // Auto-approve: the server operator already authorized usage by deploying
32
- // with their Syncro API key. Generate an auth code and redirect back.
33
- const code = randomUUID();
34
- this.codes.set(code, { client, params });
35
- // Clean up expired codes (older than 10 minutes)
41
+ // Store the pending auth and show login page
42
+ const pendingId = randomUUID();
43
+ this.pendingAuths.set(pendingId, {
44
+ client,
45
+ params,
46
+ createdAt: Date.now(),
47
+ });
48
+ // Clean up expired pending auths (older than 10 minutes)
36
49
  const cutoff = Date.now() - 10 * 60 * 1000;
37
- for (const [key, value] of this.codes) {
38
- if (!this.tokens.has(key)) {
39
- // We don't have a timestamp on codes, but they're short-lived
40
- // and cleaned up when exchanged. This is best-effort cleanup.
41
- }
50
+ for (const [key, value] of this.pendingAuths) {
51
+ if (value.createdAt < cutoff)
52
+ this.pendingAuths.delete(key);
53
+ }
54
+ // Serve a login page that requires the auth secret
55
+ res.setHeader("Content-Type", "text/html");
56
+ res.send(`<!DOCTYPE html>
57
+ <html>
58
+ <head>
59
+ <title>SyncroMSP MCP - Authorize</title>
60
+ <meta name="viewport" content="width=device-width, initial-scale=1">
61
+ <style>
62
+ body { font-family: -apple-system, system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #0f172a; color: #e2e8f0; }
63
+ .card { background: #1e293b; padding: 2rem; border-radius: 12px; max-width: 400px; width: 90%; box-shadow: 0 4px 24px rgba(0,0,0,0.3); }
64
+ h1 { font-size: 1.25rem; margin: 0 0 0.5rem; color: #f8fafc; }
65
+ p { font-size: 0.875rem; color: #94a3b8; margin: 0 0 1.5rem; }
66
+ label { display: block; font-size: 0.875rem; margin-bottom: 0.5rem; color: #cbd5e1; }
67
+ input[type="password"] { width: 100%; padding: 0.75rem; border: 1px solid #334155; border-radius: 8px; background: #0f172a; color: #f8fafc; font-size: 1rem; box-sizing: border-box; }
68
+ input[type="password"]:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59,130,246,0.2); }
69
+ button { width: 100%; padding: 0.75rem; background: #3b82f6; color: white; border: none; border-radius: 8px; font-size: 1rem; cursor: pointer; margin-top: 1rem; }
70
+ button:hover { background: #2563eb; }
71
+ .error { color: #f87171; font-size: 0.875rem; margin-top: 0.5rem; display: none; }
72
+ .client-info { font-size: 0.75rem; color: #64748b; margin-top: 1rem; padding-top: 1rem; border-top: 1px solid #334155; }
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <div class="card">
77
+ <h1>SyncroMSP MCP Server</h1>
78
+ <p>Enter the server access key to authorize this connection.</p>
79
+ <form method="POST" action="/authorize/callback">
80
+ <input type="hidden" name="pending_id" value="${pendingId}">
81
+ <label for="secret">Access Key</label>
82
+ <input type="password" id="secret" name="secret" placeholder="Enter MCP_AUTH_SECRET" required autofocus>
83
+ <div class="error" id="error">Invalid access key. Please try again.</div>
84
+ <button type="submit">Authorize</button>
85
+ </form>
86
+ <div class="client-info">Client: ${client.client_name || client.client_id}</div>
87
+ </div>
88
+ </body>
89
+ </html>`);
90
+ }
91
+ /**
92
+ * Called from the /authorize/callback POST handler.
93
+ * Validates the secret and either redirects with an auth code or shows an error.
94
+ */
95
+ async handleAuthCallback(pendingId, secret, res) {
96
+ const pending = this.pendingAuths.get(pendingId);
97
+ if (!pending) {
98
+ res.status(400).send("Authorization request expired. Please try again.");
99
+ return;
100
+ }
101
+ // Timing-safe comparison of the secret
102
+ if (!safeCompare(secret, this.authSecret)) {
103
+ // Re-show the form with error
104
+ this.pendingAuths.delete(pendingId);
105
+ res.status(403).send(`<!DOCTYPE html>
106
+ <html>
107
+ <head>
108
+ <title>Access Denied</title>
109
+ <meta name="viewport" content="width=device-width, initial-scale=1">
110
+ <style>
111
+ body { font-family: -apple-system, system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #0f172a; color: #e2e8f0; }
112
+ .card { background: #1e293b; padding: 2rem; border-radius: 12px; max-width: 400px; width: 90%; text-align: center; }
113
+ h1 { color: #f87171; font-size: 1.25rem; }
114
+ p { color: #94a3b8; }
115
+ </style>
116
+ </head>
117
+ <body>
118
+ <div class="card">
119
+ <h1>Access Denied</h1>
120
+ <p>Invalid access key. Connection rejected.</p>
121
+ </div>
122
+ </body>
123
+ </html>`);
124
+ return;
42
125
  }
43
- const redirectUrl = new URL(params.redirectUri);
126
+ // Secret valid issue auth code
127
+ this.pendingAuths.delete(pendingId);
128
+ const code = randomUUID();
129
+ this.codes.set(code, {
130
+ client: pending.client,
131
+ params: pending.params,
132
+ createdAt: Date.now(),
133
+ });
134
+ const redirectUrl = new URL(pending.params.redirectUri);
44
135
  redirectUrl.searchParams.set("code", code);
45
- if (params.state !== undefined) {
46
- redirectUrl.searchParams.set("state", params.state);
136
+ if (pending.params.state !== undefined) {
137
+ redirectUrl.searchParams.set("state", pending.params.state);
47
138
  }
48
139
  res.redirect(redirectUrl.toString());
49
140
  }
@@ -62,6 +153,11 @@ export class McpOAuthProvider {
62
153
  if (codeData.client.client_id !== client.client_id) {
63
154
  throw new Error("Authorization code was not issued to this client");
64
155
  }
156
+ // Auth codes expire after 10 minutes
157
+ if (Date.now() - codeData.createdAt > 10 * 60 * 1000) {
158
+ this.codes.delete(authorizationCode);
159
+ throw new Error("Authorization code expired");
160
+ }
65
161
  this.codes.delete(authorizationCode);
66
162
  const accessToken = randomUUID();
67
163
  const refreshToken = randomUUID();
@@ -72,7 +168,6 @@ export class McpOAuthProvider {
72
168
  expiresAt: Date.now() + this.tokenLifetimeMs,
73
169
  resource: codeData.params.resource,
74
170
  });
75
- // Store refresh token with longer lifetime (30 days)
76
171
  this.tokens.set(refreshToken, {
77
172
  token: refreshToken,
78
173
  clientId: client.client_id,
@@ -96,7 +191,6 @@ export class McpOAuthProvider {
96
191
  if (tokenData.clientId !== client.client_id) {
97
192
  throw new Error("Refresh token was not issued to this client");
98
193
  }
99
- // Issue new access token
100
194
  const newAccessToken = randomUUID();
101
195
  this.tokens.set(newAccessToken, {
102
196
  token: newAccessToken,
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -28,65 +28,83 @@ if (transport === "http") {
28
28
  const { isInitializeRequest } = await import("@modelcontextprotocol/sdk/types.js");
29
29
  const port = parseInt(process.env.MCP_PORT || "8080", 10);
30
30
  const useAuth = process.env.MCP_AUTH !== "false";
31
+ const authSecret = process.env.MCP_AUTH_SECRET;
31
32
  const baseUrl = process.env.MCP_BASE_URL || `http://localhost:${port}`;
32
33
  const mcpServerUrl = new URL(baseUrl);
34
+ if (useAuth && !authSecret) {
35
+ console.error("ERROR: MCP_AUTH_SECRET is required when auth is enabled.\n" +
36
+ " Set MCP_AUTH_SECRET to a strong secret (min 8 chars) in your environment.\n" +
37
+ " Or set MCP_AUTH=false to disable auth (not recommended for public deployments).");
38
+ process.exit(1);
39
+ }
33
40
  const app = express();
34
41
  app.use(express.json());
42
+ app.use(express.urlencoded({ extended: false }));
35
43
  // Health check (always unauthenticated)
36
44
  app.get("/health", (_req, res) => {
37
45
  res.json({ status: "ok", transport: "http", auth: useAuth });
38
46
  });
39
47
  let authMiddleware;
40
- if (useAuth) {
48
+ if (useAuth && authSecret) {
41
49
  const { McpOAuthProvider } = await import("./auth.js");
42
50
  const { mcpAuthRouter } = await import("@modelcontextprotocol/sdk/server/auth/router.js");
43
51
  const { requireBearerAuth } = await import("@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js");
44
52
  const { getOAuthProtectedResourceMetadataUrl } = await import("@modelcontextprotocol/sdk/server/auth/router.js");
45
- const oauthProvider = new McpOAuthProvider();
53
+ const oauthProvider = new McpOAuthProvider(authSecret);
46
54
  // Install OAuth routes (/.well-known/*, /authorize, /token, /register, /revoke)
47
55
  app.use(mcpAuthRouter({
48
56
  provider: oauthProvider,
49
57
  issuerUrl: mcpServerUrl,
50
58
  scopesSupported: ["mcp:tools"],
51
59
  }));
60
+ // Handle the auth secret validation callback
61
+ app.post("/authorize/callback", async (req, res) => {
62
+ const { pending_id, secret } = req.body;
63
+ if (!pending_id || !secret) {
64
+ res.status(400).send("Missing required fields");
65
+ return;
66
+ }
67
+ await oauthProvider.handleAuthCallback(pending_id, secret, res);
68
+ });
52
69
  authMiddleware = requireBearerAuth({
53
70
  verifier: oauthProvider,
54
71
  requiredScopes: [],
55
72
  resourceMetadataUrl: getOAuthProtectedResourceMetadataUrl(mcpServerUrl),
56
73
  });
57
- console.error(`OAuth enabled. Issuer: ${mcpServerUrl}`);
74
+ console.error(`OAuth enabled with access key. Issuer: ${mcpServerUrl}`);
58
75
  }
59
76
  else {
60
- console.error("Auth disabled (MCP_AUTH=false)");
77
+ console.error("Auth disabled (MCP_AUTH=false). WARNING: Server is unprotected.");
61
78
  }
62
- // Session management
63
- const transports = {};
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 = {};
64
82
  const mcpHandler = async (req, res) => {
65
83
  const sessionId = req.headers["mcp-session-id"];
66
84
  try {
67
- let sessionTransport;
68
- if (sessionId && transports[sessionId]) {
69
- sessionTransport = transports[sessionId];
85
+ if (sessionId && sessions[sessionId]) {
86
+ await sessions[sessionId].transport.handleRequest(req, res, req.body);
87
+ return;
70
88
  }
71
- else if (!sessionId && isInitializeRequest(req.body)) {
72
- sessionTransport = new StreamableHTTPServerTransport({
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({
73
93
  sessionIdGenerator: () => randomUUID(),
74
94
  onsessioninitialized: (sid) => {
75
- transports[sid] = sessionTransport;
95
+ sessions[sid] = { transport: sessionTransport, server: sessionServer };
76
96
  },
77
97
  });
78
98
  sessionTransport.onclose = () => {
79
99
  const sid = sessionTransport.sessionId;
80
100
  if (sid)
81
- delete transports[sid];
101
+ delete sessions[sid];
82
102
  };
83
- await mcpServer.connect(sessionTransport);
84
- }
85
- else {
86
- 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);
87
105
  return;
88
106
  }
89
- await sessionTransport.handleRequest(req, res, req.body);
107
+ res.status(400).json({ error: "Bad request: missing session ID or not an init request" });
90
108
  }
91
109
  catch (error) {
92
110
  console.error("MCP handler error:", error);
@@ -106,6 +124,13 @@ if (transport === "http") {
106
124
  app.get("/mcp", mcpHandler);
107
125
  app.delete("/mcp", mcpHandler);
108
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);
109
134
  app.listen(port, () => {
110
135
  console.error(`SyncroMSP MCP server listening on http://0.0.0.0:${port}`);
111
136
  console.error(`Health: http://0.0.0.0:${port}/health`);
@@ -115,8 +140,8 @@ if (transport === "http") {
115
140
  }
116
141
  });
117
142
  const shutdown = () => {
118
- for (const t of Object.values(transports)) {
119
- t.close();
143
+ for (const s of Object.values(sessions)) {
144
+ s.transport.close();
120
145
  }
121
146
  process.exit(0);
122
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "syncromsp-mcp",
3
- "version": "1.3.2",
3
+ "version": "1.4.1",
4
4
  "description": "MCP server for SyncroMSP — full API coverage for tickets, customers, assets, invoices, and 30+ resource types",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",