@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.
- package/LICENSE +21 -21
- package/README.md +134 -10
- package/dist/client.d.ts +3 -1
- package/dist/client.js +210 -26
- package/dist/client.js.map +1 -1
- package/dist/format.d.ts +12 -0
- package/dist/format.js +148 -0
- package/dist/format.js.map +1 -0
- package/dist/http.d.ts +3 -0
- package/dist/http.js +152 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +94 -16
- package/dist/index.js.map +1 -1
- package/dist/meta.d.ts +2 -0
- package/dist/meta.js +5 -0
- package/dist/meta.js.map +1 -0
- package/dist/prompts.d.ts +7 -0
- package/dist/prompts.js +22 -0
- package/dist/prompts.js.map +1 -0
- package/dist/query.d.ts +32 -0
- package/dist/query.js +61 -0
- package/dist/query.js.map +1 -0
- package/dist/tools/comments.d.ts +35 -0
- package/dist/tools/comments.js +31 -0
- package/dist/tools/comments.js.map +1 -0
- package/dist/tools/contractors.d.ts +35 -0
- package/dist/tools/contractors.js +39 -0
- package/dist/tools/contractors.js.map +1 -0
- package/dist/tools/deals.d.ts +76 -7
- package/dist/tools/deals.js +89 -16
- package/dist/tools/deals.js.map +1 -1
- package/dist/tools/employees.d.ts +21 -0
- package/dist/tools/employees.js +25 -0
- package/dist/tools/employees.js.map +1 -0
- package/dist/tools/me.d.ts +9 -0
- package/dist/tools/me.js +26 -0
- package/dist/tools/me.js.map +1 -0
- package/dist/tools/programs.d.ts +26 -0
- package/dist/tools/programs.js +25 -0
- package/dist/tools/programs.js.map +1 -0
- package/dist/tools/projects.d.ts +32 -0
- package/dist/tools/projects.js +34 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/tasks.d.ts +49 -9
- package/dist/tools/tasks.js +62 -20
- package/dist/tools/tasks.js.map +1 -1
- package/dist/types.d.ts +54 -32
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- 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.
|
|
3
|
+
MCP server for **Megaplan** project management. Tasks, deals, projects,
|
|
4
|
+
employees, clients, and comments via Megaplan API v3.
|
|
4
5
|
|
|
5
|
-
|
|
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
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
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
|
-
|
|
16
|
-
|
|
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
|
|
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 |
|
|
40
|
-
| `MEGAPLAN_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
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
8
|
-
|
|
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
|
|
11
|
-
const
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
119
|
+
response = await fetch(`${getBaseUrl()}${path}`, {
|
|
29
120
|
method,
|
|
30
121
|
headers: {
|
|
31
|
-
|
|
122
|
+
Authorization: `Bearer ${token}`,
|
|
32
123
|
"Content-Type": "application/json",
|
|
33
|
-
|
|
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 (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
48
|
-
throw new Error(`Megaplan HTTP ${response.status}: ${text}`);
|
|
138
|
+
throw normalizeNetworkError(error);
|
|
49
139
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
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
|
-
|
|
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
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,MAAM,CAAC;AACvB,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/format.d.ts
ADDED
|
@@ -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;
|