@theyahia/megaplan-mcp 1.1.1 → 4.0.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 (51) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +134 -10
  3. package/dist/client.d.ts +3 -1
  4. package/dist/client.js +210 -26
  5. package/dist/client.js.map +1 -1
  6. package/dist/format.d.ts +12 -0
  7. package/dist/format.js +148 -0
  8. package/dist/format.js.map +1 -0
  9. package/dist/http.d.ts +3 -0
  10. package/dist/http.js +152 -0
  11. package/dist/http.js.map +1 -0
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.js +94 -16
  14. package/dist/index.js.map +1 -1
  15. package/dist/meta.d.ts +2 -0
  16. package/dist/meta.js +5 -0
  17. package/dist/meta.js.map +1 -0
  18. package/dist/prompts.d.ts +7 -0
  19. package/dist/prompts.js +22 -0
  20. package/dist/prompts.js.map +1 -0
  21. package/dist/query.d.ts +32 -0
  22. package/dist/query.js +61 -0
  23. package/dist/query.js.map +1 -0
  24. package/dist/tools/comments.d.ts +35 -0
  25. package/dist/tools/comments.js +31 -0
  26. package/dist/tools/comments.js.map +1 -0
  27. package/dist/tools/contractors.d.ts +35 -0
  28. package/dist/tools/contractors.js +39 -0
  29. package/dist/tools/contractors.js.map +1 -0
  30. package/dist/tools/deals.d.ts +76 -7
  31. package/dist/tools/deals.js +89 -16
  32. package/dist/tools/deals.js.map +1 -1
  33. package/dist/tools/employees.d.ts +21 -0
  34. package/dist/tools/employees.js +25 -0
  35. package/dist/tools/employees.js.map +1 -0
  36. package/dist/tools/me.d.ts +9 -0
  37. package/dist/tools/me.js +26 -0
  38. package/dist/tools/me.js.map +1 -0
  39. package/dist/tools/programs.d.ts +26 -0
  40. package/dist/tools/programs.js +25 -0
  41. package/dist/tools/programs.js.map +1 -0
  42. package/dist/tools/projects.d.ts +32 -0
  43. package/dist/tools/projects.js +34 -0
  44. package/dist/tools/projects.js.map +1 -0
  45. package/dist/tools/tasks.d.ts +49 -9
  46. package/dist/tools/tasks.js +62 -20
  47. package/dist/tools/tasks.js.map +1 -1
  48. package/dist/types.d.ts +54 -32
  49. package/dist/types.js +4 -0
  50. package/dist/types.js.map +1 -1
  51. package/package.json +69 -57
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 theYahia
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 theYahia
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 CHANGED
@@ -1,19 +1,62 @@
1
1
  # @theyahia/megaplan-mcp
2
2
 
3
- MCP server for **Megaplan** project management. Provides tools for managing tasks and deals via API v3.
3
+ MCP server for **Megaplan** project management. Tasks, deals, projects,
4
+ employees, clients, and comments via Megaplan API v3.
4
5
 
