Skip to content

query_worker_observability fails to parse cron-triggered Worker events ($workers.outcome is absent) #435

Description

@butchewing

Summary

The observability MCP server (https://observability.mcp.cloudflare.com/mcp) cannot return any cron-triggered Worker event. Its response schema requires $workers.outcome to be a string, but the underlying Cloudflare telemetry API omits that field entirely for eventType: "cron" events. The tool therefore rejects valid data returned by the very API it wraps, and cron/scheduled Worker invocations become unqueryable through MCP.

Reproduce

Any Worker with a [triggers] crons schedule and observability enabled. Call query_worker_observability:

{
  "view": "events",
  "queryId": "repro",
  "limit": 20,
  "dry": false,
  "parameters": {
    "datasets": ["cloudflare-workers"],
    "filters": [
      { "key": "$metadata.service", "operation": "eq", "type": "string", "value": "<worker-name>" },
      { "key": "$metadata.origin",  "operation": "eq", "type": "string", "value": "cron" }
    ]
  },
  "timeframe": { "reference": "<now>", "offset": "-24h" }
}

Actual

Error analyzing worker logs: [
  {
    "code": "invalid_union",
    "errors": [[{ "expected": "string", "code": "invalid_type",
                  "path": ["outcome"],
                  "message": "Invalid input: expected string, received undefined" }]],
    "path": ["result", "events", "events", 0, "$workers"],
    "message": "Invalid input"
  },
  ...
]

Note the error names events[0], events[2], etc. — the events were retrieved; only deserialization fails.

Expected

The cron events are returned, as they are via the REST API.

Root cause

POST /accounts/{account_id}/workers/observability/telemetry/query returns different $workers shapes by event type. Same Worker, same account, same timeframe:

eventType $workers keys outcome
cron truncated, event, scriptName, eventType, scriptVersion, executionModel, requestId absent
fetch event, truncated, scriptName, outcome, eventType, executionModel, scriptVersion, requestId, cpuTimeMs, wallTimeMs "ok"

Cron events also omit cpuTimeMs and wallTimeMs.

The MCP layer's zod schema for $workers requires outcome, so every cron event fails validation. The REST endpoint returns these same events without complaint, which is the workaround (see below).

Suggested fix

Make outcome optional in the $workers schema (and likely cpuTimeMs / wallTimeMs too), or discriminate the schema on eventType.

Impact

Cron-triggered Workers cannot be observed through MCP at all. This matters for scheduled jobs, where the log line emitted by the scheduled() handler is often the only record that the job ran and what it decided — there is no request/response to inspect, and wrangler tail only shows live traffic, so a missed window is unrecoverable.

Secondary note

$metadata.origin for cron-triggered events is "cron", not "scheduled". Filtering on "scheduled" returns an empty array rather than an error, which is indistinguishable from "the cron never fired" — a misleading result when debugging a scheduled job. Worth documenting in the tool description alongside the existing $metadata.origin guidance.

Workaround

Query the REST API directly; it returns the events correctly:

POST /accounts/{account_id}/workers/observability/telemetry/query
{
  "queryId": "…", "view": "events", "limit": 25, "dry": false,
  "parameters": {
    "datasets": ["cloudflare-workers"],
    "filters": [
      { "id": "1", "key": "$metadata.service", "operation": "eq", "type": "string", "value": "<worker>" },
      { "id": "2", "key": "$metadata.origin",  "operation": "eq", "type": "string", "value": "cron" }
    ],
    "calculations": [], "groupBys": [], "havings": []
  },
  "timeframe": { "from": <epoch-ms>, "to": <epoch-ms> }
}

(The REST endpoint wants numeric epoch-ms from/to and id on each filter; the MCP tool accepts ISO strings and omits id.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions