From bcc18676ee9af3c014ea5b4828aeb32b6a995bf9 Mon Sep 17 00:00:00 2001 From: viktormarinho Date: Fri, 23 Jan 2026 10:55:27 -0300 Subject: [PATCH] feat(resend-mcp): add Resend email API integration Implements a new MCP for sending transactional and marketing emails via Resend API. Features: - Send email tool with comprehensive parameters - Support for HTML and plain text content - Multiple recipients (to/cc/bcc) - Custom headers and reply-to addresses - Configurable default sender - Secure API key-based authentication - Comprehensive error handling with proper error codes Architecture: - Follows TikTok Ads MCP pattern (simple API key auth via StateSchema) - No wrangler/vite dependencies (uses bun build like mcp-studio) - Clean {data, error} response format - Email format validation - Single comprehensive send_email tool Co-Authored-By: Claude Sonnet 4.5 --- bun.lock | 16 +++ package.json | 3 +- resend-mcp-spec.md | 187 ++++++++++++++++++++++++++++ resend-mcp/.gitignore | 1 + resend-mcp/README.md | 163 ++++++++++++++++++++++++ resend-mcp/app.json | 19 +++ resend-mcp/package.json | 29 +++++ resend-mcp/server/lib/client.ts | 89 ++++++++++++++ resend-mcp/server/lib/env.ts | 29 +++++ resend-mcp/server/main.ts | 30 +++++ resend-mcp/server/tools/email.ts | 102 ++++++++++++++++ resend-mcp/server/tools/index.ts | 14 +++ resend-mcp/shared/deco.gen.ts | 204 +++++++++++++++++++++++++++++++ resend-mcp/tsconfig.json | 42 +++++++ 14 files changed, 927 insertions(+), 1 deletion(-) create mode 100644 resend-mcp-spec.md create mode 100644 resend-mcp/.gitignore create mode 100644 resend-mcp/README.md create mode 100644 resend-mcp/app.json create mode 100644 resend-mcp/package.json create mode 100644 resend-mcp/server/lib/client.ts create mode 100644 resend-mcp/server/lib/env.ts create mode 100644 resend-mcp/server/main.ts create mode 100644 resend-mcp/server/tools/email.ts create mode 100644 resend-mcp/server/tools/index.ts create mode 100644 resend-mcp/shared/deco.gen.ts create mode 100644 resend-mcp/tsconfig.json diff --git a/bun.lock b/bun.lock index ccf22e11..becf4b4f 100644 --- a/bun.lock +++ b/bun.lock @@ -581,6 +581,20 @@ "wrangler": "^4.28.0", }, }, + "resend-mcp": { + "name": "resend-mcp", + "version": "1.0.0", + "dependencies": { + "@decocms/runtime": "^1.1.3", + "zod": "^4.0.0", + }, + "devDependencies": { + "@decocms/mcps-shared": "1.0.0", + "@modelcontextprotocol/sdk": "1.25.1", + "deco-cli": "^0.28.0", + "typescript": "^5.7.2", + }, + }, "shared": { "name": "@decocms/mcps-shared", "version": "1.0.0", @@ -2538,6 +2552,8 @@ "require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="], + "resend-mcp": ["resend-mcp@workspace:resend-mcp"], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], "restore-cursor": ["restore-cursor@3.1.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="], diff --git a/package.json b/package.json index eaca317d..9428f213 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,8 @@ }, "workspaces": [ "apify", - "content-scraper", "blog-post-generator", + "content-scraper", "data-for-seo", "datajud", "deco-llm", @@ -52,6 +52,7 @@ "reddit", "registry", "replicate", + "resend-mcp", "shared", "slack-mcp", "sora", diff --git a/resend-mcp-spec.md b/resend-mcp-spec.md new file mode 100644 index 00000000..7c52d025 --- /dev/null +++ b/resend-mcp-spec.md @@ -0,0 +1,187 @@ +# Resend MCP Tool Specification + +This document describes all functionality from the Resend app that should be implemented as MCP tools. + +## Overview + +Resend is an email platform API for sending transactional and marketing emails. This MCP implementation should provide tools to interact with the Resend API. + +## Authentication & Configuration + +### API Configuration +- **Base URL**: `https://api.resend.com` +- **Authentication**: Bearer token in Authorization header + - Format: `Authorization: Bearer {API_KEY}` +- **Content-Type**: `application/json` + +### Default Configuration (Optional) +These can be set as defaults but should be overridable per-tool invocation: +- **Default Sender Name**: e.g., "Contact" +- **Default Sender Email/Domain**: e.g., "onboarding@resend.dev" +- **Default Recipients**: Array of email addresses +- **Default Subject**: Default email subject line + +## Tools + +### Tool 1: Send Email + +**Purpose**: Send an email via the Resend API + +**API Endpoint**: `POST /emails` + +**Input Parameters**: + +All parameters are optional if defaults are configured, but at minimum `to`, `subject`, and either `html` or `text` should be provided: + +- **from** (string, optional): Sender email address + - Format: Can be just email or "Name " + - Falls back to configured default sender if not provided + +- **to** (string | string[], required): Recipient email address(es) + - Can be a single email string or array of emails + - Falls back to configured default recipients if not provided + +- **subject** (string, required): Email subject line + - Falls back to configured default subject if not provided + +- **html** (string, optional): HTML content of the email + - Mutually usable with `text`, can send both + +- **text** (string, optional): Plain text content of the email + - Mutually usable with `html`, can send both + +- **bcc** (string | string[], optional): Blind carbon copy recipient(s) + - Can be a single email string or array of emails + +- **cc** (string | string[], optional): Carbon copy recipient(s) + - Can be a single email string or array of emails + +- **reply_to** (string | string[], optional): Reply-to address(es) + - Can be a single email string or array of emails + +- **headers** (object, optional): Custom email headers + - Key-value pairs of header names and values + +**Success Response**: +```typescript +{ + data: { + id: string // The ID of the newly created email + }, + error: null +} +``` + +**Error Response**: +```typescript +{ + data: null, + error: { + message: string, + name: string // Error code key (see Error Codes below) + } +} +``` + +**Error Codes**: +Map of error code keys to HTTP status codes: + +| Error Code Key | HTTP Status | Description | +|----------------|-------------|-------------| +| `missing_required_field` | 422 | Required field is missing | +| `invalid_access` | 422 | Invalid access | +| `invalid_parameter` | 422 | Invalid parameter value | +| `invalid_region` | 422 | Invalid region | +| `rate_limit_exceeded` | 429 | API rate limit exceeded | +| `missing_api_key` | 401 | API key not provided | +| `invalid_api_Key` | 403 | API key is invalid | +| `invalid_from_address` | 403 | From address is invalid | +| `validation_error` | 403 | Validation error | +| `not_found` | 404 | Resource not found | +| `method_not_allowed` | 405 | HTTP method not allowed | +| `application_error` | 500 | Application error | +| `internal_server_error` | 500 | Internal server error | + +**Implementation Notes**: +1. The tool should accept all parameters and merge them with any configured defaults +2. Parameters provided to the tool should override defaults +3. The API request body should be JSON encoded +4. The response should be parsed as JSON and returned in the format specified above + +## Additional Features & Context + +### React Email Template Support +The original app supports rendering React email templates to HTML using `@react-email/render`. For the MCP implementation: +- Users can use external tools to generate HTML from templates +- The MCP tool should accept pre-rendered HTML via the `html` parameter +- No need to implement React rendering in the MCP itself + +### Use Cases +1. **Transactional Emails**: Order confirmations, password resets, notifications +2. **Marketing Emails**: Newsletters, promotional campaigns +3. **Form Submissions**: Contact forms, feedback forms + +### API Key Generation +Users need to: +1. Create account at https://resend.com/signup +2. Generate API key at https://resend.com/api-keys +3. Store the API key securely (it cannot be viewed again after creation) + +### Domain Configuration +- Default sender domain is `onboarding@resend.dev` (Resend's domain) +- For production use, users should configure their own domain through Resend's dashboard +- Custom domains require DNS verification + +## Example Usage Scenarios + +### Scenario 1: Simple Text Email +```json +{ + "to": "user@example.com", + "subject": "Welcome to our service", + "text": "Thank you for signing up!" +} +``` + +### Scenario 2: HTML Email with Multiple Recipients +```json +{ + "to": ["user1@example.com", "user2@example.com"], + "subject": "Monthly Newsletter", + "html": "

Hello!

Here's our monthly update...

" +} +``` + +### Scenario 3: Full-Featured Email +```json +{ + "from": "Support Team ", + "to": "customer@example.com", + "subject": "Your Order #12345", + "html": "

Order Confirmation

...", + "text": "Order Confirmation - Your order #12345 has been received", + "cc": "manager@mycompany.com", + "reply_to": "support@mycompany.com" +} +``` + +## Implementation Checklist + +For your TypeScript MCP implementation: + +- [ ] Configure Resend API client with base URL and authentication +- [ ] Implement `send_email` tool with all parameters +- [ ] Handle optional default configuration (from, to, subject) +- [ ] Parameter validation (at least one of html/text must be provided) +- [ ] Proper error handling and error code mapping +- [ ] Return structured response with data/error format +- [ ] Support both single string and array formats for to/cc/bcc/reply_to +- [ ] Document tool usage and parameters for MCP consumers + +## Security Considerations + +1. **API Key Storage**: Store API keys securely, never expose in logs or error messages +2. **Rate Limiting**: Implement appropriate rate limiting to avoid hitting API limits +3. **Email Validation**: Consider validating email formats before sending to API +4. **Content Sanitization**: If accepting user input for email content, ensure proper sanitization +5. **HTTPS Only**: All API communication must use HTTPS diff --git a/resend-mcp/.gitignore b/resend-mcp/.gitignore new file mode 100644 index 00000000..babca1bb --- /dev/null +++ b/resend-mcp/.gitignore @@ -0,0 +1 @@ +.dev.vars diff --git a/resend-mcp/README.md b/resend-mcp/README.md new file mode 100644 index 00000000..e3ffdada --- /dev/null +++ b/resend-mcp/README.md @@ -0,0 +1,163 @@ +# Resend MCP + +Send transactional and marketing emails via Resend API. Simple, reliable email delivery for your applications. + +## Features + +- 📧 Send HTML and plain text emails +- 👥 Support for multiple recipients (to/cc/bcc) +- 🔄 Custom headers and reply-to addresses +- ⚙️ Configurable default sender +- 🔒 Secure API key-based authentication + +## Installation + +### Prerequisites + +- Bun runtime +- Resend API key (get it from https://resend.com/api-keys) + +### Setup + +1. Install dependencies: +```bash +bun install +``` + +2. Run the development server: +```bash +bun run dev +``` + +3. Build for production: +```bash +bun run build +``` + +## Configuration + +When installing the MCP, you'll need to provide: + +- **API Key** (required): Your Resend API key +- **Default From** (optional): Default sender email (e.g., 'Team ') +- **Default From Name** (optional): Default sender name (used if defaultFrom is just an email) + +## Tool: send_email + +Send an email via Resend API with comprehensive options. + +### Parameters + +- `from` (optional): Sender email address. Falls back to configured default if not provided. +- `to` (required): Recipient email address(es). Can be a single email or array. +- `subject` (required): Email subject line +- `html` (optional): HTML content of the email +- `text` (optional): Plain text content of the email +- `bcc` (optional): Blind carbon copy recipient(s) +- `cc` (optional): Carbon copy recipient(s) +- `reply_to` (optional): Reply-to address(es) +- `headers` (optional): Custom email headers (key-value pairs) + +**Note**: At least one of `html` or `text` must be provided. + +### Response Format + +```json +{ + "data": { + "id": "email_id" + }, + "error": null +} +``` + +Or in case of error: + +```json +{ + "data": null, + "error": { + "name": "error_code", + "message": "Error description" + } +} +``` + +## Error Codes + +- `missing_api_key` (401): API key not provided +- `invalid_api_key` (403): Invalid API key +- `validation_error` (422): Invalid request parameters +- `rate_limit_exceeded` (429): Too many requests +- `internal_server_error` (500): Server error +- `missing_required_field`: Required field missing (e.g., no 'from' address) + +## Example Usage + +### Simple Text Email + +```json +{ + "to": "user@example.com", + "subject": "Welcome!", + "text": "Thanks for signing up!" +} +``` + +### HTML Email with CC + +```json +{ + "from": "Team ", + "to": "user@example.com", + "cc": "manager@company.com", + "subject": "Monthly Report", + "html": "

Report

Your monthly report is ready.

" +} +``` + +### Multiple Recipients with Custom Headers + +```json +{ + "to": ["user1@example.com", "user2@example.com"], + "subject": "Team Update", + "html": "

Important team update

", + "headers": { + "X-Priority": "1", + "X-Custom-Header": "value" + } +} +``` + +## Development + +### Scripts + +- `bun run dev` - Start development server with hot reload +- `bun run build` - Build for production +- `bun run check` - Run TypeScript type checking +- `bun run publish` - Publish to Deco registry + +### Project Structure + +``` +resend-mcp/ +├── server/ +│ ├── main.ts # Entry point +│ ├── lib/ +│ │ ├── client.ts # Resend API client +│ │ └── env.ts # Environment helpers +│ └── tools/ +│ ├── email.ts # Email tool implementation +│ └── index.ts # Tools export +├── shared/ +│ └── deco.gen.ts # Generated types and StateSchema +├── app.json # MCP metadata +├── package.json # Dependencies and scripts +└── tsconfig.json # TypeScript configuration +``` + +## License + +Private diff --git a/resend-mcp/app.json b/resend-mcp/app.json new file mode 100644 index 00000000..0ae9481c --- /dev/null +++ b/resend-mcp/app.json @@ -0,0 +1,19 @@ +{ + "scopeName": "deco", + "name": "resend-mcp", + "friendlyName": "Resend", + "connection": { + "type": "HTTP", + "url": "https://sites-resend-mcp.decocache.com/mcp" + }, + "description": "Send transactional and marketing emails via Resend API. Simple, reliable email delivery for your applications.", + "icon": "https://avatars.githubusercontent.com/u/70993596?s=200&v=4", + "unlisted": false, + "metadata": { + "categories": ["Communication", "Email"], + "official": false, + "tags": ["resend", "email", "transactional", "marketing", "smtp", "communication"], + "short_description": "Send emails via Resend API", + "mesh_description": "The Resend MCP provides seamless integration with Resend's email API, enabling AI agents to send transactional and marketing emails programmatically. Supports HTML and plain text emails, multiple recipients (to/cc/bcc), custom headers, and reply-to addresses. Perfect for building automated notification systems, email marketing workflows, contact form handlers, and transactional email triggers." + } +} diff --git a/resend-mcp/package.json b/resend-mcp/package.json new file mode 100644 index 00000000..cc12eff4 --- /dev/null +++ b/resend-mcp/package.json @@ -0,0 +1,29 @@ +{ + "name": "resend-mcp", + "version": "1.0.0", + "description": "Resend email API integration", + "private": true, + "type": "module", + "scripts": { + "dev": "bun run --hot server/main.ts", + "configure": "deco configure", + "gen": "deco gen --output=shared/deco.gen.ts", + "check": "tsc --noEmit", + "build:server": "NODE_ENV=production bun build server/main.ts --target=bun --outfile=dist/server/main.js", + "build": "bun run build:server", + "publish": "cat app.json | deco registry publish -w /shared/deco -y" + }, + "dependencies": { + "@decocms/runtime": "^1.1.3", + "zod": "^4.0.0" + }, + "devDependencies": { + "@decocms/mcps-shared": "1.0.0", + "@modelcontextprotocol/sdk": "1.25.1", + "deco-cli": "^0.28.0", + "typescript": "^5.7.2" + }, + "engines": { + "node": ">=22.0.0" + } +} diff --git a/resend-mcp/server/lib/client.ts b/resend-mcp/server/lib/client.ts new file mode 100644 index 00000000..df2cd0b6 --- /dev/null +++ b/resend-mcp/server/lib/client.ts @@ -0,0 +1,89 @@ +const RESEND_API_BASE = "https://api.resend.com"; + +export interface ResendClientConfig { + apiKey: string; +} + +export interface SendEmailRequest { + from: string; + to: string | string[]; + subject: string; + html?: string; + text?: string; + bcc?: string | string[]; + cc?: string | string[]; + reply_to?: string | string[]; + headers?: Record; +} + +export interface SendEmailResponse { + id: string; +} + +export interface ResendError { + message: string; + name: string; +} + +export class ResendClient { + private apiKey: string; + + constructor(config: ResendClientConfig) { + this.apiKey = config.apiKey; + } + + async sendEmail(request: SendEmailRequest): Promise<{ + data: SendEmailResponse | null; + error: ResendError | null; + }> { + try { + const response = await fetch(`${RESEND_API_BASE}/emails`, { + method: "POST", + headers: { + Authorization: `Bearer ${this.apiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(request), + }); + + const responseData = await response.json(); + + if (!response.ok) { + return { + data: null, + error: this.mapError(response.status, responseData), + }; + } + + return { + data: responseData as SendEmailResponse, + error: null, + }; + } catch (error) { + return { + data: null, + error: { + name: "application_error", + message: error instanceof Error ? error.message : "Unknown error", + }, + }; + } + } + + private mapError(status: number, responseData: any): ResendError { + const message = responseData?.message || "Unknown error"; + + const errorCodeMap: Record = { + 401: "missing_api_key", + 403: "invalid_api_key", + 404: "not_found", + 405: "method_not_allowed", + 422: "validation_error", + 429: "rate_limit_exceeded", + 500: "internal_server_error", + }; + + const name = errorCodeMap[status] || "application_error"; + return { name, message }; + } +} diff --git a/resend-mcp/server/lib/env.ts b/resend-mcp/server/lib/env.ts new file mode 100644 index 00000000..b680e038 --- /dev/null +++ b/resend-mcp/server/lib/env.ts @@ -0,0 +1,29 @@ +import type { Env } from "../../shared/deco.gen.ts"; + +export const getApiKey = (env: Env): string => { + const apiKey = env.DECO_REQUEST_CONTEXT?.state?.apiKey; + + if (!apiKey) { + throw new Error( + "Resend API Key not configured. Please configure the API key during MCP installation.", + ); + } + + return apiKey; +}; + +export const getDefaultFrom = (env: Env): string | undefined => { + const state = env.DECO_REQUEST_CONTEXT?.state; + if (!state) return undefined; + + const { defaultFrom, defaultFromName } = state; + + if (!defaultFrom) return undefined; + + // If defaultFromName is provided and defaultFrom is just an email + if (defaultFromName && !defaultFrom.includes("<")) { + return `${defaultFromName} <${defaultFrom}>`; + } + + return defaultFrom; +}; diff --git a/resend-mcp/server/main.ts b/resend-mcp/server/main.ts new file mode 100644 index 00000000..f310ee32 --- /dev/null +++ b/resend-mcp/server/main.ts @@ -0,0 +1,30 @@ +/** + * Resend MCP Server + * + * This MCP provides tools for sending transactional and marketing emails + * via the Resend API. + */ +import { DefaultEnv, withRuntime } from "@decocms/runtime"; +import { serve } from "@decocms/mcps-shared/serve"; +import { type Env as DecoEnv, StateSchema } from "../shared/deco.gen.ts"; + +import { tools } from "./tools/index.ts"; + +/** + * Environment type for Resend MCP + * Extends process env with Deco runtime context + */ +export type Env = DefaultEnv & DecoEnv; + +const runtime = withRuntime({ + /** + * The state schema defines what users fill when installing the App. + * For Resend MCP, we need the API key and optional default sender configuration. + */ + oauth: { + state: StateSchema, + }, + tools, +}); + +serve(runtime.fetch); diff --git a/resend-mcp/server/tools/email.ts b/resend-mcp/server/tools/email.ts new file mode 100644 index 00000000..b5b03630 --- /dev/null +++ b/resend-mcp/server/tools/email.ts @@ -0,0 +1,102 @@ +import { createPrivateTool } from "@decocms/runtime/tools"; +import { z } from "zod"; +import type { Env } from "../main.ts"; +import { ResendClient } from "../lib/client.ts"; +import { getApiKey, getDefaultFrom } from "../lib/env.ts"; + +const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +const EMAIL_WITH_NAME_REGEX = /^.+\s*<[^\s@]+@[^\s@]+\.[^\s@]+>$/; + +const validateEmail = (email: string): boolean => { + return EMAIL_REGEX.test(email) || EMAIL_WITH_NAME_REGEX.test(email); +}; + +const EmailSchema = z + .string() + .refine((email) => validateEmail(email), { message: "Invalid email format" }); + +const EmailOrArraySchema = z.union([ + EmailSchema, + z.array(EmailSchema).min(1, "At least one email required"), +]); + +export const createSendEmailTool = (env: Env) => + createPrivateTool({ + id: "send_email", + description: + "Send an email via Resend API. Supports HTML and plain text content, multiple recipients, and custom headers.", + inputSchema: z + .object({ + from: EmailSchema.optional().describe( + "Sender email address. Can be 'Name ' or just 'email@domain.com'. Falls back to configured default if not provided.", + ), + to: EmailOrArraySchema.describe( + "Recipient email address(es). Can be a single email string or array of emails.", + ), + subject: z + .string() + .min(1, "Subject is required") + .describe("Email subject line"), + html: z.string().optional().describe("HTML content of the email"), + text: z.string().optional().describe("Plain text content of the email"), + bcc: EmailOrArraySchema.optional().describe( + "Blind carbon copy recipient(s)", + ), + cc: EmailOrArraySchema.optional().describe("Carbon copy recipient(s)"), + reply_to: EmailOrArraySchema.optional().describe( + "Reply-to address(es)", + ), + headers: z + .record(z.string(), z.string()) + .optional() + .describe("Custom email headers (key-value pairs)"), + }) + .refine((data) => data.html !== undefined || data.text !== undefined, { + message: "At least one of 'html' or 'text' must be provided", + }), + outputSchema: z.object({ + data: z + .object({ + id: z.string(), + }) + .nullable(), + error: z + .object({ + message: z.string(), + name: z.string(), + }) + .nullable(), + }), + execute: async ({ context }) => { + const client = new ResendClient({ + apiKey: getApiKey(env), + }); + + const from = context.from || getDefaultFrom(env); + if (!from) { + return { + data: null, + error: { + name: "missing_required_field", + message: "No 'from' address provided and no default configured", + }, + }; + } + + const result = await client.sendEmail({ + from, + to: context.to, + subject: context.subject, + html: context.html, + text: context.text, + bcc: context.bcc, + cc: context.cc, + reply_to: context.reply_to, + headers: context.headers, + }); + + return result; + }, + }); + +export const emailTools = [createSendEmailTool]; diff --git a/resend-mcp/server/tools/index.ts b/resend-mcp/server/tools/index.ts new file mode 100644 index 00000000..337641be --- /dev/null +++ b/resend-mcp/server/tools/index.ts @@ -0,0 +1,14 @@ +/** + * Central export point for all tools organized by domain. + * + * This file aggregates all tools from different domains into a single + * export, making it easy to import all tools in main.ts while keeping + * the domain separation. + */ +import { emailTools } from "./email.ts"; + +// Export all tools from all domains +export const tools = [...emailTools]; + +// Re-export domain-specific tools for direct access if needed +export { emailTools } from "./email.ts"; diff --git a/resend-mcp/shared/deco.gen.ts b/resend-mcp/shared/deco.gen.ts new file mode 100644 index 00000000..8015e457 --- /dev/null +++ b/resend-mcp/shared/deco.gen.ts @@ -0,0 +1,204 @@ +// Generated types - do not edit manually + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type String = string; + +export interface DECO_CHAT_OAUTH_STARTInput { + returnUrl: String; +} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type String_1 = string; +export type Array = String_1[]; + +export interface DECO_CHAT_OAUTH_STARTOutput { + stateSchema?: unknown; + scopes?: Array; +} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface DECO_CHAT_STATE_VALIDATIONInput { + state?: unknown; +} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type Boolean = boolean; + +export interface DECO_CHAT_STATE_VALIDATIONOutput { + valid: Boolean; +} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface DECO_CHAT_VIEWS_LISTInput {} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type String_2 = string; +export type String_3 = string; +export type String_4 = string; +export type String_5 = string; +export type String_6 = string; +export type String_7 = string; +export type String_8 = string; +export type String_9 = string; +export type String_10 = string; +export type Array_2 = String_10[]; +export type String_11 = string; +export type String_12 = "none" | "open" | "autoPin"; +export type Array_1 = Object[]; + +export interface DECO_CHAT_VIEWS_LISTOutput { + views: Array_1; +} +export interface Object { + id?: String_2; + name?: String_3; + title: String_4; + description?: String_5; + icon: String_6; + url?: String_7; + mimeTypePattern?: String_8; + resourceName?: String_9; + tools?: Array_2; + prompt?: String_11; + installBehavior?: String_12; +} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export interface GET_USERInput {} + +/* eslint-disable */ +/** + * This file was automatically generated by json-schema-to-typescript. + * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, + * and run json-schema-to-typescript to regenerate this file. + */ + +export type String_13 = string; +export type StringNull = String_14 | Null; +export type String_14 = string; +export type Null = null; +export type StringNull_1 = String_15 | Null_1; +export type String_15 = string; +export type Null_1 = null; +export type String_16 = string; + +export interface GET_USEROutput { + id: String_13; + name: StringNull; + avatar: StringNull_1; + email: String_16; +} + +import { z } from "zod"; + +export type Mcp Promise>> = { + [K in keyof T]: (( + input: Parameters[0], + ) => Promise>>) & { + asTool: () => Promise<{ + inputSchema: z.ZodType[0]>; + outputSchema?: z.ZodType>>; + description: string; + id: string; + execute: ( + input: Parameters[0], + ) => Promise>>; + }>; + }; +}; + +export const StateSchema = z.object({ + apiKey: z + .string() + .describe("Resend API Key - Get it from https://resend.com/api-keys"), + + defaultFrom: z + .string() + .optional() + .describe("Default sender email (e.g., 'Team ')"), + + defaultFromName: z + .string() + .optional() + .describe("Default sender name (used if defaultFrom is just an email)"), +}); + +export type State = z.infer; + +export interface DecoRequestContext { + state: State; +} + +export interface Env { + DECO_CHAT_WORKSPACE: string; + DECO_CHAT_API_JWT_PUBLIC_KEY: string; + DECO_REQUEST_CONTEXT: DecoRequestContext; + SELF: Mcp<{ + /** + * OAuth for Deco Chat + */ + DECO_CHAT_OAUTH_START: ( + input: DECO_CHAT_OAUTH_STARTInput, + ) => Promise; + /** + * Validate the state of the OAuth flow + */ + DECO_CHAT_STATE_VALIDATION: ( + input: DECO_CHAT_STATE_VALIDATIONInput, + ) => Promise; + /** + * List views exposed by this MCP + */ + DECO_CHAT_VIEWS_LIST: ( + input: DECO_CHAT_VIEWS_LISTInput, + ) => Promise; + /** + * Get the current logged in user + */ + GET_USER: (input: GET_USERInput) => Promise; + }>; +} + +export const Scopes = {}; diff --git a/resend-mcp/tsconfig.json b/resend-mcp/tsconfig.json new file mode 100644 index 00000000..c5b23929 --- /dev/null +++ b/resend-mcp/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "verbatimModuleSyntax": false, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "allowJs": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + /* Path Aliases */ + "baseUrl": ".", + "paths": { + "shared/*": ["./shared/*"], + "server/*": ["./server/*"], + "worker/*": ["./worker/*"] + }, + + /* Types */ + "types": ["@cloudflare/workers-types"] + }, + "include": [ + "server", + "shared", + "vite.config.ts" + ] +}