anthropics / anthropics/claude-ai-mcp

Google Calendar MCP: create_event silently drops the location field (update_event sets it fine)

Abierto
#783 0 comentarios 0 reacciones 0 asignados Ver en GitHub
bug
Lenguaje dominante
Sin datos de lenguaje
Estrellas
471
Forks
76
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

### What happened?

The Google Calendar connector's `create_event` tool declares a `location` parameter in its schema ("Optional. Location.", type string), accepts it without complaint, and returns a successful, fully-formed event — but the location is never persisted. The returned event object has no `location` key at all, and a follow-up `get_event` confirms the field was never written. The event shows up in the Google Calendar UI with an empty location.

There is no error, no warning, and no partial-success signal. The call looks like it worked.

### Differential test against an independent client

I created two events on the same calendar, same Google account, 4 seconds apart. One via this connector's `create_event`, one via a separate CLI client running locally under its own OAuth credentials. Then I read both events back with *both* clients:

| Event | Created by | `location` sent | Read by independent CLI | Read by this connector's `get_event` |
|---|---|---|---|---|
| A | **this connector** | `LOCATION-A-SHOULD-BE-HERE` | `""` | *(field absent)* |
| B | independent CLI | `LOCATION-B-SHOULD-BE-HERE` | `LOCATION-B-SHOULD-BE-HERE` | `LOCATION-B-SHOULD-BE-HERE` |

The bottom-right cell is the important one: **this connector reads event B's `location` back correctly.** Its read path and response serialization are demonstrably fine — it just never wrote the field on event A. And an independent client, on a different code path with separate credentials, confirms A's location is genuinely empty in Google, so this isn't the connector misreporting its own work.

The only variable between A and B is which client performed the insert.

### Other explanations ruled out

- **Not a scope or permission problem.** Calling `update_event` on the very same event, with the identical location string, persists it immediately and returns `"location": "Test Location 12345"` — same session, same token.
- **Not calendar-specific.** Reproduced on both the primary calendar and a secondary (shared, `@group.calendar.google.com`) calendar.
- **Not a general "optional fields are ignored" bug.** In the same `create_event` call I also passed `colorId`, `description` and `timeZone` — all three persisted correctly. `location` was the only field dropped.
- **Not an unsupported field at the API level.** Google's [`events.insert` reference](https://developers.google.com/workspace/calendar/api/v3/reference/events/insert) lists `location` (`string`, "Geographic location of the event as free-form text") as **writable** on `insert` — not update-only.

So the write path for `location` appears to be missing specifically in `create_event`, while `update_event` handles it correctly.

### What did you expect to happen?

`create_event` should persist `location` on the new event and include it in the returned event object, exactly as `update_event` does.

If for some reason location cannot be set at creation time, the call should fail with an explicit error — or at minimum return a warning — rather than reporting success while silently discarding a field it advertises in its own schema. A silent drop is the worst case here, because nothing downstream can detect it.

### Steps to reproduce

1. Connect the built-in Google Calendar connector in Claude.
2. Call `create_event`:

```json
{
"summary": "MCP bug repro - safe to delete",
"startTime": "2026-08-05T23:00:00",
"endTime": "2026-08-05T23:30:00",
"timeZone": "UTC",
"location": "Test Location 12345",
"colorId": "5",
"description": "Throwaway event."
}
```

3. The response is `"status": "confirmed"` and contains `colorId`, `description`, `start`, `end`, `summary` — **but no `location` key**.
4. Call `get_event` with the returned `eventId` → still no `location`. The Google Calendar UI shows the event with no location.
5. Call `update_event` with that same `eventId` and the identical `location` string → the response now contains `"location": "Test Location 12345"`.

Reproduced 100% of the time, on both primary and secondary calendars.

### Area

Tool Discovery / Invocation

### MCP Server (if applicable)

Google Calendar (built-in Anthropic connector) — tools create_event, update_event, get_event

### Error messages or logs

