<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nickitico</title>
    <description>The latest articles on DEV Community by Nickitico (@nicholasemccormick).</description>
    <link>https://dev.to/nicholasemccormick</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3852587%2Fa72ff2b2-f9ed-44be-b51b-3bd958f5c711.png</url>
      <title>DEV Community: Nickitico</title>
      <link>https://dev.to/nicholasemccormick</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nicholasemccormick"/>
    <language>en</language>
    <item>
      <title>Why AI agents fail at scheduling (and how to fix it)</title>
      <dc:creator>Nickitico</dc:creator>
      <pubDate>Tue, 31 Mar 2026 02:39:45 +0000</pubDate>
      <link>https://dev.to/nicholasemccormick/why-ai-agents-fail-at-scheduling-and-how-to-fix-it-257h</link>
      <guid>https://dev.to/nicholasemccormick/why-ai-agents-fail-at-scheduling-and-how-to-fix-it-257h</guid>
      <description>&lt;p&gt;Your AI agent can draft emails, search the web, summarize a 40-page PDF, and write code. Then someone asks it to "find a time with Sarah and James next week" and it confidently books a slot during Sarah's all-hands meeting.&lt;br&gt;
This isn't a reasoning failure. The LLM didn't get confused. It's an API design problem — calendar APIs were built for humans navigating UIs, not for agents making sequential tool calls. And the gap between what those APIs expose and what an agent needs to do reliable scheduling is wider than it looks.&lt;/p&gt;

&lt;p&gt;The real reason: calendar APIs aren't built for agents&lt;br&gt;
To find mutual availability for two people using raw Google Calendar or Outlook, an agent has to:&lt;/p&gt;

&lt;p&gt;Authenticate with OAuth for each person (more on this in a moment)&lt;br&gt;
Fetch each person's calendar events for the target week&lt;br&gt;
Parse the free/busy data into usable windows&lt;br&gt;
Cross-reference working hours per timezone&lt;br&gt;
Apply buffer preferences (no back-to-back meetings, no 8am calls)&lt;br&gt;
Rank the resulting slots by quality&lt;br&gt;
Handle pagination if there are many events&lt;br&gt;
Present options in a format the user can act on&lt;/p&gt;

&lt;p&gt;That's 6–8 steps of stateful tool calls before a single time is suggested. Each step is a new opportunity to hallucinate or fail silently.&lt;br&gt;
Most agents either skip steps and guess, or collapse under the complexity of multi-party coordination. Add a third person across a different timezone and the combinatorial complexity quickly exceeds what fits cleanly in a single agent loop.&lt;br&gt;
There are four specific failure modes:&lt;/p&gt;

&lt;p&gt;OAuth redirect flows — agents can't click "Allow." Every major calendar API requires a browser-based OAuth flow that's simply incompatible with agentic tool use.&lt;br&gt;
Raw free/busy without scoring — the API gives you busy blocks, not ranked availability. The agent has to invent its own ranking logic or just pick the first open slot.&lt;br&gt;
Timezone math — LLMs are notoriously unreliable at timezone arithmetic. A slot that looks available in UTC might be 11pm for one participant.&lt;br&gt;
Multi-party coordination — four people across three timezones isn't just harder, it's categorically different. The intersection of constraints doesn't fit neatly into a prompt.&lt;/p&gt;

&lt;p&gt;What a scheduling API for agents actually looks like&lt;br&gt;
The fix isn't a smarter agent — it's an API designed around how agents actually work.&lt;br&gt;
MeetSync is a scheduling API built on four principles:&lt;br&gt;
API key auth, not OAuth. A single header: X-API-Key: your-key. No redirect flows, no token refresh, no browser required.&lt;br&gt;
Explicit timezone offsets in every field. Every datetime in every response includes a full ISO 8601 offset — 2025-09-22T10:00:00-04:00, not 10:00:00. The agent never has to infer a timezone.&lt;br&gt;
UUIDs as stable references. Participants, proposals, and bookings are identified by UUIDs throughout. The agent can reference the same entity across multiple tool calls without re-fetching or re-resolving names.&lt;br&gt;
Scored slot output. Instead of raw free/busy data, findMutualAvailability returns ranked slots with a 0–1 score combining working hours fit (0.5), buffer preference fit (0.3), and daily meeting load (0.2). The agent picks from a ranked list — it doesn't compute one.&lt;br&gt;
Error responses include a code, message, and details field that tells the agent exactly what failed and how to fix it — not a generic 400.&lt;/p&gt;

