Skip to main content
Glama

Calendar Week View

calendar_week_view
Read-onlyIdempotent

Display a weekly calendar with events for any 7-day period, starting from a specified date.

Instructions

Display an interactive calendar week view showing events for a 7-day period.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
startDateNoStart date (YYYY-MM-DD). Defaults to current week's Monday.

Implementation Reference

  • The async handler function for calendar_week_view. It computes the week start via getWeekMonday, queries Apple Calendar events using listEventsScript, and returns a JSON response with weekStart and events array.
    async ({ startDate }) => {
      const weekStart = getWeekMonday(startDate);
      const weekEnd = new Date(weekStart);
      weekEnd.setDate(weekEnd.getDate() + 7);
      const endStr = weekEnd.toISOString().slice(0, 10);
      const raw = await runJxa(listEventsScript(weekStart, endStr, 50, 0));
      const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
      return {
        content: [
          {
            type: "text" as const,
            text: JSON.stringify({ weekStart, events: parsed.events ?? [] }),
          },
        ],
      };
    },
  • The tool registration with input schema and metadata. The schema accepts an optional startDate string (YYYY-MM-DD). Annotations mark it as read-only, idempotent, non-destructive. Metadata links to a UI resource 'ui://airmcp/calendar-week'.
    registerAppTool(
      s,
      "calendar_week_view",
      {
        title: "Calendar Week View",
        description: "Display an interactive calendar week view showing events for a 7-day period.",
        inputSchema: {
          startDate: z
            .string()
            .max(64)
            .optional()
            .describe("Start date (YYYY-MM-DD). Defaults to current week's Monday."),
        },
        annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
        _meta: { ui: { resourceUri: "ui://airmcp/calendar-week" } },
      },
  • The tool is registered inside the 'registerApps' function under the 'if (opts.calendar)' block. It uses registerAppTool from @modelcontextprotocol/ext-apps/server to bind the name 'calendar_week_view' to its schema and handler.
    if (opts.calendar) {
      // Calendar Week View
      registerAppTool(
        s,
        "calendar_week_view",
        {
          title: "Calendar Week View",
          description: "Display an interactive calendar week view showing events for a 7-day period.",
          inputSchema: {
            startDate: z
              .string()
              .max(64)
              .optional()
              .describe("Start date (YYYY-MM-DD). Defaults to current week's Monday."),
          },
          annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
          _meta: { ui: { resourceUri: "ui://airmcp/calendar-week" } },
        },
        async ({ startDate }) => {
          const weekStart = getWeekMonday(startDate);
          const weekEnd = new Date(weekStart);
          weekEnd.setDate(weekEnd.getDate() + 7);
          const endStr = weekEnd.toISOString().slice(0, 10);
          const raw = await runJxa(listEventsScript(weekStart, endStr, 50, 0));
          const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
          return {
            content: [
              {
                type: "text" as const,
                text: JSON.stringify({ weekStart, events: parsed.events ?? [] }),
              },
            ],
          };
        },
      );
  • Helper function getWeekMonday computes the Monday of the week for a given date string (or current date). It handles Sunday edge-case (Sunday -> Monday of previous week) and returns YYYY-MM-DD using local date parts to avoid UTC timezone shifts.
    function getWeekMonday(dateStr?: string): string {
      const d = dateStr ? new Date(dateStr + "T00:00:00") : new Date();
      const day = d.getDay();
      const diff = d.getDate() - day + (day === 0 ? -6 : 1);
      d.setDate(diff);
      // Use local date parts — toISOString() returns UTC which shifts dates in UTC+ timezones
      const yyyy = d.getFullYear();
      const mm = String(d.getMonth() + 1).padStart(2, "0");
      const dd = String(d.getDate()).padStart(2, "0");
      return `${yyyy}-${mm}-${dd}`;
    }
  • The listEventsScript function generates JXA (JavaScript for Automation) code to query Apple Calendar events within a date range. It's called by the handler with weekStart, endStr, limit=50, offset=0, and no specific calendar filter. Returns a script string that when executed returns JSON with events array.
    export function listEventsScript(
      startDate: string,
      endDate: string,
      limit: number,
      offset: number,
      calendar?: string,
    ): string {
      if (calendar) {
        return `
          const Calendar = Application('Calendar');
          const cals = Calendar.calendars.whose({name: '${esc(calendar)}'})();
          if (cals.length === 0) throw new Error('Calendar not found: ${esc(calendar)}');
          const cal = cals[0];
          const start = new Date('${esc(startDate)}');
          const end = new Date('${esc(endDate)}');
          const events = cal.events.whose({
            _and: [{startDate: {_greaterThanEquals: start}}, {startDate: {_lessThanEquals: end}}]
          })();
          const total = events.length;
          const s = Math.min(${offset}, total);
          const e = Math.min(s + ${limit}, total);
          const result = [];
          for (let i = s; i < e; i++) {
            const ev = events[i];
            result.push({
              id: ev.uid(),
              summary: ev.summary(),
              startDate: ev.startDate().toISOString(),
              endDate: ev.endDate().toISOString(),
              allDay: ev.alldayEvent(),
              calendar: '${esc(calendar)}'
            });
          }
          JSON.stringify({total: total, offset: s, returned: result.length, events: result});
        `;
      }
      return `
        const Calendar = Application('Calendar');
        const cals = Calendar.calendars();
        const start = new Date('${esc(startDate)}');
        const end = new Date('${esc(endDate)}');
        const all = [];
        for (const cal of cals) {
          const filtered = cal.events.whose({
            _and: [{startDate: {_greaterThanEquals: start}}, {startDate: {_lessThanEquals: end}}]
          });
          const count = filtered.length;
          if (count === 0) continue;
          const eUids = filtered.uid();
          const eSummaries = filtered.summary();
          const eStarts = filtered.startDate();
          const eEnds = filtered.endDate();
          const eAllDay = filtered.alldayEvent();
          const calName = cal.name();
          const safe = Math.min(count, eUids.length, eSummaries.length, eStarts.length, eEnds.length, eAllDay.length);
          for (let i = 0; i < safe; i++) {
            if (eUids[i] == null || eStarts[i] == null || eEnds[i] == null) continue;
            all.push({
              id: eUids[i], summary: eSummaries[i] || '',
              startDate: eStarts[i].toISOString(), endDate: eEnds[i].toISOString(),
              allDay: eAllDay[i] ?? false, calendar: calName
            });
          }
        }
        all.sort((a, b) => new Date(a.startDate) - new Date(b.startDate));
        const total = all.length;
        const s = Math.min(${offset}, total);
        const e = Math.min(s + ${limit}, total);
        JSON.stringify({total: total, offset: s, returned: e - s, events: all.slice(s, e)});
      `;
    }
Behavior3/5

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

Annotations already provide read-only and idempotent hints. The description adds minimal behavioral context (e.g., 'interactive'), but does not contradict annotations. It does not elaborate on what 'interactive' entails or the output format.

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?

Single sentence, 12 words, no fluff. Efficiently conveys the tool's purpose without unnecessary details.

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

Completeness4/5

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

For a simple read-only tool with one optional param and annotations, the description is mostly complete. However, it could elaborate on the return type (e.g., HTML, JSON) or what 'interactive' means. Nonetheless, it suffices for basic understanding.

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?

Schema coverage is 100% with a clear description for startDate. The description does not add parameter details beyond what the schema provides, which is acceptable given high coverage.

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?

Description clearly states the tool displays an interactive calendar week view for a 7-day period. It distinguishes itself from sibling tools like list_events (list format) and get_upcoming_events (upcoming events) by specifying a calendar view.

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?

No guidance on when to use this tool versus alternatives. For example, it doesn't mention that list_events or search_events might be better for specific querying. The description lacks any context about prerequisites or when not to use it.

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/heznpc/AirMCP'

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