mcp-sms-ir
Version:
MCP Server for SMS.ir messaging services
295 lines (271 loc) • 9.14 kB
JavaScript
#!/usr/bin/env node
import axios from 'axios';
// Main function to handle async operations
const main = async () => {
try {
// Dynamically import the MCP SDK
const mcp = await import('@modelcontextprotocol/sdk');
const { Server, StdioServerTransport, CallToolRequestSchema, ListToolsRequestSchema, ErrorCode } = mcp;
// Get API key from environment variables
const API_KEY = process.env.SMS_IR_API_KEY;
if (!API_KEY) {
console.error('SMS_IR_API_KEY environment variable is required');
process.exit(1);
}
// SMS.ir API base URL
const BASE_URL = 'https://api.sms.ir/v1';
class SmsIrServer {
constructor(apiKey) {
this.server = new Server(
{
name: 'sms-ir-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Configure axios instance with default headers and base URL
this.axiosInstance = axios.create({
baseURL: BASE_URL,
headers: {
'Content-Type': 'application/json',
'Accept': 'text/plain',
'x-api-key': apiKey,
}
});
this.setupToolHandlers();
// Error handling
this.server.onerror = (error) => console.error('[MCP Error]', error);
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
setupToolHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'send_sms',
description: 'Send a SMS message to a single recipient',
inputSchema: {
type: 'object',
properties: {
mobile: {
type: 'string',
description: 'Recipient mobile number (e.g., 09121234567)',
},
message: {
type: 'string',
description: 'Message content',
},
lineNumber: {
type: 'string',
description: 'Sender line number (optional)',
},
sendDateTime: {
type: 'string',
description: 'Scheduled date and time for sending the message (optional, ISO format)',
},
},
required: ['mobile', 'message'],
},
},
{
name: 'send_bulk_sms',
description: 'Send the same SMS message to multiple recipients',
inputSchema: {
type: 'object',
properties: {
mobiles: {
type: 'array',
items: {
type: 'string',
},
description: 'Array of recipient mobile numbers',
},
messageText: {
type: 'string',
description: 'Message content to send to all recipients',
},
lineNumber: {
type: 'string',
description: 'Sender line number (optional)',
},
sendDateTime: {
type: 'string',
description: 'Scheduled date and time for sending the message (optional, ISO format)',
},
},
required: ['mobiles', 'messageText'],
},
},
{
name: 'send_verification_code',
description: 'Send a verification code SMS using a template',
inputSchema: {
type: 'object',
properties: {
mobile: {
type: 'string',
description: 'Recipient mobile number',
},
templateId: {
type: 'string',
description: 'Template ID from SMS.ir panel',
},
parameters: {
type: 'array',
items: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Parameter name as defined in the template',
},
value: {
type: 'string',
description: 'Parameter value to replace in the template',
},
},
required: ['name', 'value'],
},
description: 'Array of parameters to substitute in the template',
},
},
required: ['mobile', 'templateId', 'parameters'],
},
},
{
name: 'check_credit',
description: 'Check the remaining credit in your SMS.ir account',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
},
],
}));
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
switch (request.params.name) {
case 'send_sms': {
return await this.handleSendSms(request.params.arguments);
}
case 'send_bulk_sms': {
return await this.handleSendBulkSms(request.params.arguments);
}
case 'send_verification_code': {
return await this.handleSendVerification(request.params.arguments);
}
case 'check_credit': {
return await this.handleCheckCredit();
}
default:
throw { code: ErrorCode.MethodNotFound, message: `Unknown tool: ${request.params.name}` };
}
} catch (error) {
if (axios.isAxiosError(error)) {
const statusCode = error.response?.status;
const responseData = error.response?.data;
return {
content: [
{
type: 'text',
text: `SMS.ir API error (${statusCode}): ${JSON.stringify(responseData)}`,
},
],
isError: true,
};
}
return {
content: [
{
type: 'text',
text: `Unexpected error: ${error.message || JSON.stringify(error)}`,
},
],
isError: true,
};
}
});
}
async handleSendSms(params) {
const response = await this.axiosInstance.post('/send', {
mobile: params.mobile,
message: params.message,
lineNumber: params.lineNumber,
sendDateTime: params.sendDateTime,
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
async handleSendBulkSms(params) {
const response = await this.axiosInstance.post('/send/bulk', {
lineNumber: params.lineNumber,
messageText: params.messageText,
mobiles: params.mobiles,
sendDateTime: params.sendDateTime,
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
async handleSendVerification(params) {
const response = await this.axiosInstance.post('/send/verify', {
mobile: params.mobile,
templateId: params.templateId,
parameters: params.parameters,
});
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
async handleCheckCredit() {
const response = await this.axiosInstance.get('/credit');
return {
content: [
{
type: 'text',
text: JSON.stringify(response.data, null, 2),
},
],
};
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('SMS.ir MCP server running on stdio');
}
}
// Create and run server
const server = new SmsIrServer(API_KEY);
await server.run();
} catch (error) {
console.error('Failed to start SMS.ir MCP server:', error);
process.exit(1);
}
};
// Run the main function
main().catch(console.error);