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:168 — config.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:
- Trim: `var clean = searchQuery.Trim().Trim('"');` then wrap. Loses the agent's intent if they really wanted nested quotes (rare).
- 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.
Summary
search_emailsagainst M365 and Outlook.com providers fails withODataError: 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, image1.2.4) at 2026-05-03 03:55:35 UTC:The agent passed the literal string
\"RockBot Identity Test - Final\"(already quoted) asquery. Both providers then wrap the value in another set of quotes:src/CalendarMcp.Core/Providers/M365ProviderService.cs:168—config.QueryParameters.Search = \$\"\\\"{searchQuery}\\\"\";src/CalendarMcp.Core/Providers/OutlookComProviderService.cs:161— same patternResulting
\$searchvalue is\"\"RockBot Identity Test - Final\"\"— adjacent double quotes confuse Microsoft Graph's KQL parser at position 0.Reproduction
Call
search_emailswithqueryset 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: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_emailstool when an agent gets clever with phrase matching.