message-mcp
Version:
Desktop notifications, custom sounds, ntfy mobile notifications, email notifications, and API pushes reduce anxiety while waiting for AI tasks, allowing you to comfortably enjoy a cup of coffee.
3 lines (2 loc) • 3.83 kB
JavaScript
import{join as b,dirname as O}from"path";import{fileURLToPath as _}from"url";import{setDefaultAutoSelectFamilyAttemptTimeout as H}from"net";import{up as U}from"up-fetch";import{Command as C}from"commander";import{McpServer as E}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as I}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as h}from"zod";import D from"rfc2047";import N from"play-sound";import x from"nodemailer";import k from"node-notifier";function l(t){return typeof t=="boolean"?t:typeof t=="string"?t.toLowerCase()==="true"||t==="1":!1}var A=["POST","PUT","PATCH"];function g(t){if(!t)return"POST";let o=t.toUpperCase();return A.includes(o)?o:"POST"}function P(t){if(!t)return{};try{let o=JSON.parse(t);return o&&typeof o=="object"&&!Array.isArray(o)?o:{}}catch(o){return console.error("Invalid headers format, using empty headers:",o),{}}}var w=O(_(import.meta.url)),T=new C;T.name("message-mcp").description("Desktop notifications, custom sounds, ntfy mobile notifications, email notifications, and API pushes reduce anxiety while waiting for AI tasks, allowing you to comfortably enjoy a cup of coffee.").version("2.0.6").option("--shttp","Streamable HTTP server mode running").parse(process.argv);var R=T.opts(),S=5e3;H(S);var y=U(fetch,()=>({timeout:S})),e={disableDesktop:l(R.shttp||process.env.DISABLE_DESKTOP),soundPath:process.env.SOUND_PATH,ntfyTopic:process.env.NTFY_TOPIC,smtpHost:process.env.SMTP_HOST,smtpPort:Number(process.env.SMTP_PORT)||587,smtpSecure:l(process.env.SMTP_SECURE),smtpUser:process.env.SMTP_USER,smtpPass:process.env.SMTP_PASS,apiUrl:process.env.API_URL,apiHeaders:P(process.env.API_HEADERS),apiMethod:g(process.env.API_METHOD)},M=new E({name:"message-mcp",version:"2.0.6"});M.registerTool("notify",{title:"Send Message Notification",description:"Send notifications and messages through multiple channels (desktop, email, API). Use this tool to notify users about any important information, progress updates, task completions, alerts, or any other communication needs.",inputSchema:{title:h.string().optional().describe("The title of the notification"),message:h.string().optional().describe("The main content of the notification message")}},async({title:t,message:o})=>{let p=t||"Message MCP",c=o||"Task completed, please review.",n={};if(e.ntfyTopic){let s=encodeURIComponent(e.ntfyTopic);n.ntfy=y(`https://ntfy.sh/${s}`,{method:"POST",body:c,headers:{Title:D.encode(p),Priority:"urgent"}})}if(e.smtpHost&&e.smtpUser&&e.smtpPass){let s=x.createTransport({host:e.smtpHost,port:e.smtpPort,secure:e.smtpSecure,auth:{user:e.smtpUser,pass:e.smtpPass},pool:!0,maxConnections:5}),i={from:e.smtpUser,to:e.smtpUser,subject:p,text:c};n.nodemailer=s.sendMail(i)}if(e.apiUrl&&(n.api=y(e.apiUrl,{method:e.apiMethod,headers:e.apiHeaders,body:{title:p,message:c}})),!e.disableDesktop){let s=N({}),i=b(w,"assets","notify.mp3"),m=e.soundPath||i;n.sound=new Promise((r,f)=>{s.play(m,a=>{a&&f(a)}),setTimeout(()=>{r({message:"Sound notification played successfully!"})},1500)}),n.desktop=new Promise((r,f)=>{k.notify({title:p,message:c,sound:!1},a=>{a&&f(a)}),setTimeout(()=>{r({message:"Desktop notification sent successfully!"})},1500)})}if(Object.keys(n).length===0)return{content:[{type:"text",text:"No notification channels configured."}]};let d=Object.entries(n),v=await Promise.allSettled(d.map(([,s])=>s)),u=[];return v.forEach((s,i)=>{let[m]=d[i],r="";s.status==="fulfilled"?r=typeof s.value=="object"?`successfully! ${JSON.stringify(s.value)}`:"successfully!":r=s.reason instanceof Error?`failed! ${s.reason.message}`:"failed!",u.push({type:"text",text:`${m} ${r}`})}),{content:u}});var j=new I;M.connect(j).then(()=>{console.log("Server connected successfully")}).catch(t=>{console.error("Error occurred while connecting server:",t)});