```shell
No error is emitted. Payloads below, trimmed and with identifiers redacted.

--- create_event REQUEST (secondary calendar) ---
{
"calendarId": "@group.calendar.google.com",
"summary": "MCP bug repro - safe to delete",
"startTime": "2026-08-05T23:00:00",
"endTime": "2026-08-05T23:30:00",
"timeZone": "UTC",
"location": "Test Location 12345",
"description": "Throwaway event."
}

--- create_event RESPONSE (note: no "location") ---
{
"id": "",
"status": "confirmed",
"summary": "MCP bug repro - safe to delete",
"description": "Throwaway event.",
"start": { "dateTime": "2026-08-05T23:00:00Z", "timeZone": "UTC" },
"end": { "dateTime": "2026-08-05T23:30:00Z", "timeZone": "UTC" },
"eventType": "DEFAULT",
"created": "2026-08-05T20:45:32Z"
}

--- get_event RESPONSE for the same eventId (still no "location") ---
{
"id": "",
"status": "confirmed",
"summary": "MCP bug repro - safe to delete",
...
}

--- create_event RESPONSE, primary calendar, same params + colorId: "5" ---
{
"id": "",
"colorId": "5", <-- optional field, persisted
"description": "Throwaway event on primary calendar.",
"status": "confirmed"
<-- no "location"
}

--- update_event REQUEST (same eventId, same string) ---
{ "eventId": "", "location": "Test Location 12345" }

--- update_event RESPONSE ---
{
"id": "",
"location": "Test Location 12345", <-- works
"status": "confirmed",
"updated": "2026-08-05T20:45:52Z"
}

=== DIFFERENTIAL TEST: same calendar, same account, 4 seconds apart ===

--- Event B, created by an INDEPENDENT CLI client (separate OAuth, separate code path) ---
{
"id": "",
"summary": "TEST B - made by independent client",
"location": "LOCATION-B-SHOULD-BE-HERE", <-- saved
"status": "confirmed",
"created": "2026-08-05T21:23:47.000Z"
}

--- Event A, created by THIS CONNECTOR with the same shape of request ---
{
"id": "",
"summary": "TEST A - made by Claude connector",
"status": "confirmed",
"created": "2026-08-05T21:23:51Z"
<-- no "location"
}

--- CROSS-READ 1: this connector's get_event reading event B ---
{
"id": "",
"summary": "TEST B - made by independent client",
"location": "LOCATION-B-SHOULD-BE-HERE" <-- connector READS location fine
}

--- CROSS-READ 2: independent CLI listing both events ---
{
"count": 2,
"events": [
{ "summary": "TEST A - made by Claude connector", "location": "" },
{ "summary": "TEST B - made by independent client", "location": "LOCATION-B-SHOULD-BE-HERE" }
]
}
```

### Additional context

**Impact.** Every event created through this connector loses its location. The only reliable workaround is create-then-update: call `create_event`, immediately call `update_event` with the same `eventId` and the same `location`, and verify `location` is present in the update response before treating the event as successfully created. That doubles the write calls on every single event and leaves a window in which the event exists on the calendar in a wrong state. Any caller that trusts the success response from `create_event` — as it reasonably should — silently produces events with missing locations.

The silence is the part that bites hardest — because `create_event` returns success and the schema advertises the parameter, nothing short of an explicit read-back catches it.

**This is not the same class of issue as the existing Calendar field requests — please don't triage it as one.** #28919 (`colorId`, added), #156 (`visibility`, open) and #191 (`reminders`, closed "not planned") are all *"this field is absent from the tool schema, please add support for it."* Those are feature requests, and a maintainer can reasonably decline them.

`location` is different: it **is** declared in the `create_event` schema, it **is** accepted without validation error, and the call **reports success** — the value is then discarded. Compare #191, where passing an unsupported field at least produced a loud, honest `Unknown name "reminders": Cannot find field`. That behavior is fine; a caller can see it and react. Here the tool advertises a parameter, takes it, says "confirmed," and drops it. Nothing downstream can detect the failure without an extra read-back. That is a broken contract between the schema and the implementation, not a missing capability.

If `location` genuinely isn't wired into the create path, the minimum correct fix is to reject it the way `reminders` is rejected. The right fix is to persist it, since `update_event` already does.

**Environment:** Claude desktop app, built-in Google Calendar connector, reproduced 2026-08-05.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.