Skip to main content
Glama
yigitkonur

example-mcp-server-stdio

by yigitkonur

calculate

Perform basic arithmetic calculations with two numbers using addition, subtraction, multiplication, or division operations.

Instructions

Perform a basic arithmetic calculation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
aYesFirst operand
bYesSecond operand
opYesOperation to perform
streamNoIf true, emit progress notifications

Implementation Reference

  • The handler function for the 'calculate' tool. It handles input parameters, optional streaming progress, calls the core calculation helper, manages history, and returns structured output with error handling.
    async ({ a, b, op, stream }, { sendNotification }) => {
      log.info(`Executing calculate: ${a} ${op} ${b}`);
      requestCount++;
    
      try {
        // FEATURE: Progress notifications for streaming calculations
        // WHY: Demonstrates real-time feedback using sendNotification
        if (stream) {
          const progressId = `calc-${Date.now()}`;
          await sendNotification({
            method: 'notifications/progress',
            params: {
              progressToken: progressId,
              progress: 33,
              message: `Calculating ${a} ${op} ${b}`,
            },
          });
          await new Promise((resolve) => setTimeout(resolve, 100));
          await sendNotification({
            method: 'notifications/progress',
            params: { progressToken: progressId, progress: 66 },
          });
          await new Promise((resolve) => setTimeout(resolve, 100));
          await sendNotification({
            method: 'notifications/progress',
            params: { progressToken: progressId, progress: 100, message: 'Complete' },
          });
          await new Promise((resolve) => setTimeout(resolve, 100));
        }
    
        // Core business logic: perform the calculation
        const result = performBasicCalculation(op, a, b);
    
        // Create and store history entry
        const historyEntry = createHistoryEntry(op, a, b, result);
        addToHistory(historyEntry);
    
        // SDK-NOTE: The return object must match the `outputSchema`.
        // The SDK will validate this before sending the response.
        // We provide both a simple text `content` for basic UIs and a
        // `structuredContent` for richer clients.
        return {
          content: [
            {
              type: 'text',
              text: historyEntry.expression,
            },
          ],
          structuredContent: {
            value: result,
            meta: {
              calculationId: historyEntry.id,
              timestamp: historyEntry.timestamp,
            },
          },
        };
      } catch (error) {
        // CAVEAT: We catch the error from our business logic and re-throw it.
        // While `performBasicCalculation` already returns an McpError, this pattern
        // is crucial for wrapping any *unexpected* errors that might occur,
        // preventing stack traces from leaking to the client.
        log.error(`Calculation failed: ${error instanceof Error ? error.message : String(error)}`);
        throw new McpError(
          ErrorCode.InvalidParams,
          `Calculation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
          { operation: op, a, b },
        );
      }
    },
  • Zod input and output schemas for the 'calculate' tool, defining parameters a, b, op (enum of arithmetic operations), optional stream flag, and output value with metadata.
    const calculateInputSchema = {
      a: z.number().describe('First operand'),
      b: z.number().describe('Second operand'),
      op: z.enum(['add', 'subtract', 'multiply', 'divide']).describe('Operation to perform'),
      stream: z.boolean().optional().describe('If true, emit progress notifications'),
    };
    
    const calculateOutputSchema = {
      value: z.number(),
      meta: z.object({
        calculationId: z.string(),
        timestamp: z.string(),
      }),
    };
  • src/server.ts:274-355 (registration)
    Registration of the 'calculate' tool with the MCP server, including title, description, schemas, and handler function.
    server.registerTool(
      'calculate',
      {
        title: 'Calculate',
        description: 'Perform a basic arithmetic calculation',
        inputSchema: calculateInputSchema,
        outputSchema: calculateOutputSchema,
      },
      // HANDLER LOGIC:
      // - Async function, receives validated & typed parameters.
      // - The SDK automatically parses the input against `inputSchema`.
      // - If validation fails, the SDK sends the error; this code doesn't run.
      async ({ a, b, op, stream }, { sendNotification }) => {
        log.info(`Executing calculate: ${a} ${op} ${b}`);
        requestCount++;
    
        try {
          // FEATURE: Progress notifications for streaming calculations
          // WHY: Demonstrates real-time feedback using sendNotification
          if (stream) {
            const progressId = `calc-${Date.now()}`;
            await sendNotification({
              method: 'notifications/progress',
              params: {
                progressToken: progressId,
                progress: 33,
                message: `Calculating ${a} ${op} ${b}`,
              },
            });
            await new Promise((resolve) => setTimeout(resolve, 100));
            await sendNotification({
              method: 'notifications/progress',
              params: { progressToken: progressId, progress: 66 },
            });
            await new Promise((resolve) => setTimeout(resolve, 100));
            await sendNotification({
              method: 'notifications/progress',
              params: { progressToken: progressId, progress: 100, message: 'Complete' },
            });
            await new Promise((resolve) => setTimeout(resolve, 100));
          }
    
          // Core business logic: perform the calculation
          const result = performBasicCalculation(op, a, b);
    
          // Create and store history entry
          const historyEntry = createHistoryEntry(op, a, b, result);
          addToHistory(historyEntry);
    
          // SDK-NOTE: The return object must match the `outputSchema`.
          // The SDK will validate this before sending the response.
          // We provide both a simple text `content` for basic UIs and a
          // `structuredContent` for richer clients.
          return {
            content: [
              {
                type: 'text',
                text: historyEntry.expression,
              },
            ],
            structuredContent: {
              value: result,
              meta: {
                calculationId: historyEntry.id,
                timestamp: historyEntry.timestamp,
              },
            },
          };
        } catch (error) {
          // CAVEAT: We catch the error from our business logic and re-throw it.
          // While `performBasicCalculation` already returns an McpError, this pattern
          // is crucial for wrapping any *unexpected* errors that might occur,
          // preventing stack traces from leaking to the client.
          log.error(`Calculation failed: ${error instanceof Error ? error.message : String(error)}`);
          throw new McpError(
            ErrorCode.InvalidParams,
            `Calculation failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
            { operation: op, a, b },
          );
        }
      },
    );
  • Core helper function that executes the basic arithmetic logic based on the operation type, with validation for division by zero and unknown operations.
    function performBasicCalculation(op: string, a: number, b: number): number {
      switch (op) {
        case 'add':
          return a + b;
        case 'subtract':
          return a - b;
        case 'multiply':
          return a * b;
        case 'divide':
          if (b === 0) throw new McpError(ErrorCode.InvalidParams, 'Division by zero');
          return a / b;
        default:
          throw new McpError(ErrorCode.InvalidParams, `Unknown operation: ${op}`);
      }
    }

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/yigitkonur/example-mcp-server-stdio'

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