From 9f7e7dcd86061a9649e7bc6a15f21c1f11b73072 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Thu, 11 Sep 2025 20:18:24 +0200 Subject: [PATCH 01/17] Bootstrap a Hono + Cloudflare + Clerk example for creating authd mcp server --- bun.lock | 381 +++++++++++++++++++++++++- examples/auth-clerk/.dev.vars.example | 2 + examples/auth-clerk/.gitignore | 33 +++ examples/auth-clerk/README.md | 40 +++ examples/auth-clerk/package.json | 19 ++ examples/auth-clerk/src/index.ts | 85 ++++++ examples/auth-clerk/src/mcp.ts | 27 ++ examples/auth-clerk/tsconfig.json | 12 + examples/auth-clerk/wrangler.jsonc | 38 +++ 9 files changed, 628 insertions(+), 9 deletions(-) create mode 100644 examples/auth-clerk/.dev.vars.example create mode 100644 examples/auth-clerk/.gitignore create mode 100644 examples/auth-clerk/README.md create mode 100644 examples/auth-clerk/package.json create mode 100644 examples/auth-clerk/src/index.ts create mode 100644 examples/auth-clerk/src/mcp.ts create mode 100644 examples/auth-clerk/tsconfig.json create mode 100644 examples/auth-clerk/wrangler.jsonc diff --git a/bun.lock b/bun.lock index 758a49b..1ee8a22 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,19 @@ "typescript": "^5.9.2", }, }, + "examples/auth-clerk": { + "name": "auth-clerk", + "dependencies": { + "@clerk/mcp-tools": "^0.3.1", + "@valibot/to-json-schema": "^1.3.0", + "hono": "^4.9.6", + "mcp-lite": "workspace:*", + "valibot": "^1.1.0", + }, + "devDependencies": { + "wrangler": "^4.4.0", + }, + }, "examples/validation-arktype": { "name": "@mcp-lite-examples/validation-arktype", "version": "1.0.2", @@ -120,7 +133,7 @@ "@ark/util": ["@ark/util@0.49.0", "", {}, "sha512-/BtnX7oCjNkxi2vi6y1399b+9xd1jnCrDYhZ61f0a+3X8x8DxlK52VgEEzyuC2UQMPACIfYrmHkhD3lGt2GaMA=="], - "@babel/runtime": ["@babel/runtime@7.28.3", "", {}, "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="], + "@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="], "@biomejs/biome": ["@biomejs/biome@2.2.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.2.4", "@biomejs/cli-darwin-x64": "2.2.4", "@biomejs/cli-linux-arm64": "2.2.4", "@biomejs/cli-linux-arm64-musl": "2.2.4", "@biomejs/cli-linux-x64": "2.2.4", "@biomejs/cli-linux-x64-musl": "2.2.4", "@biomejs/cli-win32-arm64": "2.2.4", "@biomejs/cli-win32-x64": "2.2.4" }, "bin": { "biome": "bin/biome" } }, "sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg=="], @@ -178,12 +191,126 @@ "@clack/prompts": ["@clack/prompts@0.7.0", "", { "dependencies": { "@clack/core": "^0.3.3", "is-unicode-supported": "*", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA=="], + "@clerk/mcp-tools": ["@clerk/mcp-tools@0.3.1", "", { "dependencies": { "@modelcontextprotocol/sdk": "^1.17.0" }, "peerDependencies": { "better-sqlite3": "^8.7.0", "pg": "^8.11.0", "redis": "^4.0.0" }, "optionalPeers": ["better-sqlite3", "pg", "redis"] }, "sha512-c/7bmT9KxA3CYVhCS08RGmVwjU8+zJ6ZCuIA5KpcJfE5xh8XLKKvZzOD4mP0GgvUGjcnT+IViaqBRlRKAyE5rw=="], + + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], + + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.3", "", { "peerDependencies": { "unenv": "2.0.0-rc.21", "workerd": "^1.20250828.1" }, "optionalPeers": ["workerd"] }, "sha512-tsQQagBKjvpd9baa6nWVIv399ejiqcrUBBW6SZx6Z22+ymm+Odv5+cFimyuCsD/fC1fQTwfRmwXBNpzvHSeGCw=="], + + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250906.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-E+X/YYH9BmX0ew2j/mAWFif2z05NMNuhCTlNYEGLkqMe99K15UewBqajL9pMcMUKxylnlrEoK3VNxl33DkbnPA=="], + + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250906.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-X5apsZ1SFW4FYTM19ISHf8005FJMPfrcf4U5rO0tdj+TeJgQgXuZ57IG0WeW7SpLVeBo8hM6WC8CovZh41AfnA=="], + + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250906.0", "", { "os": "linux", "cpu": "x64" }, "sha512-rlKzWgsLnlQ5Nt9W69YBJKcmTmZbOGu0edUsenXPmc6wzULUxoQpi7ZE9k3TfTonJx4WoQsQlzCUamRYFsX+0Q=="], + + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250906.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-DdedhiQ+SeLzpg7BpcLrIPEZ33QKioJQ1wvL4X7nuLzEB9rWzS37NNNahQzc1+44rhG4fyiHbXBPOeox4B9XVA=="], + + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250906.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Q8Qjfs8jGVILnZL6vUpQ90q/8MTCYaGR3d1LGxZMBqte8Vr7xF3KFHPEy7tFs0j0mMjnqCYzlofmPNY+9ZaDRg=="], + + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="], + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "^1.2.0" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + "@inquirer/external-editor": ["@inquirer/external-editor@1.0.1", "", { "dependencies": { "chardet": "^2.1.0", "iconv-lite": "^0.6.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q=="], "@internal/test-utils": ["@internal/test-utils@workspace:packages/test-utils"], + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@jsdevtools/ez-spawn": ["@jsdevtools/ez-spawn@3.0.4", "", { "dependencies": { "call-me-maybe": "^1.0.1", "cross-spawn": "^7.0.3", "string-argv": "^0.3.1", "type-detect": "^4.0.8" } }, "sha512-f5DRIOZf7wxogefH03RjMPMdBF7ADTWUMoOs9kaJo06EfwF+aFhMZMDZxHg/Xe12hptN9xoZjGso2fdjapBRIA=="], "@manypkg/find-root": ["@manypkg/find-root@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@types/node": "^12.7.1", "find-up": "^4.1.0", "fs-extra": "^8.1.0" } }, "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA=="], @@ -196,6 +323,8 @@ "@mcp-lite-examples/validation-zod": ["@mcp-lite-examples/validation-zod@workspace:examples/validation-zod"], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.17.5", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-QakrKIGniGuRVfWBdMsDea/dx1PNE739QJ7gCM41s9q+qaCYTHCdsIBXQVVXry3mfWAiaM9kT22Hyz53Uw8mfg=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], @@ -228,6 +357,16 @@ "@oslojs/oauth2": ["@oslojs/oauth2@0.5.0", "", {}, "sha512-t70+e4EgnzTbU4MrUWXzqWN2A6RJrlSSvwwuBv6E0Ap6/nsIXrjsdRWeTcSvvXTcC6fi0YdWaqEWLipcEm2Cgw=="], + "@poppinss/colors": ["@poppinss/colors@4.1.5", "", { "dependencies": { "kleur": "^4.1.5" } }, "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw=="], + + "@poppinss/dumper": ["@poppinss/dumper@0.6.4", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@sindresorhus/is": "^7.0.2", "supports-color": "^10.0.0" } }, "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ=="], + + "@poppinss/exception": ["@poppinss/exception@1.2.2", "", {}, "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg=="], + + "@sindresorhus/is": ["@sindresorhus/is@7.0.2", "", {}, "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw=="], + + "@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="], + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], @@ -238,7 +377,13 @@ "@valibot/to-json-schema": ["@valibot/to-json-schema@1.3.0", "", { "peerDependencies": { "valibot": "^1.1.0" } }, "sha512-82Vv6x7sOYhv5YmTRgSppSqj1nn2pMCk5BqCMGWYp0V/fq+qirrbGncqZAtZ09/lrO40ne/7z8ejwE728aVreg=="], - "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], + + "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], @@ -252,16 +397,28 @@ "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "auth-clerk": ["auth-clerk@workspace:examples/auth-clerk"], + "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], "better-path-resolve": ["better-path-resolve@1.0.0", "", { "dependencies": { "is-windows": "^1.0.0" } }, "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g=="], + "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], + + "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "call-me-maybe": ["call-me-maybe@1.0.2", "", {}, "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="], "chardet": ["chardet@2.1.0", "", {}, "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA=="], @@ -272,12 +429,30 @@ "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="], + "create-mcp-lite": ["create-mcp-lite@workspace:packages/create-mcp-lite"], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], @@ -286,6 +461,8 @@ "dateformat": ["dateformat@4.6.3", "", {}, "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA=="], + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + "decode-uri-component": ["decode-uri-component@0.4.1", "", {}, "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ=="], "default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="], @@ -296,24 +473,64 @@ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], + "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], "enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="], + "error-stack-parser-es": ["error-stack-parser-es@1.0.5", "", {}, "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + + "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], + + "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], + + "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], + + "exsolve": ["exsolve@1.0.7", "", {}, "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw=="], + "extendable-error": ["extendable-error@0.1.7", "", {}, "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg=="], "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], @@ -326,23 +543,47 @@ "filter-obj": ["filter-obj@5.1.0", "", {}, "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng=="], + "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + "fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "giget": ["giget@1.2.5", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.5.4", "pathe": "^2.0.3", "tar": "^6.2.1" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], - "hono": ["hono@4.9.5", "", {}, "sha512-aLAVl5/67ifNnoFVxnhR89dpmSLsgwBprw/PT671ASwUpJqmd7Ne8KPTQo37DbRZfgpHaHeZ4bPVUvbOkeedMw=="], + "hono": ["hono@4.9.6", "", {}, "sha512-doVjXhSFvYZ7y0dNokjwwSahcrAfdz+/BCLvAMa/vHLzjj8+CFyV5xteThGUsKdkaasgN+gF2mUxao+SGLpUeA=="], + + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], "human-id": ["human-id@4.1.1", "", { "bin": { "human-id": "dist/cli.js" } }, "sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg=="], @@ -350,6 +591,12 @@ "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="], + "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], @@ -360,6 +607,8 @@ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + "is-subdir": ["is-subdir@1.2.0", "", { "dependencies": { "better-path-resolve": "1.0.0" } }, "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw=="], "is-windows": ["is-windows@1.0.2", "", {}, "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="], @@ -374,18 +623,36 @@ "js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "lodash.startcase": ["lodash.startcase@4.4.0", "", {}, "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mcp-lite": ["mcp-lite@workspace:packages/core"], + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], + + "miniflare": ["miniflare@4.20250906.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^7.10.0", "workerd": "1.20250906.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-T/RWn1sa0ien80s6NjU+Un/tj12gR6wqScZoiLeMJDD4/fK0UXfnbWXJDubnUED8Xjm7RPQ5ESYdE+mhPmMtuQ=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], @@ -398,12 +665,24 @@ "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], "nypm": ["nypm@0.5.4", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "tinyexec": "^0.3.2", "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA=="], + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], @@ -422,10 +701,14 @@ "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -436,7 +719,7 @@ "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], - "pino": ["pino@9.9.4", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-d1XorUQ7sSKqVcYdXuEYs2h1LKxejSorMEJ76XoZ0pPDf8VzJMe7GlPXpMBZeQ9gE4ZPIp5uGD+5Nw7scxiigg=="], + "pino": ["pino@9.9.5", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-d1s98p8/4TfYhsJ09r/Azt30aYELRi6NNnZtEbqFw6BoGsdPVf5lKNK3kUwH8BmJJfpTLNuicjUQjaMbd93dVg=="], "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], @@ -444,6 +727,8 @@ "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], + "pkce-challenge": ["pkce-challenge@5.0.0", "", {}, "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="], + "pkg-pr-new": ["pkg-pr-new@0.0.59", "", { "dependencies": { "@actions/core": "^1.11.1", "@jsdevtools/ez-spawn": "^3.0.4", "@octokit/action": "^6.1.0", "ignore": "^5.3.1", "isbinaryfile": "^5.0.2", "pkg-types": "^1.1.1", "query-registry": "^3.0.1", "tinyglobby": "^0.2.9" }, "bin": { "pkg-pr-new": "bin/cli.js" } }, "sha512-dnSddkZUs5Qz6JhMmHTyYZuscwYRw8XbANazk0uObR89XS2N0AC0gtKMqWxYhgG14BT29kUHGy8aAOYFL1wfeg=="], "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], @@ -454,8 +739,14 @@ "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + "pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="], + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], "query-registry": ["query-registry@3.0.1", "", { "dependencies": { "query-string": "^9.0.0", "quick-lru": "^7.0.0", "url-join": "^5.0.0", "validate-npm-package-name": "^5.0.1", "zod": "^3.23.8", "zod-package-json": "^1.0.3" } }, "sha512-M9RxRITi2mHMVPU5zysNjctUT8bAPx6ltEXo/ir9+qmiM47Y7f0Ir3+OxUO5OjYAWdicBQRew7RtHtqUXydqlg=="], @@ -468,6 +759,10 @@ "quick-lru": ["quick-lru@7.1.0", "", {}, "sha512-Pzd/4IFnTb8E+I1P5rbLQoqpUHcXKg48qTYKi4EANg+sTPwGFEMOcYGiiZz6xuQcOMZP7MPsrdAPx+16Q8qahg=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.1", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.7.0", "unpipe": "1.0.0" } }, "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA=="], + "read-yaml-file": ["read-yaml-file@1.1.0", "", { "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" } }, "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA=="], "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], @@ -476,10 +771,14 @@ "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="], + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], @@ -488,12 +787,30 @@ "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], + + "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.3", "semver": "^7.6.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="], + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], @@ -508,6 +825,10 @@ "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], + "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -516,6 +837,8 @@ "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], "term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="], @@ -528,10 +851,16 @@ "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], "type-detect": ["type-detect@4.1.0", "", {}, "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw=="], + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], @@ -540,28 +869,48 @@ "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "unenv": ["unenv@2.0.0-rc.21", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A=="], + "universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "url-join": ["url-join@5.0.0", "", {}, "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA=="], "valibot": ["valibot@1.1.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw=="], "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "workerd": ["workerd@1.20250906.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250906.0", "@cloudflare/workerd-darwin-arm64": "1.20250906.0", "@cloudflare/workerd-linux-64": "1.20250906.0", "@cloudflare/workerd-linux-arm64": "1.20250906.0", "@cloudflare/workerd-windows-64": "1.20250906.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-ryVyEaqXPPsr/AxccRmYZZmDAkfQVjhfRqrNTlEeN8aftBk6Ca1u7/VqmfOayjCXrA+O547TauebU+J3IpvFXw=="], + + "wrangler": ["wrangler@4.35.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.3", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250906.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.21", "workerd": "1.20250906.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250906.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-HbyXtbrh4Fi3mU8ussY85tVdQ74qpVS1vctUgaPc+bPrXBTqfDLkZ6VRtHAVF/eBhz4SFmhJtCQpN1caY2Ak8A=="], + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], - "zod": ["zod@4.1.5", "", {}, "sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg=="], + "youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], + + "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], + + "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], "zod-package-json": ["zod-package-json@1.2.0", "", { "dependencies": { "zod": "^3.25.64" } }, "sha512-tamtgPM3MkP+obfO2dLr/G+nYoYkpJKmuHdYEy6IXRKfLybruoJ5NUj0lM0LxwOpC9PpoGLbll1ecoeyj43Wsg=="], + "zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="], + "@actions/http-client/undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], "@clack/prompts/is-unicode-supported": ["is-unicode-supported@2.1.0", "", { "bundled": true }, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], @@ -574,6 +923,8 @@ "@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + "@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@octokit/auth-action/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], "@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], @@ -586,18 +937,32 @@ "@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], - "bun-types/@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="], + "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "miniflare/undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="], + + "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "mlly/acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "query-registry/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "raw-body/iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], + + "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "zod-package-json/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "zod-to-json-schema/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@octokit/auth-action/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], "@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], @@ -609,7 +974,5 @@ "@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], "@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], - - "bun-types/@types/node/undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], } } diff --git a/examples/auth-clerk/.dev.vars.example b/examples/auth-clerk/.dev.vars.example new file mode 100644 index 0000000..4105d62 --- /dev/null +++ b/examples/auth-clerk/.dev.vars.example @@ -0,0 +1,2 @@ +CLERK_PUBLISHABLE_KEY=pk_test_... +CLERK_SECRET_KEY=sk_test_... diff --git a/examples/auth-clerk/.gitignore b/examples/auth-clerk/.gitignore new file mode 100644 index 0000000..e319e06 --- /dev/null +++ b/examples/auth-clerk/.gitignore @@ -0,0 +1,33 @@ +# prod +dist/ + +# dev +.yarn/ +!.yarn/releases +.vscode/* +!.vscode/launch.json +!.vscode/*.code-snippets +.idea/workspace.xml +.idea/usage.statistics.xml +.idea/shelf + +# deps +node_modules/ +.wrangler + +# env +.env +.env.production +.dev.vars + +# logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# misc +.DS_Store diff --git a/examples/auth-clerk/README.md b/examples/auth-clerk/README.md new file mode 100644 index 0000000..3532e61 --- /dev/null +++ b/examples/auth-clerk/README.md @@ -0,0 +1,40 @@ +# mcp-lit with auth (featuring: Clerk) + +This is an example of using mcp-lite with auth, using Clerk as the auth provider. + +## Development + +Set secret variables in `.dev.vars` + +```sh +# Fill in the values for the secret variables from the example file +cp .dev.vars.example .dev.vars +``` + +Run the development server + +```sh +bun install +bun dev +``` + +## Deployment + +```sh +bun run deploy +``` + +## Type Generation + +[For generating/synchronizing types based on your Worker configuration run](https://developers.cloudflare.com/workers/wrangler/commands/#types): + +```sh +bun run cf-typegen +``` + +Pass the `CloudflareBindings` as generics when instantiation `Hono`: + +```ts +// src/index.ts +const app = new Hono<{ Bindings: CloudflareBindings }>() +``` diff --git a/examples/auth-clerk/package.json b/examples/auth-clerk/package.json new file mode 100644 index 0000000..5b0a756 --- /dev/null +++ b/examples/auth-clerk/package.json @@ -0,0 +1,19 @@ +{ + "name": "auth-clerk", + "type": "module", + "scripts": { + "dev": "wrangler dev", + "deploy": "wrangler deploy --minify", + "cf-typegen": "wrangler types --env-interface CloudflareBindings" + }, + "dependencies": { + "@clerk/mcp-tools": "^0.3.1", + "@valibot/to-json-schema": "^1.3.0", + "hono": "^4.9.6", + "mcp-lite": "workspace:*", + "valibot": "^1.1.0" + }, + "devDependencies": { + "wrangler": "^4.4.0" + } +} diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts new file mode 100644 index 0000000..455627b --- /dev/null +++ b/examples/auth-clerk/src/index.ts @@ -0,0 +1,85 @@ +// https://github.com/clerk/mcp-tools +import { + corsHeaders, + fetchClerkAuthorizationServerMetadata, + generateClerkProtectedResourceMetadata, +} from "@clerk/mcp-tools/server"; +import { Hono } from "hono"; +import { cors } from "hono/cors"; +import { createMiddleware } from "hono/factory"; +import { httpHandler as mcpHttpHandler } from "./mcp"; + +type AppType = { Bindings: { CLERK_PUBLISHABLE_KEY: string } }; + +// Create a Hono app to serve our api routes +const app = new Hono(); + +/** + * Create middleware to handle CORS for the OAuth endpoints, + * this is useful for testing auth from a browser-based MCP client, + * or the MCP inspector (which makes requests from a browser) + * + * We convert the CORS headers that we get from the @clerk/mcp-tools library + * into a format that Hono middleware can understand + * + * https://github.com/clerk/mcp-tools/blob/main/server.ts + */ +const oauthCorsMiddleware = cors({ + origin: corsHeaders["Access-Control-Allow-Origin"], + // HACK - split the comma-separated list of methods into an array + allowMethods: corsHeaders["Access-Control-Allow-Methods"].split(","), + allowHeaders: [corsHeaders["Access-Control-Allow-Headers"]], + maxAge: parseInt(corsHeaders["Access-Control-Max-Age"], 10), +}); + +app.on( + ["GET", "OPTIONS"], + ".well-known/oauth-protected-resource", + oauthCorsMiddleware, + (c) => { + const result = generateClerkProtectedResourceMetadata({ + publishableKey: c.env.CLERK_PUBLISHABLE_KEY, + resourceUrl: "https://myapp.com/current-route", + }); + + return c.json(result); + }, +); + +// NOTE - In our case, Clerk is the authorization server, so we shouldn't *need* to implement this; +// however, in earlier versions of the MCP spec, this was required, +// so we implement it for backwards compatibility with clients. +app.on( + ["GET", "OPTIONS"], + ".well-known/oauth-authorization-server", + oauthCorsMiddleware, + (c) => { + const result = fetchClerkAuthorizationServerMetadata({ + publishableKey: c.env.CLERK_PUBLISHABLE_KEY, + }); + // TODO - Remove this log statement, I just wanted to see the output since it isn't typed properly + console.log("🔑 Clerk Authorization Server Metadata:", result); + + return c.json(result); + }, +); + +const mcpAuthMiddleware = createMiddleware(async (_c, next) => { + // TODO: Implement auth middleware for the MCP server. + // - [ ] Use Clerk Machine auth: https://clerk.com/docs/nextjs/mcp/build-mcp-server + // - [ ] Return a 401 with proper WWW-Authenticate header when auth fails + await next(); +}); + +// Add MCP endpoint +app.all("/mcp", mcpAuthMiddleware, async (c) => { + const response = await mcpHttpHandler(c.req.raw); + return response; +}); + +// Root route describing where to find the MCP endpoint +app.get("/", (c) => { + return c.text("Authenticated MCP Server! Connect to /mcp"); +}); + +export default app; diff --git a/examples/auth-clerk/src/mcp.ts b/examples/auth-clerk/src/mcp.ts new file mode 100644 index 0000000..41d21a2 --- /dev/null +++ b/examples/auth-clerk/src/mcp.ts @@ -0,0 +1,27 @@ +import { toJsonSchema } from "@valibot/to-json-schema"; +import { McpServer, StreamableHttpTransport } from "mcp-lite"; +import * as v from "valibot"; + +const mcp = new McpServer({ + name: "auth-clerk", + version: "1.0.0", + schemaAdapter: (schema) => toJsonSchema(schema as v.AnySchema), +}); + +// Define schema +const EchoSchema = v.object({ + message: v.string(), +}); + +// Add a tool +mcp.tool("echo", { + description: "Echoes the input message", + inputSchema: EchoSchema, + handler: (args) => ({ + content: [{ type: "text", text: args.message }], + }), +}); + +// Create HTTP transport +const transport = new StreamableHttpTransport(); +export const httpHandler = transport.bind(mcp); diff --git a/examples/auth-clerk/tsconfig.json b/examples/auth-clerk/tsconfig.json new file mode 100644 index 0000000..5e1f025 --- /dev/null +++ b/examples/auth-clerk/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "lib": ["ESNext"], + "jsx": "react-jsx", + "jsxImportSource": "hono/jsx" + } +} diff --git a/examples/auth-clerk/wrangler.jsonc b/examples/auth-clerk/wrangler.jsonc new file mode 100644 index 0000000..a0bcfe5 --- /dev/null +++ b/examples/auth-clerk/wrangler.jsonc @@ -0,0 +1,38 @@ +{ + "$schema": "node_modules/wrangler/config-schema.json", + "name": "auth-clerk", + "main": "src/index.ts", + "compatibility_date": "2025-09-11" + // "compatibility_flags": [ + // "nodejs_compat" + // ], + // "vars": { + // "MY_VAR": "my-variable" + // }, + // "kv_namespaces": [ + // { + // "binding": "MY_KV_NAMESPACE", + // "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + // } + // ], + // "r2_buckets": [ + // { + // "binding": "MY_BUCKET", + // "bucket_name": "my-bucket" + // } + // ], + // "d1_databases": [ + // { + // "binding": "MY_DB", + // "database_name": "my-database", + // "database_id": "" + // } + // ], + // "ai": { + // "binding": "AI" + // }, + // "observability": { + // "enabled": true, + // "head_sampling_rate": 1 + // } +} From b783fbc50b62460076a3f49184a6d6364487b35a Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Thu, 11 Sep 2025 20:25:17 +0200 Subject: [PATCH 02/17] Update docstrings --- examples/auth-clerk/src/index.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index 455627b..184a04b 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -32,6 +32,9 @@ const oauthCorsMiddleware = cors({ maxAge: parseInt(corsHeaders["Access-Control-Max-Age"], 10), }); +/** + * Implement the OAuth Protected Resource endpoint + */ app.on( ["GET", "OPTIONS"], ".well-known/oauth-protected-resource", @@ -46,9 +49,13 @@ app.on( }, ); -// NOTE - In our case, Clerk is the authorization server, so we shouldn't *need* to implement this; -// however, in earlier versions of the MCP spec, this was required, -// so we implement it for backwards compatibility with clients. +/** + * Implement the OAuth Authorization Server endpoint + * + * @note - In our case, Clerk is the authorization server, so we shouldn't *need* to implement this; + * however, in earlier versions of the MCP spec, this was required, + * so we implement it for backwards compatibility with clients. + */ app.on( ["GET", "OPTIONS"], ".well-known/oauth-authorization-server", @@ -64,6 +71,10 @@ app.on( }, ); +/** + * Create auth middleware for the MCP server. + * This should be run on all "/mcp" requests. + */ const mcpAuthMiddleware = createMiddleware(async (_c, next) => { // TODO: Implement auth middleware for the MCP server. // - [ ] Use Clerk Machine auth: https://clerk.com/docs/nextjs/mcp/build-mcp-server From c8488bace38117e755df7eeddd68d26897ccc9fe Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 09:59:23 +0200 Subject: [PATCH 03/17] Create an unholy incompliete mash of express mcp oauth flow and hono clerk middleware --- bun.lock | 25 ++++ examples/auth-clerk/.dev.vars.example | 3 + examples/auth-clerk/README.md | 15 ++- examples/auth-clerk/package.json | 1 + examples/auth-clerk/src/auth/auth.ts | 170 +++++++++++++++++++++++++ examples/auth-clerk/src/auth/errors.ts | 37 ++++++ examples/auth-clerk/src/index.ts | 16 +-- examples/auth-clerk/src/types.ts | 8 ++ 8 files changed, 260 insertions(+), 15 deletions(-) create mode 100644 examples/auth-clerk/src/auth/auth.ts create mode 100644 examples/auth-clerk/src/auth/errors.ts create mode 100644 examples/auth-clerk/src/types.ts diff --git a/bun.lock b/bun.lock index 1ee8a22..276bfe7 100644 --- a/bun.lock +++ b/bun.lock @@ -13,6 +13,7 @@ "examples/auth-clerk": { "name": "auth-clerk", "dependencies": { + "@clerk/backend": "^2.13.0", "@clerk/mcp-tools": "^0.3.1", "@valibot/to-json-schema": "^1.3.0", "hono": "^4.9.6", @@ -191,8 +192,14 @@ "@clack/prompts": ["@clack/prompts@0.7.0", "", { "dependencies": { "@clack/core": "^0.3.3", "is-unicode-supported": "*", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA=="], + "@clerk/backend": ["@clerk/backend@2.13.0", "", { "dependencies": { "@clerk/shared": "^3.24.2", "@clerk/types": "^4.85.0", "cookie": "1.0.2", "standardwebhooks": "^1.0.0", "tslib": "2.8.1" } }, "sha512-MjEeDjlteMcEC+RUmrtlwkrJ+1Zv7Gb+atCg6mD+1N8/01v66LjYWKk2eQ+T0v+znQkSiFS8JPQ8yqaLH2sbqg=="], + "@clerk/mcp-tools": ["@clerk/mcp-tools@0.3.1", "", { "dependencies": { "@modelcontextprotocol/sdk": "^1.17.0" }, "peerDependencies": { "better-sqlite3": "^8.7.0", "pg": "^8.11.0", "redis": "^4.0.0" }, "optionalPeers": ["better-sqlite3", "pg", "redis"] }, "sha512-c/7bmT9KxA3CYVhCS08RGmVwjU8+zJ6ZCuIA5KpcJfE5xh8XLKKvZzOD4mP0GgvUGjcnT+IViaqBRlRKAyE5rw=="], + "@clerk/shared": ["@clerk/shared@3.24.2", "", { "dependencies": { "@clerk/types": "^4.85.0", "dequal": "2.0.3", "glob-to-regexp": "0.4.1", "js-cookie": "3.0.5", "std-env": "^3.9.0", "swr": "2.3.4" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-gGnB08PWdM6gHVhlyrQ32xwWt/bIyg8nQhrxUCnNSf/xlPC2mFUtx24JYLsFRjbIGg/uA3z2qVnllBMkxejIDA=="], + + "@clerk/types": ["@clerk/types@4.85.0", "", { "dependencies": { "csstype": "3.1.3" } }, "sha512-0s7KZbWpX4e9/CHl29sYGGBUBbZa7qlXp74OaaXfm1WTzYGiOOTyyE54j2WTz91+TZxIZZu5UA5rfn9qc79hYA=="], + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="], "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.7.3", "", { "peerDependencies": { "unenv": "2.0.0-rc.21", "workerd": "^1.20250828.1" }, "optionalPeers": ["workerd"] }, "sha512-tsQQagBKjvpd9baa6nWVIv399ejiqcrUBBW6SZx6Z22+ymm+Odv5+cFimyuCsD/fC1fQTwfRmwXBNpzvHSeGCw=="], @@ -367,6 +374,8 @@ "@speed-highlight/core": ["@speed-highlight/core@1.2.7", "", {}, "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g=="], + "@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="], + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], @@ -477,6 +486,8 @@ "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], "detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="], @@ -535,6 +546,8 @@ "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + "fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="], + "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], @@ -621,6 +634,8 @@ "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + "js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="], + "js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], @@ -763,6 +778,8 @@ "raw-body": ["raw-body@3.0.1", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.7.0", "unpipe": "1.0.0" } }, "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA=="], + "react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="], + "read-yaml-file": ["read-yaml-file@1.1.0", "", { "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" } }, "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA=="], "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], @@ -825,8 +842,12 @@ "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "standardwebhooks": ["standardwebhooks@1.0.0", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "fast-sha256": "^1.3.0" } }, "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + "std-env": ["std-env@3.9.0", "", {}, "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw=="], + "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], @@ -839,6 +860,8 @@ "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], + "swr": ["swr@2.3.4", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-bYd2lrhc+VarcpkgWclcUi92wYCpOgMws9Sd1hG1ntAu0NEy+14CbotuFjshBU2kt9rYj9TSmDcybpxpeTU1fg=="], + "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], "term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="], @@ -881,6 +904,8 @@ "url-join": ["url-join@5.0.0", "", {}, "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA=="], + "use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="], + "valibot": ["valibot@1.1.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw=="], "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], diff --git a/examples/auth-clerk/.dev.vars.example b/examples/auth-clerk/.dev.vars.example index 4105d62..901685d 100644 --- a/examples/auth-clerk/.dev.vars.example +++ b/examples/auth-clerk/.dev.vars.example @@ -1,2 +1,5 @@ CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... +# Create an OAuth app in Clerk: https://dashboard.clerk.com/last-active?path=user-authentication/oauth-applications +CLERK_OAUTH_CLIENT_ID= +CLERK_OAUTH_CLIENT_SECRET= \ No newline at end of file diff --git a/examples/auth-clerk/README.md b/examples/auth-clerk/README.md index 3532e61..d9ada80 100644 --- a/examples/auth-clerk/README.md +++ b/examples/auth-clerk/README.md @@ -2,7 +2,7 @@ This is an example of using mcp-lite with auth, using Clerk as the auth provider. -## Development +## Configuration Set secret variables in `.dev.vars` @@ -11,6 +11,19 @@ Set secret variables in `.dev.vars` cp .dev.vars.example .dev.vars ``` +Create an OAuth app in Clerk: https://dashboard.clerk.com/last-active?path=user-authentication/oauth-applications + +Copy your Clerk OAuth client secret and client ID from the OAuth app you created into your `.dev.vars` file. + +Add a redirect URI to the OAuth app in the Clerk dashboard. + +Enable Dynamic Client Registration using the toggle in the Clerk dashboard: https://dashboard.clerk.com/last-active?path=user-authentication/oauth-applications + + +## Development + + + Run the development server ```sh diff --git a/examples/auth-clerk/package.json b/examples/auth-clerk/package.json index 5b0a756..8e3e390 100644 --- a/examples/auth-clerk/package.json +++ b/examples/auth-clerk/package.json @@ -7,6 +7,7 @@ "cf-typegen": "wrangler types --env-interface CloudflareBindings" }, "dependencies": { + "@clerk/backend": "^2.13.0", "@clerk/mcp-tools": "^0.3.1", "@valibot/to-json-schema": "^1.3.0", "hono": "^4.9.6", diff --git a/examples/auth-clerk/src/auth/auth.ts b/examples/auth-clerk/src/auth/auth.ts new file mode 100644 index 0000000..2334267 --- /dev/null +++ b/examples/auth-clerk/src/auth/auth.ts @@ -0,0 +1,170 @@ +import { createClerkClient } from "@clerk/backend"; +import { TokenType } from "@clerk/backend/internal"; +import { verifyClerkToken } from "@clerk/mcp-tools/server"; +import { env } from "hono/adapter"; +import { createMiddleware } from "hono/factory"; +import type { AppType } from "../types"; +import { BaseAuthError, InvalidTokenError } from "./errors"; + +// Minimal AuthInfo shape to avoid importing @modelcontextprotocol/sdk types +type AuthInfo = { + token: string; + /** Epoch seconds */ + expiresAt?: number; + scopes: string[]; + /** Additional provider-specific data */ + extra?: Record; +}; + +/** + * Create auth middleware for the MCP server. + * This should be run on all "/mcp" requests. + * + * Sets the "auth" variable on the request context + */ +export const mcpAuthMiddleware = createMiddleware< + AppType & { Variables: { auth: AuthInfo } } +>(async (c, next) => { + const req = c.req.raw; + const url = new URL(req.url); + const origin = url.origin; + // This is the path to our OAuth Protected Resource endpoint we set up in index.ts + const resourceMetadataPath = "/.well-known/oauth-protected-resource"; + const resourceMetadataUrl = `${origin}${resourceMetadataPath}`; + + try { + const authHeader = c.req.header("Authorization"); + const [type, token] = authHeader?.split(" ") || []; + const bearerToken = type?.toLowerCase() === "bearer" ? token : undefined; + + // Return 401 with proper www-authenticate header if no authorization is provided + if (!bearerToken) { + const err = new InvalidTokenError("No authorization provided"); + return new Response(JSON.stringify(err.toResponseObject()), { + status: err.status, + headers: { + "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, + "Content-Type": "application/json", + }, + }); + } + + const clerkEnv = env(c); + const { secretKey, publishableKey, ...rest } = { + secretKey: clerkEnv.CLERK_SECRET_KEY || "", + publishableKey: clerkEnv.CLERK_PUBLISHABLE_KEY || "", + // apiUrl: clerkEnv.CLERK_API_URL, + // apiVersion: clerkEnv.CLERK_API_VERSION, + }; + + const clerkClient = createClerkClient({ + ...rest, + // apiUrl, + // apiVersion, + secretKey, + publishableKey, + }); + + const requestState = await clerkClient.authenticateRequest(c.req.raw, { + ...rest, + secretKey, + publishableKey, + acceptsToken: TokenType.OAuthToken, + }); + + // Copied this logic from the Hono middleware, but might not be necessary for OAuth flows + // (This logic assumes classic Clerk session auth is being used) + // https://github.com/honojs/middleware/blob/main/packages/clerk-auth/src/clerk-auth.ts + if (requestState.headers) { + requestState.headers.forEach((value, key) => { + c.res.headers.append(key, value); + }); + + const locationHeader = requestState.headers.get("location"); + + if (locationHeader) { + return c.redirect(locationHeader, 307); + } + + // @ts-expect-error - defensive check + if (requestState.status === "handshake") { + throw new Error("Clerk: unexpected handshake without redirect"); + } + } + + let authInfo: AuthInfo | undefined; + try { + // This is the result of the authenticateRequest call, with the token type being OAuthToken + const auth = requestState.toAuth(); + // TODO - call verifyClerkToken + const verifiedAuth = verifyClerkToken(auth, token); + authInfo = verifiedAuth; + } catch (e) { + console.error("Unexpected error authenticating bearer token:", e); + const publicError = new InvalidTokenError("Invalid token"); + return new Response(JSON.stringify(publicError.toResponseObject()), { + status: publicError.status, + headers: { + "WWW-Authenticate": `Bearer error="${publicError.errorCode}", error_description="${publicError.message}", resource_metadata="${resourceMetadataUrl}"`, + "Content-Type": "application/json", + }, + }); + } + + // Require valid auth for this endpoint + if (!authInfo) { + const err = new InvalidTokenError("Invalid or missing token"); + return new Response(JSON.stringify(err.toResponseObject()), { + status: err.status, + headers: { + "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, + "Content-Type": "application/json", + }, + }); + } + + // Optional: enforce scopes if desired; read from context if provided upstream + // const requiredScopes = c.get("requiredScopes") as string[] | undefined; + // if (Array.isArray(requiredScopes) && requiredScopes.length > 0) { + // const hasAll = requiredScopes.every((s: string) => + // authInfo.scopes.includes(s), + // ); + // if (!hasAll) { + // const err = new InsufficientScopeError("Insufficient scope"); + // return new Response(JSON.stringify(err.toResponseObject()), { + // status: err.status, + // headers: { + // "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, + // "Content-Type": "application/json", + // }, + // }); + // } + // } + + // Expiry check (epoch seconds) + // if (authInfo.expiresAt && authInfo.expiresAt < Date.now() / 1000) { + // const err = new InvalidTokenError("Token has expired"); + // return new Response(JSON.stringify(err.toResponseObject()), { + // status: err.status, + // headers: { + // "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, + // "Content-Type": "application/json", + // }, + // }); + // } + + // Attach auth to Request and Hono context for downstream handlers + c.set("auth", authInfo); + + await next(); + } catch (error) { + if (error instanceof BaseAuthError) { + return new Response(JSON.stringify(error.toResponseObject()), { + status: error.status, + headers: { "Content-Type": "application/json" }, + }); + } + console.error("Unexpected auth middleware error:", error); + return c.json({ error: "Internal Server Error" }, 500); + } +}); diff --git a/examples/auth-clerk/src/auth/errors.ts b/examples/auth-clerk/src/auth/errors.ts new file mode 100644 index 0000000..4070abe --- /dev/null +++ b/examples/auth-clerk/src/auth/errors.ts @@ -0,0 +1,37 @@ +/** + * Auth errors - mimics the errors from the @modelcontextprotocol/sdk package + */ + +/** + * Base auth error class + */ +export class BaseAuthError extends Error { + errorCode: string; + status: number; + constructor(code: string, message: string, status: number) { + super(message); + this.errorCode = code; + this.status = status; + } + toResponseObject(): Record { + return { error: this.errorCode, error_description: this.message }; + } +} + +export class InvalidTokenError extends BaseAuthError { + constructor(message: string) { + super("invalid_token", message, 401); + } +} + +export class InsufficientScopeError extends BaseAuthError { + constructor(message: string) { + super("insufficient_scope", message, 403); + } +} + +export class ServerError extends BaseAuthError { + constructor(message: string) { + super("server_error", message, 500); + } +} diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index 184a04b..f0e7cc1 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -6,10 +6,9 @@ import { } from "@clerk/mcp-tools/server"; import { Hono } from "hono"; import { cors } from "hono/cors"; -import { createMiddleware } from "hono/factory"; +import { mcpAuthMiddleware } from "./auth/auth"; import { httpHandler as mcpHttpHandler } from "./mcp"; - -type AppType = { Bindings: { CLERK_PUBLISHABLE_KEY: string } }; +import type { AppType } from "./types"; // Create a Hono app to serve our api routes const app = new Hono(); @@ -71,17 +70,6 @@ app.on( }, ); -/** - * Create auth middleware for the MCP server. - * This should be run on all "/mcp" requests. - */ -const mcpAuthMiddleware = createMiddleware(async (_c, next) => { - // TODO: Implement auth middleware for the MCP server. - // - [ ] Use Clerk Machine auth: https://clerk.com/docs/nextjs/mcp/build-mcp-server - // - [ ] Return a 401 with proper WWW-Authenticate header when auth fails - await next(); -}); - // Add MCP endpoint app.all("/mcp", mcpAuthMiddleware, async (c) => { const response = await mcpHttpHandler(c.req.raw); diff --git a/examples/auth-clerk/src/types.ts b/examples/auth-clerk/src/types.ts new file mode 100644 index 0000000..cbbdf95 --- /dev/null +++ b/examples/auth-clerk/src/types.ts @@ -0,0 +1,8 @@ +export type AppType = { + Bindings: { + CLERK_PUBLISHABLE_KEY: string; + CLERK_SECRET_KEY: string; + CLERK_OAUTH_CLIENT_ID: string; + CLERK_OAUTH_CLIENT_SECRET: string; + }; +}; From 35ac955ca958692871bd8f2c497a71ed4fcf4180 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 10:29:20 +0200 Subject: [PATCH 04/17] Fix metadata discovery --- examples/auth-clerk/.dev.vars.example | 1 + examples/auth-clerk/src/auth/auth.ts | 4 ---- examples/auth-clerk/src/index.ts | 10 +++++++--- examples/auth-clerk/wrangler.jsonc | 6 ++---- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/auth-clerk/.dev.vars.example b/examples/auth-clerk/.dev.vars.example index 901685d..1643778 100644 --- a/examples/auth-clerk/.dev.vars.example +++ b/examples/auth-clerk/.dev.vars.example @@ -1,3 +1,4 @@ +# Find in Clerk Dashboard under Application > Configure > Api Keys CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... # Create an OAuth app in Clerk: https://dashboard.clerk.com/last-active?path=user-authentication/oauth-applications diff --git a/examples/auth-clerk/src/auth/auth.ts b/examples/auth-clerk/src/auth/auth.ts index 2334267..e3dabb4 100644 --- a/examples/auth-clerk/src/auth/auth.ts +++ b/examples/auth-clerk/src/auth/auth.ts @@ -53,14 +53,10 @@ export const mcpAuthMiddleware = createMiddleware< const { secretKey, publishableKey, ...rest } = { secretKey: clerkEnv.CLERK_SECRET_KEY || "", publishableKey: clerkEnv.CLERK_PUBLISHABLE_KEY || "", - // apiUrl: clerkEnv.CLERK_API_URL, - // apiVersion: clerkEnv.CLERK_API_VERSION, }; const clerkClient = createClerkClient({ ...rest, - // apiUrl, - // apiVersion, secretKey, publishableKey, }); diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index f0e7cc1..53c19a1 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -39,9 +39,13 @@ app.on( ".well-known/oauth-protected-resource", oauthCorsMiddleware, (c) => { + // NOTE - The resource URL is the `/mcp` endpoint + const req = c.req.raw; + const url = new URL(req.url); + const resourceUrl = `${url.origin}/mcp`; const result = generateClerkProtectedResourceMetadata({ publishableKey: c.env.CLERK_PUBLISHABLE_KEY, - resourceUrl: "https://myapp.com/current-route", + resourceUrl, }); return c.json(result); @@ -59,8 +63,8 @@ app.on( ["GET", "OPTIONS"], ".well-known/oauth-authorization-server", oauthCorsMiddleware, - (c) => { - const result = fetchClerkAuthorizationServerMetadata({ + async (c) => { + const result = await fetchClerkAuthorizationServerMetadata({ publishableKey: c.env.CLERK_PUBLISHABLE_KEY, }); // TODO - Remove this log statement, I just wanted to see the output since it isn't typed properly diff --git a/examples/auth-clerk/wrangler.jsonc b/examples/auth-clerk/wrangler.jsonc index a0bcfe5..48d0814 100644 --- a/examples/auth-clerk/wrangler.jsonc +++ b/examples/auth-clerk/wrangler.jsonc @@ -2,10 +2,8 @@ "$schema": "node_modules/wrangler/config-schema.json", "name": "auth-clerk", "main": "src/index.ts", - "compatibility_date": "2025-09-11" - // "compatibility_flags": [ - // "nodejs_compat" - // ], + "compatibility_date": "2025-09-11", + "compatibility_flags": ["nodejs_compat"] // "vars": { // "MY_VAR": "my-variable" // }, From b26571b8b85ac67df6b12def5c141f962f6aed03 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 10:50:38 +0200 Subject: [PATCH 05/17] Separate out the well-known endpoints into their own router --- examples/auth-clerk/.dev.vars.example | 7 +- .../src/auth/{auth.ts => middleware.ts} | 0 examples/auth-clerk/src/auth/routes.ts | 92 +++++++++++++++++++ examples/auth-clerk/src/index.ts | 76 ++------------- 4 files changed, 103 insertions(+), 72 deletions(-) rename examples/auth-clerk/src/auth/{auth.ts => middleware.ts} (100%) create mode 100644 examples/auth-clerk/src/auth/routes.ts diff --git a/examples/auth-clerk/.dev.vars.example b/examples/auth-clerk/.dev.vars.example index 1643778..04e43e6 100644 --- a/examples/auth-clerk/.dev.vars.example +++ b/examples/auth-clerk/.dev.vars.example @@ -1,6 +1,7 @@ # Find in Clerk Dashboard under Application > Configure > Api Keys CLERK_PUBLISHABLE_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_... -# Create an OAuth app in Clerk: https://dashboard.clerk.com/last-active?path=user-authentication/oauth-applications -CLERK_OAUTH_CLIENT_ID= -CLERK_OAUTH_CLIENT_SECRET= \ No newline at end of file + +# Recall that for this example to work, you must +# create an OAuth app in Clerk: +# https://dashboard.clerk.com/last-active?path=user-authentication/oauth-applications diff --git a/examples/auth-clerk/src/auth/auth.ts b/examples/auth-clerk/src/auth/middleware.ts similarity index 100% rename from examples/auth-clerk/src/auth/auth.ts rename to examples/auth-clerk/src/auth/middleware.ts diff --git a/examples/auth-clerk/src/auth/routes.ts b/examples/auth-clerk/src/auth/routes.ts new file mode 100644 index 0000000..27bb714 --- /dev/null +++ b/examples/auth-clerk/src/auth/routes.ts @@ -0,0 +1,92 @@ +// https://github.com/clerk/mcp-tools +import { + corsHeaders, + fetchClerkAuthorizationServerMetadata, + generateClerkProtectedResourceMetadata, +} from "@clerk/mcp-tools/server"; +import { Hono } from "hono"; +import { cors } from "hono/cors"; +import type { AppType } from "../types"; + +/** + * Create middleware to handle CORS for the OAuth endpoints, + * this is useful for testing auth from a browser-based MCP client, + * or the MCP inspector (`bunx @modelcontextprotocol/inspector`) + * + * @note We convert the CORS headers that we get from the @clerk/mcp-tools library + * into a format that Hono middleware can understand + * + * @see https://github.com/clerk/mcp-tools/blob/main/server.ts + */ +const oauthCorsMiddleware = cors({ + origin: corsHeaders["Access-Control-Allow-Origin"], + // HACK - split the comma-separated list of methods into an array + allowMethods: corsHeaders["Access-Control-Allow-Methods"].split(","), + allowHeaders: [corsHeaders["Access-Control-Allow-Headers"]], + maxAge: parseInt(corsHeaders["Access-Control-Max-Age"], 10), +}); + +export const authRoutes = new Hono(); + +/** + * Implement the OAuth Protected Resource endpoint + * + * We define the "OPTIONS" method to handle preflight requests with the CORS middleware + * + * @note - This expects that the resource URL we are protecting is the `/mcp` endpoint + */ +authRoutes.on( + ["GET", "OPTIONS"], + ".well-known/oauth-protected-resource", + oauthCorsMiddleware, + (c) => { + if (!c.env.CLERK_PUBLISHABLE_KEY) { + console.error( + "CLERK_PUBLISHABLE_KEY is not set for OAuth Authorization Server endpoint", + ); + return c.json({ error: "Internal Server Error" }, 500); + } + + // NOTE - The resource URL we are protecting is the `/mcp` endpoint + const req = c.req.raw; + const url = new URL(req.url); + const resourceUrl = `${url.origin}/mcp`; + + const result = generateClerkProtectedResourceMetadata({ + publishableKey: c.env.CLERK_PUBLISHABLE_KEY, + resourceUrl, + }); + + return c.json(result); + }, +); + +/** + * Implement the OAuth Authorization Server endpoint + * + * We define the "OPTIONS" method to handle preflight requests with the CORS middleware + * + * @note - In our case, Clerk is the authorization server, so we shouldn't *need* to implement this; + * however, in earlier versions of the MCP spec (prior to 2025-06-18), this route was expected/required, + * so we implement it for backwards compatibility with clients. + */ +authRoutes.on( + ["GET", "OPTIONS"], + ".well-known/oauth-authorization-server", + oauthCorsMiddleware, + async (c) => { + if (!c.env.CLERK_PUBLISHABLE_KEY) { + console.error( + "CLERK_PUBLISHABLE_KEY is not set for OAuth Authorization Server endpoint", + ); + return c.json({ error: "Internal Server Error" }, 500); + } + + // NOTE - If your CLERK_PUBLISHABLE_KEY is misconfigured, this *will* result in a 500 + const result = await fetchClerkAuthorizationServerMetadata({ + publishableKey: c.env.CLERK_PUBLISHABLE_KEY, + }); + + return c.json(result); + }, +); diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index 53c19a1..4983f06 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -1,78 +1,14 @@ -// https://github.com/clerk/mcp-tools -import { - corsHeaders, - fetchClerkAuthorizationServerMetadata, - generateClerkProtectedResourceMetadata, -} from "@clerk/mcp-tools/server"; import { Hono } from "hono"; -import { cors } from "hono/cors"; -import { mcpAuthMiddleware } from "./auth/auth"; +import { mcpAuthMiddleware } from "./auth/middleware"; +import { authRoutes } from "./auth/routes"; import { httpHandler as mcpHttpHandler } from "./mcp"; import type { AppType } from "./types"; // Create a Hono app to serve our api routes const app = new Hono(); -/** - * Create middleware to handle CORS for the OAuth endpoints, - * this is useful for testing auth from a browser-based MCP client, - * or the MCP inspector (which makes requests from a browser) - * - * We convert the CORS headers that we get from the @clerk/mcp-tools library - * into a format that Hono middleware can understand - * - * https://github.com/clerk/mcp-tools/blob/main/server.ts - */ -const oauthCorsMiddleware = cors({ - origin: corsHeaders["Access-Control-Allow-Origin"], - // HACK - split the comma-separated list of methods into an array - allowMethods: corsHeaders["Access-Control-Allow-Methods"].split(","), - allowHeaders: [corsHeaders["Access-Control-Allow-Headers"]], - maxAge: parseInt(corsHeaders["Access-Control-Max-Age"], 10), -}); - -/** - * Implement the OAuth Protected Resource endpoint - */ -app.on( - ["GET", "OPTIONS"], - ".well-known/oauth-protected-resource", - oauthCorsMiddleware, - (c) => { - // NOTE - The resource URL is the `/mcp` endpoint - const req = c.req.raw; - const url = new URL(req.url); - const resourceUrl = `${url.origin}/mcp`; - const result = generateClerkProtectedResourceMetadata({ - publishableKey: c.env.CLERK_PUBLISHABLE_KEY, - resourceUrl, - }); - - return c.json(result); - }, -); - -/** - * Implement the OAuth Authorization Server endpoint - * - * @note - In our case, Clerk is the authorization server, so we shouldn't *need* to implement this; - * however, in earlier versions of the MCP spec, this was required, - * so we implement it for backwards compatibility with clients. - */ -app.on( - ["GET", "OPTIONS"], - ".well-known/oauth-authorization-server", - oauthCorsMiddleware, - async (c) => { - const result = await fetchClerkAuthorizationServerMetadata({ - publishableKey: c.env.CLERK_PUBLISHABLE_KEY, - }); - // TODO - Remove this log statement, I just wanted to see the output since it isn't typed properly - console.log("🔑 Clerk Authorization Server Metadata:", result); - - return c.json(result); - }, -); +// Mount the `.well-known` routes for OAuth discovery to work +app.route("/", authRoutes); // Add MCP endpoint app.all("/mcp", mcpAuthMiddleware, async (c) => { @@ -82,7 +18,9 @@ app.all("/mcp", mcpAuthMiddleware, async (c) => { // Root route describing where to find the MCP endpoint app.get("/", (c) => { - return c.text("Authenticated MCP Server! Connect to /mcp"); + return c.text( + "Authenticated MCP Server! Connect to /mcp to start the auth flow", + ); }); export default app; From f41e7911056eeffd1abfc7e940c012e376e65c77 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 11:02:15 +0200 Subject: [PATCH 06/17] Start cleaning up middleware by removing the 3rd party hono-clerk logic that is not applicable to oauth --- examples/auth-clerk/src/auth/middleware.ts | 75 ++++++---------------- examples/auth-clerk/src/auth/types.ts | 15 +++++ 2 files changed, 35 insertions(+), 55 deletions(-) create mode 100644 examples/auth-clerk/src/auth/types.ts diff --git a/examples/auth-clerk/src/auth/middleware.ts b/examples/auth-clerk/src/auth/middleware.ts index e3dabb4..4d6c90f 100644 --- a/examples/auth-clerk/src/auth/middleware.ts +++ b/examples/auth-clerk/src/auth/middleware.ts @@ -1,20 +1,10 @@ import { createClerkClient } from "@clerk/backend"; import { TokenType } from "@clerk/backend/internal"; import { verifyClerkToken } from "@clerk/mcp-tools/server"; -import { env } from "hono/adapter"; import { createMiddleware } from "hono/factory"; import type { AppType } from "../types"; import { BaseAuthError, InvalidTokenError } from "./errors"; - -// Minimal AuthInfo shape to avoid importing @modelcontextprotocol/sdk types -type AuthInfo = { - token: string; - /** Epoch seconds */ - expiresAt?: number; - scopes: string[]; - /** Additional provider-specific data */ - extra?: Record; -}; +import type { AuthInfo } from "./types"; /** * Create auth middleware for the MCP server. @@ -28,66 +18,41 @@ export const mcpAuthMiddleware = createMiddleware< const req = c.req.raw; const url = new URL(req.url); const origin = url.origin; - // This is the path to our OAuth Protected Resource endpoint we set up in index.ts + // This is the path to our OAuth Protected Resource endpoint we set up in `auth/routes.ts` const resourceMetadataPath = "/.well-known/oauth-protected-resource"; const resourceMetadataUrl = `${origin}${resourceMetadataPath}`; - try { - const authHeader = c.req.header("Authorization"); - const [type, token] = authHeader?.split(" ") || []; - const bearerToken = type?.toLowerCase() === "bearer" ? token : undefined; - - // Return 401 with proper www-authenticate header if no authorization is provided - if (!bearerToken) { - const err = new InvalidTokenError("No authorization provided"); - return new Response(JSON.stringify(err.toResponseObject()), { - status: err.status, - headers: { - "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, - "Content-Type": "application/json", - }, - }); - } + const authHeader = c.req.header("Authorization"); + const [type, token] = authHeader?.split(" ") || []; + const bearerToken = type?.toLowerCase() === "bearer" ? token : undefined; + + // Return 401 with proper www-authenticate header if no authorization is provided + if (!bearerToken) { + const err = new InvalidTokenError("No authorization provided"); + return new Response(JSON.stringify(err.toResponseObject()), { + status: err.status, + headers: { + "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, + "Content-Type": "application/json", + }, + }); + } - const clerkEnv = env(c); - const { secretKey, publishableKey, ...rest } = { - secretKey: clerkEnv.CLERK_SECRET_KEY || "", - publishableKey: clerkEnv.CLERK_PUBLISHABLE_KEY || "", - }; + try { + const secretKey = c.env.CLERK_SECRET_KEY || ""; + const publishableKey = c.env.CLERK_PUBLISHABLE_KEY || ""; const clerkClient = createClerkClient({ - ...rest, secretKey, publishableKey, }); const requestState = await clerkClient.authenticateRequest(c.req.raw, { - ...rest, secretKey, publishableKey, acceptsToken: TokenType.OAuthToken, }); - // Copied this logic from the Hono middleware, but might not be necessary for OAuth flows - // (This logic assumes classic Clerk session auth is being used) - // https://github.com/honojs/middleware/blob/main/packages/clerk-auth/src/clerk-auth.ts - if (requestState.headers) { - requestState.headers.forEach((value, key) => { - c.res.headers.append(key, value); - }); - - const locationHeader = requestState.headers.get("location"); - - if (locationHeader) { - return c.redirect(locationHeader, 307); - } - - // @ts-expect-error - defensive check - if (requestState.status === "handshake") { - throw new Error("Clerk: unexpected handshake without redirect"); - } - } - let authInfo: AuthInfo | undefined; try { // This is the result of the authenticateRequest call, with the token type being OAuthToken diff --git a/examples/auth-clerk/src/auth/types.ts b/examples/auth-clerk/src/auth/types.ts new file mode 100644 index 0000000..1fbbf16 --- /dev/null +++ b/examples/auth-clerk/src/auth/types.ts @@ -0,0 +1,15 @@ +/** + * Minimal AuthInfo shape that resembles the @modelcontextprotocol/sdk AuthInfo type: + * + * ```typescript + * import { AuthInfo } from "@modelcontextprotocol/sdk/types.js"; + * ``` + */ +export type AuthInfo = { + token: string; + /** Seconds since epoch */ + expiresAt?: number; + scopes: string[]; + /** Additional provider-specific data */ + extra?: Record; +}; From 97e78e3e5cc32bc193b0b18649dc58785a900149 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 11:04:20 +0200 Subject: [PATCH 07/17] Set up a hono logger --- examples/auth-clerk/src/index.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index 4983f06..552eb7c 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -1,4 +1,5 @@ import { Hono } from "hono"; +import { logger } from 'hono/logger' import { mcpAuthMiddleware } from "./auth/middleware"; import { authRoutes } from "./auth/routes"; import { httpHandler as mcpHttpHandler } from "./mcp"; @@ -7,6 +8,9 @@ import type { AppType } from "./types"; // Create a Hono app to serve our api routes const app = new Hono(); +// Set up a logger to log requests +app.use(logger()); + // Mount the `.well-known` routes for OAuth discovery to work app.route("/", authRoutes); From 25eb21c84595b623bdbd58203c85199dde2eb70a Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 13:32:43 +0200 Subject: [PATCH 08/17] Cut out some silliness when creating authInfo --- examples/auth-clerk/src/auth/middleware.ts | 24 ++++++---------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/examples/auth-clerk/src/auth/middleware.ts b/examples/auth-clerk/src/auth/middleware.ts index 4d6c90f..b1be131 100644 --- a/examples/auth-clerk/src/auth/middleware.ts +++ b/examples/auth-clerk/src/auth/middleware.ts @@ -53,24 +53,11 @@ export const mcpAuthMiddleware = createMiddleware< acceptsToken: TokenType.OAuthToken, }); - let authInfo: AuthInfo | undefined; - try { - // This is the result of the authenticateRequest call, with the token type being OAuthToken - const auth = requestState.toAuth(); - // TODO - call verifyClerkToken - const verifiedAuth = verifyClerkToken(auth, token); - authInfo = verifiedAuth; - } catch (e) { - console.error("Unexpected error authenticating bearer token:", e); - const publicError = new InvalidTokenError("Invalid token"); - return new Response(JSON.stringify(publicError.toResponseObject()), { - status: publicError.status, - headers: { - "WWW-Authenticate": `Bearer error="${publicError.errorCode}", error_description="${publicError.message}", resource_metadata="${resourceMetadataUrl}"`, - "Content-Type": "application/json", - }, - }); - } + // This is the result of the authenticateRequest call, with the token type being OAuthToken + const auth = requestState.toAuth(); + + // Source code for verifyClerkToken: https://github.com/clerk/mcp-tools/blob/b0c946c97c41f248289c31174d0d5c84e977c55c/server.ts#L103 + const authInfo = verifyClerkToken(auth, token); // Require valid auth for this endpoint if (!authInfo) { @@ -84,6 +71,7 @@ export const mcpAuthMiddleware = createMiddleware< }); } + // Optional: enforce scopes if desired; read from context if provided upstream // const requiredScopes = c.get("requiredScopes") as string[] | undefined; // if (Array.isArray(requiredScopes) && requiredScopes.length > 0) { From fb1dbbc5722b67311308f9dc2113b4cda21813f1 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 13:54:09 +0200 Subject: [PATCH 09/17] Update example package name --- bun.lock | 16 ++++++++-------- examples/auth-clerk/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bun.lock b/bun.lock index 276bfe7..a7f508a 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,7 @@ }, }, "examples/auth-clerk": { - "name": "auth-clerk", + "name": "@mcp-lite-examples/auth-clerk", "dependencies": { "@clerk/backend": "^2.13.0", "@clerk/mcp-tools": "^0.3.1", @@ -26,7 +26,7 @@ }, "examples/validation-arktype": { "name": "@mcp-lite-examples/validation-arktype", - "version": "1.0.2", + "version": "1.0.3", "dependencies": { "arktype": "^2.1.22", "hono": "^4.9.5", @@ -39,7 +39,7 @@ }, "examples/validation-valibot": { "name": "@mcp-lite-examples/validation-valibot", - "version": "1.0.2", + "version": "1.0.3", "dependencies": { "@valibot/to-json-schema": "^1.3.0", "hono": "^4.9.5", @@ -53,7 +53,7 @@ }, "examples/validation-zod": { "name": "@mcp-lite-examples/validation-zod", - "version": "1.0.2", + "version": "1.0.3", "dependencies": { "hono": "^4.9.5", "mcp-lite": "workspace:*", @@ -66,7 +66,7 @@ }, "packages/core": { "name": "mcp-lite", - "version": "0.1.4", + "version": "0.2.0", "dependencies": { "@standard-schema/spec": "^1.0.0", }, @@ -98,7 +98,7 @@ }, "packages/test-utils": { "name": "@internal/test-utils", - "version": "1.0.2", + "version": "1.0.3", "dependencies": { "mcp-lite": "workspace:*", }, @@ -324,6 +324,8 @@ "@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="], + "@mcp-lite-examples/auth-clerk": ["@mcp-lite-examples/auth-clerk@workspace:examples/auth-clerk"], + "@mcp-lite-examples/validation-arktype": ["@mcp-lite-examples/validation-arktype@workspace:examples/validation-arktype"], "@mcp-lite-examples/validation-valibot": ["@mcp-lite-examples/validation-valibot@workspace:examples/validation-valibot"], @@ -406,8 +408,6 @@ "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], - "auth-clerk": ["auth-clerk@workspace:examples/auth-clerk"], - "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], "better-path-resolve": ["better-path-resolve@1.0.0", "", { "dependencies": { "is-windows": "^1.0.0" } }, "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g=="], diff --git a/examples/auth-clerk/package.json b/examples/auth-clerk/package.json index 8e3e390..59358da 100644 --- a/examples/auth-clerk/package.json +++ b/examples/auth-clerk/package.json @@ -1,5 +1,5 @@ { - "name": "auth-clerk", + "name": "@mcp-lite-examples/auth-clerk", "type": "module", "scripts": { "dev": "wrangler dev", From 37b66e02a0ebc58b85e1408ec713b736bc127505 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 13:55:05 +0200 Subject: [PATCH 10/17] Update wrangler --- bun.lock | 8 ++++---- examples/auth-clerk/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bun.lock b/bun.lock index a7f508a..0066eca 100644 --- a/bun.lock +++ b/bun.lock @@ -21,7 +21,7 @@ "valibot": "^1.1.0", }, "devDependencies": { - "wrangler": "^4.4.0", + "wrangler": "^4.36.0", }, }, "examples/validation-arktype": { @@ -666,7 +666,7 @@ "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], - "miniflare": ["miniflare@4.20250906.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^7.10.0", "workerd": "1.20250906.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-T/RWn1sa0ien80s6NjU+Un/tj12gR6wqScZoiLeMJDD4/fK0UXfnbWXJDubnUED8Xjm7RPQ5ESYdE+mhPmMtuQ=="], + "miniflare": ["miniflare@4.20250906.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", "workerd": "1.20250906.0", "ws": "8.18.0", "youch": "4.1.0-beta.10", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-yuPHog7j+GKHtRaKKF3Mpwvb5SVtvmkQpY/f9Ue0xhG/fYQcaxTKVO6RAB1pUN1jSyvmDOxVEAFFVoni8GYl3g=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], @@ -916,7 +916,7 @@ "workerd": ["workerd@1.20250906.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250906.0", "@cloudflare/workerd-darwin-arm64": "1.20250906.0", "@cloudflare/workerd-linux-64": "1.20250906.0", "@cloudflare/workerd-linux-arm64": "1.20250906.0", "@cloudflare/workerd-windows-64": "1.20250906.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-ryVyEaqXPPsr/AxccRmYZZmDAkfQVjhfRqrNTlEeN8aftBk6Ca1u7/VqmfOayjCXrA+O547TauebU+J3IpvFXw=="], - "wrangler": ["wrangler@4.35.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.3", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250906.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.21", "workerd": "1.20250906.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250906.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-HbyXtbrh4Fi3mU8ussY85tVdQ74qpVS1vctUgaPc+bPrXBTqfDLkZ6VRtHAVF/eBhz4SFmhJtCQpN1caY2Ak8A=="], + "wrangler": ["wrangler@4.36.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.7.3", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250906.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.21", "workerd": "1.20250906.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250906.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-J1sZh7ePy7BtzvIyt9ufiL6aQOW6OE0VEi9YJiyXOuaXDKrR7V5HJBTsraNdFDqXgi30mYGGBVs0mgZHGRhTBA=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], @@ -970,7 +970,7 @@ "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "miniflare/undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="], + "miniflare/undici": ["undici@7.14.0", "", {}, "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ=="], "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], diff --git a/examples/auth-clerk/package.json b/examples/auth-clerk/package.json index 59358da..b25dd65 100644 --- a/examples/auth-clerk/package.json +++ b/examples/auth-clerk/package.json @@ -15,6 +15,6 @@ "valibot": "^1.1.0" }, "devDependencies": { - "wrangler": "^4.4.0" + "wrangler": "^4.36.0" } } From 4b35eccb202bf20ca5314a1f241931bfd6a512e9 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 14:40:07 +0200 Subject: [PATCH 11/17] Clean up auth middleware: Add utils for PRM, remove unnecessary error abstractions --- examples/auth-clerk/src/auth/errors.ts | 37 ---------- examples/auth-clerk/src/auth/middleware.ts | 81 +++++----------------- examples/auth-clerk/src/auth/routes.ts | 28 +++++++- examples/auth-clerk/src/auth/utils.ts | 17 +++++ examples/auth-clerk/src/index.ts | 2 +- 5 files changed, 60 insertions(+), 105 deletions(-) delete mode 100644 examples/auth-clerk/src/auth/errors.ts create mode 100644 examples/auth-clerk/src/auth/utils.ts diff --git a/examples/auth-clerk/src/auth/errors.ts b/examples/auth-clerk/src/auth/errors.ts deleted file mode 100644 index 4070abe..0000000 --- a/examples/auth-clerk/src/auth/errors.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Auth errors - mimics the errors from the @modelcontextprotocol/sdk package - */ - -/** - * Base auth error class - */ -export class BaseAuthError extends Error { - errorCode: string; - status: number; - constructor(code: string, message: string, status: number) { - super(message); - this.errorCode = code; - this.status = status; - } - toResponseObject(): Record { - return { error: this.errorCode, error_description: this.message }; - } -} - -export class InvalidTokenError extends BaseAuthError { - constructor(message: string) { - super("invalid_token", message, 401); - } -} - -export class InsufficientScopeError extends BaseAuthError { - constructor(message: string) { - super("insufficient_scope", message, 403); - } -} - -export class ServerError extends BaseAuthError { - constructor(message: string) { - super("server_error", message, 500); - } -} diff --git a/examples/auth-clerk/src/auth/middleware.ts b/examples/auth-clerk/src/auth/middleware.ts index b1be131..7dd1e0e 100644 --- a/examples/auth-clerk/src/auth/middleware.ts +++ b/examples/auth-clerk/src/auth/middleware.ts @@ -3,8 +3,8 @@ import { TokenType } from "@clerk/backend/internal"; import { verifyClerkToken } from "@clerk/mcp-tools/server"; import { createMiddleware } from "hono/factory"; import type { AppType } from "../types"; -import { BaseAuthError, InvalidTokenError } from "./errors"; import type { AuthInfo } from "./types"; +import { getPRMUrl } from "./utils"; /** * Create auth middleware for the MCP server. @@ -15,27 +15,20 @@ import type { AuthInfo } from "./types"; export const mcpAuthMiddleware = createMiddleware< AppType & { Variables: { auth: AuthInfo } } >(async (c, next) => { - const req = c.req.raw; - const url = new URL(req.url); - const origin = url.origin; - // This is the path to our OAuth Protected Resource endpoint we set up in `auth/routes.ts` - const resourceMetadataPath = "/.well-known/oauth-protected-resource"; - const resourceMetadataUrl = `${origin}${resourceMetadataPath}`; - const authHeader = c.req.header("Authorization"); const [type, token] = authHeader?.split(" ") || []; const bearerToken = type?.toLowerCase() === "bearer" ? token : undefined; // Return 401 with proper www-authenticate header if no authorization is provided if (!bearerToken) { - const err = new InvalidTokenError("No authorization provided"); - return new Response(JSON.stringify(err.toResponseObject()), { - status: err.status, - headers: { - "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, - "Content-Type": "application/json", - }, - }); + // Get the resource metadata url for the protected resource + // We return this in the `WWW-Authenticate` header so the MCP client knows where to find the protected resource metadata + const resourceMetadataUrl = getPRMUrl(c.req.raw); + c.header( + "WWW-Authenticate", + `Bearer resource_metadata="${resourceMetadataUrl}"`, + ); + return c.json({ error: "Unauthorized" }, 401); } try { @@ -53,67 +46,27 @@ export const mcpAuthMiddleware = createMiddleware< acceptsToken: TokenType.OAuthToken, }); - // This is the result of the authenticateRequest call, with the token type being OAuthToken + // This is the result of the authenticateRequest call, with the `TokenType.OAuthToken` type const auth = requestState.toAuth(); - // Source code for verifyClerkToken: https://github.com/clerk/mcp-tools/blob/b0c946c97c41f248289c31174d0d5c84e977c55c/server.ts#L103 + // TODO - We could probably implement `verifyClerkToken` ourselves, to have clearer control over error paths and error logging + // (the library implementation uses console.error for logging) + // + // Source code for verifyClerkToken: + // https://github.com/clerk/mcp-tools/blob/b0c946c97c41f248289c31174d0d5c84e977c55c/server.ts#L103 const authInfo = verifyClerkToken(auth, token); // Require valid auth for this endpoint if (!authInfo) { - const err = new InvalidTokenError("Invalid or missing token"); - return new Response(JSON.stringify(err.toResponseObject()), { - status: err.status, - headers: { - "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, - "Content-Type": "application/json", - }, - }); + return c.json({ error: "Unauthorized" }, 401); } - - // Optional: enforce scopes if desired; read from context if provided upstream - // const requiredScopes = c.get("requiredScopes") as string[] | undefined; - // if (Array.isArray(requiredScopes) && requiredScopes.length > 0) { - // const hasAll = requiredScopes.every((s: string) => - // authInfo.scopes.includes(s), - // ); - // if (!hasAll) { - // const err = new InsufficientScopeError("Insufficient scope"); - // return new Response(JSON.stringify(err.toResponseObject()), { - // status: err.status, - // headers: { - // "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, - // "Content-Type": "application/json", - // }, - // }); - // } - // } - - // Expiry check (epoch seconds) - // if (authInfo.expiresAt && authInfo.expiresAt < Date.now() / 1000) { - // const err = new InvalidTokenError("Token has expired"); - // return new Response(JSON.stringify(err.toResponseObject()), { - // status: err.status, - // headers: { - // "WWW-Authenticate": `Bearer error="${err.errorCode}", error_description="${err.message}", resource_metadata="${resourceMetadataUrl}"`, - // "Content-Type": "application/json", - // }, - // }); - // } - // Attach auth to Request and Hono context for downstream handlers c.set("auth", authInfo); await next(); } catch (error) { - if (error instanceof BaseAuthError) { - return new Response(JSON.stringify(error.toResponseObject()), { - status: error.status, - headers: { "Content-Type": "application/json" }, - }); - } - console.error("Unexpected auth middleware error:", error); + console.error("Unexpected mcp auth middleware error:", error); return c.json({ error: "Internal Server Error" }, 500); } }); diff --git a/examples/auth-clerk/src/auth/routes.ts b/examples/auth-clerk/src/auth/routes.ts index 27bb714..a212c82 100644 --- a/examples/auth-clerk/src/auth/routes.ts +++ b/examples/auth-clerk/src/auth/routes.ts @@ -7,6 +7,7 @@ import { import { Hono } from "hono"; import { cors } from "hono/cors"; import type { AppType } from "../types"; +import { getResourceUrl } from "./utils"; /** * Create middleware to handle CORS for the OAuth endpoints, @@ -48,13 +49,34 @@ authRoutes.on( } // NOTE - The resource URL we are protecting is the `/mcp` endpoint - const req = c.req.raw; - const url = new URL(req.url); - const resourceUrl = `${url.origin}/mcp`; + // const req = c.req.raw; + // const url = new URL(req.url); + // const resourceUrl = `${url.origin}/mcp`; + + const resourceUrl = getResourceUrl(c.req.raw); + + const result = generateClerkProtectedResourceMetadata({ + publishableKey: c.env.CLERK_PUBLISHABLE_KEY, + resourceUrl, + }); + + return c.json(result); + }, +); + +authRoutes.on( + ["GET", "OPTIONS"], + "/.well-known/oauth-protected-resource/mcp", + oauthCorsMiddleware, + (c) => { + const resourceUrl = getResourceUrl(c.req.raw); const result = generateClerkProtectedResourceMetadata({ publishableKey: c.env.CLERK_PUBLISHABLE_KEY, resourceUrl, + properties: { + scopes_supported: ["profile", "email"], + }, }); return c.json(result); diff --git a/examples/auth-clerk/src/auth/utils.ts b/examples/auth-clerk/src/auth/utils.ts new file mode 100644 index 0000000..11a29bb --- /dev/null +++ b/examples/auth-clerk/src/auth/utils.ts @@ -0,0 +1,17 @@ +// Given a protected resource metadata url generate the url of the original +// resource +export function getResourceUrl(req: Request) { + const url = new URL(req.url); + url.pathname = url.pathname.replace( + /\.well-known\/oauth-protected-resource\/?/, + "", + ); + return url.toString(); +} + +// Get given a request, generate a protected resource metadata url for the +// given resource url +export function getPRMUrl(req: Request) { + const url = new URL(req.url); + return `${url.origin}/.well-known/oauth-protected-resource${url.pathname}`; +} diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index 552eb7c..d997ce6 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -1,5 +1,5 @@ import { Hono } from "hono"; -import { logger } from 'hono/logger' +import { logger } from "hono/logger"; import { mcpAuthMiddleware } from "./auth/middleware"; import { authRoutes } from "./auth/routes"; import { httpHandler as mcpHttpHandler } from "./mcp"; From ed90f2a5b291330f3adc588811c05dad167db108 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 14:40:17 +0200 Subject: [PATCH 12/17] Format .changeset/config.json --- .changeset/config.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.changeset/config.json b/.changeset/config.json index d7624b7..8826c42 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -7,7 +7,5 @@ "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", - "ignore": [ - "@mcp-lite-examples/*" - ] + "ignore": ["@mcp-lite-examples/*"] } From d03c2d6786e2f9253cfe16d6edd670702da3449f Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 15:40:12 +0200 Subject: [PATCH 13/17] Tweak welcome message --- examples/auth-clerk/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index d997ce6..e6da2d9 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -23,7 +23,7 @@ app.all("/mcp", mcpAuthMiddleware, async (c) => { // Root route describing where to find the MCP endpoint app.get("/", (c) => { return c.text( - "Authenticated MCP Server! Connect to /mcp to start the auth flow", + "This is Authenticated MCP Server\n\nConnect to /mcp with your MCP client to start the auth flow", ); }); From d72b51e75e83d6525b0e0d2c1ce44e74fb8edc57 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 18:25:34 +0200 Subject: [PATCH 14/17] (wip) Start adding authInfo to the library itself --- examples/auth-clerk/src/auth/middleware.ts | 2 ++ examples/auth-clerk/src/index.ts | 3 ++- packages/core/src/auth.ts | 12 ++++++++++++ packages/core/src/transport-http.ts | 19 ++++++++++++++++--- 4 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 packages/core/src/auth.ts diff --git a/examples/auth-clerk/src/auth/middleware.ts b/examples/auth-clerk/src/auth/middleware.ts index 7dd1e0e..3b441a0 100644 --- a/examples/auth-clerk/src/auth/middleware.ts +++ b/examples/auth-clerk/src/auth/middleware.ts @@ -26,6 +26,8 @@ export const mcpAuthMiddleware = createMiddleware< const resourceMetadataUrl = getPRMUrl(c.req.raw); c.header( "WWW-Authenticate", + // NOTE - The mcp sdk adds `error` and `error_description` to this header as well, depending on the error + // see: https://github.com/modelcontextprotocol/typescript-sdk/blob/b28c297184cb0cb64611a3357d6438dd1b0824c6/src/server/auth/middleware/bearerAuth.ts#L76C1-L95C8 `Bearer resource_metadata="${resourceMetadataUrl}"`, ); return c.json({ error: "Unauthorized" }, 401); diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index e6da2d9..7b7d6f7 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -16,7 +16,8 @@ app.route("/", authRoutes); // Add MCP endpoint app.all("/mcp", mcpAuthMiddleware, async (c) => { - const response = await mcpHttpHandler(c.req.raw); + const authInfo = c.get("auth"); + const response = await mcpHttpHandler(c.req.raw, { authInfo }); return response; }); diff --git a/packages/core/src/auth.ts b/packages/core/src/auth.ts new file mode 100644 index 0000000..d5b3bce --- /dev/null +++ b/packages/core/src/auth.ts @@ -0,0 +1,12 @@ +/** + * Similar type to the @modelcontextprotocol/sdk AuthInfo type. + * Allows for cross-compatibility with the @modelcontextprotocol/sdk. + */ +export type AuthInfo = { + token: string; + scopes: string[]; + /** Token expiry in seconds since epoch */ + expiresAt?: number; + /** Additional provider-specific data */ + extra?: Record; +}; diff --git a/packages/core/src/transport-http.ts b/packages/core/src/transport-http.ts index 72706eb..faf06f0 100644 --- a/packages/core/src/transport-http.ts +++ b/packages/core/src/transport-http.ts @@ -1,3 +1,4 @@ +import type { AuthInfo } from "./auth.js"; import { JSON_RPC_VERSION, MCP_LAST_EVENT_ID_HEADER, @@ -66,7 +67,12 @@ export class StreamableHttpTransport { this.allowedHosts = options.allowedHosts; } - bind(server: McpServer): (request: Request) => Promise { + bind( + server: McpServer, + ): ( + request: Request, + options?: { authInfo?: AuthInfo }, + ) => Promise { this.server = server; server._setNotificationSender(async (sessionId, notification, options) => { @@ -132,7 +138,10 @@ export class StreamableHttpTransport { return this.handleRequest.bind(this); } - private async handleRequest(request: Request): Promise { + private async handleRequest( + request: Request, + options?: { authInfo?: AuthInfo }, + ): Promise { if (!this.server) { throw new Error("Transport not bound to a server"); } @@ -176,7 +185,10 @@ export class StreamableHttpTransport { } } - private async handlePost(request: Request): Promise { + private async handlePost( + request: Request, + options?: { authInfo?: AuthInfo }, + ): Promise { try { const body = await request.text(); const jsonRpcMessage = parseJsonRpc(body); @@ -252,6 +264,7 @@ export class StreamableHttpTransport { const response = await this.server?._dispatch(jsonRpcMessage, { sessionId: sessionId || undefined, + authInfo: options?.authInfo, }); if (isInitializeRequest && response) { From 42a9fc82783454d96a4faf5789bc793b590d5770 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Fri, 12 Sep 2025 18:25:42 +0200 Subject: [PATCH 15/17] Revert "(wip) Start adding authInfo to the library itself" This reverts commit d72b51e75e83d6525b0e0d2c1ce44e74fb8edc57. --- examples/auth-clerk/src/auth/middleware.ts | 2 -- examples/auth-clerk/src/index.ts | 3 +-- packages/core/src/auth.ts | 12 ------------ packages/core/src/transport-http.ts | 19 +++---------------- 4 files changed, 4 insertions(+), 32 deletions(-) delete mode 100644 packages/core/src/auth.ts diff --git a/examples/auth-clerk/src/auth/middleware.ts b/examples/auth-clerk/src/auth/middleware.ts index 3b441a0..7dd1e0e 100644 --- a/examples/auth-clerk/src/auth/middleware.ts +++ b/examples/auth-clerk/src/auth/middleware.ts @@ -26,8 +26,6 @@ export const mcpAuthMiddleware = createMiddleware< const resourceMetadataUrl = getPRMUrl(c.req.raw); c.header( "WWW-Authenticate", - // NOTE - The mcp sdk adds `error` and `error_description` to this header as well, depending on the error - // see: https://github.com/modelcontextprotocol/typescript-sdk/blob/b28c297184cb0cb64611a3357d6438dd1b0824c6/src/server/auth/middleware/bearerAuth.ts#L76C1-L95C8 `Bearer resource_metadata="${resourceMetadataUrl}"`, ); return c.json({ error: "Unauthorized" }, 401); diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index 7b7d6f7..e6da2d9 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -16,8 +16,7 @@ app.route("/", authRoutes); // Add MCP endpoint app.all("/mcp", mcpAuthMiddleware, async (c) => { - const authInfo = c.get("auth"); - const response = await mcpHttpHandler(c.req.raw, { authInfo }); + const response = await mcpHttpHandler(c.req.raw); return response; }); diff --git a/packages/core/src/auth.ts b/packages/core/src/auth.ts deleted file mode 100644 index d5b3bce..0000000 --- a/packages/core/src/auth.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Similar type to the @modelcontextprotocol/sdk AuthInfo type. - * Allows for cross-compatibility with the @modelcontextprotocol/sdk. - */ -export type AuthInfo = { - token: string; - scopes: string[]; - /** Token expiry in seconds since epoch */ - expiresAt?: number; - /** Additional provider-specific data */ - extra?: Record; -}; diff --git a/packages/core/src/transport-http.ts b/packages/core/src/transport-http.ts index faf06f0..72706eb 100644 --- a/packages/core/src/transport-http.ts +++ b/packages/core/src/transport-http.ts @@ -1,4 +1,3 @@ -import type { AuthInfo } from "./auth.js"; import { JSON_RPC_VERSION, MCP_LAST_EVENT_ID_HEADER, @@ -67,12 +66,7 @@ export class StreamableHttpTransport { this.allowedHosts = options.allowedHosts; } - bind( - server: McpServer, - ): ( - request: Request, - options?: { authInfo?: AuthInfo }, - ) => Promise { + bind(server: McpServer): (request: Request) => Promise { this.server = server; server._setNotificationSender(async (sessionId, notification, options) => { @@ -138,10 +132,7 @@ export class StreamableHttpTransport { return this.handleRequest.bind(this); } - private async handleRequest( - request: Request, - options?: { authInfo?: AuthInfo }, - ): Promise { + private async handleRequest(request: Request): Promise { if (!this.server) { throw new Error("Transport not bound to a server"); } @@ -185,10 +176,7 @@ export class StreamableHttpTransport { } } - private async handlePost( - request: Request, - options?: { authInfo?: AuthInfo }, - ): Promise { + private async handlePost(request: Request): Promise { try { const body = await request.text(); const jsonRpcMessage = parseJsonRpc(body); @@ -264,7 +252,6 @@ export class StreamableHttpTransport { const response = await this.server?._dispatch(jsonRpcMessage, { sessionId: sessionId || undefined, - authInfo: options?.authInfo, }); if (isInitializeRequest && response) { From 455f54e3abecae7802e6fb23467b89a8cf880d3d Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Mon, 15 Sep 2025 11:57:16 +0200 Subject: [PATCH 16/17] Add support for `authInfo` on context (#65) * Revert "Revert "(wip) Start adding authInfo to the library itself"" This reverts commit 42a9fc82783454d96a4faf5789bc793b590d5770. * Add support for authInfo on context and pass it along to POST handler * Add tests * Refactor test file --- examples/auth-clerk/src/auth/middleware.ts | 2 + examples/auth-clerk/src/index.ts | 3 +- packages/core/src/auth.ts | 12 + packages/core/src/context.ts | 3 + packages/core/src/core.ts | 1 + packages/core/src/transport-http.ts | 27 +- packages/core/src/types.ts | 5 + .../core/tests/integration/auth-info.test.ts | 495 ++++++++++++++++++ 8 files changed, 542 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/auth.ts create mode 100644 packages/core/tests/integration/auth-info.test.ts diff --git a/examples/auth-clerk/src/auth/middleware.ts b/examples/auth-clerk/src/auth/middleware.ts index 7dd1e0e..3b441a0 100644 --- a/examples/auth-clerk/src/auth/middleware.ts +++ b/examples/auth-clerk/src/auth/middleware.ts @@ -26,6 +26,8 @@ export const mcpAuthMiddleware = createMiddleware< const resourceMetadataUrl = getPRMUrl(c.req.raw); c.header( "WWW-Authenticate", + // NOTE - The mcp sdk adds `error` and `error_description` to this header as well, depending on the error + // see: https://github.com/modelcontextprotocol/typescript-sdk/blob/b28c297184cb0cb64611a3357d6438dd1b0824c6/src/server/auth/middleware/bearerAuth.ts#L76C1-L95C8 `Bearer resource_metadata="${resourceMetadataUrl}"`, ); return c.json({ error: "Unauthorized" }, 401); diff --git a/examples/auth-clerk/src/index.ts b/examples/auth-clerk/src/index.ts index e6da2d9..7b7d6f7 100644 --- a/examples/auth-clerk/src/index.ts +++ b/examples/auth-clerk/src/index.ts @@ -16,7 +16,8 @@ app.route("/", authRoutes); // Add MCP endpoint app.all("/mcp", mcpAuthMiddleware, async (c) => { - const response = await mcpHttpHandler(c.req.raw); + const authInfo = c.get("auth"); + const response = await mcpHttpHandler(c.req.raw, { authInfo }); return response; }); diff --git a/packages/core/src/auth.ts b/packages/core/src/auth.ts new file mode 100644 index 0000000..d5b3bce --- /dev/null +++ b/packages/core/src/auth.ts @@ -0,0 +1,12 @@ +/** + * Similar type to the @modelcontextprotocol/sdk AuthInfo type. + * Allows for cross-compatibility with the @modelcontextprotocol/sdk. + */ +export type AuthInfo = { + token: string; + scopes: string[]; + /** Token expiry in seconds since epoch */ + expiresAt?: number; + /** Additional provider-specific data */ + extra?: Record; +}; diff --git a/packages/core/src/context.ts b/packages/core/src/context.ts index 57bb4c5..616dc0b 100644 --- a/packages/core/src/context.ts +++ b/packages/core/src/context.ts @@ -1,3 +1,4 @@ +import type { AuthInfo } from "./auth.js"; import { SUPPORTED_MCP_PROTOCOL_VERSION } from "./constants.js"; import type { JsonRpcId, @@ -13,6 +14,7 @@ export interface CreateContextOptions { sessionId?: string; progressToken?: ProgressToken; progressSender?: (update: ProgressUpdate) => Promise | void; + authInfo?: AuthInfo; } /** @@ -44,6 +46,7 @@ export function createContext( const context: MCPServerContext = { request: message, + authInfo: options.authInfo, requestId, response: null, env: {}, diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 63b0c33..494b958 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -730,6 +730,7 @@ export class McpServer { sessionId, progressToken, progressSender, + authInfo: contextOptions.authInfo, }); const method = (message as JsonRpcMessage).method; diff --git a/packages/core/src/transport-http.ts b/packages/core/src/transport-http.ts index 72706eb..7bc42f6 100644 --- a/packages/core/src/transport-http.ts +++ b/packages/core/src/transport-http.ts @@ -1,3 +1,4 @@ +import type { AuthInfo } from "./auth.js"; import { JSON_RPC_VERSION, MCP_LAST_EVENT_ID_HEADER, @@ -66,7 +67,12 @@ export class StreamableHttpTransport { this.allowedHosts = options.allowedHosts; } - bind(server: McpServer): (request: Request) => Promise { + bind( + server: McpServer, + ): ( + request: Request, + options?: { authInfo?: AuthInfo }, + ) => Promise { this.server = server; server._setNotificationSender(async (sessionId, notification, options) => { @@ -132,7 +138,10 @@ export class StreamableHttpTransport { return this.handleRequest.bind(this); } - private async handleRequest(request: Request): Promise { + private async handleRequest( + request: Request, + options?: { authInfo?: AuthInfo }, + ): Promise { if (!this.server) { throw new Error("Transport not bound to a server"); } @@ -153,7 +162,7 @@ export class StreamableHttpTransport { switch (request.method) { case "POST": - return this.handlePost(request); + return this.handlePost(request, { authInfo: options?.authInfo }); case "GET": return this.handleGet(request); case "DELETE": @@ -176,7 +185,10 @@ export class StreamableHttpTransport { } } - private async handlePost(request: Request): Promise { + private async handlePost( + request: Request, + options?: { authInfo?: AuthInfo }, + ): Promise { try { const body = await request.text(); const jsonRpcMessage = parseJsonRpc(body); @@ -247,11 +259,13 @@ export class StreamableHttpTransport { jsonRpcRequest: jsonRpcMessage, sessionId, isNotification, + authInfo: options?.authInfo, }); } const response = await this.server?._dispatch(jsonRpcMessage, { sessionId: sessionId || undefined, + authInfo: options?.authInfo, }); if (isInitializeRequest && response) { @@ -420,8 +434,10 @@ export class StreamableHttpTransport { jsonRpcRequest: unknown; sessionId: string | null; isNotification: boolean; + authInfo?: AuthInfo; }): Promise { - const { request, jsonRpcRequest, sessionId, isNotification } = args; + const { request, jsonRpcRequest, sessionId, isNotification, authInfo } = + args; if (isNotification) { return new Response( @@ -459,6 +475,7 @@ export class StreamableHttpTransport { Promise.resolve( this.server?._dispatch(jsonRpcRequest as JsonRpcReq, { sessionId: sessionId || undefined, + authInfo, }), ) .then(async (rpcResponse) => { diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index f04ea60..3316225 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -1,4 +1,5 @@ import type { StandardSchemaV1 } from "@standard-schema/spec"; +import type { AuthInfo } from "./auth.js"; import { JSON_RPC_VERSION } from "./constants.js"; import type { UriMatcher } from "./uri-template.js"; import { @@ -94,6 +95,10 @@ export interface MCPServerContext { response: JsonRpcRes | null; env: Record; state: Record; + /** + * Info on the authenticated user, if any + */ + authInfo?: AuthInfo; session?: { id: string; protocolVersion: string }; progressToken?: ProgressToken; validate(validator: unknown, input: unknown): T; diff --git a/packages/core/tests/integration/auth-info.test.ts b/packages/core/tests/integration/auth-info.test.ts new file mode 100644 index 0000000..7e53893 --- /dev/null +++ b/packages/core/tests/integration/auth-info.test.ts @@ -0,0 +1,495 @@ +import { beforeEach, describe, expect, it } from "bun:test"; +import type { AuthInfo } from "../../src/auth.js"; +import { McpServer, StreamableHttpTransport } from "../../src/index.js"; +import type { MCPServerContext } from "../../src/types.js"; + +// Type for JSON-RPC response +interface JsonRpcResponse { + jsonrpc: string; + id: string | number | null; + result?: unknown; + error?: { + code: number; + message: string; + data?: unknown; + }; +} + +// Reusable initialize request payload +const INIT_REQUEST_BODY = { + jsonrpc: "2.0", + id: "init", + method: "initialize", + params: { + protocolVersion: "2025-06-18", + clientInfo: { name: "test-client", version: "1.0.0" }, + }, +} as const; + +// Utility function to create initialize request +function createInitializationRequest(): Request { + return new Request("http://localhost/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + "MCP-Protocol-Version": "2025-06-18", + }, + body: JSON.stringify(INIT_REQUEST_BODY), + }); +} + +describe("AuthInfo Integration", () => { + let server: McpServer; + let transport: StreamableHttpTransport; + + const mockAuthInfo: AuthInfo = { + token: "test-token-123", + scopes: ["read", "write"], + expiresAt: Date.now() / 1000 + 3600, // 1 hour from now + extra: { userId: "user-123", provider: "test" }, + }; + + beforeEach(() => { + server = new McpServer({ + name: "test-server", + version: "1.0.0", + }); + transport = new StreamableHttpTransport(); + }); + + describe("Tool handler authInfo access", () => { + it("should pass authInfo to tool handlers when provided", async () => { + let capturedAuthInfo: AuthInfo | undefined; + let capturedContext: MCPServerContext | undefined; + + server.tool("auth-test", { + description: "Test tool that captures authInfo", + handler: (_args, ctx) => { + capturedAuthInfo = ctx.authInfo; + capturedContext = ctx; + return { + content: [{ type: "text", text: "auth-test-response" }], + }; + }, + }); + + const handler = transport.bind(server); + + // Initialize the server first + const initRequest = createInitializationRequest(); + + await handler(initRequest, { authInfo: mockAuthInfo }); + + // Call the tool with authInfo + const toolRequest = new Request("http://localhost/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + "MCP-Protocol-Version": "2025-06-18", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "tool-call", + method: "tools/call", + params: { + name: "auth-test", + arguments: {}, + }, + }), + }); + + const response = await handler(toolRequest, { authInfo: mockAuthInfo }); + expect(response.ok).toBe(true); + + const result = (await response.json()) as JsonRpcResponse; + expect(result.error).toBeUndefined(); + expect(result.result).toEqual({ + content: [{ type: "text", text: "auth-test-response" }], + }); + + // Verify authInfo was passed correctly + expect(capturedAuthInfo).toEqual(mockAuthInfo); + expect(capturedContext?.authInfo).toEqual(mockAuthInfo); + }); + + it("should work normally when authInfo is not provided", async () => { + let capturedAuthInfo: AuthInfo | undefined; + + server.tool("no-auth-test", { + description: "Test tool without authInfo", + handler: (_args, ctx) => { + capturedAuthInfo = ctx.authInfo; + return { + content: [{ type: "text", text: "no-auth-response" }], + }; + }, + }); + + const handler = transport.bind(server); + + // Initialize without authInfo + const initRequest = createInitializationRequest(); + + await handler(initRequest); + + // Call tool without authInfo + const toolRequest = new Request("http://localhost/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + "MCP-Protocol-Version": "2025-06-18", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "tool-call", + method: "tools/call", + params: { + name: "no-auth-test", + arguments: {}, + }, + }), + }); + + const response = await handler(toolRequest); + expect(response.ok).toBe(true); + + const result = (await response.json()) as JsonRpcResponse; + expect(result.error).toBeUndefined(); + expect(result.result).toEqual({ + content: [{ type: "text", text: "no-auth-response" }], + }); + + // Verify authInfo is undefined when not provided + expect(capturedAuthInfo).toBeUndefined(); + }); + }); + + describe("Middleware authInfo access", () => { + it("should pass authInfo to middleware when provided", async () => { + const middlewareLog: Array<{ + phase: string; + authInfo?: AuthInfo; + hasAuthInfo: boolean; + }> = []; + + // Add middleware that captures authInfo + server.use(async (ctx, next) => { + middlewareLog.push({ + phase: "before", + authInfo: ctx.authInfo, + hasAuthInfo: !!ctx.authInfo, + }); + + await next(); + + middlewareLog.push({ + phase: "after", + authInfo: ctx.authInfo, + hasAuthInfo: !!ctx.authInfo, + }); + }); + + server.tool("middleware-test", { + description: "Test tool for middleware authInfo", + handler: () => ({ + content: [{ type: "text", text: "middleware-test-response" }], + }), + }); + + const handler = transport.bind(server); + + // Initialize with authInfo + const initRequest = createInitializationRequest(); + + await handler(initRequest, { authInfo: mockAuthInfo }); + + // Clear log after initialization + middlewareLog.length = 0; + + // Call tool with authInfo + const toolRequest = new Request("http://localhost/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + "MCP-Protocol-Version": "2025-06-18", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "tool-call", + method: "tools/call", + params: { + name: "middleware-test", + arguments: {}, + }, + }), + }); + + const response = await handler(toolRequest, { authInfo: mockAuthInfo }); + expect(response.ok).toBe(true); + + // Verify middleware received authInfo + expect(middlewareLog).toHaveLength(2); + expect(middlewareLog[0]).toEqual({ + phase: "before", + authInfo: mockAuthInfo, + hasAuthInfo: true, + }); + expect(middlewareLog[1]).toEqual({ + phase: "after", + authInfo: mockAuthInfo, + hasAuthInfo: true, + }); + }); + + it("should work in middleware when authInfo is not provided", async () => { + const middlewareLog: Array<{ + phase: string; + authInfo?: AuthInfo; + hasAuthInfo: boolean; + }> = []; + + server.use(async (ctx, next) => { + middlewareLog.push({ + phase: "before", + authInfo: ctx.authInfo, + hasAuthInfo: !!ctx.authInfo, + }); + + await next(); + + middlewareLog.push({ + phase: "after", + authInfo: ctx.authInfo, + hasAuthInfo: !!ctx.authInfo, + }); + }); + + server.tool("no-middleware-auth-test", { + description: "Test tool for middleware without authInfo", + handler: () => ({ + content: [{ type: "text", text: "no-middleware-auth-response" }], + }), + }); + + const handler = transport.bind(server); + + // Initialize without authInfo + const initRequest = createInitializationRequest(); + + await handler(initRequest); + + // Clear log after initialization + middlewareLog.length = 0; + + // Call tool without authInfo + const toolRequest = new Request("http://localhost/mcp", { + method: "POST", + headers: { + "Content-Type": "application/json", + "MCP-Protocol-Version": "2025-06-18", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "tool-call", + method: "tools/call", + params: { + name: "no-middleware-auth-test", + arguments: {}, + }, + }), + }); + + const response = await handler(toolRequest); + expect(response.ok).toBe(true); + + // Verify middleware received no authInfo + expect(middlewareLog).toHaveLength(2); + expect(middlewareLog[0]).toEqual({ + phase: "before", + authInfo: undefined, + hasAuthInfo: false, + }); + expect(middlewareLog[1]).toEqual({ + phase: "after", + authInfo: undefined, + hasAuthInfo: false, + }); + }); + }); + + describe("Direct server dispatch with authInfo", () => { + it("should pass authInfo through _dispatch method", async () => { + let capturedAuthInfo: AuthInfo | undefined; + + server.tool("direct-auth-test", { + description: "Test tool for direct dispatch with authInfo", + handler: (_args, ctx) => { + capturedAuthInfo = ctx.authInfo; + return { + content: [{ type: "text", text: "direct-auth-response" }], + }; + }, + }); + + // Use _dispatch directly with authInfo + const result = await server._dispatch( + { + jsonrpc: "2.0", + id: "direct-call", + method: "tools/call", + params: { + name: "direct-auth-test", + arguments: {}, + }, + }, + { authInfo: mockAuthInfo }, + ); + + expect(result?.error).toBeUndefined(); + expect(result?.result).toEqual({ + content: [{ type: "text", text: "direct-auth-response" }], + }); + + // Verify authInfo was passed correctly + expect(capturedAuthInfo).toEqual(mockAuthInfo); + }); + + it("should work with _dispatch when authInfo is not provided", async () => { + let capturedAuthInfo: AuthInfo | undefined; + + server.tool("direct-no-auth-test", { + description: "Test tool for direct dispatch without authInfo", + handler: (_args, ctx) => { + capturedAuthInfo = ctx.authInfo; + return { + content: [{ type: "text", text: "direct-no-auth-response" }], + }; + }, + }); + + // Use _dispatch without authInfo + const result = await server._dispatch({ + jsonrpc: "2.0", + id: "direct-call", + method: "tools/call", + params: { + name: "direct-no-auth-test", + arguments: {}, + }, + }); + + expect(result?.error).toBeUndefined(); + expect(result?.result).toEqual({ + content: [{ type: "text", text: "direct-no-auth-response" }], + }); + + // Verify authInfo is undefined + expect(capturedAuthInfo).toBeUndefined(); + }); + }); + + describe("AuthInfo data integrity", () => { + it("should preserve all authInfo fields correctly", async () => { + let capturedAuthInfo: AuthInfo | undefined; + + const complexAuthInfo: AuthInfo = { + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test", + scopes: ["read:user", "write:repo", "admin:org"], + expiresAt: 1234567890, + extra: { + userId: "user-456", + provider: "oauth2", + refreshToken: "refresh-123", + metadata: { + roles: ["admin", "user"], + permissions: { canRead: true, canWrite: true }, + }, + }, + }; + + server.tool("complex-auth-test", { + description: "Test tool for complex authInfo", + handler: (_args, ctx) => { + capturedAuthInfo = ctx.authInfo; + return { + content: [{ type: "text", text: "complex-auth-response" }], + }; + }, + }); + + const result = await server._dispatch( + { + jsonrpc: "2.0", + id: "complex-call", + method: "tools/call", + params: { + name: "complex-auth-test", + arguments: {}, + }, + }, + { authInfo: complexAuthInfo }, + ); + + expect(result?.error).toBeUndefined(); + + // Verify all fields are preserved correctly + expect(capturedAuthInfo).toEqual(complexAuthInfo); + expect(capturedAuthInfo?.token).toBe(complexAuthInfo.token); + expect(capturedAuthInfo?.scopes).toEqual(complexAuthInfo.scopes); + // @ts-expect-error - expiresAt is optional + expect(capturedAuthInfo?.expiresAt).toBe(complexAuthInfo.expiresAt); + // @ts-expect-error - extra is optional + expect(capturedAuthInfo?.extra).toEqual(complexAuthInfo.extra); + }); + }); + + describe("Context authInfo consistency", () => { + it("should maintain authInfo consistency across request lifecycle", async () => { + const capturedAuthInfos: AuthInfo[] = []; + + // Middleware that captures authInfo at different phases + server.use(async (ctx, next) => { + if (ctx.authInfo) { + capturedAuthInfos.push({ ...ctx.authInfo }); + } + await next(); + if (ctx.authInfo) { + capturedAuthInfos.push({ ...ctx.authInfo }); + } + }); + + server.tool("consistency-test", { + description: "Test authInfo consistency", + handler: (_args, ctx) => { + if (ctx.authInfo) { + capturedAuthInfos.push({ ...ctx.authInfo }); + } + return { + content: [{ type: "text", text: "consistency-response" }], + }; + }, + }); + + await server._dispatch( + { + jsonrpc: "2.0", + id: "consistency-call", + method: "tools/call", + params: { + name: "consistency-test", + arguments: {}, + }, + }, + { authInfo: mockAuthInfo }, + ); + + // Should have captured authInfo three times (middleware before, handler, middleware after) + expect(capturedAuthInfos).toHaveLength(3); + + // All should be identical + capturedAuthInfos.forEach((authInfo) => { + expect(authInfo).toEqual(mockAuthInfo); + }); + }); + }); +}); From 074d82c41acb4116d115aba9892ae32444e9d443 Mon Sep 17 00:00:00 2001 From: Brett Beutell Date: Mon, 15 Sep 2025 14:08:13 +0200 Subject: [PATCH 17/17] Add log statement to verify authInfo is being passed correctly --- examples/auth-clerk/src/mcp.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/auth-clerk/src/mcp.ts b/examples/auth-clerk/src/mcp.ts index 41d21a2..99e5ede 100644 --- a/examples/auth-clerk/src/mcp.ts +++ b/examples/auth-clerk/src/mcp.ts @@ -17,9 +17,14 @@ const EchoSchema = v.object({ mcp.tool("echo", { description: "Echoes the input message", inputSchema: EchoSchema, - handler: (args) => ({ - content: [{ type: "text", text: args.message }], - }), + handler: (args, context) => { + // Log the authInfo to show it's here + console.log("[echo] authInfo", context.authInfo); + + return { + content: [{ type: "text", text: args.message }], + }; + }, }); // Create HTTP transport