worklore-mcp
An MCP (Model Context Protocol) connector for worklore.dev —
it lets any MCP-capable agent (Claude, ChatGPT, Cursor, …) search worklore's
developer stories, read one with its capability disclosure attached, x-ray any
skill or story before running it — all without an account — and, once you've
signed in, record how a reproduction went, publish a story of your own, or revise
one you published.
- Endpoint:
https://worklore.dev/mcp (Streamable HTTP, JSON-RPC over POST)
- Auth: none to search and read public stories. Writes (and your private
stories) use OAuth 2.1 (PKCE + dynamic client registration). Sign-in is with your
GitHub public profile only — worklore sees your handle and avatar, no
scopes, no email, no repositories.
- Listed on: the official MCP Registry
as
io.github.worklore/worklore, and Smithery
- Roadmap / progress: Project #1
(a "Relay Board" — the human does the site actions, the agent writes the code)
What it's for
worklore stories are text your agent executes. This connector brings them —
and their capability tier — into your agent, so you can find relevant work and
see what it can touch before you run it. Tiers describe reach (blast radius),
not virtue, and this is never a "safe" verdict. See the write-up:
Stop asking "is this skill safe?" — ask "what can it do?"
and the tool it wraps, skill-xray.
Capability tiers: T0 inert · T1 local · T2 network · T3 elevated
(secrets / persistence / privilege) · T4 opaque (fetches/runs code at runtime).
Tools
Read-only — no sign-in needed (public stories only; check_capability with a
url needs sign-in, because the server fetches it for you):
Write — these act as you, and need your authenticated session:
All eight carry MCP annotations (readOnlyHint / openWorldHint / idempotentHint)
so a client can tell the user what a call will do before they approve it, and all
eight declare an outputSchema and return structuredContent, so a consuming agent
can rely on shape instead of parsing prose.
Every result carries a human capability string (e.g. T0 · inert — touches nothing) so a tier code is never shown bare.
Resources
Since 0.6.0 resources/list is a fixed list of three documents — the same
for everyone, every day — all readable without an account:
Stories are reached through one resource template, worklore://story/{slug}
(resources/templates/list). Public stories read without a token; a private
story reads only for its author and answers like a missing one to everyone else.
Every worklore://story/… URI that resources/list handed out before 0.6.0
still reads. To find a story, use search_stories / suggest_for_project.
Why the stories left the list: a list that changes whenever someone publishes
cannot be part of a surface fingerprint — the fingerprint would "break" every day
without anything breaking, and teach clients to ignore a mismatch. The contents
of the three documents may change between releases; the list entries may not
without a new version.
Verify the surface yourself
A version number is a promise that nothing a client depends on changed without
it. Since 0.6.0 worklore publishes its surface fingerprint in the shared form
mcp-surface/1 (SPEC,
by Sidney Bissoli), so you check worklore exactly the way you check every other
server that publishes it. The registry entry carries it in server.json under
_meta → io.modelcontextprotocol.registry/publisher-provided →
io.github.sidneybissoli/mcp-surface:
declared.sha256 — the sha256 of what a client sees before it calls anything:
the initialize result (protocol version, capabilities, instructions,
serverInfo without its version) and the four lists (tools, resources, resource
templates, prompts), normalised and serialised as the SPEC says;
anonymous — which methods answer without a token (plus one named,
harmless tools/call: check_capability on inline text), and its sha256.
The fastest check is Sidney's dependency-free
verify.mjs
(Node 18+). It reads the registry entry for the version, makes sure the endpoint
can say "no" to a method that does not exist, captures the live surface, and
compares:
Or in Python, with nothing installed (the declared hash only):
If the version is the same and the hash differs, the server changed without
saying so. Tell me in an issue. 0.5.1 published worklore's own per-section
hashes under a surface key; 0.6.0 replaced them with this one shared format.
The idea of publishing the fingerprint with each release came from a comment by
@_firelinks under Sidney Bissoli's
Your MCP server changed. Its version didn't.
What answers without a token
Since 0.5.0 one rule decides it, everywhere — the site, the REST API and this
server alike. It lives as a single table in worklore's backend (access.py,
rendered as docs/ACCESS.md); the summary below is generated from it.
The rule. Anyone can search and read all public stories without signing in — site, REST API and MCP alike. Private stories and every write (publish, edit, report a reproduction or a check, visibility, per-user data, anything acting as a person) need a signed-in session. Anonymous reads go through the single visibility rule, so a private story answers exactly like a missing one. Anything that costs worklore on someone else's behalf — the server fetching an arbitrary URL — needs a session too, unless the input is inline text.
- Methods with no credential:
initialize, notifications/initialized, notifications/cancelled, ping, tools/list, resources/list, resources/read, resources/templates/list, prompts/list.
- Tools with no credential:
search_stories, get_story, suggest_for_project, check_capability (without url) — public stories only; a private story answers exactly like a missing one.
- Need a signed-in session:
check_capability with url, report_reproduction, report_check, publish_story, edit_story, suggest_edit. Without one they answer 401 with a WWW-Authenticate header pointing at the authorization server.
- A JSON-RPC batch answers without a token only if every message in it does.
In practice: you can connect worklore and search, read, get suggestions and
x-ray pasted text without an account. Signing in adds your own private stories
to what you can see, lets check_capability fetch a URL for you, and is what
lets your agent record a reproduction or a check, publish, or edit — all of
which act as you.
History. Until 0.4.0 the line sat between describing the server and using
it: the list and the call do not need the same answer. Anonymous
callers got the server's description — names, descriptions, input and output
schemas, annotations — which is the same information already published in the
MCP Registry, in Smithery's listing and in this README. They got nothing that
executed, nothing per-user, and no session. 0.5.0 keeps the last two and opens
reading public stories, which the website never gated in the first place.
This is written down because it was a mistake first. The original build gated
the whole endpoint, on reasoning that felt airtight: one gate, one place to get
it right. The consequence was invisible from inside the code and obvious from
outside — a registry-mirroring directory listed worklore with its name, its
description, and zero tools, because a crawler has nobody to authenticate
as. The same property also means nobody outside the repository — a scanner, a
conformance harness, a curious stranger — can check what the server actually
publishes. Two symptoms, one cause. The fix was about fifteen lines: an
allow-list of anonymous methods plus a batch check, so a privileged call cannot
be smuggled in beside an anonymous one.
The whole thing is written up, with the diff and how to verify it against your
own endpoint, here: My MCP server hid its own tool list behind a
login.
If somebody proposes gating enumeration on a server you work on, that page is
the short version of the argument.
Gating enumeration is a legitimate choice for a server whose tool names are
sensitive. It is worth making on purpose rather than inheriting it from a
transport-level gate, which is how most of them happen — including, by their
own audit, the one that prompted this section being written down.
Add the connector
In Claude Code:
On claude.ai (web): Settings → Connectors → Add custom connector → name
worklore, URL https://worklore.dev/mcp. (Custom connectors need a paid plan.)
Via Smithery:
Any other MCP client: point it at https://worklore.dev/mcp (Streamable
HTTP). Searching and reading work right away; the first call that needs a session
(a write, or a URL to x-ray) answers 401 and your client is walked through OAuth —
it registers itself, so there is nothing to paste and no API key to manage.
Example prompts
- "Use worklore to check what this skill can do before I install it:
<paste a URL or the skill text>."
- "Search worklore for stories about Flutter golden tests, and tell me each one's capability tier."
- "Here's my project: a Python AWS-Lambda backend with DynamoDB. Suggest 3 worklore stories worth reproducing here, and read me the top one's Reproduce-this contract."
Notes
- The connector is a route on worklore's existing backend Lambda; it reuses the
vendored skill-xray scanner.
- Origin is validated (native clients send none and are allowed; unknown web
origins are rejected); HTTPS enforced.
- How this server was built and shipped, end to end, including what went wrong:
Build and ship your own MCP server.
MIT-licensed.