Skip to main content
Glama
pshempel

MCP Time Server Node

by pshempel

days_until

Calculate days remaining until a specific date or event using ISO strings, natural language, or Unix timestamps, with optional timezone adjustments and formatted output.

Instructions

Calculate days until a target date/event

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
target_dateYesTarget date (ISO string, natural language, or Unix timestamp)
timezoneNoTimezone for calculation (default: system timezone)
format_resultNoReturn formatted string (e.g., "in 5 days") instead of number (default: false)

Implementation Reference

  • The core handler function `daysUntil` that implements the tool logic: parses target date, handles timezone conversion, calculates calendar days difference using date-fns, applies caching with withCache, optional human-readable formatting, comprehensive validation, and custom MCP error throwing.
    export function daysUntil(params: DaysUntilParams): DaysUntilResult {
      debug.timing('daysUntil called with params: %O', params);
      // Validate required parameter
      if (!params.target_date) {
        debug.error('target_date is required');
        throw new ValidationError('target_date is required', { field: 'target_date' });
      }
    
      // Validate string length first (general limit for very long strings)
      if (typeof params.target_date === 'string') {
        validateStringLength(params.target_date, LIMITS.MAX_STRING_LENGTH, 'target_date');
      }
    
      const { target_date, timezone: userTimezone, format_result = false } = params;
      const { defaultTimezone } = getConfig();
      const timezone = resolveTimezoneUtil(userTimezone, defaultTimezone);
      debug.timezone('Resolved timezone: %s', timezone);
    
      // Use withCache wrapper with CacheTTL.CALCULATIONS (since TTL depends on result)
      return withCache(
        `days_until:${target_date}:${timezone}:${format_result}`,
        CacheTTL.CALCULATIONS,
        () => {
          // Validate timezone if provided
          if (userTimezone !== undefined && !validateTimezone(timezone)) {
            debug.error('Invalid timezone: %s', timezone);
            throw new TimezoneError(`Invalid timezone: ${timezone}`, timezone);
          }
    
          // Parse target date
          let targetDate: Date;
          debug.parse('Parsing target_date: %s', target_date);
          try {
            targetDate = parseTargetDate(target_date, timezone);
            debug.parse('Parsed date: %s', targetDate.toISOString());
          } catch (error) {
            debug.error(
              'Invalid target_date format: %s, error: %s',
              target_date,
              error instanceof Error ? error.message : String(error)
            );
            throw new DateParsingError(`Invalid target_date format: ${target_date}`, {
              target_date,
              error: error instanceof Error ? error.message : String(error),
            });
          }
    
          // Get current date in the specified timezone
          const now = new Date();
          debug.timing('Current time: %s', now.toISOString());
    
          // Convert both dates to the specified timezone for calendar day comparison
          const nowInTimezone = convertToTimezone(now, timezone);
          const targetInTimezone = convertToTimezone(targetDate, timezone);
          debug.timezone('Now in timezone: %s', nowInTimezone.toISOString());
          debug.timezone('Target in timezone: %s', targetInTimezone.toISOString());
    
          // Calculate calendar days difference
          const daysUntil = differenceInCalendarDays(targetInTimezone, nowInTimezone);
          debug.timing('Days until: %d', daysUntil);
    
          let result: DaysUntilResult;
    
          if (format_result) {
            // Format the result as a human-readable string
            result = formatDaysUntil(daysUntil);
            debug.timing('Formatted result: %s', result);
          } else {
            // Return just the number
            result = daysUntil;
          }
    
          return result;
        }
      );
    }
  • Type definitions: `DaysUntilParams` interface for inputs (target_date required as string|number, optional timezone and format_result) and `DaysUntilResult` union type for output (number or formatted string).
    export interface DaysUntilParams {
      target_date: string | number;
      timezone?: string;
      format_result?: boolean;
    }
    
    export type DaysUntilResult = number | string;
  • `formatDaysUntil` helper function converts raw days number to human-readable phrases like 'Today', 'Tomorrow', 'in X days', or 'X days ago'.
    export function formatDaysUntil(days: number): string {
      if (days === 0) return 'Today';
      if (days === 1) return 'Tomorrow';
      if (days === -1) return 'Yesterday';
      if (days > 0) return `in ${days} days`;
      return `${Math.abs(days)} days ago`;
    }
  • `parseTargetDate` helper parses the target_date input (string|number) into a Date object using the shared parseTimeInput utility.
    export function parseTargetDate(target_date: string | number, timezone?: string): Date {
      // Convert to string first for parseTimeInput
      const input = String(target_date);
      return parseTimeInput(input, timezone).date;
    }
  • Re-export of `daysUntil` handler from './daysUntil', aggregating all tools for easy import and registration in the MCP server.
    export { daysUntil } from './daysUntil';
Behavior2/5

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

No annotations are provided, so the description carries full burden for behavioral disclosure. While 'calculate' implies a read-only operation, the description doesn't specify whether this requires permissions, has rate limits, handles errors, or returns structured data. It mentions formatting options but doesn't describe the actual return format or any side effects.

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, efficient sentence that states the core functionality without unnecessary elaboration. Every word earns its place - 'calculate' (verb), 'days until' (measurement), 'target date/event' (resource). There's no fluff or redundant information, making it maximally concise while still being clear.

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?

For a calculation tool with no annotations and no output schema, the description provides adequate basic context about what the tool does. However, it doesn't address important contextual elements like return format (beyond mentioning formatting options), error handling, or how it differs from similar sibling tools. The 100% schema coverage helps, but the description itself is minimal given the tool's complexity.

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?

With 100% schema description coverage, the input schema already documents all three parameters thoroughly. The description adds no additional parameter semantics beyond what's in the schema - it doesn't explain parameter interactions, default behaviors beyond what's in schema descriptions, or edge cases. The baseline 3 is appropriate when the schema does the heavy lifting.

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

Purpose4/5

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

The description clearly states the tool's purpose with a specific verb ('calculate') and resource ('days until a target date/event'). It distinguishes itself from siblings like 'calculate_duration' or 'get_business_days' by focusing on countdown calculations rather than interval measurements or business logic. However, it doesn't explicitly differentiate from 'next_occurrence' which might have overlapping functionality.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. With siblings like 'calculate_duration', 'get_business_days', and 'next_occurrence' that might handle similar date calculations, there's no indication of when this specific countdown calculation is preferred. No prerequisites, exclusions, or comparative context is mentioned.

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/pshempel/mcp-time-server-node'

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