@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 +17 -0
- package/README.md +78 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +131 -0
- package/package.json +44 -0
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
|
package/dist/index.d.ts
ADDED
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
|
+
}
|