inspector icon indicating copy to clipboard operation
inspector copied to clipboard

feat: support manual entry of OAuth client information

Open xiaoyijun opened this issue 8 months ago • 11 comments

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.

image image

xiaoyijun avatar Apr 24 '25 07:04 xiaoyijun

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.

Screenshot 2025-04-24 at 4 38 32 PM

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.

cliffhall avatar Apr 24 '25 20:04 cliffhall

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.

xiaoyijun avatar Apr 25 '25 06:04 xiaoyijun

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.

cliffhall avatar Apr 25 '25 15:04 cliffhall

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.

gao-sun avatar Apr 25 '25 17:04 gao-sun

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

xiaoyijun avatar May 14 '25 03:05 xiaoyijun

I will update this PR once modelcontextprotocol/typescript-sdk#491 is merged, and will also include the scope settings 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 avatar May 14 '25 20:05 cliffhall

@cliffhall Of course, I’ll keep an eye on it and wrap up the PR once the new SDK is out.

xiaoyijun avatar May 15 '25 00:05 xiaoyijun

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.

xiaoyijun avatar May 16 '25 09:05 xiaoyijun

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

cliffhall avatar May 17 '25 16:05 cliffhall

👋 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 avatar May 20 '25 19:05 pcarleton

@pcarleton thanks for your information, I'll update this PR once the issue is addressed.

xiaoyijun avatar May 21 '25 15:05 xiaoyijun

Hi @cliffhall @pcarleton , I just rebased this pr and update the implementation, PTAL.

You can use mcp-auth sample for testing.

  1. Clone the js sdk repo by git clone https://github.com/mcp-auth/js.git
  2. Install & build the repo using pnpm: pnpm i && pnpm -r prepack
  3. Enter the packages/sample-servers folder 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:

  1. Create a .env file in the /sample-servers folder
MCP_AUTH_ISSUER=https://8xfzlr.app.logto.dev/oidc
  1. 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
  1. Click connect.

xiaoyijun avatar Jun 04 '25 10:06 xiaoyijun

@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 avatar Jun 04 '25 17:06 cliffhall

@cliffhall Thanks for the suggestion! I’ll give that a try and see how it works.

xiaoyijun avatar Jun 05 '25 15:06 xiaoyijun

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:

  1. In src/examples/server/demoInMemoryOAuthProvider.ts, remove the registerClient method in the DemoInMemoryClientsStore class to disable client registration endpoint for the test OAuth server.

  2. 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

Click "Connect".

Test result: image

xiaoyijun avatar Jun 06 '25 15:06 xiaoyijun

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 avatar Jun 25 '25 20:06 MOmarMiraj

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

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.

cliffhall avatar Jun 27 '25 16:06 cliffhall

@xiaoyijun Sorry to have let this one slip through the cracks. Could you resolve conflicts, so I can test?

cliffhall avatar Jun 27 '25 16:06 cliffhall

@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.

xiaoyijun avatar Jul 03 '25 14:07 xiaoyijun

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.

xiaoyijun avatar Jul 08 '25 02:07 xiaoyijun

Hi @cliffhall , thanks for your testing and detailed feedback. I will update it in the next few days.

xiaoyijun avatar Jul 17 '25 08:07 xiaoyijun

Hi @cliffhall , I’ve updated the code according to your suggestions. Please take a look when you have time. image image

xiaoyijun avatar Jul 21 '25 03:07 xiaoyijun

@xiaoyijun Almost over the finish line.... but you're going to need to run prettier-fix to pass CI.

cliffhall avatar Jul 22 '25 16:07 cliffhall

Hi @cliffhall, CI failed due to test failures after the rebase. I’ve updated it — PTAL.

xiaoyijun avatar Jul 23 '25 00:07 xiaoyijun

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 avatar Jul 23 '25 18:07 cliffhall

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.

xiaoyijun avatar Jul 24 '25 09:07 xiaoyijun

@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 avatar Jul 24 '25 14:07 cliffhall

@cliffhall We did it! Thanks for your patience ❤️

xiaoyijun avatar Jul 24 '25 23:07 xiaoyijun