Skip to content

M365/Outlook search_emails fails when query already contains quotes #53

@rockfordlhotka

Description

@rockfordlhotka

Summary

search_emails against M365 and Outlook.com providers fails with ODataError: An identifier was expected at position 0. when the agent's query string already contains double-quote characters.

Observed against both providers in production logs (k8s pod calendar-mcp, image 1.2.4) at 2026-05-03 03:55:35 UTC:

[ERR] Error searching emails from M365 account marimer-work with query '\"RockBot Identity Test - Final\"'
[ERR] Error searching emails from Outlook.com account rockyl with query '\"RockBot Identity Test - Final\"'
Microsoft.Graph.Models.ODataErrors.ODataError: An identifier was expected at position 0.

The agent passed the literal string \"RockBot Identity Test - Final\" (already quoted) as query. Both providers then wrap the value in another set of quotes:

  • src/CalendarMcp.Core/Providers/M365ProviderService.cs:168config.QueryParameters.Search = \$\"\\\"{searchQuery}\\\"\";
  • src/CalendarMcp.Core/Providers/OutlookComProviderService.cs:161 — same pattern

Resulting \$search value is \"\"RockBot Identity Test - Final\"\" — adjacent double quotes confuse Microsoft Graph's KQL parser at position 0.

Reproduction

Call search_emails with query set to \"any phrase\" (with leading/trailing quotes) against any M365 or Outlook.com account.

Expected

Search succeeds, treating the inner phrase as the search term.

Suggested fix

Strip surrounding quotes from query (or escape any embedded quotes) before wrapping. Two options:

  1. Trim: `var clean = searchQuery.Trim().Trim('"');` then wrap. Loses the agent's intent if they really wanted nested quotes (rare).
  2. Pass-through if already quoted: detect leading-and-trailing quote pair and pass as-is; only wrap unquoted strings.

Option 1 is simpler and matches what most agents seem to want (treat the whole query as one phrase to find).

Same fix needed in both files. Add a regression test that exercises a quoted query against the M365 provider seam.

Severity

Low — workaround is to send the query without quotes. Affects discoverability of the search_emails tool when an agent gets clever with phrase matching.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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