&lt;p&gt;Five tool calls from "schedule a meeting" to confirmed booking&lt;br&gt;
Here's what the full flow looks like when an agent receives: "Schedule a 30-minute call with Sarah and James next week."&lt;br&gt;
Call 1 — Register participants (if not already registered)&lt;br&gt;
createParticipant → { id: "sarah-uuid", name: "Sarah", email: "&lt;a href="mailto:sarah@"&gt;sarah@&lt;/a&gt;..." }&lt;br&gt;
createParticipant → { id: "james-uuid", name: "James", email: "&lt;a href="mailto:james@"&gt;james@&lt;/a&gt;..." }&lt;br&gt;
Call 2 — Find mutual availability&lt;br&gt;
json// Tool call&lt;br&gt;
{&lt;br&gt;
  "tool": "findMutualAvailability",&lt;br&gt;
  "input": {&lt;br&gt;
    "participantIds": ["sarah-uuid", "james-uuid"],&lt;br&gt;
    "durationMinutes": 30,&lt;br&gt;
    "startDate": "2025-09-22",&lt;br&gt;
    "endDate": "2025-09-26",&lt;br&gt;
    "limit": 5&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// Response&lt;br&gt;
{&lt;br&gt;
  "slots": [&lt;br&gt;
    { "start": "2025-09-22T10:00:00-04:00", "end": "2025-09-22T10:30:00-04:00", "score": 0.91 },&lt;br&gt;
    { "start": "2025-09-22T14:00:00-04:00", "end": "2025-09-22T14:30:00-04:00", "score": 0.84 },&lt;br&gt;
    { "start": "2025-09-23T11:00:00-04:00", "end": "2025-09-23T11:30:00-04:00", "score": 0.79 }&lt;br&gt;
  ]&lt;br&gt;
}&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
One call. Ranked results. No availability reasoning required from the agent.

**Call 3 — Confirm with the user, then book**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;createBooking → {&lt;br&gt;
  organizerParticipantId: "sarah-uuid",&lt;br&gt;
  participantIds: ["james-uuid"],&lt;br&gt;
  startTime: "2025-09-22T10:00:00-04:00",&lt;br&gt;
  endTime: "2025-09-22T10:30:00-04:00"&lt;br&gt;
}&lt;br&gt;
The agent's job throughout is orchestration — not reasoning about calendars. The API handles all the availability intelligence.&lt;/p&gt;

&lt;p&gt;Setting it up: MCP server, Claude tool use, LangChain&lt;br&gt;
There are three ways to connect MeetSync to your agent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MCP server (Claude Desktop and any MCP-compatible agent)
bashnpx mcp-meetsync
Set MEETSYNC_API_URL and MEETSYNC_API_KEY as environment variables and all 19 endpoints are immediately available as named tools. No code required.&lt;/li&gt;
&lt;li&gt;Claude tool use (TypeScript)
Define the tools using the JSON schemas in docs/tool-definition.md and pass them to the Anthropic client. The full TypeScript agentic loop is in the tutorial.&lt;/li&gt;
&lt;li&gt;LangChain (Python)
Three @tool functions wrapping the MeetSync endpoints, passed to create_tool_calling_agent. The full Python example with AgentExecutor is in the tutorial.
Copy-paste definitions for all three are in docs/tool-definition.md.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The proposal workflow: let participants vote before booking&lt;br&gt;
Sometimes the agent is acting on behalf of an organizer who can't commit for the invitees. In that case, use the proposal workflow instead of booking directly.&lt;br&gt;
It's two extra tool calls: createProposal with a set of candidate slots, then respondToProposal once per participant to record their preference. Once all participants have accepted the same slot, the proposal moves to accepted and you call createBooking with the proposalId and acceptedSlotId.&lt;br&gt;
This is useful for external meetings, cross-team scheduling, or any situation where the agent shouldn't make the final commitment unilaterally.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
Scheduling fails in agents because the APIs were built for humans. The fix is an API that does the availability intelligence — auth, timezone normalization, slot scoring, error explanations — so the agent only has to orchestrate tool calls and talk to the user.&lt;br&gt;
MeetSync is that API.&lt;/p&gt;

&lt;p&gt;Install: npx mcp-meetsync&lt;br&gt;
Full tutorial (worked example, Claude TypeScript + LangChain Python): github.com/nicholasemccormick/mcp-meetsync/docs/tutorial.md&lt;br&gt;
API reference: github.com/nicholasemccormick/mcp-meetsync/docs/README.md&lt;/p&gt;

&lt;p&gt;Questions or feedback? Drop them in the comments — happy to help if you're building something similar.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>mcp</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
