mcp-mail-server 1.0.0 → 1.0.1

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.
Files changed (2) hide show
  1. package/dist/index.js +1 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
+ #!/usr/bin/env node
1
2
  import{Server as e}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as t}from"@modelcontextprotocol/sdk/server/stdio.js";import{ListToolsRequestSchema as n,CallToolRequestSchema as r}from"@modelcontextprotocol/sdk/types.js";import s from"net";import o from"tls";import{EventEmitter as i}from"events";import c from"nodemailer";class POP3Client extends i{socket=null;config;connected=!1;authenticated=!1;buffer="";constructor(e){super(),this.config=e}async connect(){return new Promise((e,t)=>{console.error(`[POP3] Connecting to ${this.config.host}:${this.config.port} (TLS: ${this.config.tls})`);const n=setTimeout(()=>{this.socket&&this.socket.destroy(),t(new Error(`Connection timeout to ${this.config.host}:${this.config.port}`))},1e4);this.config.tls?this.socket=o.connect({host:this.config.host,port:this.config.port,rejectUnauthorized:!1}):this.socket=s.createConnection(this.config.port,this.config.host),this.socket.on("connect",()=>{console.error("[POP3] Socket connected, waiting for server greeting..."),this.connected=!0}),this.socket.on("secureConnect",()=>{console.error("[POP3] TLS connection established, waiting for server greeting..."),this.connected=!0}),this.socket.on("data",r=>{console.error("[POP3] Received data:",r.toString().trim()),this.buffer+=r.toString(),this.processBuffer(e,t,n)}),this.socket.on("error",e=>{console.error("[POP3] Connection error:",e.message),clearTimeout(n),t(new Error(`POP3 connection failed: ${e.message}`))}),this.socket.on("close",()=>{console.error("[POP3] Connection closed"),clearTimeout(n),this.connected=!1,this.authenticated=!1})})}processBuffer(e,t,n){const r=this.buffer.split("\r\n");if(r.length>1){const s=r[0];this.buffer=r.slice(1).join("\r\n"),console.error("[POP3] Server response:",s),s.startsWith("+OK")?(n&&clearTimeout(n),e&&(console.error("[POP3] Connection successful!"),e())):s.startsWith("-ERR")&&(n&&clearTimeout(n),t&&(console.error("[POP3] Server error:",s),t(new Error(`POP3 server error: ${s}`))))}}async sendCommand(e){return new Promise((t,n)=>{if(!this.socket||!this.connected)return void n(new Error("Not connected"));this.socket.write(e+"\r\n");const r=e=>{const s=e.toString();this.socket?.removeListener("data",r),s.startsWith("+OK")?t(s):n(new Error(s))};this.socket.on("data",r)})}async authenticate(){if(!this.connected)throw new Error("Not connected to server");try{console.error("[POP3] Authenticating user:",this.config.username),await this.sendCommand(`USER ${this.config.username}`),console.error("[POP3] Sending password..."),await this.sendCommand(`PASS ${this.config.password}`),this.authenticated=!0,console.error("[POP3] Authentication successful!")}catch(e){throw console.error("[POP3] Authentication failed:",e),new Error(`Authentication failed: ${e instanceof Error?e.message:String(e)}`)}}async getMessageCount(){if(!this.authenticated)throw new Error("Not authenticated");const e=(await this.sendCommand("STAT")).match(/\+OK (\d+)/);return e?parseInt(e[1]):0}async listMessages(){if(!this.authenticated)throw new Error("Not authenticated");return new Promise((e,t)=>{if(!this.socket)return void t(new Error("Not connected"));this.socket.write("LIST\r\n");let n="";const r=t=>{if(n+=t.toString(),n.includes("\r\n.\r\n")){this.socket?.removeListener("data",r);const t=n.split("\r\n"),s=[];for(let e=1;e<t.length-2;e++){const n=t[e].split(" ");n.length>=2&&s.push({id:parseInt(n[0]),size:parseInt(n[1])})}e(s)}};this.socket.on("data",r)})}async retrieveMessage(e){if(!this.authenticated)throw new Error("Not authenticated");return new Promise((t,n)=>{if(!this.socket)return void n(new Error("Not connected"));this.socket.write(`RETR ${e}\r\n`);let r="";const s=n=>{if(r+=n.toString(),r.includes("\r\n.\r\n")){this.socket?.removeListener("data",s);const n=r.substring(r.indexOf("\r\n")+2,r.lastIndexOf("\r\n.\r\n")),o=this.parseMessage(e,n);t(o)}};this.socket.on("data",s)})}parseMessage(e,t){const n=t.indexOf("\r\n\r\n"),r=n>-1?t.substring(0,n):"",s=n>-1?t.substring(n+4):t,o={},i=r.split("\r\n");for(const e of i){const t=e.indexOf(":");if(t>-1){const n=e.substring(0,t).trim().toLowerCase(),r=e.substring(t+1).trim();o[n]=r}}return{id:e,size:t.length,headers:o,body:s.trim(),raw:t}}async deleteMessage(e){if(!this.authenticated)throw new Error("Not authenticated");await this.sendCommand(`DELE ${e}`)}async quit(){this.socket&&this.connected&&(await this.sendCommand("QUIT"),this.socket.end())}disconnect(){this.socket&&(this.socket.destroy(),this.connected=!1,this.authenticated=!1)}}class SMTPClient{transporter=null;config;constructor(e){this.config=e}async connect(){this.transporter=c.createTransport({host:this.config.host,port:this.config.port,secure:this.config.secure||!1,auth:{user:this.config.username,pass:this.config.password}});try{this.transporter&&await this.transporter.verify()}catch(e){throw new Error(`SMTP connection failed: ${e instanceof Error?e.message:String(e)}`)}}async sendMail(e){if(!this.transporter)throw new Error("SMTP client not connected");const t={from:e.from||this.config.username,to:Array.isArray(e.to)?e.to.join(", "):e.to,cc:e.cc?Array.isArray(e.cc)?e.cc.join(", "):e.cc:void 0,bcc:e.bcc?Array.isArray(e.bcc)?e.bcc.join(", "):e.bcc:void 0,subject:e.subject,text:e.text,html:e.html,attachments:e.attachments};try{const e=await this.transporter.sendMail(t);return{messageId:e.messageId,response:e.response,accepted:e.accepted||[],rejected:e.rejected||[]}}catch(e){throw new Error(`Failed to send email: ${e instanceof Error?e.message:String(e)}`)}}async disconnect(){this.transporter&&(this.transporter.close(),this.transporter=null)}}function a(e){const t=process.env[e];if(!t)throw new Error(`Missing required environment variable: ${e}. Please set this variable in your MCP server configuration.`);return t}function h(e){const t=process.env[e];if(!t)throw new Error(`Missing required environment variable: ${e}. Please set this variable to 'true' or 'false' in your MCP server configuration.`);if("true"!==t.toLowerCase()&&"false"!==t.toLowerCase())throw new Error(`Invalid boolean value for environment variable ${e}: ${t}. Must be 'true' or 'false'.`);return"true"===t.toLowerCase()}function l(e){const t=process.env[e];if(!t)throw new Error(`Missing required environment variable: ${e}. Please set this variable to a valid number in your MCP server configuration.`);const n=parseInt(t,10);if(isNaN(n))throw new Error(`Invalid number value for environment variable ${e}: ${t}. Must be a valid number.`);return n}const p={POP3:{host:a("POP3_HOST"),port:l("POP3_PORT"),username:a("EMAIL_USER"),password:a("EMAIL_PASS"),tls:h("POP3_SECURE")},SMTP:{host:a("SMTP_HOST"),port:l("SMTP_PORT"),username:a("EMAIL_USER"),password:a("EMAIL_PASS"),secure:h("SMTP_SECURE")}};(new class{server;pop3Client=null;smtpClient=null;constructor(){this.validateConfig(),this.server=new e({name:"mcp-mail",version:"1.0.0"},{capabilities:{tools:{}}}),this.setupToolHandlers(),this.setupErrorHandling()}setupErrorHandling(){this.server.onerror=e=>console.error("[MCP Error]",e),process.on("SIGINT",async()=>{this.pop3Client&&this.pop3Client.disconnect(),this.smtpClient&&await this.smtpClient.disconnect(),await this.server.close(),process.exit(0)})}setupToolHandlers(){this.server.setRequestHandler(n,async()=>({tools:[{name:"connect_pop3",description:"Connect to POP3 email server (using preconfigured settings)",inputSchema:{type:"object",properties:{}}},{name:"list_messages",description:"List all messages in the mailbox",inputSchema:{type:"object",properties:{}}},{name:"get_message",description:"Retrieve a specific email message",inputSchema:{type:"object",properties:{messageId:{type:"number",description:"Message ID to retrieve"}},required:["messageId"]}},{name:"delete_message",description:"Delete a specific email message",inputSchema:{type:"object",properties:{messageId:{type:"number",description:"Message ID to delete"}},required:["messageId"]}},{name:"get_message_count",description:"Get the total number of messages in the mailbox",inputSchema:{type:"object",properties:{}}},{name:"disconnect",description:"Disconnect from the POP3 server",inputSchema:{type:"object",properties:{}}},{name:"connect_smtp",description:"Connect to SMTP email server for sending emails (using preconfigured settings)",inputSchema:{type:"object",properties:{}}},{name:"send_email",description:"Send an email via SMTP",inputSchema:{type:"object",properties:{to:{type:"string",description:"Recipient email address(es), comma-separated"},subject:{type:"string",description:"Email subject"},text:{type:"string",description:"Plain text email body"},html:{type:"string",description:"HTML email body (optional)"},cc:{type:"string",description:"CC recipients, comma-separated (optional)"},bcc:{type:"string",description:"BCC recipients, comma-separated (optional)"}},required:["to","subject"]}},{name:"disconnect_smtp",description:"Disconnect from the SMTP server",inputSchema:{type:"object",properties:{}}},{name:"quick_connect",description:"Connect to both POP3 and SMTP servers at once (using preconfigured settings)",inputSchema:{type:"object",properties:{}}}]})),this.server.setRequestHandler(r,async e=>{const{name:t,arguments:n}=e.params;try{switch(t){case"connect_pop3":return await this.handleConnect();case"list_messages":return await this.handleListMessages();case"get_message":return await this.handleGetMessage(n);case"delete_message":return await this.handleDeleteMessage(n);case"get_message_count":return await this.handleGetMessageCount();case"disconnect":return await this.handleDisconnect();case"connect_smtp":return await this.handleConnectSMTP();case"send_email":return await this.handleSendEmail(n);case"disconnect_smtp":return await this.handleDisconnectSMTP();case"quick_connect":return await this.handleQuickConnect();default:throw new Error(`Unknown tool: ${t}`)}}catch(e){return{content:[{type:"text",text:`Error: ${e instanceof Error?e.message:String(e)}`}]}}})}async handleConnect(){const e=p.POP3;try{return this.pop3Client=new POP3Client(e),await this.pop3Client.connect(),await this.pop3Client.authenticate(),{content:[{type:"text",text:`Successfully connected to POP3 server ${e.host}:${e.port}`}]}}catch(e){throw new Error(`Failed to connect: ${e instanceof Error?e.message:String(e)}`)}}async handleListMessages(){if(!this.pop3Client)throw new Error("Not connected to POP3 server");const e=await this.pop3Client.listMessages();return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}async handleGetMessage(e){if(!this.pop3Client)throw new Error("Not connected to POP3 server");const t=e.messageId;if("number"!=typeof t)throw new Error("messageId must be a number");const n=await this.pop3Client.retrieveMessage(t);return{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}async handleDeleteMessage(e){if(!this.pop3Client)throw new Error("Not connected to POP3 server");const t=e.messageId;if("number"!=typeof t)throw new Error("messageId must be a number");return await this.pop3Client.deleteMessage(t),{content:[{type:"text",text:`Message ${t} marked for deletion`}]}}async handleGetMessageCount(){if(!this.pop3Client)throw new Error("Not connected to POP3 server");return{content:[{type:"text",text:`Total messages: ${await this.pop3Client.getMessageCount()}`}]}}async handleDisconnect(){if(!this.pop3Client)throw new Error("Not connected to POP3 server");return await this.pop3Client.quit(),this.pop3Client=null,{content:[{type:"text",text:"Disconnected from POP3 server"}]}}async handleConnectSMTP(){const e=p.SMTP;try{return this.smtpClient=new SMTPClient(e),await this.smtpClient.connect(),{content:[{type:"text",text:`Successfully connected to SMTP server ${e.host}:${e.port}`}]}}catch(e){throw new Error(`Failed to connect to SMTP server: ${e instanceof Error?e.message:String(e)}`)}}async handleSendEmail(e){if(!this.smtpClient)throw new Error("Not connected to SMTP server");const t={to:e.to.split(",").map(e=>e.trim()),subject:e.subject,text:e.text,html:e.html,cc:e.cc?e.cc.split(",").map(e=>e.trim()):void 0,bcc:e.bcc?e.bcc.split(",").map(e=>e.trim()):void 0};if(!t.text&&!t.html)throw new Error("Either text or html content is required");try{const e=await this.smtpClient.sendMail(t);return{content:[{type:"text",text:JSON.stringify(e,null,2)}]}}catch(e){throw new Error(`Failed to send email: ${e instanceof Error?e.message:String(e)}`)}}async handleDisconnectSMTP(){if(!this.smtpClient)throw new Error("Not connected to SMTP server");return await this.smtpClient.disconnect(),this.smtpClient=null,{content:[{type:"text",text:"Disconnected from SMTP server"}]}}async handleQuickConnect(){const e=[];let t=!1,n=!1;try{const n=p.POP3;this.pop3Client=new POP3Client(n),await this.pop3Client.connect(),await this.pop3Client.authenticate(),e.push(`✅ POP3: Successfully connected to ${n.host}:${n.port}`),t=!0}catch(t){e.push(`❌ POP3: Failed to connect - ${t instanceof Error?t.message:String(t)}`)}try{const t=p.SMTP;this.smtpClient=new SMTPClient(t),await this.smtpClient.connect(),e.push(`✅ SMTP: Successfully connected to ${t.host}:${t.port}`),n=!0}catch(t){e.push(`❌ SMTP: Failed to connect - ${t instanceof Error?t.message:String(t)}`)}const r=`Connection Summary: POP3 ${t?"✅":"❌"} | SMTP ${n?"✅":"❌"}`;return e.push("",r),{content:[{type:"text",text:e.join("\n")}]}}validateConfig(){try{console.error("=== MCP Mail Server Configuration ==="),console.error(`POP3: ${p.POP3.host}:${p.POP3.port} (TLS: ${p.POP3.tls})`),console.error(`SMTP: ${p.SMTP.host}:${p.SMTP.port} (Secure: ${p.SMTP.secure})`),console.error(`User: ${p.POP3.username}`),console.error("Password: [CONFIGURED]"),console.error("Configuration loaded successfully")}catch(e){throw console.error("Configuration error:",e instanceof Error?e.message:String(e)),console.error("Please ensure all required environment variables are set in your MCP server configuration."),e}}async run(){const e=new t;await this.server.connect(e),console.error("MCP Mail server running on stdio")}}).run().catch(console.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-mail-server",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "MCP server for POP3/SMTP email access with environment-based configuration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",