@rocketverifier/mcp 1.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/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # @rocketverifier/mcp
2
+
3
+ Official [Model Context Protocol](https://modelcontextprotocol.io) server for [RocketVerifier](https://rocketverifier.com). Verify emails, run bulk verification jobs, and check deliverability signals directly from Claude, ChatGPT, Cursor, or any MCP-compatible AI assistant — no code required.
4
+
5
+ ## Tools
6
+
7
+ | Tool | Credits | Description |
8
+ |---|---|---|
9
+ | `verify_email` | 1 | Real-time single email verification |
10
+ | `create_bulk_job` | 1 per email | Submit up to 100,000 emails for bulk verification |
11
+ | `get_job_status` | free | Check progress/summary counts of a bulk job |
12
+ | `get_job_results` | free | Fetch paginated per-email results |
13
+ | `list_jobs` | free | List recent bulk jobs |
14
+ | `cancel_job` | free | Cancel a pending/processing job and refund credits |
15
+ | `check_credits` | free | Check credit balance and usage |
16
+ | `check_disposable` | free | Check if an email/domain is disposable |
17
+ | `mx_lookup` | free | Look up MX records for a domain |
18
+ | `check_domain_auth` | free | Score SPF/DMARC/DKIM and get fix recommendations |
19
+
20
+ ## Get an API key
21
+
22
+ Sign up at [app.rocketverifier.com](https://app.rocketverifier.com) and grab a key from **Dashboard → API Keys**. For testing without consuming credits, use a sandbox key (`rv_test_...`) with `@sandbox.rocketverifier.com` addresses (e.g. `deliverable@sandbox.rocketverifier.com`).
23
+
24
+ ## Claude Desktop
25
+
26
+ Add to your `claude_desktop_config.json`:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "rocketverifier": {
32
+ "command": "npx",
33
+ "args": ["-y", "@rocketverifier/mcp"],
34
+ "env": {
35
+ "ROCKETVERIFIER_API_KEY": "rv_live_your_api_key"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## Cursor
43
+
44
+ Add to `.cursor/mcp.json` (project) or your global MCP settings:
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "rocketverifier": {
50
+ "command": "npx",
51
+ "args": ["-y", "@rocketverifier/mcp"],
52
+ "env": {
53
+ "ROCKETVERIFIER_API_KEY": "rv_live_your_api_key"
54
+ }
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ ## ChatGPT / other remote-MCP clients
61
+
62
+ If your client supports remote (Streamable HTTP) MCP servers, you can skip the npm install entirely and connect straight to RocketVerifier's hosted endpoint:
63
+
64
+ ```
65
+ URL: https://api.rocketverifier.com/mcp
66
+ Auth: Bearer rv_live_your_api_key
67
+ ```
68
+
69
+ ## Run manually
70
+
71
+ ```bash
72
+ ROCKETVERIFIER_API_KEY=rv_live_your_api_key npx @rocketverifier/mcp
73
+ ```
74
+
75
+ ## Example prompts
76
+
77
+ - "Verify whether jane@acme.com is deliverable."
78
+ - "Check if mailinator.com is a disposable email provider."
79
+ - "Run a domain authentication check on rocketverifier.com and tell me what DNS records I'm missing."
80
+ - "Verify this list of 200 emails in bulk and summarize how many are risky."
81
+ - "How many RocketVerifier credits do I have left?"
82
+
83
+ ## Configuration
84
+
85
+ | Environment variable | Required | Description |
86
+ |---|---|---|
87
+ | `ROCKETVERIFIER_API_KEY` | Yes | Your RocketVerifier API key (`rv_live_...` or `rv_test_...`) |
88
+ | `ROCKETVERIFIER_BASE_URL` | No | Override the API base URL (default `https://api.rocketverifier.com`) |
89
+
90
+ ## Development
91
+
92
+ ```bash
93
+ npm install
94
+ npm run build
95
+ npm run dev # watch mode
96
+ ```
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+
4
+ interface CreateServerOptions {
5
+ apiKey: string;
6
+ baseUrl?: string;
7
+ }
8
+ declare function createServer(options: CreateServerOptions): McpServer;
9
+
10
+ export { createServer };
package/dist/index.js ADDED
@@ -0,0 +1,353 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+
6
+ // src/server.ts
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import { z } from "zod";
9
+
10
+ // src/client.ts
11
+ var RocketVerifierApiError = class extends Error {
12
+ constructor(message, code, statusCode, details) {
13
+ super(message);
14
+ this.code = code;
15
+ this.statusCode = statusCode;
16
+ this.details = details;
17
+ this.name = "RocketVerifierApiError";
18
+ }
19
+ code;
20
+ statusCode;
21
+ details;
22
+ };
23
+ var RocketVerifierClient = class {
24
+ apiKey;
25
+ baseUrl;
26
+ timeoutMs;
27
+ constructor(options) {
28
+ if (!options.apiKey) {
29
+ throw new Error(
30
+ "A RocketVerifier API key is required. Set the ROCKETVERIFIER_API_KEY environment variable."
31
+ );
32
+ }
33
+ this.apiKey = options.apiKey;
34
+ this.baseUrl = (options.baseUrl || "https://api.rocketverifier.com").replace(/\/$/, "");
35
+ this.timeoutMs = options.timeoutMs ?? 3e4;
36
+ }
37
+ async request(method, path, query, body) {
38
+ const url = new URL(`${this.baseUrl}${path}`);
39
+ if (query) {
40
+ for (const [key, value] of Object.entries(query)) {
41
+ if (value !== void 0 && value !== "") {
42
+ url.searchParams.set(key, value);
43
+ }
44
+ }
45
+ }
46
+ const controller = new AbortController();
47
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
48
+ try {
49
+ const response = await fetch(url.toString(), {
50
+ method,
51
+ headers: {
52
+ Authorization: `Bearer ${this.apiKey}`,
53
+ "Content-Type": "application/json",
54
+ "User-Agent": "@rocketverifier/mcp/1.0.0"
55
+ },
56
+ body: body ? JSON.stringify(body) : void 0,
57
+ signal: controller.signal
58
+ });
59
+ const data = await response.json().catch(() => ({}));
60
+ if (!response.ok) {
61
+ const error = data.error || {};
62
+ throw new RocketVerifierApiError(
63
+ error.message || `HTTP ${response.status}`,
64
+ error.code || "unknown_error",
65
+ response.status,
66
+ error.details
67
+ );
68
+ }
69
+ return data;
70
+ } catch (err) {
71
+ if (err instanceof RocketVerifierApiError) throw err;
72
+ if (err instanceof Error && err.name === "AbortError") {
73
+ throw new RocketVerifierApiError("Request timed out", "timeout", 408);
74
+ }
75
+ throw new RocketVerifierApiError(
76
+ err instanceof Error ? err.message : "Network error",
77
+ "network_error",
78
+ 0
79
+ );
80
+ } finally {
81
+ clearTimeout(timeout);
82
+ }
83
+ }
84
+ verifyEmail(email) {
85
+ return this.request("POST", "/v1/verify", void 0, { email });
86
+ }
87
+ createBulkJob(emails, name) {
88
+ return this.request("POST", "/v1/verify/bulk", void 0, { emails, name });
89
+ }
90
+ getJobStatus(jobId) {
91
+ return this.request("GET", `/v1/jobs/${encodeURIComponent(jobId)}`);
92
+ }
93
+ getJobResults(jobId, page = 1, limit = 100, classification) {
94
+ return this.request("GET", `/v1/jobs/${encodeURIComponent(jobId)}/results`, {
95
+ page: String(page),
96
+ limit: String(limit),
97
+ classification
98
+ });
99
+ }
100
+ listJobs(page = 1, limit = 20, status) {
101
+ return this.request("GET", "/v1/jobs", { page: String(page), limit: String(limit), status });
102
+ }
103
+ cancelJob(jobId) {
104
+ return this.request("DELETE", `/v1/jobs/${encodeURIComponent(jobId)}`);
105
+ }
106
+ getCredits() {
107
+ return this.request("GET", "/v1/credits");
108
+ }
109
+ checkDisposable(emailOrDomain) {
110
+ const isEmail = emailOrDomain.includes("@");
111
+ return this.request("POST", "/v1/tools/disposable-check", void 0, {
112
+ email: isEmail ? emailOrDomain : void 0,
113
+ domain: isEmail ? void 0 : emailOrDomain
114
+ });
115
+ }
116
+ mxLookup(domain) {
117
+ return this.request("GET", "/v1/tools/mx-lookup", { domain });
118
+ }
119
+ checkDomainAuth(domain) {
120
+ return this.request("GET", "/v1/tools/domain-auth", { domain });
121
+ }
122
+ };
123
+
124
+ // src/server.ts
125
+ function textResult(data) {
126
+ return {
127
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
128
+ };
129
+ }
130
+ function errorResult(error) {
131
+ if (error instanceof RocketVerifierApiError) {
132
+ return {
133
+ isError: true,
134
+ content: [
135
+ {
136
+ type: "text",
137
+ text: `RocketVerifier API error (${error.code}, HTTP ${error.statusCode}): ${error.message}`
138
+ }
139
+ ]
140
+ };
141
+ }
142
+ return {
143
+ isError: true,
144
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }]
145
+ };
146
+ }
147
+ function createServer(options) {
148
+ const client = new RocketVerifierClient({ apiKey: options.apiKey, baseUrl: options.baseUrl });
149
+ const server = new McpServer({
150
+ name: "rocketverifier",
151
+ version: "1.0.0"
152
+ });
153
+ server.registerTool(
154
+ "verify_email",
155
+ {
156
+ title: "Verify Email",
157
+ description: "Verify whether a single email address is deliverable using RocketVerifier. Returns deliverability status (deliverable, undeliverable, risky, unknown), a confidence score, and details about the domain and mailbox. Costs 1 credit per call unless the email is an @sandbox.rocketverifier.com test address.",
158
+ inputSchema: {
159
+ email: z.string().describe("The email address to verify, e.g. user@example.com")
160
+ }
161
+ },
162
+ async ({ email }) => {
163
+ try {
164
+ return textResult(await client.verifyEmail(email));
165
+ } catch (error) {
166
+ return errorResult(error);
167
+ }
168
+ }
169
+ );
170
+ server.registerTool(
171
+ "create_bulk_job",
172
+ {
173
+ title: "Create Bulk Verification Job",
174
+ description: "Submit a list of email addresses (up to 100,000) for asynchronous bulk verification. Returns a job ID you can poll with get_job_status / get_job_results. Costs 1 credit per unique email.",
175
+ inputSchema: {
176
+ emails: z.array(z.string()).min(1).describe("List of email addresses to verify"),
177
+ name: z.string().optional().describe("Optional name to identify this job")
178
+ }
179
+ },
180
+ async ({ emails, name }) => {
181
+ try {
182
+ return textResult(await client.createBulkJob(emails, name));
183
+ } catch (error) {
184
+ return errorResult(error);
185
+ }
186
+ }
187
+ );
188
+ server.registerTool(
189
+ "get_job_status",
190
+ {
191
+ title: "Get Bulk Job Status",
192
+ description: "Check the progress and summary counts (valid/invalid/risky/unknown) of a bulk verification job.",
193
+ inputSchema: {
194
+ jobId: z.string().describe("The job ID returned by create_bulk_job")
195
+ }
196
+ },
197
+ async ({ jobId }) => {
198
+ try {
199
+ return textResult(await client.getJobStatus(jobId));
200
+ } catch (error) {
201
+ return errorResult(error);
202
+ }
203
+ }
204
+ );
205
+ server.registerTool(
206
+ "get_job_results",
207
+ {
208
+ title: "Get Bulk Job Results",
209
+ description: "Fetch paginated per-email results for a completed or in-progress bulk verification job.",
210
+ inputSchema: {
211
+ jobId: z.string().describe("The job ID to fetch results for"),
212
+ page: z.number().int().min(1).optional().describe("Page number, default 1"),
213
+ limit: z.number().int().min(1).max(1e3).optional().describe("Results per page, default 100"),
214
+ classification: z.enum(["valid", "invalid", "risky", "catch_all", "disposable", "unknown"]).optional().describe("Filter results to a single classification")
215
+ }
216
+ },
217
+ async ({ jobId, page, limit, classification }) => {
218
+ try {
219
+ return textResult(await client.getJobResults(jobId, page, limit, classification));
220
+ } catch (error) {
221
+ return errorResult(error);
222
+ }
223
+ }
224
+ );
225
+ server.registerTool(
226
+ "list_jobs",
227
+ {
228
+ title: "List Bulk Jobs",
229
+ description: "List your recent bulk verification jobs, optionally filtered by status.",
230
+ inputSchema: {
231
+ page: z.number().int().min(1).optional().describe("Page number, default 1"),
232
+ limit: z.number().int().min(1).max(100).optional().describe("Jobs per page, default 20"),
233
+ status: z.enum(["pending", "processing", "completed", "failed", "cancelled"]).optional().describe("Filter jobs by status")
234
+ }
235
+ },
236
+ async ({ page, limit, status }) => {
237
+ try {
238
+ return textResult(await client.listJobs(page, limit, status));
239
+ } catch (error) {
240
+ return errorResult(error);
241
+ }
242
+ }
243
+ );
244
+ server.registerTool(
245
+ "cancel_job",
246
+ {
247
+ title: "Cancel Bulk Job",
248
+ description: "Cancel a pending or in-progress bulk verification job and refund unused credits.",
249
+ inputSchema: {
250
+ jobId: z.string().describe("The job ID to cancel")
251
+ }
252
+ },
253
+ async ({ jobId }) => {
254
+ try {
255
+ return textResult(await client.cancelJob(jobId));
256
+ } catch (error) {
257
+ return errorResult(error);
258
+ }
259
+ }
260
+ );
261
+ server.registerTool(
262
+ "check_credits",
263
+ {
264
+ title: "Check Credit Balance",
265
+ description: "Get the current RocketVerifier credit balance and usage for today and this month.",
266
+ inputSchema: {}
267
+ },
268
+ async () => {
269
+ try {
270
+ return textResult(await client.getCredits());
271
+ } catch (error) {
272
+ return errorResult(error);
273
+ }
274
+ }
275
+ );
276
+ server.registerTool(
277
+ "check_disposable",
278
+ {
279
+ title: "Check Disposable Email",
280
+ description: "Free tool (no credits): check whether an email address or domain belongs to a known disposable/temporary email provider.",
281
+ inputSchema: {
282
+ emailOrDomain: z.string().describe('An email address or bare domain, e.g. "user@mailinator.com" or "mailinator.com"')
283
+ }
284
+ },
285
+ async ({ emailOrDomain }) => {
286
+ try {
287
+ return textResult(await client.checkDisposable(emailOrDomain));
288
+ } catch (error) {
289
+ return errorResult(error);
290
+ }
291
+ }
292
+ );
293
+ server.registerTool(
294
+ "mx_lookup",
295
+ {
296
+ title: "MX Lookup",
297
+ description: "Free tool (no credits): look up MX records for a domain to confirm it can receive email.",
298
+ inputSchema: {
299
+ domain: z.string().describe('Domain to look up, e.g. "example.com"')
300
+ }
301
+ },
302
+ async ({ domain }) => {
303
+ try {
304
+ return textResult(await client.mxLookup(domain));
305
+ } catch (error) {
306
+ return errorResult(error);
307
+ }
308
+ }
309
+ );
310
+ server.registerTool(
311
+ "check_domain_auth",
312
+ {
313
+ title: "Check Domain Email Authentication",
314
+ description: "Free tool (no credits): analyze SPF, DMARC, and common DKIM selectors for a domain. Returns a 0-100 deliverability authentication score and concrete DNS fix recommendations.",
315
+ inputSchema: {
316
+ domain: z.string().describe('Domain to analyze, e.g. "example.com"')
317
+ }
318
+ },
319
+ async ({ domain }) => {
320
+ try {
321
+ return textResult(await client.checkDomainAuth(domain));
322
+ } catch (error) {
323
+ return errorResult(error);
324
+ }
325
+ }
326
+ );
327
+ return server;
328
+ }
329
+
330
+ // src/index.ts
331
+ async function main() {
332
+ const apiKey = process.env.ROCKETVERIFIER_API_KEY;
333
+ if (!apiKey) {
334
+ console.error(
335
+ "Error: ROCKETVERIFIER_API_KEY environment variable is required.\nGet an API key at https://app.rocketverifier.com/dashboard/api-keys and set it, e.g.:\n ROCKETVERIFIER_API_KEY=rv_live_xxx npx @rocketverifier/mcp"
336
+ );
337
+ process.exit(1);
338
+ }
339
+ const server = createServer({
340
+ apiKey,
341
+ baseUrl: process.env.ROCKETVERIFIER_BASE_URL
342
+ });
343
+ const transport = new StdioServerTransport();
344
+ await server.connect(transport);
345
+ console.error("RocketVerifier MCP server running on stdio.");
346
+ }
347
+ main().catch((error) => {
348
+ console.error("Fatal error starting RocketVerifier MCP server:", error);
349
+ process.exit(1);
350
+ });
351
+ export {
352
+ createServer
353
+ };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@rocketverifier/mcp",
3
+ "version": "1.0.0",
4
+ "description": "Official RocketVerifier MCP server - verify emails from Claude, ChatGPT, Cursor, and any MCP-compatible AI assistant",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "rocketverifier-mcp": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup src/index.ts --format esm --dts --clean",
16
+ "dev": "tsup src/index.ts --format esm --dts --watch",
17
+ "start": "node dist/index.js",
18
+ "test": "vitest run",
19
+ "lint": "eslint src/",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "email",
26
+ "verification",
27
+ "email-verification",
28
+ "rocketverifier",
29
+ "ai",
30
+ "claude",
31
+ "chatgpt",
32
+ "cursor",
33
+ "llm-tools"
34
+ ],
35
+ "author": "RocketVerifier",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/rocketverifier/mcp-server.git"
40
+ },
41
+ "homepage": "https://docs.rocketverifier.com/mcp",
42
+ "bugs": {
43
+ "url": "https://github.com/rocketverifier/mcp-server/issues"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "dependencies": {
49
+ "@modelcontextprotocol/sdk": "^1.12.0",
50
+ "zod": "^3.23.8"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^20.0.0",
54
+ "tsup": "^8.0.0",
55
+ "typescript": "^5.0.0",
56
+ "vitest": "^1.0.0"
57
+ }
58
+ }