feat: support manual entry of OAuth client information
Add support for manually entering OAuth client information in the UI
Motivation and Context
This PR addresses issue #167 where users encounter errors when connecting to MCP servers that use OAuth authentication but don't support dynamic client registration. Per MCP spec, servers without dynamic registration need alternative ways for clients to obtain credentials. This implementation adds a UI for users to manually enter OAuth client information, providing graceful degradation when automatic registration isn't available.
How Has This Been Tested?
Tested by connecting to an MCP server requiring OAuth authentication without dynamic client registration capabilities. Verified that:
- Users can manually enter client ID in the UI
- The client ID persists between sessions
- Connections succeed with manually provided OAuth credentials
- The redirect URL is correctly displayed for reference
Breaking Changes
None. This is a non-breaking addition that enhances functionality without changing existing behavior.
Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation update
Checklist
- [x] I have read the MCP Documentation
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
Additional context
This implementation directly resolves issue #167 by providing a solution for MCP clients to connect to servers without dynamic client registration. By adding a dedicated UI section for OAuth configuration, users can now manually enter their client ID after registering through the server's interface. The solution maintains the redirect URL in the UI for easy reference during client registration, enabling seamless authentication even with servers that don't support dynamic registration.
Hi @xiaoyijun! Thanks for this. I haven't done a local test of it yet, but I like what I see in the PR description and it does make sense for use case of servers that don't support dynamic client registration.
Based on the spec I want to think that this complies, but it seems like a mix of options 1 and 2. We're providing a UI for users to enter this information, but it's not actually being registered, just passed to the server as if hardcoded.
Given that this is the inspector and not an actual real-world client, I think this approach is OK. @localden might have a more nuanced view.
Hi @cliffhall , thanks for the feedback! You’re right, this setup is mainly for inspection/debugging purposes, not intended for production clients. Let me know if there’s anything you think I should adjust.
Tested by connecting to an MCP server requiring OAuth authentication without dynamic client registration capabilities.
@xiaoyijun can you drop a link to the server you tested with? I'd really like to test this locally.
Tested by connecting to an MCP server requiring OAuth authentication without dynamic client registration capabilities.
@xiaoyijun can you drop a link to the server you tested with? I'd really like to test this locally.
Hi @cliffhall! founder of Logto here. our team (primarily @xiaoyijun) is currently working on some MCP projects (primarily auth-related). we're excited about contributing to the MCP community and would love to share more details about what we are doing and server info for testing.
since the project is still in early-stage development, we’re unsure whether we can share everything publicly. what’s the best way to get in touch with you? it'll be great to have a direct channel for team-to-team communication (e.g., Slack or Teams) to help things move more efficiently.
looking forward to your thoughts.
Hi @cliffhall , sorry for the late response.
I just found that the MCP Typescript SDK has supported passing scope to the OAuth auth request, but in the wrong way.
I created a PR(https://github.com/modelcontextprotocol/typescript-sdk/pull/491) to support custom scope when making an auth request, which is needed when we use a pre-registered OAuth client.
I will update this PR once https://github.com/modelcontextprotocol/typescript-sdk/pull/491 is merged, and will also include the scope settings in the "OAuth Configuration" section so that you can test smoothly.
We forked this project and implemented an enhanced inspector which supports configuring OAuth flow parameters. Here is how we use it in our MCP Auth tutorial: https://mcp-auth.dev/docs/tutorials/whoami (the sample server code can be found here: https://github.com/mcp-auth/js/tree/master/packages/sample-servers)
The inspector used in the tutorial is available at https://github.com/mcp-auth/inspector
I will update this PR once modelcontextprotocol/typescript-sdk#491 is merged, and will also include the
scopesettings in the "OAuth Configuration" section so that you can test smoothly.
Nice one, @xiaoyijun!
Ok, I see that your fix to the SDK has been merged, but there's going to be a lag before the next release, and of the inspector leveling up to that release. I'm going to tag this as waiting for submitter AND waiting for SDK. Can you keep an eye on the status of those things and wrap up this PR when the new SDK is out? I'll try to get the Inspector upgraded to the new SDK ASAP upon the next release.
@cliffhall Of course, I’ll keep an eye on it and wrap up the PR once the new SDK is out.
Hi @cliffhall ,
The SDK has been updated, but when I rebased this branch, I noticed some significant changes in the Inspector's auth implementation.
Previously, we could initiate the auth flow directly during the connection process. However, now I notice that the Inspector redirects to http://localhost:6277/authorize, while we actually need to redirect to the authorization_endpoint specified in the OAuth server metadata returned by the MCP server.
I also noticed there's a new OAuth debug module in the UI. Does this indicate a change in how OAuth flows are handled in the Inspector?
Could you provide some guidance on these changes? This will help me align my implementation with the new OAuth flow architecture.
Previously, we could initiate the auth flow directly during the connection process. However, now I notice that the Inspector redirects to
http://localhost:6277/authorize, while we actually need to redirect to the authorization_endpoint specified in the OAuth server metadata returned by the MCP server.I also noticed there's a new OAuth debug module in the UI. Does this indicate a change in how OAuth flows are handled in the Inspector?
Could you provide some guidance on these changes? This will help me align my implementation with the new OAuth flow architecture.
@pcarleton could you provide some insight to @xiaoyijun
👋 https://github.com/modelcontextprotocol/inspector/pull/418 should fix the connection issue, it was unrelated to the debugger.
regarding auth flows changing overall, we're working to add support in the typescript sdk for the new draft spec here, and then will follow up with supporting them in the inspector: https://modelcontextprotocol.io/specification/draft/basic/authorization
There's a client PR here: https://github.com/modelcontextprotocol/typescript-sdk/pull/416 and server PR here: https://github.com/modelcontextprotocol/typescript-sdk/pull/503
These should all be backwards compatible (if the new metadata endpoint /.well-known/oauth-protected-resource isn't there, will fall back to /.well-known/oauth-authorization-server)
@pcarleton thanks for your information, I'll update this PR once the issue is addressed.
Hi @cliffhall @pcarleton , I just rebased this pr and update the implementation, PTAL.
You can use mcp-auth sample for testing.
- Clone the js sdk repo by
git clone https://github.com/mcp-auth/js.git - Install & build the repo using pnpm:
pnpm i && pnpm -r prepack - Enter the
packages/sample-serversfolder and follow the sample README and start the "todo manager" mcp server:pnpm dev:todo-manager
The following configuration is provided to facilitate your testing:
- Create a
.envfile in the/sample-serversfolder
MCP_AUTH_ISSUER=https://8xfzlr.app.logto.dev/oidc
- Enter these configs in the OAuthConfig section in the Inspector sidebar:
- Transport type: SSE
- URL:
http://localhost:3001/sse - Client ID:
0ahw5qrrnv3eo4ve6ibtt - Scope:
create:todos delete:todos read:todos - Resource:
https://todo.mcp-server.app
- Click connect.
@xiaoyijun Is there a way you could test this against an example server in the TypeScript SDK? I'm wary of installing random code for testing, and would much rather test against in-project resources wherever possible.
For instance, we were able to test #469 by starting the simpleStreamableHttp example server with:
npx tsx src/examples/server/simpleStreamableHttp.ts --oauth
@cliffhall Thanks for the suggestion! I’ll give that a try and see how it works.
Hi @cliffhall , I just tested this implementation with the simpleStreamableHttp example from the TypeScript SDK server, and it works as expected.
However, some setup is required beforehand:
-
In
src/examples/server/demoInMemoryOAuthProvider.ts, remove theregisterClientmethod in theDemoInMemoryClientsStoreclass to disable client registration endpoint for the test OAuth server. -
Provide a default client for the in-memory client store to simulate a preregistered OAuth client:
export class DemoInMemoryClientsStore implements OAuthRegisteredClientsStore {
private clients = new Map<string, OAuthClientInformationFull>([
// 👇 Preregistered OAuth client here
[
"preregistered-client-id",
{
client_id: "preregistered-client-id",
redirect_uris: ["http://localhost:6274/oauth/callback"],
scope: "mcp:tools",
},
],
]);
async getClient(clientId: string) {
return this.clients.get(clientId);
}
// async registerClient(clientMetadata: OAuthClientInformationFull) {
// this.clients.set(clientMetadata.client_id, clientMetadata);
// return clientMetadata;
// }
}
Now, start the mcp server:
npx tsx src/examples/server/simpleStreamableHttp.ts --oauth
Enter the following configuration in the Inspector:
- Transport Type: Streamable HTTP
- URL:
http://localhost:3000/mcp - OAuth Configuration
- Client ID:
preregistered-client-id - Scope:
mcp:tools
- Client ID:
Click "Connect".
Test result:
Quick question here, does any MCP client even support this type of flow? I see all MCP clients force DCR when the spec doesn't enforce it.
Quick question here, does any MCP client even support this type of flow? I see all MCP clients force DCR when the spec doesn't enforce it.
@MOmarMiraj
- VSCode does.
- True the spec doesn't say MUST, but it does say SHOULD.
MCP clients and authorization servers SHOULD support the OAuth 2.0 Dynamic Client Registration Protocol RFC7591 to allow MCP clients to obtain OAuth client IDs without user interaction.
@xiaoyijun Sorry to have let this one slip through the cracks. Could you resolve conflicts, so I can test?
@xiaoyijun Sorry to have let this one slip through the cracks. Could you resolve conflicts, so I can test?
Sure,let's do it next monday.
Hi @cliffhall , thanks for your patience, I have updated this PR, you can test it follow what I mentioned above (https://github.com/modelcontextprotocol/inspector/pull/345#issuecomment-2949668632).
I also removed the resource config since the typescript sdk handles it automatically.
Hi @cliffhall , thanks for your testing and detailed feedback. I will update it in the next few days.
Hi @cliffhall , I’ve updated the code according to your suggestions.
Please take a look when you have time.
@xiaoyijun Almost over the finish line.... but you're going to need to run prettier-fix to pass CI.
Hi @cliffhall, CI failed due to test failures after the rebase. I’ve updated it — PTAL.
Question, @xiaoyijun could this also have a field for OAuth roles to ask for? We currently don't have a good solution for that. Definitely feel free to push back if it's too far out of scope for you on this PR. We can tackle it in a separate one.
Question, @xiaoyijun could this also have a field for OAuth roles to ask for? We currently don't have a good solution for that. Definitely feel free to push back if it's too far out of scope for you on this PR. We can tackle it in a separate one.
@cliffhall Thanks for bringing this up! I’m not very familiar with OAuth roles (since, as far as I know, roles are not defined as part of the OAuth specification). I think we can revisit this requirement and look into implementing it in a future PR.
@cliffhall Thanks for bringing this up! I’m not very familiar with OAuth roles (since, as far as I know, roles are not defined as part of the OAuth specification). I think we can revisit this requirement and look into implementing it in a future PR.
DOH! You already have the field I was looking for, it's called Scope. I'm dealing with way to many interrupts these days. :)
@cliffhall We did it! Thanks for your patience ❤️