Bowmark turns live websites into typed functions an agent can call. Look up what
exists with get_library, write a short async JavaScript script against thebowmark global, and send it to run. One script can call several sites in
parallel and combine the results, so a multi-site comparison is one call instead
of a long chain of tool calls.
quote, a listing, a schedule.
their own data behind a login).
product across shops).
Do not use it for localhost or private-network targets, open-ended news search
with no destination, local files, plain JSON APIs you can already call, or facts
the model already knows.
A remote MCP connection (Streamable HTTP) with a Bowmark API key:
Endpoint: https://api.bowmark.ai/mcp
Authorization: Bearer <BOWMARK_API_KEY>
The user signs up at https://bowmark.ai/sign-up and creates a key at
https://bowmark.ai/dashboard/keys. Never ask for a key, password or one-time code
in the conversation.
get_library({ query }): query is what you want to do ("flights", "price aGPU") or a company ("Kayak"). It is read-only and touches no site. An
unmatched query returns an index of the library, not an error.
the library returned. bowmark is a global; every function is async.
run({ script }) returns { runId, ok, status, result, logs, error, ms }.Prefer a capability (bowmark.flights.search, several sites, one normalized
shape) over a single provider (bowmark.providers.kayak.search) unless the user
named that site.
The examples assume comparable, numeric prices in the same currency. Verify currency, fees and coverage before calling a result cheapest; disclose missing providers.
const { flights, warnings } = await bowmark.flights.search({ from: "SFO", to: "JFK", depart: "2026-12-01" });
return { cheapest: flights.sort((a, b) => (a.price ?? 1e9) - (b.price ?? 1e9))[0], warnings };
// Sweep three dates in parallel and keep the cheapest of each.
const dates = ["2026-12-01", "2026-12-02", "2026-12-03"];
const runs = await Promise.all(dates.map((depart) => bowmark.flights.search({ from: "SFO", to: "JFK", depart })));
return runs.map((r, i) => ({ depart: dates[i], cheapest: [...r.flights].sort((a, b) => (a.price ?? Infinity) - (b.price ?? Infinity))[0], warnings: r.warnings }));
Branch on status, not ok:
ok: use result.partial: result is real but some calls never answered. Tell the user what is missing.error: read error with logs, fix the script, retry once.needs_user: a site needs the user signed in. Give them the sign-in link fromthe response and wait. Re-sending the same script will stop at the same place.
If a function is missing, wrong or thin, explain the issue. Only send a report when the user explicitly asks for it; show its exact contents first and exclude credentials and private site data.
bowmark is the only I/O inside a script: no fetch, filesystem or imports.get_usage reports spend.Adapted from the Bowmark skill; its MIT license is retained in LICENSE.