Implement MCP 2026-07-28 (#2286)

Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
Co-authored-by: Konstantin Konstantinov <KKonstantinov@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Felix Weinberger 2026-06-26 14:01:10 +01:00 • committed by GitHub
commit 1823aae891
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -0,0 +1,26 @@
# scoped-tools — per-tool scope enforced in the tool handler
Demonstrates per-tool OAuth scope enforcement on a `createMcpHandler`
deployment: the HTTP gate does **bearer-verify + 401 only**, and each tool
handler checks `ctx.http?.authInfo?.scopes` for the scope it needs. The scope
decision lives next to the code it guards — the handler is the only place that
authoritatively knows which tool is executing — instead of in middleware that
would have to re-derive the operation from the request body.
`server.ts` runs a minimal demo Authorization Server alongside the MCP Resource
Server. `client.ts` connects with a `files:read` token, calls `list-files`
(works), then calls `write-file` → the handler returns `{ isError: true }` with
`insufficient_scope: requires files:write`.
The transport's automatic `403 insufficient_scope` **step-up** flow (SEP-2350 —
scope union, refresh-bypass, `maxStepUpRetries`) applies when the RS responds
`403` at the HTTP layer; that path is exercised by
`test/e2e/scenarios/client-auth.test.ts`.
```bash
pnpm --filter @mcp-examples/scoped-tools server -- --http --port 3000
pnpm --filter @mcp-examples/scoped-tools client -- --http http://127.0.0.1:3000/mcp
```
> DEMO ONLY — the bundled AS auto-approves and grants whatever scope is asked
> for. Do not deploy.