syncromsp-mcp 0.1.0

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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +244 -0
  3. package/dist/api-client.d.ts +21 -0
  4. package/dist/api-client.d.ts.map +1 -0
  5. package/dist/api-client.js +117 -0
  6. package/dist/api-client.js.map +1 -0
  7. package/dist/auth.d.ts +37 -0
  8. package/dist/auth.d.ts.map +1 -0
  9. package/dist/auth.js +133 -0
  10. package/dist/auth.js.map +1 -0
  11. package/dist/domains/admin.d.ts +4 -0
  12. package/dist/domains/admin.d.ts.map +1 -0
  13. package/dist/domains/admin.js +807 -0
  14. package/dist/domains/admin.js.map +1 -0
  15. package/dist/domains/appointments.d.ts +4 -0
  16. package/dist/domains/appointments.d.ts.map +1 -0
  17. package/dist/domains/appointments.js +231 -0
  18. package/dist/domains/appointments.js.map +1 -0
  19. package/dist/domains/assets.d.ts +4 -0
  20. package/dist/domains/assets.d.ts.map +1 -0
  21. package/dist/domains/assets.js +138 -0
  22. package/dist/domains/assets.js.map +1 -0
  23. package/dist/domains/contacts.d.ts +4 -0
  24. package/dist/domains/contacts.d.ts.map +1 -0
  25. package/dist/domains/contacts.js +148 -0
  26. package/dist/domains/contacts.js.map +1 -0
  27. package/dist/domains/contracts.d.ts +4 -0
  28. package/dist/domains/contracts.d.ts.map +1 -0
  29. package/dist/domains/contracts.js +125 -0
  30. package/dist/domains/contracts.js.map +1 -0
  31. package/dist/domains/customers.d.ts +4 -0
  32. package/dist/domains/customers.d.ts.map +1 -0
  33. package/dist/domains/customers.js +323 -0
  34. package/dist/domains/customers.js.map +1 -0
  35. package/dist/domains/estimates.d.ts +4 -0
  36. package/dist/domains/estimates.d.ts.map +1 -0
  37. package/dist/domains/estimates.js +262 -0
  38. package/dist/domains/estimates.js.map +1 -0
  39. package/dist/domains/index.d.ts +5 -0
  40. package/dist/domains/index.d.ts.map +1 -0
  41. package/dist/domains/index.js +34 -0
  42. package/dist/domains/index.js.map +1 -0
  43. package/dist/domains/invoices.d.ts +4 -0
  44. package/dist/domains/invoices.d.ts.map +1 -0
  45. package/dist/domains/invoices.js +292 -0
  46. package/dist/domains/invoices.js.map +1 -0
  47. package/dist/domains/leads.d.ts +4 -0
  48. package/dist/domains/leads.d.ts.map +1 -0
  49. package/dist/domains/leads.js +135 -0
  50. package/dist/domains/leads.js.map +1 -0
  51. package/dist/domains/payments.d.ts +4 -0
  52. package/dist/domains/payments.d.ts.map +1 -0
  53. package/dist/domains/payments.js +188 -0
  54. package/dist/domains/payments.js.map +1 -0
  55. package/dist/domains/products.d.ts +4 -0
  56. package/dist/domains/products.d.ts.map +1 -0
  57. package/dist/domains/products.js +350 -0
  58. package/dist/domains/products.js.map +1 -0
  59. package/dist/domains/rmm.d.ts +4 -0
  60. package/dist/domains/rmm.d.ts.map +1 -0
  61. package/dist/domains/rmm.js +100 -0
  62. package/dist/domains/rmm.js.map +1 -0
  63. package/dist/domains/scheduling.d.ts +4 -0
  64. package/dist/domains/scheduling.d.ts.map +1 -0
  65. package/dist/domains/scheduling.js +206 -0
  66. package/dist/domains/scheduling.js.map +1 -0
  67. package/dist/domains/tickets.d.ts +4 -0
  68. package/dist/domains/tickets.d.ts.map +1 -0
  69. package/dist/domains/tickets.js +533 -0
  70. package/dist/domains/tickets.js.map +1 -0
  71. package/dist/domains/time.d.ts +4 -0
  72. package/dist/domains/time.d.ts.map +1 -0
  73. package/dist/domains/time.js +93 -0
  74. package/dist/domains/time.js.map +1 -0
  75. package/dist/index.d.ts +3 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +137 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/server.d.ts +5 -0
  80. package/dist/server.d.ts.map +1 -0
  81. package/dist/server.js +183 -0
  82. package/dist/server.js.map +1 -0
  83. package/dist/session.d.ts +12 -0
  84. package/dist/session.d.ts.map +1 -0
  85. package/dist/session.js +31 -0
  86. package/dist/session.js.map +1 -0
  87. package/dist/types.d.ts +46 -0
  88. package/dist/types.d.ts.map +1 -0
  89. package/dist/types.js +44 -0
  90. package/dist/types.js.map +1 -0
  91. package/dist/utils/pagination.d.ts +12 -0
  92. package/dist/utils/pagination.d.ts.map +1 -0
  93. package/dist/utils/pagination.js +18 -0
  94. package/dist/utils/pagination.js.map +1 -0
  95. package/dist/utils/rate-limiter.d.ts +15 -0
  96. package/dist/utils/rate-limiter.d.ts.map +1 -0
  97. package/dist/utils/rate-limiter.js +63 -0
  98. package/dist/utils/rate-limiter.js.map +1 -0
  99. package/dist/utils/validators.d.ts +9 -0
  100. package/dist/utils/validators.d.ts.map +1 -0
  101. package/dist/utils/validators.js +59 -0
  102. package/dist/utils/validators.js.map +1 -0
  103. package/dist/utils/version-check.d.ts +7 -0
  104. package/dist/utils/version-check.d.ts.map +1 -0
  105. package/dist/utils/version-check.js +59 -0
  106. package/dist/utils/version-check.js.map +1 -0
  107. package/manifest.json +64 -0
  108. package/package.json +57 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chris
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ # SyncroMSP MCP Server
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.
4
+
5
+ ## Features
6
+
7
+ - **170 API endpoints** across 15 lazy-loaded domains
8
+ - **Domain navigation** — only 3-8 tools visible at a time, not 170
9
+ - **Full CRUD** for tickets, customers, invoices, estimates, appointments, contracts, products, and more
10
+ - **Ticket comments** — email replies, public notes, and private/internal notes
11
+ - **Line items** — add products from catalog or manual entries to tickets, invoices, estimates, schedules
12
+ - **RMM alerts** — create, read, mute, resolve alerts on assets
13
+ - **Rate limiting** — built-in 180 req/min token bucket (Syncro API limit)
14
+ - **Confirmation required** for all destructive operations (DELETE, etc.)
15
+ - **Docker deployment** with OAuth2 proxy for remote/team access
16
+
17
+ ## Quick Start
18
+
19
+ ### Claude Code
20
+
21
+ ```bash
22
+ claude mcp add syncromsp \
23
+ --env SYNCRO_API_KEY=your-api-key \
24
+ --env SYNCRO_SUBDOMAIN=your-subdomain \
25
+ -- npx syncromsp-mcp
26
+ ```
27
+
28
+ ### Claude Desktop
29
+
30
+ #### Option 1: MCPB Extension (Recommended)
31
+
32
+ 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
+
34
+ #### Option 2: Manual Configuration
35
+
36
+ Add to your `claude_desktop_config.json`:
37
+
38
+ ```json
39
+ {
40
+ "mcpServers": {
41
+ "syncromsp": {
42
+ "command": "npx",
43
+ "args": ["syncromsp-mcp"],
44
+ "env": {
45
+ "SYNCRO_API_KEY": "your-api-key",
46
+ "SYNCRO_SUBDOMAIN": "your-subdomain"
47
+ }
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ Config file location:
54
+ - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
55
+ - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
56
+
57
+ ### From Source
58
+
59
+ ```bash
60
+ git clone https://github.com/advenimus/syncromsp-mcp.git
61
+ 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
71
+ ```
72
+
73
+ ## Getting Your API Key
74
+
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`).
83
+
84
+ ## How It Works
85
+
86
+ ### Domain Navigation
87
+
88
+ Instead of loading 170+ tools at once (which would overwhelm any AI), the server uses a **navigation pattern**:
89
+
90
+ ```
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
+
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 |
121
+
122
+ ## Docker Deployment (Remote MCP with OAuth)
123
+
124
+ For connecting Claude.ai or other remote MCP clients with built-in OAuth 2.1 authentication:
125
+
126
+ ```bash
127
+ cp .env.example .env
128
+ # Edit .env with your Syncro credentials and base URL
129
+ ```
130
+
131
+ Set `MCP_BASE_URL` to your public HTTPS URL (required for OAuth):
132
+
133
+ ```bash
134
+ SYNCRO_API_KEY=your-api-key
135
+ SYNCRO_SUBDOMAIN=your-subdomain
136
+ MCP_BASE_URL=https://mcp.yourcompany.com
137
+ ```
138
+
139
+ Then deploy:
140
+
141
+ ```bash
142
+ docker compose up -d
143
+ ```
144
+
145
+ ### Connecting Claude.ai
146
+
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
151
+
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
158
+
159
+ ### Disabling Auth
160
+
161
+ For testing or private networks, disable OAuth:
162
+
163
+ ```bash
164
+ MCP_AUTH=false docker compose up -d
165
+ ```
166
+
167
+ ## Environment Variables
168
+
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) |
178
+
179
+ ## API Rate Limits
180
+
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.
182
+
183
+ ## Important Notes
184
+
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
189
+
190
+ ## Staying Up to Date
191
+
192
+ The server checks for updates on startup and logs a warning if a newer version is available.
193
+
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.
204
+
205
+ ### Docker
206
+
207
+ ```bash
208
+ docker compose pull
209
+ docker compose up -d
210
+ ```
211
+
212
+ For **automatic updates**, add [Watchtower](https://containrrr.dev/watchtower/):
213
+
214
+ ```yaml
215
+ services:
216
+ watchtower:
217
+ image: containrrr/watchtower
218
+ volumes:
219
+ - /var/run/docker.sock:/var/run/docker.sock
220
+ environment:
221
+ - WATCHTOWER_POLL_INTERVAL=86400 # Check daily
222
+ - WATCHTOWER_CLEANUP=true
223
+ ```
224
+
225
+ ### From Source
226
+
227
+ ```bash
228
+ git pull
229
+ npm install
230
+ npm run build
231
+ ```
232
+
233
+ ## Development
234
+
235
+ ```bash
236
+ npm run dev # Run with tsx (hot reload)
237
+ npm run build # Compile TypeScript
238
+ npm test # Run tests
239
+ npm run lint # Lint source
240
+ ```
241
+
242
+ ## License
243
+
244
+ MIT
@@ -0,0 +1,21 @@
1
+ import type { SyncroApiConfig, SyncroErrorResponse } from "./types.js";
2
+ export declare class SyncroApiError extends Error {
3
+ readonly statusCode: number;
4
+ readonly details?: SyncroErrorResponse | undefined;
5
+ constructor(message: string, statusCode: number, details?: SyncroErrorResponse | undefined);
6
+ }
7
+ export declare class SyncroApiClient {
8
+ private readonly baseUrl;
9
+ private readonly apiKey;
10
+ private readonly rateLimiter;
11
+ constructor(config: SyncroApiConfig);
12
+ private buildUrl;
13
+ private request;
14
+ private formatErrorMessage;
15
+ get<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
16
+ post<T>(path: string, body?: Record<string, unknown>, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
17
+ put<T>(path: string, body?: Record<string, unknown>, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
18
+ patch<T>(path: string, body?: Record<string, unknown>, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
19
+ delete<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
20
+ }
21
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGvE,qBAAa,cAAe,SAAQ,KAAK;aAGrB,UAAU,EAAE,MAAM;aAClB,OAAO,CAAC,EAAE,mBAAmB;gBAF7C,OAAO,EAAE,MAAM,EACC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,mBAAmB,YAAA;CAKhD;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,MAAM,EAAE,eAAe;IAQnC,OAAO,CAAC,QAAQ;YAYF,OAAO;IA4CrB,OAAO,CAAC,kBAAkB;IA8BpB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhG,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjI,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhI,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlI,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAG1G"}
@@ -0,0 +1,117 @@
1
+ import { RateLimiter } from "./utils/rate-limiter.js";
2
+ export class SyncroApiError extends Error {
3
+ statusCode;
4
+ details;
5
+ constructor(message, statusCode, details) {
6
+ super(message);
7
+ this.statusCode = statusCode;
8
+ this.details = details;
9
+ this.name = "SyncroApiError";
10
+ }
11
+ }
12
+ export class SyncroApiClient {
13
+ baseUrl;
14
+ apiKey;
15
+ rateLimiter;
16
+ constructor(config) {
17
+ if (!config.apiKey)
18
+ throw new Error("SYNCRO_API_KEY is required");
19
+ if (!config.subdomain)
20
+ throw new Error("SYNCRO_SUBDOMAIN is required");
21
+ this.baseUrl = `https://${config.subdomain}.syncromsp.com/api/v1`;
22
+ this.apiKey = config.apiKey;
23
+ this.rateLimiter = new RateLimiter(180);
24
+ }
25
+ buildUrl(path, params) {
26
+ const url = new URL(`${this.baseUrl}${path}`);
27
+ if (params) {
28
+ for (const [key, value] of Object.entries(params)) {
29
+ if (value !== undefined) {
30
+ url.searchParams.set(key, String(value));
31
+ }
32
+ }
33
+ }
34
+ return url.toString();
35
+ }
36
+ async request(method, path, options = {}) {
37
+ await this.rateLimiter.acquire();
38
+ const url = this.buildUrl(path, options.params);
39
+ const headers = {
40
+ Authorization: `Bearer ${this.apiKey}`,
41
+ Accept: "application/json",
42
+ };
43
+ const fetchOptions = { method, headers };
44
+ if (options.body) {
45
+ headers["Content-Type"] = "application/json";
46
+ fetchOptions.body = JSON.stringify(options.body);
47
+ }
48
+ const response = await fetch(url, fetchOptions);
49
+ if (!response.ok) {
50
+ let details;
51
+ try {
52
+ details = (await response.json());
53
+ }
54
+ catch {
55
+ // response may not be JSON
56
+ }
57
+ const message = this.formatErrorMessage(response.status, details);
58
+ throw new SyncroApiError(message, response.status, details);
59
+ }
60
+ if (response.status === 204) {
61
+ return undefined;
62
+ }
63
+ return (await response.json());
64
+ }
65
+ formatErrorMessage(status, details) {
66
+ const base = `Syncro API error (${status})`;
67
+ if (status === 401)
68
+ return `${base}: Invalid or expired API key. Check SYNCRO_API_KEY.`;
69
+ if (status === 403)
70
+ return `${base}: Insufficient permissions. Check your API token's custom permissions.`;
71
+ if (status === 404)
72
+ return `${base}: Resource not found.`;
73
+ if (status === 429)
74
+ return `${base}: Rate limit exceeded. Please wait before retrying.`;
75
+ if (details?.errors) {
76
+ let errMsg;
77
+ if (Array.isArray(details.errors)) {
78
+ errMsg = details.errors.join(", ");
79
+ }
80
+ else if (typeof details.errors === "string") {
81
+ errMsg = details.errors;
82
+ }
83
+ else if (typeof details.errors === "object") {
84
+ // Handle nested error objects like { mute_for: ["is not valid"] }
85
+ errMsg = Object.entries(details.errors)
86
+ .map(([field, msgs]) => `${field}: ${Array.isArray(msgs) ? msgs.join(", ") : msgs}`)
87
+ .join("; ");
88
+ }
89
+ else {
90
+ errMsg = String(details.errors);
91
+ }
92
+ if (errMsg.length > 0)
93
+ return `${base}: ${errMsg}`;
94
+ }
95
+ if (details?.error)
96
+ return `${base}: ${details.error}`;
97
+ if (details?.message)
98
+ return `${base}: ${details.message}`;
99
+ return base;
100
+ }
101
+ async get(path, params) {
102
+ return this.request("GET", path, { params });
103
+ }
104
+ async post(path, body, params) {
105
+ return this.request("POST", path, { body, params });
106
+ }
107
+ async put(path, body, params) {
108
+ return this.request("PUT", path, { body, params });
109
+ }
110
+ async patch(path, body, params) {
111
+ return this.request("PATCH", path, { body, params });
112
+ }
113
+ async delete(path, params) {
114
+ return this.request("DELETE", path, { params });
115
+ }
116
+ }
117
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type { OAuthServerProvider, AuthorizationParams } from "@modelcontextprotocol/sdk/server/auth/provider.js";
2
+ import type { OAuthRegisteredClientsStore } from "@modelcontextprotocol/sdk/server/auth/clients.js";
3
+ import type { OAuthClientInformationFull, OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
4
+ import type { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
5
+ import type { Response } from "express";
6
+ declare class InMemoryClientsStore implements OAuthRegisteredClientsStore {
7
+ private readonly clients;
8
+ getClient(clientId: string): Promise<OAuthClientInformationFull | undefined>;
9
+ registerClient(clientMetadata: OAuthClientInformationFull): Promise<OAuthClientInformationFull>;
10
+ }
11
+ /**
12
+ * OAuth provider for MCP server authentication.
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.
16
+ *
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.
20
+ */
21
+ export declare class McpOAuthProvider implements OAuthServerProvider {
22
+ readonly clientsStore: InMemoryClientsStore;
23
+ private readonly codes;
24
+ private readonly tokens;
25
+ private readonly tokenLifetimeMs;
26
+ constructor(tokenLifetimeHours?: number);
27
+ authorize(client: OAuthClientInformationFull, params: AuthorizationParams, res: Response): Promise<void>;
28
+ challengeForAuthorizationCode(_client: OAuthClientInformationFull, authorizationCode: string): Promise<string>;
29
+ exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string, _codeVerifier?: string): Promise<OAuthTokens>;
30
+ exchangeRefreshToken(client: OAuthClientInformationFull, refreshToken: string, _scopes?: string[], _resource?: URL): Promise<OAuthTokens>;
31
+ verifyAccessToken(token: string): Promise<AuthInfo>;
32
+ revokeToken(_client: OAuthClientInformationFull, request: {
33
+ token: string;
34
+ }): Promise<void>;
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +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"}
package/dist/auth.js ADDED
@@ -0,0 +1,133 @@
1
+ import { randomUUID } from "node:crypto";
2
+ class InMemoryClientsStore {
3
+ clients = new Map();
4
+ async getClient(clientId) {
5
+ return this.clients.get(clientId);
6
+ }
7
+ async registerClient(clientMetadata) {
8
+ this.clients.set(clientMetadata.client_id, clientMetadata);
9
+ return clientMetadata;
10
+ }
11
+ }
12
+ /**
13
+ * OAuth provider for MCP server authentication.
14
+ *
15
+ * Implements the MCP OAuth 2.1 + PKCE spec so that Claude.ai and other
16
+ * remote MCP clients can authenticate against this server.
17
+ *
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.
21
+ */
22
+ export class McpOAuthProvider {
23
+ clientsStore = new InMemoryClientsStore();
24
+ codes = new Map();
25
+ tokens = new Map();
26
+ tokenLifetimeMs;
27
+ constructor(tokenLifetimeHours = 24) {
28
+ this.tokenLifetimeMs = tokenLifetimeHours * 60 * 60 * 1000;
29
+ }
30
+ 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)
36
+ 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
+ }
42
+ }
43
+ const redirectUrl = new URL(params.redirectUri);
44
+ redirectUrl.searchParams.set("code", code);
45
+ if (params.state !== undefined) {
46
+ redirectUrl.searchParams.set("state", params.state);
47
+ }
48
+ res.redirect(redirectUrl.toString());
49
+ }
50
+ async challengeForAuthorizationCode(_client, authorizationCode) {
51
+ const codeData = this.codes.get(authorizationCode);
52
+ if (!codeData) {
53
+ throw new Error("Invalid authorization code");
54
+ }
55
+ return codeData.params.codeChallenge;
56
+ }
57
+ async exchangeAuthorizationCode(client, authorizationCode, _codeVerifier) {
58
+ const codeData = this.codes.get(authorizationCode);
59
+ if (!codeData) {
60
+ throw new Error("Invalid authorization code");
61
+ }
62
+ if (codeData.client.client_id !== client.client_id) {
63
+ throw new Error("Authorization code was not issued to this client");
64
+ }
65
+ this.codes.delete(authorizationCode);
66
+ const accessToken = randomUUID();
67
+ const refreshToken = randomUUID();
68
+ this.tokens.set(accessToken, {
69
+ token: accessToken,
70
+ clientId: client.client_id,
71
+ scopes: codeData.params.scopes || [],
72
+ expiresAt: Date.now() + this.tokenLifetimeMs,
73
+ resource: codeData.params.resource,
74
+ });
75
+ // Store refresh token with longer lifetime (30 days)
76
+ this.tokens.set(refreshToken, {
77
+ token: refreshToken,
78
+ clientId: client.client_id,
79
+ scopes: codeData.params.scopes || [],
80
+ expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,
81
+ resource: codeData.params.resource,
82
+ });
83
+ return {
84
+ access_token: accessToken,
85
+ token_type: "bearer",
86
+ expires_in: Math.floor(this.tokenLifetimeMs / 1000),
87
+ refresh_token: refreshToken,
88
+ scope: (codeData.params.scopes || []).join(" "),
89
+ };
90
+ }
91
+ async exchangeRefreshToken(client, refreshToken, _scopes, _resource) {
92
+ const tokenData = this.tokens.get(refreshToken);
93
+ if (!tokenData || tokenData.expiresAt < Date.now()) {
94
+ throw new Error("Invalid or expired refresh token");
95
+ }
96
+ if (tokenData.clientId !== client.client_id) {
97
+ throw new Error("Refresh token was not issued to this client");
98
+ }
99
+ // Issue new access token
100
+ const newAccessToken = randomUUID();
101
+ this.tokens.set(newAccessToken, {
102
+ token: newAccessToken,
103
+ clientId: client.client_id,
104
+ scopes: tokenData.scopes,
105
+ expiresAt: Date.now() + this.tokenLifetimeMs,
106
+ resource: tokenData.resource,
107
+ });
108
+ return {
109
+ access_token: newAccessToken,
110
+ token_type: "bearer",
111
+ expires_in: Math.floor(this.tokenLifetimeMs / 1000),
112
+ refresh_token: refreshToken,
113
+ scope: tokenData.scopes.join(" "),
114
+ };
115
+ }
116
+ async verifyAccessToken(token) {
117
+ const tokenData = this.tokens.get(token);
118
+ if (!tokenData || tokenData.expiresAt < Date.now()) {
119
+ throw new Error("Invalid or expired token");
120
+ }
121
+ return {
122
+ token,
123
+ clientId: tokenData.clientId,
124
+ scopes: tokenData.scopes,
125
+ expiresAt: Math.floor(tokenData.expiresAt / 1000),
126
+ resource: tokenData.resource,
127
+ };
128
+ }
129
+ async revokeToken(_client, request) {
130
+ this.tokens.delete(request.token);
131
+ }
132
+ }
133
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { SyncroApiClient } from "../api-client.js";
2
+ import type { DomainHandler } from "../types.js";
3
+ export declare function createDomain(client: SyncroApiClient): DomainHandler;
4
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/domains/admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,aAAa,CAAC;AAI7D,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,CAgyBnE"}