diff --git a/docs/provider-guides/README.mdx b/docs/provider-guides/README.mdx new file mode 100644 index 0000000..89fc70d --- /dev/null +++ b/docs/provider-guides/README.mdx @@ -0,0 +1,15 @@ +--- +sidebar_label: Overview +--- + +import DocCardList from '@theme/DocCardList'; + +# Provider Guides + +This section contains configuration guides for various OAuth 2.0 and OpenID Connect providers. + + + +:::info Want to contribute? +If your provider is not listed, feel free to create a pull request in [mcp-auth/docs](https://github.com/mcp-auth/docs). +::: diff --git a/docs/provider-guides/generic.mdx b/docs/provider-guides/generic.mdx new file mode 100644 index 0000000..36df693 --- /dev/null +++ b/docs/provider-guides/generic.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 100 +sidebar_label: Generic OAuth 2.0 / OIDC +--- + +# Generic OAuth 2.0 / OIDC + +This guide covers general configuration steps for OAuth 2.0 and OpenID Connect providers. Since OIDC is built on top of OAuth 2.0, both follow similar steps. + +:::tip +Check our [Provider List](/provider-list) to see if your specific provider has been tested with MCP Auth. +::: + +## Get issuer URL {#get-issuer-url} + +The issuer URL (also called authorization server URL or base URL) is required for MCP Auth configuration. To find it: + +1. Check your provider's documentation for the authorization server URL +2. Some providers expose this at `https://{your-domain}/.well-known/oauth-authorization-server` +3. For OIDC providers, try `https://{your-domain}/.well-known/openid-configuration` +4. Look in your provider's admin console under OAuth/API settings + +## Configure scopes {#configure-scopes} + +You'll need to define scopes in your authorization server that represent the permissions your MCP server needs: + +1. **Define scopes** in your authorization server, e.g.: + - `create:todos` + - `read:todos` + - `delete:todos` + +2. **Assign scopes to users** using your provider's interface + - Some providers support role-based management + - Others use direct scope assignments + +Check your provider's documentation for specific instructions on scope management. + +## Retrieving user identity {#retrieving-user-identity} + +### OIDC providers + +Most OpenID Connect providers support the [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) to retrieve user identity information. + +Check your provider's documentation to see if it supports this endpoint. If your provider supports [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html), you can also check if the `userinfo_endpoint` is included in the discovery document (response from the `.well-known/openid-configuration` endpoint). + +To fetch an access token that can be used to access the userinfo endpoint, at least two scopes are required: `openid` and `profile`. Check your provider's documentation to see the mapping of scopes to user identity claims. + +### OAuth 2.0 providers + +While OAuth 2.0 does not define a standard way to retrieve user identity information, many providers implement their own endpoints to do so. Check your provider's documentation to see how to retrieve user identity information using an access token and what parameters are required to fetch such access token when invoking the authorization flow. + +## Token request parameters {#token-request-parameters} + +Different authorization servers use various approaches for specifying the target resource: + +### Resource indicator based + +Uses the `resource` parameter ([RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)): + +```json +{ + "resource": "http://localhost:3001/", + "scope": "create:todos read:todos" +} +``` + +### Audience based + +Uses the `audience` parameter: + +```json +{ + "audience": "todo-api", + "scope": "create:todos read:todos" +} +``` + +### Pure scope based + +Relies solely on scopes (traditional OAuth 2.0): + +```json +{ + "scope": "todo-api:create todo-api:read openid profile" +} +``` + +Check your provider's documentation for supported parameters. + +## Register MCP client {#register-mcp-client} + +If your provider supports [Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) or [OAuth Client ID Metadata Document](https://www.ietf.org/archive/id/draft-parecki-oauth-client-id-metadata-document-00.html), you may skip manual registration. Otherwise: + +1. Sign in to your provider's console +2. Navigate to "Applications" or "Clients" section +3. Create a new application/client +4. Select "Native App" or "Public client" if required +5. Configure the redirect URIs. For VS Code: + ``` + http://127.0.0.1 + https://vscode.dev/redirect + ``` +6. Configure the required scopes/permissions +7. Copy the "Client ID" or "Application ID" for use in your MCP client diff --git a/docs/provider-guides/keycloak.mdx b/docs/provider-guides/keycloak.mdx new file mode 100644 index 0000000..ac26610 --- /dev/null +++ b/docs/provider-guides/keycloak.mdx @@ -0,0 +1,87 @@ +--- +sidebar_position: 2 +sidebar_label: Keycloak +--- + +# Keycloak + +[Keycloak](https://www.keycloak.org) is an open-source identity and access management solution that supports multiple protocols, including OpenID Connect (OIDC). As an OIDC provider, it implements the standard userinfo endpoint to retrieve user identity information. + +## Prerequisites {#prerequisites} + +:::note +Although Keycloak can be installed in [various ways](https://www.keycloak.org/guides#getting-started) (bare metal, kubernetes, etc.), for this guide, we'll use Docker for a quick and straightforward setup. +::: + +Run a Keycloak instance using Docker following the [official documentation](https://www.keycloak.org/getting-started/getting-started-docker): + +```bash +docker run -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.2.4 start-dev +``` + +## Get issuer URL {#get-issuer-url} + +1. Access the Keycloak Admin Console (http://localhost:8080/admin) and log in with these credentials: + - Username: `admin` + - Password: `admin` +2. Navigate to "Realm settings" in the left menu +3. Click "Endpoints" then "OpenID Endpoint Configuration" +4. The `issuer` field in the JSON document will contain your issuer URL + +For a realm named `mcp-realm`, the issuer URL should look like: + +``` +http://localhost:8080/realms/mcp-realm +``` + +## Create a realm and test user {#create-realm-and-user} + +1. Create a new Realm: + - Click "Create Realm" in the top-left corner + - Enter a name in the "Realm name" field (e.g., `mcp-realm`) + - Click "Create" + +2. Create a test user: + - Click "Users" in the left menu + - Click "Create new user" + - Fill in the user details: + - Username: e.g., `testuser` + - First name and Last name can be any values + - Click "Create" + - In the "Credentials" tab, set a password and uncheck "Temporary" + +## Configure scopes {#configure-scopes} + +If your MCP server requires custom scopes (e.g., for RBAC): + +1. In the Keycloak Admin Console, navigate to "Client scopes" +2. Click "Create client scope" +3. Define the scope name (e.g., `create:todos`, `read:todos`, `delete:todos`) +4. Assign these scopes to clients or roles as needed + +## Retrieving user identity {#retrieving-user-identity} + +As an OIDC provider, Keycloak exposes a standard [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) that allows applications to retrieve claims about the authenticated user. + +To fetch an access token that can be used to access the userinfo endpoint, at least two scopes are required: `openid` and `profile`. + +## Register MCP client {#register-mcp-client} + +While Keycloak supports dynamic client registration, its client registration endpoint does not support CORS, preventing most MCP clients from registering directly. Therefore, you'll need to manually register your client. + +### Register a client for VS Code + +1. In the Keycloak Admin Console, click "Clients" in the left menu +2. Click "Create client" +3. Fill in the client details: + - Client type: Select "OpenID Connect" + - Client ID: Enter a name (e.g., `vscode`) + - Click "Next" +4. On the "Capability config" page: + - Ensure "Standard flow" is enabled + - Click "Next" +5. On the "Login settings" page: + - Add `http://127.0.0.1/*` to "Valid redirect URIs" + - Add `https://vscode.dev/redirect` to "Valid redirect URIs" + - Click "Save" +6. Copy the "Client ID" for later use diff --git a/docs/provider-guides/logto.mdx b/docs/provider-guides/logto.mdx new file mode 100644 index 0000000..af0ad39 --- /dev/null +++ b/docs/provider-guides/logto.mdx @@ -0,0 +1,104 @@ +--- +sidebar_position: 1 +sidebar_label: Logto +--- + +# Logto + +[Logto](https://logto.io) is an open-source identity platform that provides OpenID Connect authentication with built-in RBAC support through API resources and roles. + +## Get issuer URL {#get-issuer-url} + +You can find the issuer URL on your application details page within Logto Console, under the "Endpoints & Credentials / Issuer endpoint" section. It should look like: + +``` +https://my-project.logto.app/oidc +``` + +## Create API resource and scopes {#create-api-resource-and-scopes} + +1. Sign in to [Logto Console](https://cloud.logto.io) (or your self-hosted Logto Console) +2. Go to "API Resources" +3. Create a new API resource: + - **Name**: e.g., "Todo Manager" + - **Resource indicator**: Your MCP server URL, e.g., `http://localhost:3001/` + - The resource indicator must match your MCP server's URL. +4. Add the scopes your MCP server needs, e.g.: + - `create:todos`: "Create new todo items" + - `read:todos`: "Read all todo items" + - `delete:todos`: "Delete any todo item" + +:::note[Trailing slash in resource indicator] +Always include a trailing slash (`/`) in the resource indicator. Due to a current bug in the MCP official SDK, clients using the SDK will automatically append a trailing slash to resource identifiers when initiating auth requests. +::: + +## Create roles {#create-roles} + +Roles make it easier to manage permissions for groups of users: + +1. Go to "Roles" +2. Create roles with appropriate scopes, e.g.: + - **Admin**: Assign all scopes + - **User**: Assign limited scopes +3. (Optional) Set a default role for new users in the role's "General" tab. + +## Assign permissions to users {#assign-permissions-to-users} + +1. Go to "User management" +2. Select a user +3. In the "Roles" tab, assign the appropriate roles + +:::tip Programmatic Role Management +You can use Logto's [Management API](https://docs.logto.io/integrate-logto/interact-with-management-api) to programmatically manage user roles. +::: + +## Retrieving user identity {#retrieving-user-identity} + +Logto is an OpenID Connect provider that supports the standard [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) to retrieve user identity information. + +To fetch an access token that can be used to access the userinfo endpoint, at least two scopes are required: `openid` and `profile`. + +## Register MCP client {#register-mcp-client} + +Since Logto does not support Dynamic Client Registration yet, you need to manually register your MCP client in Logto Console. + +### Third-party vs. first-party applications + +Before creating the application, you need to understand the difference: + +- **Third-party application**: Use this when the MCP client is developed by someone else (e.g., VS Code, Cursor, or other community tools). These clients need to access your users' data, but are not under your control. Users will see a consent screen asking them to authorize the MCP client to access their information. +- **First-party application**: Use this when you are building your own MCP client (e.g., an AI assistant embedded in your own product). In this case, both the MCP client and MCP server are managed by you, and the users are your own users. No consent screen is needed. + +### Application type + +Choose the application type based on how the MCP client runs: + +| MCP Client | Application Type | +| ---------- | ---------------- | +| VS Code, Cursor (desktop apps) | Native App | +| MCP Inspector (browser-based) | Single Page App (SPA) | + +### Register a third-party app + +Take VS Code as an example: + +1. Navigate to **Applications > Third-party apps** and click "Create application". +2. Select **Native App** as the application type (since VS Code is a desktop application). +3. Fill in the application name (e.g., "VS Code") and description. +4. Set the **Redirect URIs** (check the MCP client's documentation for the required URIs): + ``` + http://127.0.0.1 + https://vscode.dev/redirect + ``` +5. Click "Save changes". +6. Go to the app's **Permissions** tab, under **User** section, add the required permissions from your API resource (e.g., `create:todos`, `read:todos`, `delete:todos`). +7. Copy the "App ID" value for use in VS Code. + +### Register a first-party app + +If you are building your own MCP client: + +1. Navigate to **Applications** and click "Create application". +2. Select the appropriate application type based on your client (Native App, SPA, etc.). +3. Complete the setup following the in-app guide. +4. Copy the "App ID" (and "App Secret" if applicable) for use in your MCP client. diff --git a/docs/tutorials/todo-manager/README.mdx b/docs/tutorials/todo-manager/README.mdx index 3a8df94..79a40ab 100644 --- a/docs/tutorials/todo-manager/README.mdx +++ b/docs/tutorials/todo-manager/README.mdx @@ -1,14 +1,16 @@ --- sidebar_position: 2 -sidebar_label: 'Tutorial: Build a todo manager' +sidebar_label: 'Build a todo manager' --- import { NpmLikeInstallation } from '@site/src/components/NpmLikeInstallation'; -import TabItem from '@theme/TabItem'; -import Tabs from '@theme/Tabs'; # Tutorial: Build a todo manager +:::tip Using a different authorization server? +This tutorial uses [Logto](https://logto.io) as the example authorization server. If you're using a different provider, check out our [Provider Guides](/docs/provider-guides) for configuration steps. +::: + :::tip Python SDK available MCP Auth is also available for Python! Check out the [Python SDK repository](https://github.com/mcp-auth/python) for installation and usage. ::: @@ -67,10 +69,7 @@ sequenceDiagram To implement [role-based access control (RBAC)](https://auth.wiki/rbac) in your MCP server, your authorization server needs to support issuing access tokens with scopes. Scopes represent the permissions that a user has been granted. - - - -[Logto](https://logto.io) provides RBAC support through its API resources (conforming [RFC 8707: Resource Indicators for OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc8707)) and roles features. Here's how to set it up: +[Logto](https://logto.io) provides RBAC support through its API resources (conforming [RFC 8707: Resource Indicators for OAuth 2.0](https://datatracker.ietf.org/doc/html/rfc8707)) and roles features. Here's a quick overview: 1. Sign in to [Logto Console](https://cloud.logto.io) (or your self-hosted Logto Console) @@ -98,24 +97,7 @@ To implement [role-based access control (RBAC)](https://auth.wiki/rbac) in your The scopes will be included in the JWT access token's `scope` claim as a space-separated string. - - - -OAuth 2.0 / OIDC providers typically support scope-based access control. When implementing RBAC: - -1. Define your required scopes in your authorization server -2. Configure your client to request these scopes during the authorization flow -3. Ensure your authorization server includes the granted scopes in the access token -4. The scopes are usually included in the JWT access token's `scope` claim - -Check your provider's documentation for specific details on: - -- How to define and manage scopes -- How scopes are included in the access token -- Any additional RBAC features like role management - - - +> 📖 See [Logto Provider Guide](/docs/provider-guides/logto) for detailed setup instructions. ### Validating tokens and checking permissions \{#validating-tokens-and-checking-permissions} @@ -218,12 +200,7 @@ To dive deeper into RBAC concepts and best practices, check out [Mastering RBAC: ## Configure authorization in your provider \{#configure-authorization-in-your-provider} -To implement the access control system we described earlier, you'll need to configure your authorization server to support the required scopes. Here's how to do it with different providers: - - - - -[Logto](https://logto.io) provides RBAC support through its API resources and roles features. Here's how to set it up: +To implement the access control system we described earlier, you'll need to configure your authorization server to support the required scopes. 1. Sign in to [Logto Console](https://cloud.logto.io) (or your self-hosted Logto Console) @@ -258,35 +235,6 @@ You can also use Logto's [Management API](https://docs.logto.io/integrate-logto/ When requesting an access token, Logto will include scopes in the token's `scope` claim based on the user's role permissions. - - - -For OAuth 2.0 or OpenID Connect providers, you'll need to configure the scopes that represent different permissions. The exact steps will depend on your provider, but generally: - -1. Define scopes: - - - Configure your authorization server to support: - - `create:todos` - - `read:todos` - - `delete:todos` - -2. Configure client: - - - Register or update your client to request these scopes - - Ensure the scopes are included in the access token - -3. Assign permissions: - - Use your provider's interface to grant appropriate scopes to users - - Some providers may support role-based management, while others might use direct scope assignments - - Check your provider's documentation for the recommended approach - -:::tip -Most providers will include the granted scopes in the access token's `scope` claim. The format is typically a space-separated string of scope values. -::: - - - - :::note[Trailing slash in resource indicator] Always include a trailing slash (`/`) in the resource indicator. Due to a current bug in the MCP official SDK, clients using the SDK will automatically append a trailing slash to resource identifiers when initiating auth requests. If your resource indicator doesn't include the trailing slash, resource validation will fail for those clients. (VS Code is not affected by this bug.) ::: @@ -512,14 +460,15 @@ When requesting access tokens from different authorization servers, you'll encou -While each provider may have its own specific requirements, the following steps will guide you through the process of integrating VS Code and the MCP server with provider-specific configurations. +While each provider may have its own specific requirements, the following steps will guide you through the process of integrating VS Code and the MCP server. ### Register MCP client as a third-party app \{#register-mcp-client-as-a-third-party-app} - - +:::info Why third-party app? +Since VS Code is not controlled by you (the MCP server operator), it should be registered as a third-party application. Users will see a consent screen when authorizing. -Integrating the todo manager with [Logto](https://logto.io) is straightforward as it's an OpenID Connect provider that supports resource indicators and scopes, allowing you to secure your todo API with `http://localhost:3001/` as the resource indicator. +If you're building your own MCP client, check the [Logto Provider Guide](/docs/provider-guides/logto#register-mcp-client) for first-party app registration. +::: Since Logto does not support Dynamic Client Registration yet, you will need to manually register your MCP client (VS Code) as a third-party app in your Logto tenant: @@ -538,39 +487,6 @@ Since Logto does not support Dynamic Client Registration yet, you will need to m 7. Go to the app's **Permissions** tab, under **User** section, add the `create:todos`, `read:todos`, and `delete:todos` permissions from the **Todo Manager** API resource you created earlier. 8. In the top card, you will see the "App ID" value. Copy it for later use. - - - -:::note -This is a generic OAuth 2.0 / OpenID Connect provider integration guide. Both OAuth 2.0 and OIDC follow similar steps as OIDC is built on top of OAuth 2.0. Check your provider's documentation for specific details. -::: - -If your provider supports Dynamic Client Registration, you may skip the manual registration; otherwise, you will need to manually register the MCP client: - -1. Sign in to your provider's console. - -2. Navigate to the "Applications" or "Clients" section, then create a new application or client. - -3. If your provider requires a client type, select "Native App" or "Public client". - -4. After creating the application, configure the redirect URIs. For VS Code, add the following: - - ``` - http://127.0.0.1 - https://vscode.dev/redirect - ``` - -5. Configure the required scopes/permissions for the application: - - ```text - create:todos read:todos delete:todos - ``` - -6. Find the "Client ID" or "Application ID" of the newly created application and copy it for later use. - - - - ### Set up MCP Auth \{#set-up-mcp-auth} First, install the MCP Auth SDK in your MCP server project. @@ -586,27 +502,7 @@ There are two ways to configure authorization servers: #### Configure protected resource metadata \{#configure-protected-resource-metadata} -First, get your authorization server's issuer URL: - - - - - -In Logto, you can find the issuer URL on your application details page within Logto Console, under the "Endpoints & Credentials / Issuer endpoint" section. It should look like `https://my-project.logto.app/oidc`. - - - - - -For OAuth 2.0 providers, you'll need to: - -1. Check your provider's documentation for the authorization server URL (often called issuer URL or base URL) -2. Some providers may expose this at `https://{your-domain}/.well-known/oauth-authorization-server` -3. Look in your provider's admin console under OAuth/API settings - - - - +First, get your authorization server's issuer URL. In Logto, you can find the issuer URL on your application details page within Logto Console, under the "Endpoints & Credentials / Issuer endpoint" section. It should look like `https://my-project.logto.app/oidc`. Now, configure the Protected Resource Metadata when building the MCP Auth instance: diff --git a/docs/tutorials/whoami/README.mdx b/docs/tutorials/whoami/README.mdx new file mode 100644 index 0000000..3e8ac64 --- /dev/null +++ b/docs/tutorials/whoami/README.mdx @@ -0,0 +1,348 @@ +--- +sidebar_position: 3 +sidebar_label: 'Who am I?' +--- + +# Tutorial: Who am I? + +:::tip Using a different authorization server? +This tutorial uses [Logto](https://logto.io) as the example authorization server. If you're using a different provider, check out our [Provider Guides](/docs/provider-guides) for configuration steps. +::: + +:::tip Python SDK available +MCP Auth is also available for Python! Check out the [Python SDK repository](https://github.com/mcp-auth/python) for installation and usage. +::: + +This tutorial will guide you through the process of setting up MCP Auth to authenticate users and retrieve their identity information from the authorization server. + +After completing this tutorial, you will have: + +- ✅ A basic understanding of how to use MCP Auth to authenticate users. +- ✅ A MCP server that offers a tool to retrieve user identity information. + +## Overview \{#overview} + +The tutorial will involve the following components: + +- **MCP server**: A simple MCP server that uses MCP official SDKs to handle requests. +- **VS Code**: A code editor with built-in MCP support. It also acts as an OAuth / OIDC client to initiate the authorization flow and retrieve access tokens. +- **Authorization server**: An OAuth 2.1 or OpenID Connect provider that manages user identities and issues access tokens. + +Here's a high-level diagram of the interaction between these components: + +```mermaid +sequenceDiagram + participant Client as VS Code + participant Server as MCP Server + participant Auth as Authorization Server + + Client->>Server: Request tool `whoami` + Server->>Client: Return 401 Unauthorized + Client->>Auth: Initiate authorization flow + Auth->>Auth: Complete authorization flow + Auth->>Client: Redirect back with authorization code + Client->>Auth: Exchange code for access token + Auth->>Client: Return access token + Client->>Server: Request `whoami` with access token + Server->>Auth: Fetch user identity with access token + Auth->>Server: Return user identity + Server->>Client: Return user identity +``` + +## Understand your authorization server \{#understand-your-authorization-server} + +### Retrieving user identity information \{#retrieving-user-identity-information} + +To complete this tutorial, your authorization server should offer an API to retrieve user identity information. + +[Logto](https://logto.io) is an OpenID Connect provider that supports the standard [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) to retrieve user identity information. + +To fetch an access token that can be used to access the userinfo endpoint, at least two scopes are required: `openid` and `profile`. You can continue reading as we'll cover the scope configuration later. + +> 📖 See [Generic OAuth 2.0 / OIDC Provider Guide](/docs/provider-guides/generic#retrieving-user-identity) for details on user identity retrieval with other providers. + +### Dynamic Client Registration \{#dynamic-client-registration} + +Dynamic Client Registration is not required for this tutorial, but it can be useful if you want to automate the MCP client registration process with your authorization server. Check [Is Dynamic Client Registration required?](/provider-list#is-dcr-required) for more details. + +## Set up the MCP server \{#set-up-the-mcp-server} + +We will use the [MCP official SDKs](https://github.com/modelcontextprotocol) to create a MCP server with a `whoami` tool that retrieves user identity information from the authorization server. + +### Create a new project \{#create-a-new-project} + +Set up a new Node.js project: + +```bash +mkdir mcp-server +cd mcp-server +npm init -y # Or use `pnpm init` +npm pkg set type="module" +npm pkg set main="whoami.js" +npm pkg set scripts.start="node whoami.js" +``` + +### Install the MCP SDK and dependencies \{#install-the-mcp-sdk-and-dependencies} + +```bash +npm install @modelcontextprotocol/sdk express +``` + +Or any other package manager you prefer, such as `pnpm` or `yarn`. + +### Create the MCP server \{#create-the-mcp-server} + +First, let's create an MCP server that implements a `whoami` tool. + +You can also use `pnpm` or `yarn` if you prefer. + +Create a file named `whoami.js` and add the following code: + +```js +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import express from 'express'; + +// Factory function to create an MCP server instance +// In stateless mode, each request needs its own server instance +const createMcpServer = () => { + const mcpServer = new McpServer({ + name: 'WhoAmI', + version: '0.0.0', + }); + + // Add a tool to the server that returns the current user's information + mcpServer.registerTool( + 'whoami', + { + description: 'Get the current user information', + inputSchema: {}, + }, + () => { + return { + content: [{ type: 'text', text: JSON.stringify({ error: 'Not authenticated' }) }], + }; + } + ); + + return mcpServer; +}; + +const PORT = 3001; +const app = express(); + +app.post('/', async (request, response) => { + // In stateless mode, create a new instance of transport and server for each request + // to ensure complete isolation. A single instance would cause request ID collisions + // when multiple clients connect concurrently. + const mcpServer = createMcpServer(); + const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }); + await mcpServer.connect(transport); + await transport.handleRequest(request, response, request.body); + response.on('close', () => { + transport.close(); + mcpServer.close(); + }); +}); + +app.listen(PORT); +``` + +Run the server with: + +```bash +npm start +``` + +## Integrate with your authorization server \{#integrate-with-your-authorization-server} + +To complete this section, there are several considerations to take into account: + +
+**The issuer URL of your authorization server** + +This is usually the base URL of your authorization server, such as `https://auth.example.com`. Some providers may have a path like `https://example.logto.app/oidc`, so make sure to check your provider's documentation. + +
+ +
+**How to retrieve the authorization server metadata** + +- If your authorization server conforms to the [OAuth 2.0 Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) or [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html), you can use the MCP Auth built-in utilities to fetch the metadata automatically. +- If your authorization server does not conform to these standards, you will need to manually specify the metadata URL or endpoints in the MCP server configuration. Check your provider's documentation for the specific endpoints. + +
+ +
+**How to register VS Code as a client in your authorization server** + +- If your authorization server supports [Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591), you can skip this step as VS Code will automatically register itself as a client. +- If your authorization server does not support Dynamic Client Registration, you will need to manually register VS Code as a client in your authorization server. + +
+ +
+**How to retrieve user identity information and how to configure the authorization request parameters** + +For OpenID Connect providers like Logto: you need to request at least the `openid` and `profile` scopes when initiating the authorization flow. This will ensure that the access token returned by the authorization server contains the necessary scopes to access the [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) to retrieve user identity information. + +> 📖 See [Generic OAuth 2.0 / OIDC Provider Guide](/docs/provider-guides/generic#retrieving-user-identity) for details on other providers. + +
+ +While each provider may have its own specific requirements, the following steps will guide you through the process of integrating VS Code and MCP server with Logto. + +### Register VS Code as a client \{#register-vs-code-as-a-client} + +Integrating with [Logto](https://logto.io) is straightforward as it's an OpenID Connect provider that supports the standard [userinfo endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) to retrieve user identity information. + +Since Logto does not support Dynamic Client Registration yet, you will need to manually register VS Code as a client in your Logto tenant: + +1. Sign in to [Logto Console](https://cloud.logto.io) (or your self-hosted Logto Console). +2. Navigate to the "Applications" tab, click on "Create application". In the bottom of the page, click on "Create app without framework". +3. Fill in the application details, then click on "Create application": + - **Select an application type**: Choose "Native app". + - **Application name**: Enter a name for your application, e.g., "VS Code". +4. In the "Settings / Redirect URIs" section, add the following redirect URIs for VS Code, then click on "Save changes" in the bottom bar: + ``` + http://127.0.0.1 + https://vscode.dev/redirect + ``` +5. In the top card, you will see the "App ID" value. Copy it for later use. + +> 📖 See [Logto Provider Guide](/docs/provider-guides/logto#register-mcp-client) for more details on registering MCP clients. + +### Set up MCP auth \{#set-up-mcp-auth} + +In your MCP server project, you need to install the MCP Auth SDK and configure it to use your authorization server metadata. + +First, install the `mcp-auth` package: + +```bash +npm install mcp-auth +``` + +MCP Auth requires the authorization server metadata to be able to initialize. The issuer URL can be found in your application details page in Logto Console, in the "Endpoints & Credentials / Issuer endpoint" section. It should look like `https://my-project.logto.app/oidc`. + +Update the `whoami.js` to include the MCP Auth configuration: + +```js +import { fetchServerConfig, MCPAuth } from 'mcp-auth'; + +const authIssuer = ''; // Replace with your issuer endpoint +const authServerConfig = await fetchServerConfig(authIssuer, { type: 'oidc' }); + +const mcpAuth = new MCPAuth({ + server: authServerConfig, +}); +``` + +:::note +If your provider does not support OpenID Connect Discovery, you can manually specify the metadata URL or endpoints. Check [Other ways to initialize MCP Auth](/docs/configure-server/mcp-auth#other-ways) for more details. +::: + +Now, we need to create a custom access token verifier that will fetch the user identity information from the authorization server using the access token provided by the MCP client. + +```js +import { MCPAuthTokenVerificationError } from 'mcp-auth'; + +/** + * Verifies the provided Bearer token by fetching user information from the authorization server. + * If the token is valid, it returns an `AuthInfo` object containing the user's information. + */ +const verifyToken = async (token) => { + const { issuer, userinfoEndpoint } = authServerConfig.metadata; + + if (!userinfoEndpoint) { + throw new Error('Userinfo endpoint is not configured in the server metadata'); + } + + const response = await fetch(userinfoEndpoint, { + headers: { Authorization: `Bearer ${token}` }, + }); + + if (!response.ok) { + throw new MCPAuthTokenVerificationError('token_verification_failed', response); + } + + const userInfo = await response.json(); + + if (typeof userInfo !== 'object' || userInfo === null || !('sub' in userInfo)) { + throw new MCPAuthTokenVerificationError('invalid_token', response); + } + + return { + token, + issuer, + subject: String(userInfo.sub), // 'sub' is a standard claim for the subject (user's ID) + clientId: '', // Client ID is not used in this example, but can be set if needed + scopes: [], + claims: userInfo, + }; +}; +``` + +### Update MCP server \{#update-mcp-server} + +We are almost done! It's time to update the MCP server to apply the MCP Auth route and middleware function, then make the `whoami` tool return the actual user identity information. + +```js +// In the factory function, update the `whoami` tool to return the actual user identity +mcpServer.registerTool( + 'whoami', + { + description: 'Get the current user information', + inputSchema: {}, + }, + (_params, { authInfo }) => { + return { + content: [ + { + type: 'text', + text: JSON.stringify(authInfo?.claims ?? { error: 'Not authenticated' }), + }, + ], + }; + } +); + +// ... + +// Apply MCP Auth middleware before the MCP endpoint +app.use(mcpAuth.delegatedRouter()); +app.use(mcpAuth.bearerAuth(verifyToken)); +``` + +## Checkpoint: Run the `whoami` tool with authentication \{#checkpoint-run-the-whoami-tool-with-authentication} + +Restart your MCP server and connect VS Code to it. Here's how to connect with authentication: + +1. In VS Code, press `Command + Shift + P` (macOS) or `Ctrl + Shift + P` (Windows/Linux) to open the Command Palette. +2. Type `MCP: Add Server...` and select it. +3. Choose `HTTP` as the server type. +4. Enter the MCP server URL: `http://localhost:3001/` +5. After an OAuth request is initiated, VS Code will prompt you to enter the **App ID** (Client ID). Enter the App ID you copied from your authorization server. +6. Since we don't have an **App Secret** (it's a public client), just press Enter to skip. +7. Complete the sign-in flow in your browser. + +Once you sign in, you can use the `whoami` tool in VS Code. This time, you should see the user identity information returned by the authorization server. + +:::info +Check out the [MCP Auth Node.js SDK repository](https://github.com/mcp-auth/js/blob/master/packages/sample-servers/src) for the complete code of the MCP server (OIDC version). This directory contains both TypeScript and JavaScript versions of the code. +::: + +## Closing notes \{#closing-notes} + +🎊 Congratulations! You have successfully completed the tutorial. Let's recap what we've done: + +- Setting up a basic MCP server with the `whoami` tool +- Integrating the MCP server with an authorization server using MCP Auth +- Configuring VS Code to authenticate users and retrieve their identity information + +You may also want to explore some advanced topics, including: + +- Using [JWT (JSON Web Token)](https://auth.wiki/jwt) for authentication and authorization +- Leveraging [resource indicators (RFC 8707)](https://auth-wiki.logto.io/resource-indicator) to specify the resources being accessed +- Implementing custom access control mechanisms, such as [role-based access control (RBAC)](https://auth.wiki/rbac) or [attribute-based access control (ABAC)](https://auth.wiki/abac) + +Be sure to check out other tutorials and documentation to make the most of MCP Auth. diff --git a/docs/tutorials/whoami/assets/inspector-first-run.png b/docs/tutorials/whoami/assets/inspector-first-run.png new file mode 100644 index 0000000..e5e0502 Binary files /dev/null and b/docs/tutorials/whoami/assets/inspector-first-run.png differ diff --git a/docs/tutorials/whoami/assets/result.png b/docs/tutorials/whoami/assets/result.png new file mode 100644 index 0000000..b7cded5 Binary files /dev/null and b/docs/tutorials/whoami/assets/result.png differ diff --git a/sidebars.ts b/sidebars.ts index 667d6c2..05f64ca 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -24,7 +24,17 @@ const sidebars: SidebarsConfig = { { type: 'category', label: 'Tutorials', - items: ['tutorials/todo-manager/README'], + items: ['tutorials/todo-manager/README', 'tutorials/whoami/README'], + }, + { + type: 'category', + label: 'Provider Guides', + link: { type: 'doc', id: 'provider-guides/README' }, + items: [ + 'provider-guides/logto', + 'provider-guides/keycloak', + 'provider-guides/generic', + ], }, { type: 'category',