Skip to content

get_calendar_events throws "accountId is required" where sibling read tools default to all accounts #59

Description

@rockfordlhotka

Summary

get_calendar_events throws accountId is required when accountId (and calendarId) are omitted, even though accountId is declared optional in the tool schema and the analogous read tool search_emails handles the same case by querying all accounts. This is an inconsistency that reads as a bug: a caller following the schema (and the server's own prompt guidance) gets a hard error.

Impact

Observed downstream in a consuming agent: accountId is required on get_calendar_events was the single largest tool-call failure over a recent 14-day window (~30 occurrences, ~55% of that agent's structural failures). The model isn't misbehaving — it's treating accountId as optional, which the schema and a sibling tool both say it is.

Root cause

accountId is declared optional on the tool method, so the SDK-generated input schema does not mark it required:

// GetCalendarEventsTool.cs:26
[Description("Account ID to query. Obtain from list_accounts. Required unless calendarId uniquely identifies a single account.")] string? accountId = null,

The "required" is enforced only at runtime, by a throw:

// GetCalendarEventsTool.cs:34-37
if (string.IsNullOrEmpty(accountId))
{
    if (string.IsNullOrEmpty(calendarId))
        throw new McpException("accountId is required");
    ...
}

The sibling read tool does the opposite — omitting accountId queries all accounts:

// SearchEmailsTool.cs:36-41
if (string.IsNullOrEmpty(accountId))
{
    validAccounts = (await accountRegistry.GetAllAccountsAsync()).ToList();
    if (validAccounts.Count == 0)
        throw new McpException("No accounts found");
}

get_calendar_events already has the same multi-account machinery (a validAccounts list queried via Task.WhenAll with per-account warning aggregation) — it's just artificially restricted to a single account and throws when none is supplied.

The server's own prompt also assumes the all-accounts behavior, contradicting the tool:

// CalendarPrompts.cs:22 (daily_briefing)
2. Call get_calendar_events with timeZone="...", startDate=today, endDate=today for each account (or omit accountId to query all at once).

Proposed fix

Make calendar read tools mirror search_emails: when accountId (and calendarId) are omitted, query all enabled calendar-capable accounts instead of throwing. For get_calendar_events this is a small change — set validAccounts to all enabled accounts in the empty-accountId branch rather than throwing.

Keep write / targeted tools (respond_to_event, create_event, move_email) requiring an explicit accountId — guessing an account for a write is unsafe, and the respond_to_invite prompt already enforces this ("defaulting to the first account often picks the wrong calendar").

Scope / audit

  • get_calendar_events — default to all enabled accounts when accountId/calendarId omitted (primary fix).
  • Audit other read tools for the same throw-vs-query-all inconsistency: get_emails, list_calendars, get_contextual_email_summary, get_contacts.
  • Confirm write/targeted tools still require accountId.

Related (separate, lower priority)

get_email_details and get_calendar_event_details read a specific item by an account-scoped id, so they legitimately require accountId. Upstream search_emails/get_calendar_events results already return accountId per item; the gap there is callers carrying that paired accountId forward (or an id-fallback search). Tracking here only for context — not part of this fix.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions