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.
- package/README.md +3 -0
- package/package.json +1 -1
- 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
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
|
|
90
|
-
|
|
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
|
-
|
|
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.
|
|
274
|
+
{ name: "apimail-mcp", version: "1.2.0" },
|
|
169
275
|
{ capabilities: { tools: { listChanged: false } } }
|
|
170
276
|
);
|
|
171
277
|
|