Repository navigation
Conversation
…horization server takes one An MCP server's authorization server that advertises client_id_metadata_document_supported is now given <APP_URL>/oauth/client-metadata.json as the client id, a document the api serves about itself, rather than turned away when it has no registration endpoint. The document is preferred over registering a client, as the MCP spec orders them, when APP_URL is a public https address the authorization server can fetch it from; otherwise a client is registered as before. Discovered servers also ask for offline_access where the authorization server offers it, so the sign-in comes with a refresh token.
hkonsti
force-pushed
the
hkonsti/mcp-cimd
branch
from
October 31, 2026 06:47
6403f78 to
f19f3e9
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Connecting a custom MCP server whose authorization server takes a Client ID Metadata Document (CIMD) but has no registration endpoint failed with "This server's sign-in doesn't let apps register themselves".
https://ampcode.com/mcpis one: its authorization server,auth.ampcode.com, hasclient_id_metadata_document_supported: trueand noregistration_endpoint. These servers can now be signed in to.The document. The api serves
GET /oauth/client-metadata.jsononAPP_URL, next to its own/oauth/and/.well-known/routes. The document'sclient_idis its own URL. It lists the callback of every MCP sign-in (the custom server's and each built-in integration's),client_name,client_uri,logo_uri, theauthorization_codeandrefresh_tokengrants, andtoken_endpoint_auth_method: none./oauth/already goes to the api in the Vite dev proxy, inserve-web.tsand through Caddy, so nothing else needed changing to serve it.Which client a sign-in uses. Discovery now reads
client_id_metadata_document_supportedfrom the authorization server's metadata, andMcpServercan say the server takes the document (clientIdMetadataDocument), has aregisterUrl, or both. When starting a sign-in, the MCP spec's order applies (CIMD before Dynamic Client Registration, which the spec's draft deprecates). The document's URL is the client when the server takes one andAPP_URLishttpson a host that resolves only to public addresses. Otherwise a client is registered as before. A self-hosted instance on a private network, or one in development, keeps registering, because an authorization server out on the internet couldn't fetch the document from it. A server that takes only the document can't be signed in to from such an instance, and the form explains why. A server that offers neither is still turned away.Refresh. Nothing changes in how refresh works. The client id a sign-in used is kept in the credential, as a registered one was, and sent on every token request. For a CIMD sign-in that client id is the document's URL. Existing connections keep their registered clients.
offline_access. Some authorization servers, Amp's among them, give a refresh token only for
offline_access. Without it, a connection would end when its first access token expired. When the authorization server'sscopes_supportedlists it, discovered servers now add it to the scopes from the server's metadata, as the MCP spec allows.The built-in integrations go through the same sign-in code. They still name their endpoints, so they keep registering. Granola, Notion, Linear and Exa also take the document, so each could switch to it by adding
clientIdMetadataDocument: true. That is left for a separate change.Testing
bun run typecheck,bun run test,bun run lintoffline_accessadded only where the authorization server offers it; a sign-in sends the document's URL asclient_idand registers nothing; with anAPP_URLon a private address or onhttpit registers instead, and refuses a server that takes only the document; the callback keeps the document's URL as the client, and refreshing sends it; the document itselfcreateHttpApp: 200, JSON, cached for an hour, open to any origin, about 800 bytesampcode.com/mcpanswers 401 pointing at its resource metadata. That metadata namesauth.ampcode.com, whose metadata matches the description above. Discovery from this branch, run against it, givesclientIdMetadataDocument: trueand scopeoffline_access. Its authorize endpoint takes a URLclient_id(tried with a public CIMD client's document), withoffline_accesstoo. It turns down a redirect URI that isn't in the document, and a document it can't fetch (invalid_client).APP_URL