Skip to content

Preload & Caching

Some tools return data that barely moves — a full list of hospitals in a country, every memorial stone in a city, a reference table that is refreshed once a week. Re-fetching such a dataset on every call costs bandwidth and time for no benefit. The optional preload field lets a schema author declare that a tool’s response is safe to cache and for how long, so a runtime can serve a stored copy instead of hitting the network each time. Caching always stays optional on the runtime’s side: preload expresses intent, and the runtime decides whether to honour it. The sections below specify the field, its validation rules, the cache key derivation, the runtime cache flow, and the author guidelines for choosing a sensible time-to-live.


preload is an optional object on route level, alongside method, path, description, parameters, output, and tests.

routes: {
getLocations: {
method: 'GET',
path: '/locations.json',
description: 'All hospital locations in Germany',
parameters: [],
preload: {
enabled: true,
ttl: 604800,
description: 'All hospital locations in Germany (~760KB)'
},
output: { /* ... */ },
tests: [ /* ... */ ]
}
}
FieldTypeRequiredDescription
enabledbooleanYesWhether caching is allowed for this route. Must be true to activate caching.
ttlnumberYesCache time-to-live in seconds. Must be a positive integer.
descriptionstringNoHuman-readable note shown on cache hit (e.g. dataset size, update frequency).
  • enabled: true signals that the route’s response is safe to cache. The runtime decides whether to actually cache (caching is always optional).
  • enabled: false explicitly disables caching even if present. Equivalent to omitting preload entirely.
  • ttl defines the maximum age of a cached response in seconds before it must be re-fetched. Common values:
TTLDurationUse Case
36001 hourFrequently updated data
864001 dayDaily snapshots
6048001 weekWeekly releases, semi-static data
259200030 daysStatic reference data

These rules extend the validation rule set indexed in 09-validation-rules.md:

CodeSeverityRule
VAL060errorIf preload is present, it must be a plain object.
VAL061errorpreload.enabled must be a boolean.
VAL062errorpreload.ttl must be a positive integer (> 0).
VAL063warningpreload.description if present MUST be a string.
VAL064infoRoutes with preload.enabled: true and no parameters are ideal cache candidates.
VAL065warningRoutes with preload.enabled: true and required parameters SHOULD document caching behavior — the cache key MUST include parameter values.

When a route has parameters, the cache key MUST include the parameter values to avoid serving stale data for different inputs. The recommended cache key format is:

{namespace}/{routeName}/{paramHash}.json

Where paramHash is a deterministic hash of the sorted, JSON-serialized user parameters.

For routes with no parameters (or only optional parameters that were omitted), the cache key simplifies to:

{namespace}/{routeName}.json

The recommended cache directory is ~/.flowmcp/cache/. Each cached response is stored as a JSON file with metadata:

{
"meta": {
"fetchedAt": "2026-02-17T12:00:00.000Z",
"expiresAt": "2026-02-24T12:00:00.000Z",
"ttl": 604800,
"size": 760123,
"paramHash": null
},
"data": { }
}

No

Yes

No

Yes

No

Yes

flowmcp call tool-name

preload.enabled?

Normal fetch

Cache file exists?

Fetch + store in cache

Cache expired?

Return cached response

Return fresh response

Runtimes SHOULD support these override mechanisms:

FlagBehavior
--no-cacheSkip cache entirely, always fetch fresh
--refreshFetch fresh and update cache

Runtimes SHOULD provide cache management:

CommandDescription
cache statusList all cached responses with size, age, expiry
cache clearRemove all cached responses
cache clear {namespace}Remove cached responses for a specific namespace
EventMessage
Cache hitCached (fetched: {date}, expires: {date})
Cache missFetching fresh data...Cached for {ttl human}
Cache expiredCache expired, refreshing...
Force refreshRefreshing cache...

Use preload when:

  • The endpoint returns a complete, static or slow-changing dataset
  • The response is larger than ~10KB
  • The data doesn’t change based on time-of-day or real-time events
  • Multiple calls with the same parameters return identical results

Do not use preload when:

  • The data changes frequently (live prices, real-time feeds)
  • The response depends on authentication state
  • The endpoint has rate limits that make caching counterproductive (use rate limiting instead)

Yes

No

Yes

No

Yes

No

How often does this data change?

Daily or more?

ttl: 3600-86400

Weekly?

ttl: 604800

Monthly or less?

ttl: 2592000

Don't use preload


Handlers (preRequest, postRequest) still execute on cached data. The cache stores the raw API response before postRequest transformation. This ensures handler logic always runs on the most appropriate data format.

Alternative (simpler): Cache the final transformed response after postRequest. This avoids re-running handlers on every cache hit but requires cache invalidation when handler logic changes.

Runtimes SHOULD document which approach they use.

Tool tests (see 10-tests.md) always bypass the cache to ensure they exercise the live API. The --no-cache flag is implied during test execution.

The output schema (see 04-output-schema.md) describes the response shape regardless of whether the response comes from cache or a live fetch. Caching does not affect the output contract.