@useblip/email 0.1.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 ADDED
@@ -0,0 +1,17 @@
1
+ GNU AFFERO GENERAL PUBLIC LICENSE
2
+ Version 3, 19 November 2007
3
+
4
+ Copyright (C) 2026 bmcreations
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU Affero General Public License as published
8
+ by the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU Affero General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Affero General Public License
17
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # @useblip/email
2
+
3
+ MCP server for [Blip](https://useblip.email) disposable email. Create inboxes, receive emails, and extract OTP codes — all from your AI agent.
4
+
5
+ ## Setup
6
+
7
+ ### Claude Desktop
8
+
9
+ Add to your `claude_desktop_config.json`:
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "blip": {
15
+ "command": "npx",
16
+ "args": ["-y", "@useblip/email"],
17
+ "env": {
18
+ "BLIP_API_KEY": "blip_ak_..."
19
+ }
20
+ }
21
+ }
22
+ }
23
+ ```
24
+
25
+ ### Claude Code
26
+
27
+ ```bash
28
+ claude mcp add blip -- npx -y @useblip/email
29
+ ```
30
+
31
+ Set your API key:
32
+
33
+ ```bash
34
+ export BLIP_API_KEY=blip_ak_...
35
+ ```
36
+
37
+ ### Other MCP clients
38
+
39
+ Run the server directly:
40
+
41
+ ```bash
42
+ BLIP_API_KEY=blip_ak_... npx @useblip/email
43
+ ```
44
+
45
+ ## Getting an API key
46
+
47
+ 1. Sign in at [app.useblip.email](https://app.useblip.email)
48
+ 2. Subscribe to the **Agent** tier
49
+ 3. Create an API key from the dashboard
50
+
51
+ ## Tools
52
+
53
+ | Tool | Description |
54
+ |------|-------------|
55
+ | `create_inbox` | Create a disposable email inbox with optional custom slug, domain, and TTL |
56
+ | `list_inboxes` | List all active inboxes |
57
+ | `get_inbox` | Get inbox details and list of received emails |
58
+ | `read_email` | Read full email content (body, headers, attachments) |
59
+ | `extract_codes` | Extract OTP codes and verification links from the latest email |
60
+ | `wait_for_email` | Poll until an email arrives (configurable timeout, default 60s) |
61
+ | `delete_inbox` | Delete an inbox and all its emails |
62
+
63
+ ## Example prompts
64
+
65
+ - "Create a disposable email and sign up for example.com, then give me the verification code"
66
+ - "Make an inbox, wait for the password reset email, and extract the link"
67
+ - "List my active inboxes and show me the latest emails"
68
+
69
+ ## Environment variables
70
+
71
+ | Variable | Required | Default | Description |
72
+ |----------|----------|---------|-------------|
73
+ | `BLIP_API_KEY` | Yes | — | Your Blip API key |
74
+ | `BLIP_API_URL` | No | `https://api.useblip.email` | API base URL (for self-hosted) |
75
+
76
+ ## License
77
+
78
+ AGPL-3.0
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ const API_URL = process.env.BLIP_API_URL || "https://api.useblip.email";
6
+ const API_KEY = process.env.BLIP_API_KEY || "";
7
+ if (!API_KEY) {
8
+ console.error("BLIP_API_KEY is required. Create one at https://useblip.email/app");
9
+ process.exit(1);
10
+ }
11
+ async function blipFetch(path, options = {}) {
12
+ const url = `${API_URL}${path}`;
13
+ const res = await fetch(url, {
14
+ ...options,
15
+ headers: {
16
+ Authorization: `Bearer ${API_KEY}`,
17
+ "Content-Type": "application/json",
18
+ ...options.headers,
19
+ },
20
+ });
21
+ if (!res.ok) {
22
+ const body = await res.text();
23
+ throw new Error(`Blip API error ${res.status}: ${body}`);
24
+ }
25
+ if (res.status === 204)
26
+ return null;
27
+ return res.json();
28
+ }
29
+ const server = new McpServer({
30
+ name: "blip",
31
+ version: "0.1.0",
32
+ });
33
+ // --- Tools ---
34
+ server.tool("create_inbox", "Create a new disposable email inbox. Returns the inbox ID and email address.", {
35
+ slug: z
36
+ .string()
37
+ .optional()
38
+ .describe("Custom address slug (e.g. 'mytest' for mytest@useblip.email)"),
39
+ domain: z
40
+ .string()
41
+ .optional()
42
+ .describe("Email domain (defaults to useblip.email)"),
43
+ ttl_minutes: z
44
+ .number()
45
+ .optional()
46
+ .describe("How long the inbox should live, in minutes (AGENT tier only, max 90 days). Defaults to 60 minutes if omitted."),
47
+ }, async ({ slug, domain, ttl_minutes }) => {
48
+ const body = {};
49
+ if (slug)
50
+ body.slug = slug;
51
+ if (domain)
52
+ body.domain = domain;
53
+ if (ttl_minutes !== undefined)
54
+ body.windowMinutes = ttl_minutes;
55
+ const result = await blipFetch("/v1/inboxes", {
56
+ method: "POST",
57
+ body: JSON.stringify(body),
58
+ });
59
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
60
+ });
61
+ server.tool("list_inboxes", "List all active inboxes for the current API key.", {}, async () => {
62
+ const result = await blipFetch("/v1/inboxes");
63
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
64
+ });
65
+ server.tool("get_inbox", "Get inbox details and list of received emails.", {
66
+ inbox_id: z.string().describe("The inbox ID"),
67
+ }, async ({ inbox_id }) => {
68
+ const result = await blipFetch(`/v1/inboxes/${inbox_id}`);
69
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
70
+ });
71
+ server.tool("read_email", "Read the full content of a specific email including body, headers, and attachments.", {
72
+ email_id: z.string().describe("The email ID to read"),
73
+ }, async ({ email_id }) => {
74
+ const result = await blipFetch(`/v1/emails/${email_id}`);
75
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
76
+ });
77
+ server.tool("extract_codes", "Extract OTP codes and verification links from the most recent email in an inbox. Use this after creating an inbox and receiving a verification/signup email.", {
78
+ inbox_id: z
79
+ .string()
80
+ .describe("The inbox ID to extract codes from (uses most recent email)"),
81
+ }, async ({ inbox_id }) => {
82
+ const result = await blipFetch(`/v1/inboxes/${inbox_id}/extract`);
83
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
84
+ });
85
+ server.tool("wait_for_email", "Poll an inbox until an email arrives. Returns the email once received. Times out after the specified duration.", {
86
+ inbox_id: z.string().describe("The inbox ID to wait on"),
87
+ timeout_seconds: z
88
+ .number()
89
+ .optional()
90
+ .describe("Max seconds to wait (default: 60, max: 300)"),
91
+ }, async ({ inbox_id, timeout_seconds }) => {
92
+ const timeout = Math.min(timeout_seconds ?? 60, 300);
93
+ const deadline = Date.now() + timeout * 1000;
94
+ const interval = 2000;
95
+ while (Date.now() < deadline) {
96
+ const result = (await blipFetch(`/v1/inboxes/${inbox_id}`));
97
+ if (result?.emails && result.emails.length > 0) {
98
+ // Return the full detail of the most recent email
99
+ const email = await blipFetch(`/v1/emails/${result.emails[0].id}`);
100
+ return {
101
+ content: [{ type: "text", text: JSON.stringify(email, null, 2) }],
102
+ };
103
+ }
104
+ await new Promise((resolve) => setTimeout(resolve, interval));
105
+ }
106
+ return {
107
+ content: [
108
+ {
109
+ type: "text",
110
+ text: `No email received in inbox ${inbox_id} after ${timeout} seconds.`,
111
+ },
112
+ ],
113
+ };
114
+ });
115
+ server.tool("delete_inbox", "Delete an inbox and all its emails.", {
116
+ inbox_id: z.string().describe("The inbox ID to delete"),
117
+ }, async ({ inbox_id }) => {
118
+ await blipFetch(`/v1/inboxes/${inbox_id}`, { method: "DELETE" });
119
+ return {
120
+ content: [{ type: "text", text: `Inbox ${inbox_id} deleted.` }],
121
+ };
122
+ });
123
+ // --- Start ---
124
+ async function main() {
125
+ const transport = new StdioServerTransport();
126
+ await server.connect(transport);
127
+ }
128
+ main().catch((err) => {
129
+ console.error("Fatal error:", err);
130
+ process.exit(1);
131
+ });
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@useblip/email",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Blip disposable email — create inboxes, receive emails, extract OTP codes",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "blip-email": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "start": "node dist/index.js",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.12.1"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.7.0",
23
+ "@types/node": "^22.0.0"
24
+ },
25
+ "license": "AGPL-3.0",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/blipemail/blip"
29
+ },
30
+ "keywords": [
31
+ "mcp",
32
+ "mcp-server",
33
+ "model-context-protocol",
34
+ "email",
35
+ "disposable-email",
36
+ "temporary-email",
37
+ "otp",
38
+ "verification",
39
+ "ai-agent",
40
+ "claude",
41
+ "cursor",
42
+ "blip"
43
+ ]
44
+ }