---
title: "FootyCal: adding WebMCP | James Donnelly"
description: "Adding browser tools to FootyCal after OpenAI introduced WebMCP support in Codex and ChatGPT Work."
canonical_url: "https://jamesdonnelly.au/blog/2026-09-14-footycal-webmcp"
markdown_url: "https://jamesdonnelly.au/blog/2026-09-14-footycal-webmcp.md"
last_updated: "2026-09-14T00:00:00.000Z"
---

# FootyCal: adding WebMCP

Adding browser tools to FootyCal after OpenAI introduced WebMCP support in Codex and ChatGPT Work.

Published 2026-09-14.

OpenAI added [WebMCP support to the built-in browser used by Codex and ChatGPT Work](https://learn.chatgpt.com/docs/webmcp). That prompted me to add it to [FootyCal](https://footycal.au).

FootyCal takes a few preferences and produces a calendar URL, so there was an obvious function to expose. The homepage now registers two tools: `list_subscription_options` and `prepare_subscription`.

The registration for the second looks like this, with the error handling omitted and the description shortened:

```js
import { prepareSubscription, subscriptionSchema } from './subscriptions';

if (typeof document.modelContext?.registerTool === 'function') {
  await document.modelContext.registerTool({
    name: 'prepare_subscription',
    description: 'Return an AFL calendar URL for the given preferences.',
    inputSchema: subscriptionSchema,
    annotations: { readOnlyHint: true },
    execute: async input => prepareSubscription(input),
  });
}
```

The browser makes the tool's name, description and input schema available to the agent. When it calls the tool, the browser runs `execute` in the page and returns the result.

An agent can first call `list_subscription_options` to get the valid teams, venues, cities and defaults. For a request like "St Kilda away games in Melbourne or Geelong, with full team names", it can then call `prepare_subscription` with:

```json
{
  "scope": "team",
  "team": "saints",
  "filter": "away",
  "cities": ["melbourne", "geelong"],
  "names": "full"
}
```

`prepareSubscription` validates the arguments and builds the URL. Unknown teams and unsupported combinations return errors. Both tools run locally in the page; subscribing to the returned URL is the caller's responsibility.

I also exposed the same functions through `GET /api/subscriptions/options` and `POST /api/subscriptions/prepare`. Those use the same validation and work for agents without a WebMCP browser.

I'm curious whether this gets any use. WebMCP is still experimental, and using it means having an agent visit the site in a supporting browser. I haven't added tracking for the browser tool calls, so I don't have a usage figure. For now I wanted to see what was involved in supporting it.

## Sitemap

See the full [site map](/sitemap.md).
