apimail-mcp 1.0.0 → 1.2.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 (3) hide show
  1. package/README.md +3 -0
  2. package/package.json +1 -1
  3. package/server.js +112 -6
package/README.md CHANGED
@@ -46,6 +46,9 @@ Bump `version` in `package.json` for each release (`npm version patch`).
46
46
  - `apimail_domain_availability`
47
47
  - `apimail_purchase_accounts`
48
48
  - `apimail_purchased_emails`
49
+ - `apimail_email_risk` — check an email address risk/reputation (0–100 score); $0.005 per check
50
+ - `apimail_user_auth_submit` — submit your own Microsoft account (email + password; optional cookies, client proxy, backup_email) for OAuth authorization; returns `task_id`; token costs $0.0015 minus loyalty discount, charged at delivery
51
+ - `apimail_user_auth_status` — poll a user-auth job by `task_id` until terminal (`success` → refresh_token + client_id; `email_linked` → backup email bound, no token, free, retry later; `failed`/`timeout` → reason in `error`/`error_message`)
49
52
 
50
53
  ## Security
51
54
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apimail-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for ApiMail API (stdio, Model Context Protocol)",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -57,6 +57,50 @@ const TOOL_DEFS = [
57
57
  required: ["payment_id"],
58
58
  additionalProperties: false
59
59
  }
60
+ },
61
+ {
62
+ name: "apimail_email_risk",
63
+ description: "Check the risk and reputation of an email address. Returns a transparent 0-100 risk score and signals: disposable/temporary mail, free provider, suspicious TLD, role account, MX/domain resolution, SPF/DMARC (spoofability), domain age and Gravatar. Costs $0.005 per check from the account balance.",
64
+ inputSchema: {
65
+ type: "object",
66
+ properties: {
67
+ email: { type: "string", description: "Email address to check." },
68
+ token: { type: "string", description: "Optional API token override." },
69
+ smtp: { type: "boolean", description: "Also run an SMTP deliverability probe (optional, slower)." }
70
+ },
71
+ required: ["email"],
72
+ additionalProperties: false
73
+ }
74
+ },
75
+ {
76
+ name: "apimail_user_auth_submit",
77
+ description: "Submit YOUR OWN Microsoft account (email + password, optional MSA cookies, client proxy and desired backup email) for OAuth authorization. Returns a task_id; poll apimail_user_auth_status until a terminal status (job lives up to 3 minutes). On success returns a Graph-verified refresh_token + client_id ($0.0015 minus loyalty discount, charged at delivery). Backup-email binding is free. Limits: 50 concurrent jobs per key, 200 global.",
78
+ inputSchema: {
79
+ type: "object",
80
+ properties: {
81
+ email: { type: "string", description: "Microsoft account email (Outlook/Hotmail)." },
82
+ password: { type: "string", description: "Microsoft account password." },
83
+ cookies: { type: "string", description: "Optional MSA session cookies string 'name=value, name2=value2' — cookie-first login with password fallback." },
84
+ proxy: { type: "string", description: "Optional client proxy 'scheme://[user:pass@]host:port' (http/https/socks4/socks5/socks5h). Used instead of the service pool; its failures are reported as CLIENT_PROXY_ERROR." },
85
+ backup_email: { type: "string", description: "Optional backup (recovery) email to bind if Microsoft demands one; verification codes are readable only for temp-mail.io-style inboxes." },
86
+ token: { type: "string", description: "Optional API token override." }
87
+ },
88
+ required: ["email", "password"],
89
+ additionalProperties: false
90
+ }
91
+ },
92
+ {
93
+ name: "apimail_user_auth_status",
94
+ description: "Poll a user-auth job by task_id. task_status: pending/processing (keep polling; bound backup email appears early), success (token + client_id, charged once at first delivery), email_linked (terminal, NOT a failure: backup email bound but no token — free; save the account and re-submit later to retry), failed/timeout (reason in error + error_message). Poll every few seconds, up to ~3 minutes.",
95
+ inputSchema: {
96
+ type: "object",
97
+ properties: {
98
+ task_id: { type: "string", description: "32-hex task id returned by apimail_user_auth_submit." },
99
+ token: { type: "string", description: "Optional API token override." }
100
+ },
101
+ required: ["task_id"],
102
+ additionalProperties: false
103
+ }
60
104
  }
