working-on-mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited working-on-mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Read docs/mcp.md for tool contracts, OAuth flow, notes, and search architecture. Read docs/mcp-design.md for cross-platform MCP tool design best practices.
just test-worker # MCP tests are part of the Worker test suiteNo SDK. The MCP server is hand-rolled JSON-RPC 2.0 in src/mcp/handler.ts. The official @modelcontextprotocol/sdk depends on ajv/express/hono (CJS, incompatible with workerd). The Cloudflare agents SDK's createMcpHandler ignores the env parameter so tools can't access D1/R2 bindings.
Tool functions are pure. Every tool in src/mcp/tools.ts takes (db, snapshots, userUuid) and returns a ToolResult or ViewToolResult. No side effects, no request objects, testable without the MCP protocol layer.
Two response formats. textResult(data, presentation?) for tools without views (legacy, being migrated). viewResult(structuredContent, narrative) for tools with MCP Apps views — returns { structuredContent, content } where the view widget renders structuredContent and the model uses content for its response. See docs/views.md and the working-on-views skill.
MCP Apps extension. Server declares extensions: { "io.modelcontextprotocol/ui": {} } in the initialize response. Handler auto-wires _meta.ui.resourceUri on tool definitions from views.gen.ts.
Protocol version: 2025-06-18. Transport: Streamable HTTP (POST + JSON responses, not SSE).
The Worker is itself the OAuth 2.1 Authorization Server via @cloudflare/workers-oauth-provider. Clerk is the upstream IdP only — users authenticate via Clerk, but the Worker issues its own opaque access tokens stored in OAUTH_KV.
Key properties:
ctx.props.userUuid flows from Clerk's sub claim through to R2 prefix scoping.OAUTH_ENDPOINTS constant in src/oauth.ts is shared with test helpers.Protected resource metadata gotcha: RFC 8707 uses exact string comparison. MCP clients send resource=https://host/ with trailing slash. The metadata resource URL MUST have the trailing slash or token validation silently fails. Our index.ts overrides the library's response to include the trailing slash.
src/auth.ts handles two separate auth concerns:
OAuthProvider wrapper in index.ts. Token → KV lookup → ctx.props.userUuid.src/auth.ts. Stub mode: bearer token IS user UUID (when CLERK_ISSUER not set). Clerk mode: JWT validation via JWKS.These are separate concerns. Don't conflate them.
ai_bots_protection must be disabled on the Cloudflare zone. Claude.ai's MCP client makes requests from Anthropic's IPs (160.79.104-106.x), and "Block AI Scrapers and Crawlers" silently blocks them at the edge. The OAuth flow completes but the authenticated MCP request never reaches the Worker.
worker/src/mcp/handler.ts # JSON-RPC 2.0 routing
worker/src/mcp/tools.ts # Pure tool functions
worker/src/oauth.ts # OAUTH_ENDPOINTS, Clerk redirect logic
worker/src/auth.ts # Session/daemon auth (stub + Clerk modes)
worker/src/index.ts # OAuthProvider wrapper, protected resource metadata override~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.