5
- ## Tools
6
+ > **v4.0 is a breaking release** (and the first npm release of this overhaul —
7
+ > it supersedes the older 8-tool `3.0.0`). Request/response shapes changed to
8
+ > match the real v3 API, and `--http` now requires an auth token. See
9
+ > [CHANGELOG.md](./CHANGELOG.md) and [Migrating from older versions](#migrating-from-older-versions).
10
+
11
+ ## Tools (18)
6
12
 
7
13
  | Tool | Description |
8
14
  |------|------------|
9
- | `get_tasks` | List tasks with filters by status, responsible, search |
10
- | `create_task` | Create a new task with name, description, deadline |
11
- | `get_deals` | List deals with filters by status, responsible, search |
15
+ | `get_tasks` | List tasks; filter by status code(s), responsible, search |
16
+ | `get_task` | Get one task by ID |
17
+ | `create_task` | Create a task (name, description, responsible, deadline) |
18
+ | `update_task` | Update a task (name, description, responsible, deadline, status) |
19
+ | `get_deals` | List deals; filter by status code(s), responsible, search |
20
+ | `get_deal` | Get one deal by ID |
21
+ | `create_deal` | Create a deal (requires a program/pipeline ID) |
22
+ | `update_deal` | Update a deal (name, responsible, amount, description, status) |
23
+ | `get_projects` | List projects; filter by status code(s), search |
24
+ | `get_project` | Get one project by ID |
25
+ | `get_employees` | List employees; search + department filter |
26
+ | `get_deal_programs` | List deal programs (pipelines) — find the `program_id` for `create_deal` |
27
+ | `get_deal_program` | Get one deal program by ID |
28
+ | `list_clients` | List clients (contractors): people (`human`) or orgs (`company`) |
29
+ | `get_client` | Get one client by type + ID |
30
+ | `get_current_user` | Authenticated user's employee record (**experimental**) |
31
+ | `get_comments` | List comments on a task/deal/project |
32
+ | `create_comment` | Add a comment to a task/deal/project |
33
+
34
+ All list/get tools return a **compact summary** by default; pass `raw: true` for
35
+ the unmodified API JSON. Lists are cursor-paginated: pass the returned
36
+ `nextPageAfter` as `page_after` to get the next page.
37
+
38
+ ## Skills (Prompts)
39
+
40
+ | Skill | Description |
41
+ |-------|------------|
42
+ | `my-tasks-today` | "Мои задачи на сегодня" — your tasks (scoped via `get_current_user`) |
43
+ | `create-deal-wizard` | "Создай сделку" — guided deal creation (lists pipelines first) |
12
44
 
13
45
  ## Setup
14
46
 
15
- 1. In Megaplan, go to **Settings > Integration > API**
16
- 2. Generate an access token
47
+ ### Option A: Access Token
48
+
49
+ 1. In Megaplan, go to **Settings → Integration → API**.
50
+ 2. Generate an access token, and set it as `MEGAPLAN_TOKEN`.
51
+
52
+ ### Option B: Login + Password
53
+
54
+ Set `MEGAPLAN_LOGIN` (email) + `MEGAPLAN_PASSWORD`. The server exchanges them for
55
+ an access token (cached in memory, re-authenticated on expiry).
56
+
57
+ `MEGAPLAN_DOMAIN` is your account host. A bare subdomain like `yourcompany` is
58
+ expanded to `yourcompany.megaplan.ru`; a full host (`crm.example.com`) is used
59
+ as-is.
17
60
 
18
61
  ## Usage with Claude Desktop
19
62
 
@@ -24,7 +67,7 @@ MCP server for **Megaplan** project management. Provides tools for managing task
24
67
  "command": "npx",
25
68
  "args": ["-y", "@theyahia/megaplan-mcp"],
26
69
  "env": {
27
- "MEGAPLAN_DOMAIN": "yourcompany.megaplan.ru",
70
+ "MEGAPLAN_DOMAIN": "yourcompany",
28
71
  "MEGAPLAN_TOKEN": "your-access-token"
29
72
  }
30
73
  }
@@ -32,12 +75,93 @@ MCP server for **Megaplan** project management. Provides tools for managing task
32
75
  }