61
105
  ];
62
106
 
@@ -85,16 +129,30 @@ function toQuery(params) {
85
129
  return query.toString();
86
130
  }
87
131
 
88
- async function callApi(endpoint, params) {
89
- const query = toQuery(params);
90
- const url = `${API_BASE_URL}/${endpoint}${query ? `?${query}` : ""}`;
132
+ async function callApi(endpoint, params, options = {}) {
133
+ const method = options.method || "GET";
134
+ let url;
135
+ const fetchOptions = {
136
+ method,
137
+ headers: { Accept: "application/json" }
138
+ };
139
+ if (method === "POST") {
140
+ // Тело — JSON; токен остаётся в query (API принимает и Bearer, и query).
141
+ url = `${API_BASE_URL}/${endpoint}`;
142
+ fetchOptions.headers["Content-Type"] = "application/json";
143
+ fetchOptions.body = JSON.stringify(options.body || {});
144
+ const query = toQuery(params);
145
+ if (query) url += `?${query}`;
146
+ } else {
147
+ const query = toQuery(params);
148
+ url = `${API_BASE_URL}/${endpoint}${query ? `?${query}` : ""}`;
149
+ }
91
150
  const controller = new AbortController();
92
151
  const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
93
152
 
94
153
  try {
95
154
  const response = await fetch(url, {
96
- method: "GET",
97
- headers: { Accept: "application/json" },
155
+ ...fetchOptions,
98
156
  signal: controller.signal
99
157
  });
100
158
  const text = await response.text();
@@ -161,11 +219,59 @@ async function handleTool(name, args) {
161
219
  return asText(JSON.stringify(result, null, 2));
162
220
  }
163
221
 
222
+ if (name === "apimail_email_risk") {
223
+ const token = getTokenFromArgs(args || {});
224
+ const email = args && typeof args.email === "string" ? args.email.trim() : "";
225
+ if (!email) {
226
+ throw new Error("email is required.");
227
+ }
228
+ const params = { token, email };
229
+ if (args && args.smtp === true) {
230
+ params.smtp = 1;
231
+ }
232
+ const result = await callApi("emailRisk", params);
233
+ return asText(JSON.stringify(result, null, 2));
234
+ }
235
+
236
+ if (name === "apimail_user_auth_submit") {
237
+ const token = getTokenFromArgs(args || {});
238
+ const email = args && typeof args.email === "string" ? args.email.trim() : "";
239
+ const password = args && typeof args.password === "string" ? args.password : "";
240
+ if (!email) {
241
+ throw new Error("email is required.");
242
+ }
243
+ if (!password) {
244
+ throw new Error("password is required.");
245
+ }
246
+ const body = { email, password };
247
+ if (args && typeof args.cookies === "string" && args.cookies.trim()) {
248
+ body.cookies = args.cookies.trim();
249
+ }
250
+ if (args && typeof args.proxy === "string" && args.proxy.trim()) {
251
+ body.proxy = args.proxy.trim();
252
+ }
253
+ if (args && typeof args.backup_email === "string" && args.backup_email.trim()) {
254
+ body.backup_email = args.backup_email.trim();
255
+ }
256
+ const result = await callApi("userAuthSubmit", { token }, { method: "POST", body });
257
+ return asText(JSON.stringify(result, null, 2));
258
+ }
259
+
260
+ if (name === "apimail_user_auth_status") {
261
+ const token = getTokenFromArgs(args || {});
262
+ const taskId = args && typeof args.task_id === "string" ? args.task_id.trim() : "";
263
+ if (!/^[0-9a-f]{32}$/.test(taskId)) {
264
+ throw new Error("task_id must be a 32-character hex string.");
265
+ }
266
+ const result = await callApi("userAuthStatus", { token, task_id: taskId });
267
+ return asText(JSON.stringify(result, null, 2));
268
+ }
269
+
164
270
  throw new Error(`Unknown tool: ${name}`);
165
271
  }
166
272
 
167
273
  const server = new Server(
168
- { name: "apimail-mcp", version: "1.1.0" },
274
+ { name: "apimail-mcp", version: "1.2.0" },
169
275
  { capabilities: { tools: { listChanged: false } } }
170
276
  );
171
277