Skip to main content
Glama
palhamel

46elks MCP Server

by palhamel

estimate_sms_cost

Calculate SMS pricing and message segmentation before sending, using recipient number and message content to provide cost estimates.

Instructions

Estimate cost and message segments for SMS without sending it

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fromNoSender phone number or name (optional, uses default if not specified)
messageYesSMS message content to estimate cost for
toYesRecipient phone number with country code (e.g., +46XXXXXXXXX for Swedish numbers)

Implementation Reference

  • Main execution logic for the 'estimate_sms_cost' tool: input validation, dry-run API call via ElksClient for estimation, segment calculation, and formatted response generation.
    case 'estimate_sms_cost':
      const { to: estimateTo, message: estimateMessage, from: estimateFrom } = args as {
        to: string;
        message: string;
        from?: string;
      };
    
      // Validate inputs
      handleValidationError('phone number', validatePhoneNumber(estimateTo));
      const estimateMessageValidation = validateSmsMessage(estimateMessage);
      handleValidationError('message', estimateMessageValidation);
      if (estimateFrom) {
        handleValidationError('sender ID', validateSenderId(estimateFrom));
      }
    
      // Use dry run to get cost estimate
      const elksClientForEstimate = new ElksClient();
      const estimateResponse = await elksClientForEstimate.sendSms(estimateTo, estimateMessage, estimateFrom, true);
      
      const estimatedCost = estimateResponse.estimated_cost ? estimateResponse.estimated_cost / 10000 : 0;
      const messageLength = estimateMessage.length;
      const segments = estimateResponse.parts || (messageLength <= 160 ? 1 : Math.ceil(messageLength / 153));
      
      let costEstimateText = `๐Ÿ’ฐ SMS Cost Estimate\n\n`;
      costEstimateText += `To: ${estimateTo}\n`;
      costEstimateText += `From: ${estimateResponse.from}\n`;
      costEstimateText += `Message length: ${messageLength} characters\n`;
      costEstimateText += `Message segments: ${segments}\n`;
      costEstimateText += `Estimated cost: ${estimatedCost.toFixed(2)} SEK\n\n`;
      
      if (segments > 1) {
        costEstimateText += `โš ๏ธ  Multi-part SMS: This message will be sent as ${segments} parts\n`;
        costEstimateText += `๐Ÿ’ก Tip: Consider shortening to โ‰ค160 characters for single SMS\n\n`;
      }
      
      costEstimateText += `๐Ÿ“ Message preview:\n"${estimateMessage}"\n\n`;
      
      // Add validation warning if present
      if (estimateMessageValidation.warning) {
        costEstimateText += `${estimateMessageValidation.warning}\n\n`;
      }
      
      costEstimateText += `๐Ÿงช This was an estimate only - no SMS was sent`;
      
      return {
        content: [
          {
            type: 'text',
            text: costEstimateText
          }
        ]
      };
  • Input schema and metadata for the 'estimate_sms_cost' tool, defined in the ListTools response.
    {
      name: 'estimate_sms_cost',
      description: 'Estimate cost and message segments for SMS without sending it',
      inputSchema: {
        type: 'object',
        properties: {
          to: {
            type: 'string',
            description: 'Recipient phone number with country code (e.g., +46XXXXXXXXX for Swedish numbers)'
          },
          message: {
            type: 'string',
            description: 'SMS message content to estimate cost for'
          },
          from: {
            type: 'string',
            description: 'Sender phone number or name (optional, uses default if not specified)'
          }
        },
        required: ['to', 'message']
      }
    },
  • src/index.ts:32-149 (registration)
    Registration of all tools including 'estimate_sms_cost' via the ListToolsRequestHandler.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: 'send_sms',
            description: 'Send SMS message via 46elks',
            inputSchema: {
              type: 'object',
              properties: {
                to: {
                  type: 'string',
                  description: 'Recipient phone number with country code - MUST be a real phone number, not a placeholder (e.g., +46XXXXXXXXX for Swedish numbers)'
                },
                message: {
                  type: 'string',
                  description: 'SMS message content (max 160 characters for single SMS)'
                },
                from: {
                  type: 'string',
                  description: 'Sender phone number or name (optional, uses default if not specified)'
                },
                flashsms: {
                  type: 'string',
                  description: 'Set to "yes" for flash SMS that displays immediately and is not stored (optional)'
                },
                dry_run: {
                  type: 'boolean',
                  description: 'Test mode - verify request without sending actual SMS (optional, defaults to environment setting)'
                }
              },
              required: ['to', 'message']
            }
          },
          {
            name: 'get_sms_messages',
            description: 'Retrieve SMS message history from 46elks',
            inputSchema: {
              type: 'object',
              properties: {
                limit: {
                  type: 'number',
                  description: 'Maximum number of messages to retrieve (default: 10, max: 100)',
                  minimum: 1,
                  maximum: 100
                },
                direction: {
                  type: 'string',
                  enum: ['inbound', 'outbound', 'both'],
                  description: 'Filter messages by direction (default: both)'
                }
              },
              required: []
            }
          },
          {
            name: 'check_sms_status',
            description: 'Check delivery status and details of a sent SMS',
            inputSchema: {
              type: 'object',
              properties: {
                message_id: {
                  type: 'string',
                  description: '46elks message ID returned when SMS was sent'
                }
              },
              required: ['message_id']
            }
          },
          {
            name: 'check_account_balance',
            description: 'Check 46elks account balance and account information to verify funds availability for SMS sending',
            inputSchema: {
              type: 'object',
              properties: {},
              required: []
            }
          },
          {
            name: 'estimate_sms_cost',
            description: 'Estimate cost and message segments for SMS without sending it',
            inputSchema: {
              type: 'object',
              properties: {
                to: {
                  type: 'string',
                  description: 'Recipient phone number with country code (e.g., +46XXXXXXXXX for Swedish numbers)'
                },
                message: {
                  type: 'string',
                  description: 'SMS message content to estimate cost for'
                },
                from: {
                  type: 'string',
                  description: 'Sender phone number or name (optional, uses default if not specified)'
                }
              },
              required: ['to', 'message']
            }
          },
          {
            name: 'get_delivery_statistics',
            description: 'Get SMS delivery statistics and success rates from recent messages',
            inputSchema: {
              type: 'object',
              properties: {
                limit: {
                  type: 'number',
                  description: 'Number of recent messages to analyze for statistics (default: 50, max: 100)',
                  minimum: 10,
                  maximum: 100
                }
              },
              required: []
            }
          }
        ]
      };
    });
  • ElksClient.sendSms method that implements dry-run mode (dryrun=yes) for cost estimation without sending actual SMS, used by the tool handler.
    async sendSms(to: string, message: string, from?: string, dryRun?: boolean, flashsms?: string): Promise<SendSmsResponse> {
      const formData = new URLSearchParams({
        to,
        message,
        from: from || this.phoneNumber
      });
    
      // Add dry run parameter if enabled
      const isDryRun = dryRun !== undefined ? dryRun : this.dryRun;
      if (isDryRun) {
        formData.append('dryrun', 'yes');
      }
    
      // Add flash SMS parameter if specified
      if (flashsms === 'yes') {
        formData.append('flashsms', 'yes');
      }
    
      const response = await fetch(`${this.baseUrl}/sms`, {
        method: 'POST',
        headers: {
          'Authorization': this.auth,
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: formData
      });
    
      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`Failed to send SMS: ${response.status} ${response.statusText} - ${errorText}`);
      }
    
      return await response.json();
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses the tool's non-destructive nature ('without sending it'), which is useful behavioral context. However, it lacks details on rate limits, authentication needs, or error handling, leaving gaps for a tool that interacts with billing/systems.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence that efficiently conveys the tool's purpose and key constraint ('without sending it'). There is no wasted verbiage, and every word earns its place in clarifying the tool's function.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (cost estimation with 3 parameters) and no annotations or output schema, the description is adequate but incomplete. It covers the core purpose but lacks details on output format (e.g., cost breakdown, segment count) or prerequisites, which would help an agent use it effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage, so parameters are well-documented there. The description adds no additional parameter semantics beyond implying the tool uses 'message' and 'to' for estimation, which is already clear from the schema. Baseline 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Estimate cost and message segments') and the resource ('SMS'), distinguishing it from sibling tools like 'send_sms' (which sends) and 'check_sms_status' (which checks status). It explicitly mentions 'without sending it' to differentiate from the sending functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context for when to use this tool: to estimate costs before sending an SMS. It implies an alternative ('send_sms' for actual sending) but does not explicitly name it or specify when not to use this tool (e.g., for real-time cost checks vs. historical data).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/palhamel/46elks-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server