33
76
  ```
34
77
 
78
+ Or with login/password — replace `MEGAPLAN_TOKEN` with `MEGAPLAN_LOGIN` +
79
+ `MEGAPLAN_PASSWORD`.
80
+
81
+ ## Finding IDs
82
+
83
+ Several tools take IDs. Here's how to discover them via the server itself:
84
+
85
+ - **`responsible_id`, `filter_responsible_id`** → `get_employees` (each item has an `id`).
86
+ - **`filter_department_id`** → IDs appear on employees' `department` (or your Megaplan UI).
87
+ - **`program_id`** (required by `create_deal`) → `get_deal_programs`.
88
+ - **`contact_id`** (for `create_deal`) → `list_clients` with `type: "human"` or `"company"`; pass the matching `contact_type`.
89
+ - **status codes** (`filter_status`) are account-specific enum codes (e.g. `filter_any`), not display names. Find them in your Megaplan UI / account API schema.
90
+
91
+ ## Streamable HTTP transport
92
+
93
+ For remote/cloud deployments, run with `--http`. **Auth is mandatory** — the
94
+ server holds your Megaplan credentials, so it refuses to start without
95
+ `MCP_HTTP_TOKEN` and binds to loopback by default.
96
+
97
+ ```bash
98
+ MEGAPLAN_DOMAIN=yourcompany \
99
+ MEGAPLAN_TOKEN=xxx \
100
+ MCP_HTTP_TOKEN=$(openssl rand -hex 32) \
101
+ npx @theyahia/megaplan-mcp --http
102
+ # → http://127.0.0.1:3000/mcp (send: Authorization: Bearer $MCP_HTTP_TOKEN)
103
+ # Health: http://127.0.0.1:3000/health
104
+ ```
105
+
106
+ To expose beyond loopback, set `HOST=0.0.0.0` **and** add the public host:port to
107
+ `MCP_HTTP_ALLOWED_HOSTS` (DNS-rebinding protection is on). Only do this behind
108
+ your own network controls.
109
+
35
110
  ## Environment Variables
36
111
 
37
112
  | Variable | Required | Description |
38
113
  |----------|----------|-------------|
39
- | `MEGAPLAN_DOMAIN` | Yes | Your Megaplan domain (e.g. `yourcompany.megaplan.ru`) |
40
- | `MEGAPLAN_TOKEN` | Yes | Bearer access token |
114
+ | `MEGAPLAN_DOMAIN` | Yes | Account host (`yourcompany` `yourcompany.megaplan.ru`, or a full host) |
115
+ | `MEGAPLAN_TOKEN` | One of | Bearer access token |
116
+ | `MEGAPLAN_LOGIN` | One of | Login email (if no token) |
117
+ | `MEGAPLAN_PASSWORD` | One of | Password (if no token) |
118
+ | `MEGAPLAN_DEBUG` | No | `1` to log full upstream error bodies |
119
+ | `PORT` | No | HTTP port for `--http` mode (default: 3000) |
120
+ | `MCP_HTTP_TOKEN` | `--http` | Bearer token required to call `/mcp` (server refuses to start without it) |
121
+ | `HOST` | No | Bind address for `--http` (default `127.0.0.1`) |
122
+ | `MCP_HTTP_ALLOWED_HOSTS` | No | Comma-separated allowed `Host` values (default loopback:port) |
123
+ | `MCP_HTTP_BODY_LIMIT` | No | Max request body size (default `1mb`) |
124
+ | `MCP_HTTP_MAX_SESSIONS` | No | Max concurrent sessions (default `100`) |
125
+ | `MCP_HTTP_SESSION_TTL_MS` | No | Idle session eviction TTL (default 30 min) |
126
+
127
+ ## Migrating from older versions
128
+
129
+ Applies to the previously published 8-tool builds (`1.x`–`3.0.0`):
130
+
131
+ - `get_*` list tools: `offset` → `page_after` (cursor); `filter_status` now takes
132
+ status **code(s)**, not names like `active`.
133
+ - Output is a compact summary by default — pass `raw: true` for the old raw JSON.
134
+ - `create_comment`: the text field is now `content` (was `text`).
135
+ - `--http`: set `MCP_HTTP_TOKEN`; the default bind is now `127.0.0.1`.
136
+
137
+ ## Verification status
138
+
139
+ Most behaviour is confirmed against the official v3 RAML and real v3 client
140
+ libraries. A few items are best-effort from docs and marked `TODO(live-verify)`
141
+ in the source (and `experimental` here), pending a test against a live account:
142
+ auth body encoding, the free-text search param name, the `get_current_user`
143
+ endpoint, and the task/deal status-change field shape. Errors are surfaced
144
+ clearly (set `MEGAPLAN_DEBUG=1` for full detail) so any mismatch is diagnosable.
145
+
146
+ ## Referral
147
+
148
+ Get **20-50% recurring** commission by referring Megaplan:
149
+
150
+ - [Megaplan Partner Program](https://megaplan.ru/partners/)
151
+ - Sign up as a partner, get your referral link.
152
+ - Every client you bring = recurring revenue share.
153
+
154
+ ## Development
155
+
156
+ ```bash
157
+ npm install
158
+ npm run build # tsc -> dist/
159
+ npm run typecheck # tsc --noEmit (src + tests)
160
+ npm run lint # eslint
161
+ npm test # vitest
162
+ npm run dev # stdio mode with tsx
163
+ npm run start:http # HTTP mode (needs MCP_HTTP_TOKEN)
164
+ ```
41
165
 
42
166
  ## License
43
167
 
package/dist/client.d.ts CHANGED
@@ -1,2 +1,4 @@
1
- export declare function megaplanGet(path: string, params?: Record<string, string>): Promise<unknown>;
1
+ /** Test helper: reset cached auth state between cases. */
2
+ export declare function __resetAuth(): void;
3
+ export declare function megaplanGet(path: string, params?: Record<string, unknown>): Promise<unknown>;
2
4
  export declare function megaplanPost(path: string, body: unknown): Promise<unknown>;
package/dist/client.js CHANGED
@@ -1,20 +1,109 @@
1
1
  const TIMEOUT = 15_000;
2
2
  const MAX_RETRIES = 3;
3
- function getBaseUrl() {
4
- const domain = process.env.MEGAPLAN_DOMAIN;
5
- if (!domain)
3
+ // Show full upstream response bodies in logs/errors only when explicitly enabled.
4
+ // Deliberately scoped to MEGAPLAN_DEBUG so a generic DEBUG=* doesn't log bodies.
5
+ const DEBUG = Boolean(process.env.MEGAPLAN_DEBUG);
6
+ let cachedToken = null;
7
+ // Single in-flight auth, shared by concurrent callers (avoids a thundering herd
8
+ // of password grants on cold start / after a 401 invalidation).
9
+ let authPromise = null;
10
+ /** Test helper: reset cached auth state between cases. */
11
+ export function __resetAuth() {
12
+ cachedToken = null;
13
+ authPromise = null;
14
+ }
15
+ function isStaticToken() {
16
+ return Boolean(process.env.MEGAPLAN_TOKEN);
17
+ }
18
+ function getDomain() {
19
+ const raw = process.env.MEGAPLAN_DOMAIN;
20
+ if (!raw)
6
21
  throw new Error("MEGAPLAN_DOMAIN is not set");
7
- const clean = domain.replace(/^https?:\/\//, "").replace(/\/$/, "");
8
- return `https://${clean}/api/v3`;
22
+ let domain = raw.replace(/^https?:\/\//i, "").replace(/\/+$/, "").trim();
23
+ // Config-time SSRF guard: a bare host[:port] only — no path, credentials, or spaces.
24
+ if (!/^[a-zA-Z0-9.\-]+(:[0-9]+)?$/.test(domain)) {
25
+ throw new Error(`MEGAPLAN_DOMAIN is invalid: "${raw}". Provide a bare host like "yourcompany" or "yourcompany.megaplan.ru".`);
26
+ }
27
+ // A bare subdomain ("yourcompany") is expanded to "yourcompany.megaplan.ru".
28
+ if (!domain.includes("."))
29
+ domain = `${domain}.megaplan.ru`;
30
+ return domain;
31
+ }
32
+ function getBaseUrl() {
33
+ return `https://${getDomain()}/api/v3`;
9
34
  }
10
- function getToken() {
11
- const token = process.env.MEGAPLAN_TOKEN;
35
+ async function authenticate() {
36
+ const login = process.env.MEGAPLAN_LOGIN;
37
+ const password = process.env.MEGAPLAN_PASSWORD;
38
+ if (!login || !password) {
39
+ throw new Error("Either MEGAPLAN_TOKEN or (MEGAPLAN_LOGIN + MEGAPLAN_PASSWORD) must be set");
40
+ }
41
+ // The v3 access_token endpoint expects form fields, not a JSON body. We send
42
+ // application/x-www-form-urlencoded (the OAuth2 password-grant standard).
43
+ // TODO(live-verify): if an account rejects urlencoded, switch to multipart
44
+ // FormData (the form the official curl example shows) or JSON.
45
+ const body = new URLSearchParams({
46
+ username: login,
47
+ password,
48
+ grant_type: "password",
49
+ });
50
+ const controller = new AbortController();
51
+ const timer = setTimeout(() => controller.abort(), TIMEOUT);
52
+ let response;
53
+ try {
54
+ response = await fetch(`https://${getDomain()}/api/v3/auth/access_token`, {
55
+ method: "POST",
56
+ headers: { Accept: "application/json" },
57
+ body,
58
+ signal: controller.signal,
59
+ });
60
+ }
61
+ catch (error) {
62
+ if (error instanceof DOMException && error.name === "AbortError") {
63
+ throw new Error("Megaplan auth timed out");
64
+ }
65
+ throw error;
66
+ }
67
+ finally {
68
+ clearTimeout(timer);
69
+ }
70
+ if (!response.ok) {
71
+ const text = await safeText(response);
72
+ throw new Error(`Megaplan auth failed (${response.status})${errorDetail(text)}`);
73
+ }
74
+ const data = (await response.json());
75
+ const token = data.access_token ?? data.data?.access_token;
12
76
  if (!token)
13
- throw new Error("MEGAPLAN_TOKEN is not set");
77
+ throw new Error("Megaplan auth: no access_token in response");
14
78
  return token;
15
79
  }
80
+ async function getToken() {
81
+ const envToken = process.env.MEGAPLAN_TOKEN;
82
+ if (envToken)
83
+ return envToken;
84
+ if (cachedToken)
85
+ return cachedToken;
86
+ if (authPromise)
87
+ return authPromise;
88
+ authPromise = authenticate()
89
+ .then((token) => {
90
+ cachedToken = token;
91
+ return token;
92
+ })
93
+ .finally(() => {
94
+ authPromise = null;
95
+ });
96
+ return authPromise;
97
+ }
16
98
  export async function megaplanGet(path, params) {
17
- const query = params ? `?${new URLSearchParams(params).toString()}` : "";
99
+ // v3 collection endpoints take a single JSON object (limit, filter, pageAfter,
100
+ // …) URL-encoded into the query string — not flat query params.
101
+ // TODO(live-verify): some accounts accept the raw `?{json}` form; percent-
102
+ // encoding is the safe default.
103
+ let query = "";
104
+ if (params && Object.keys(params).length > 0) {
105
+ query = `?${encodeURIComponent(JSON.stringify(params))}`;
106
+ }
18
107
  return megaplanRequest("GET", `${path}${query}`);
19
108
  }
20
109
  export async function megaplanPost(path, body) {
@@ -22,40 +111,135 @@ export async function megaplanPost(path, body) {
22
111
  }
23
112
  async function megaplanRequest(method, path, body) {
24
113
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
114
+ const token = await getToken();
25
115
  const controller = new AbortController();
26
116
  const timer = setTimeout(() => controller.abort(), TIMEOUT);
117
+ let response;
27
118
  try {
28
- const response = await fetch(`${getBaseUrl()}${path}`, {
119
+ response = await fetch(`${getBaseUrl()}${path}`, {
29
120
  method,
30
121
  headers: {
31
- "Authorization": `Bearer ${getToken()}`,
122
+ Authorization: `Bearer ${token}`,
32
123
  "Content-Type": "application/json",
33
- "Accept": "application/json",
124
+ Accept: "application/json",
34
125
  },
35
- body: body ? JSON.stringify(body) : undefined,
126
+ body: body !== undefined ? JSON.stringify(body) : undefined,
36
127
  signal: controller.signal,
37
128
  });
129
+ }
130
+ catch (error) {
38
131
  clearTimeout(timer);
39
- if (response.ok)
40
- return response.json();
41
- if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {
42
- const delay = Math.min(1000 * 2 ** (attempt - 1), 8000);
43
- console.error(`[megaplan-mcp] ${response.status}, retry in ${delay}ms (${attempt}/${MAX_RETRIES})`);
44
- await new Promise(r => setTimeout(r, delay));
132
+ if (isRetriableNetworkError(error) && attempt < MAX_RETRIES) {
133
+ if (DEBUG)
134
+ console.error(`[megaplan-mcp] network error, retry (${attempt}/${MAX_RETRIES})`);
135
+ await sleep(backoff(attempt));
45
136
  continue;
46
137
  }
47
- const text = await response.text();
48
- throw new Error(`Megaplan HTTP ${response.status}: ${text}`);
138
+ throw normalizeNetworkError(error);
49
139
  }
50
- catch (error) {
51
- clearTimeout(timer);
52
- if (error instanceof DOMException && error.name === "AbortError" && attempt < MAX_RETRIES) {
53
- console.error(`[megaplan-mcp] Timeout, retry (${attempt}/${MAX_RETRIES})`);
140
+ clearTimeout(timer);
141
+ if (response.status === 401) {
142
+ if (isStaticToken()) {
143
+ throw new Error("Megaplan HTTP 401: access token rejected (check MEGAPLAN_TOKEN).");
144
+ }
145
+ // login/password mode: invalidate only the token we actually used, then retry.
146
+ // We deliberately do NOT null authPromise here: leaving it intact lets
147
+ // concurrent 401s (e.g. a token expiring under load) share getToken's single
148
+ // in-flight re-auth instead of each kicking off its own auth request. The
149
+ // `=== token` guard avoids wiping a fresh token a peer already obtained.
150
+ if (cachedToken === token) {
151
+ cachedToken = null;
152
+ }
153
+ if (attempt < MAX_RETRIES) {
154
+ if (DEBUG)
155
+ console.error(`[megaplan-mcp] 401, re-authenticating (${attempt}/${MAX_RETRIES})`);
54
156
  continue;
55
157
  }
56
- throw error;
158
+ const text = await safeText(response);
159
+ throw new Error(`Megaplan HTTP 401${errorDetail(text)}`);
57
160
  }
161
+ if (response.ok)
162
+ return parseBody(response);
163
+ if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {
164
+ const delay = retryAfterDelay(response, attempt);
165
+ if (DEBUG) {
166
+ console.error(`[megaplan-mcp] ${response.status}, retry in ${delay}ms (${attempt}/${MAX_RETRIES})`);
167
+ }
168
+ await sleep(delay);
169
+ continue;
170
+ }
171
+ const text = await safeText(response);
172
+ throw new Error(`Megaplan HTTP ${response.status}${errorDetail(text)}`);
58
173
  }
59
174
  throw new Error("Megaplan: all retries exhausted");
60
175
  }
176
+ // ── helpers ──
177
+ function sleep(ms) {
178
+ return new Promise((r) => setTimeout(r, ms));
179
+ }
180
+ function backoff(attempt) {
181
+ return Math.min(1000 * 2 ** (attempt - 1), 8000);
182
+ }
183
+ function retryAfterDelay(response, attempt) {
184
+ const header = response.headers.get("retry-after");
185
+ if (header) {
186
+ const seconds = Number(header);
187
+ if (Number.isFinite(seconds))
188
+ return clampDelay(seconds * 1000);
189
+ const date = Date.parse(header);
190
+ if (!Number.isNaN(date))
191
+ return clampDelay(date - Date.now());
192
+ }
193
+ return backoff(attempt);
194
+ }
195
+ function clampDelay(ms) {
196
+ return Math.min(Math.max(ms, 0), 60_000);
197
+ }
198
+ function isRetriableNetworkError(error) {
199
+ // AbortError = our timeout fired; TypeError = undici "fetch failed"
200
+ // (ECONNRESET/ENOTFOUND/ECONNREFUSED/TLS hiccups).
201
+ if (error instanceof DOMException && error.name === "AbortError")
202
+ return true;
203
+ if (error instanceof TypeError)
204
+ return true;
205
+ return false;
206
+ }
207
+ function normalizeNetworkError(error) {
208
+ if (error instanceof DOMException && error.name === "AbortError") {
209
+ return new Error("Megaplan request timed out");
210
+ }
211
+ if (error instanceof Error)
212
+ return error;
213
+ return new Error(String(error));
214
+ }
215
+ async function parseBody(response) {
216
+ if (response.status === 204)
217
+ return null;
218
+ const text = await response.text();
219
+ if (!text)
220
+ return null;
221
+ try {
222
+ return JSON.parse(text);
223
+ }
224
+ catch {
225
+ throw new Error(`Megaplan: expected JSON but got a non-JSON response (${response.status})${errorDetail(text)}`);
226
+ }
227
+ }
228
+ async function safeText(response) {
229
+ try {
230
+ return await response.text();
231
+ }
232
+ catch {
233
+ return "";
234
+ }
235
+ }
236
+ /** A short, sanitized snippet of an upstream error body for the thrown message. */
237
+ function errorDetail(text) {
238
+ if (!text)
239
+ return "";
240
+ if (DEBUG)
241
+ return `: ${text}`;
242
+ const snippet = text.replace(/\s+/g, " ").trim().slice(0, 200);
243
+ return snippet ? `: ${snippet}` : "";
244
+ }
61
245
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { MegaplanTask, MegaplanDeal, MegaplanProject, MegaplanEmployee, MegaplanComment, MegaplanProgram, MegaplanClient } from "./types.js";
2
+ export declare function formatTask(e: unknown): MegaplanTask;
3
+ export declare function formatDeal(e: unknown): MegaplanDeal;
4
+ export declare function formatProject(e: unknown): MegaplanProject;
5
+ export declare function formatEmployee(e: unknown): MegaplanEmployee;
6
+ export declare function formatComment(e: unknown): MegaplanComment;
7
+ export declare function formatProgram(e: unknown): MegaplanProgram;
8
+ export declare function formatClient(e: unknown): MegaplanClient;
9
+ /** Unwrap a v3 `{meta, data}` list envelope into a compact summary string. */
10
+ export declare function formatList<T>(result: unknown, formatter: (e: unknown) => T, raw?: boolean): string;
11
+ /** Unwrap a v3 `{data: {...}}` single-entity envelope and format it. */
12
+ export declare function formatEntity<T>(result: unknown, formatter: (e: unknown) => T, raw?: boolean): string;