Agentic Data Plane

Set Up a GitHub OAuth Provider and MCP Server

This tutorial shows how to connect Redpanda Agentic Data Plane to GitHub using OAuth, so users can authenticate with their own GitHub credentials when calling GitHub MCP tools.

After completing this tutorial, you will be able to:

  • Create a GitHub OAuth app and register it as an OAuth provider in Agentic Data Plane

  • Test the OAuth connection proactively on the Connections page

  • Configure a GitHub managed MCP server with user-delegated OAuth

Before you begin

  • You need a GitHub account with permission to create OAuth apps (personal account or organization with appropriate role).

  • You need Agentic Data Plane administrator permissions to create OAuth providers and MCP servers.

  • You should understand the difference between user-delegated OAuth (each user authenticates as themselves) and service-account OAuth (all users share one identity). This tutorial covers user-delegated OAuth.

GitHub recommends considering GitHub Apps instead of OAuth Apps for production use, as they offer fine-grained permissions and short-lived tokens. However, OAuth Apps work well for getting started with Redpanda Agentic Data Plane’s AI Gateway integration.

Create a GitHub OAuth app

Register an OAuth application in GitHub to obtain the client ID and client secret.

Throughout this tutorial, fields marked with * are required.

  1. Sign in to GitHub and navigate to Settings → Developer settings → OAuth Apps.

  2. Click New OAuth App (or Register a new application if this is your first OAuth app).

  3. Fill in the application details:

    Field Value

    Application name

    Agentic Data Plane AI Gateway (or your preferred name)

    Homepage URL

    https://aigw.<cluster-id>.clusters.rdpa.co
    Replace <cluster-id> with your actual cluster ID, such as https://aigw.d6kjl4h19241bg3ek3t0.clusters.rdpa.co.

    Application description

    Optional. For example: "Redpanda AI Gateway GitHub integration".

    Authorization callback URL

    https://aigw.<cluster-id>.clusters.rdpa.co/oauth/v1/callback
    This must match exactly. Replace <cluster-id> with your actual cluster ID, such as https://aigw.d6kjl4h19241bg3ek3t0.clusters.rdpa.co/oauth/v1/callback.

  4. Click Register application.

  5. On the application page, note your Client ID. Copy it for later.

  6. Click Generate a new client secret and copy it immediately (you won’t see it again).

Store your client secret securely. GitHub will not show it again after you navigate away.

Create the GitHub OAuth provider in Agentic Data Plane

Register GitHub as an OAuth provider in Agentic Data Plane.

  1. Open Integrations setup in the sidebar and click the Outbound providers tab.

  2. Click Add provider and click GitHub in the catalog.

  3. Fill in the provider details:

Provider details

Field Value Notes

Name *

A name for this OAuth provider, for example, github.

Lowercase letters, numbers, and hyphens only. This is the machine identifier used when attaching the provider to an MCP server. Immutable after creation.

Client ID *

The client ID from your GitHub OAuth app, for example, <your-client-id>

This is found in GitHub Settings → Developer settings → OAuth Apps → [Your App].

Display name *

GitHub

Human-readable name shown in Agentic Data Plane.

Authorization endpoint *

https://github.com/login/oauth/authorize

GitHub’s OAuth authorization URL where users are redirected to grant permission.

Token endpoint *

https://github.com/login/oauth/access_token

GitHub’s OAuth token exchange endpoint where authorization codes are exchanged for access tokens.

Revocation endpoint

Leave empty

GitHub doesn’t provide a standard RFC 7009 token revocation endpoint. Agentic Data Plane will handle token lifecycle without this.

Client secret reference *

GITHUB_CLIENT_SECRET

Click New. Enter GITHUB_CLIENT_SECRET as the key name, paste in your client secret from GitHub, and then click Create secret. This creates the secret in the Secrets Store and links it to this provider in Agentic Data Plane. If you already have a secret in Secrets Store, click Existing instead.

Scopes

The GitHub preset fills in one scope field for each of repo, read:user, read:org, and workflow. The GitHub (Read) MCP server in this tutorial only reads, so remove the field that holds workflow, a scope that grants the ability to add and update GitHub Actions workflow files. Keep repo, which a read-only server still needs for private repositories.

Common GitHub OAuth scopes:

  • repo - Full access to public and private repositories

  • public_repo - Access to public repositories only

  • read:user, user:email - Read user profile and email addresses

  • read:org - Read-only access to organization membership

  • workflow - Add and update GitHub Actions workflow files

  • gist - Write access to gists

See the GitHub OAuth scopes documentation for the complete list.

Scope management: Include every scope any MCP server attached to this provider might need. Users must re-consent when scopes are added later, so it’s better to include all necessary scopes upfront.

Grant types

Select Browser consent (OAuth 2.0 Authorization Code flow). This is the standard flow for user-delegated OAuth.

Token endpoint authentication method

Select Client Secret (Basic)

This sends credentials as client_id:client_secret in the HTTP Basic Authorization header. The GitHub preset selects this method.

Method When to use

Client Secret (Basic)

Most common, and what the GitHub preset uses. Credentials sent in Authorization header.

Client Secret (POST)

Credentials sent in the POST body. Use only if the provider requires it.

None (PKCE only)

For public clients with no client secret. Not applicable for GitHub OAuth Apps.

Require PKCE

Turn on Require PKCE. The GitHub preset leaves it off.

Proof Key for Code Exchange (PKCE) adds an extra layer of security to the OAuth flow.

PKCE (RFC 7636) protects against authorization code interception attacks. When enabled, the gateway generates a code challenge before redirecting the user to GitHub and verifies it when exchanging the authorization code for a token.

Complete creation

  1. Review all fields to ensure they match the values above

  2. Click Create provider

The provider appears in the Outbound providers list with status "Enabled".

Test the connection on the Connections page

Before creating an MCP server, proactively test the OAuth flow to verify your provider configuration is correct.

  1. Open Connections in the sidebar.

  2. Find GitHub in the connections rail, under Available to connect.

  3. Click Connect.

  4. You’ll be redirected to GitHub’s authorization page.

  5. Review the requested permissions (scopes) and click Authorize [Your App Name].

  6. GitHub redirects you back to Agentic Data Plane.

  7. GitHub now shows status "Connected".

If the connection fails:

  • Check that the Authorization callback URL in your GitHub OAuth app exactly matches the expected URL with your cluster ID.

  • Verify the Client ID and Client secret ref in the Agentic Data Plane OAuth provider are correct.

  • Check that the secret GITHUB_CLIENT_SECRET exists and contains the correct value.

See Troubleshooting for more debugging tips.

Create the GitHub MCP server

Now create an MCP server that uses the GitHub OAuth provider for user-delegated authentication.

  1. Open MCP servers in the sidebar.

  2. Click Add MCP server.

  3. Use the search bar or browse the catalog to find GitHub (Read), and click it.

    GitHub (Read) is a managed MCP server, meaning Redpanda provides and maintains the implementation. It is read-only: its tools read repositories, pull requests, commits, and code, and none of them write to GitHub. You only need to configure authentication.

Configure the GitHub MCP server

Fill in the basic server details:

Field Example value Notes

Name *

my-gh

Unique identifier. Lowercase letters, numbers, and hyphens only.

Description

What this server does (shown in detail views)

Optional human-readable description.

Code mode

Toggle on/off

Adds search and execute tools that let agents run sandboxed code against this server’s tools. The toggle starts on for this server type.

Restrict To Org

redpanda-data

GitHub-specific field. If set, confines this MCP server to the named GitHub org (for example, "redpanda-data"). Leave empty for unrestricted access to all repositories the user can access.

Configure authentication

GitHub (Read) takes either a per-user OAuth token or one shared token. This tutorial uses per-user OAuth, so every tool call runs as the person who made it. For the alternative, see Authenticate with one shared token.

  1. In the Auth dropdown, select User OAuth.

    This enables user-delegated authentication where each user authenticates with their own GitHub credentials.

  2. In the User OAuth section that appears:

Field Value Notes

Provider name *

GitHub

Select the GitHub OAuth provider you created earlier from the dropdown. If "Not set" appears, you haven’t created a provider yet or it’s not visible.

Required scopes

Click + Add required scopes

Add the same scopes you defined in the OAuth provider, adding each scope to a new line. If a user’s stored connection has fewer scopes than specified here, they’ll be prompted to re-consent with upgraded scopes.

Token injection (advanced)

The Injection section controls how the resolved OAuth token is placed on upstream requests:

Field Default value Notes

Header name

Authorization

HTTP header name for the token. GitHub expects Authorization, so keep the default.

Header prefix

Bearer

Value prefix before the token. GitHub expects Bearer <token>, so keep the default. Set empty to omit the prefix entirely (for upstreams that expect a bare API key as the token).

How to authenticate to GitHub link explains GitHub’s expected authentication format. For standard GitHub OAuth, the defaults (Authorization: Bearer <token>) are correct.

Authenticate with one shared token

Select Static Token in the Auth dropdown to have every call reach GitHub with the same token instead of each caller’s own. The User OAuth fields give way to a reference to a secret that holds a GitHub token, and the server sends that token on every tool call, so GitHub sees one identity for every agent and user, and applies that identity’s repository access.

Choose this when the server should act as one automation identity. Otherwise keep User OAuth, which keeps each call attributable to the person who made it.

Field Value Notes

Key Secret Ref *

GITHUB_TOKEN

The secret store key that holds the GitHub token. Select an existing secret or create one, and name it in UPPER_SNAKE_CASE. The token has to be one GitHub accepts on its REST API, with access to the repositories this server reads. For which kind of token to issue, and which permissions to grant it, see GitHub’s own documentation. A server whose secret is missing, or holds an empty value, doesn’t start. The server reads the token once and never refreshes it, so a short-lived token stops working when it expires.

Header Name

Leave empty

The token reaches GitHub in the Authorization header, as Bearer <token>. Leave this empty, or set it to Authorization. Any other header name is rejected when you save the server.

Nobody connects a GitHub account for a server that authenticates this way. There’s no consent step, and a tool call never asks for authorization. Restrict To Org and SQL exposure work as they do with per-user OAuth, except that a query returns the rows the shared token can read rather than the rows the calling user can read.

Complete creation

  1. If the form shows Queryable, leave Enabled on if your agents need the SQL tools described in Expose GitHub data as SQL tables, or turn it off. The form shows it, switched on, only if SQL tools are available in your organization. Creating a server with rpk ai leaves it off unless the configuration sets it.

  2. Review all fields.

  3. Click Create server.

The server’s detail page shows a Managed badge next to its name. Its tools read the signed-in user’s profile, organizations, repositories, pull requests, commits, and code.

User OAuth compared with Static Token:

  • User OAuth: Each person authenticates with their own GitHub account. GitHub sees each request as that person, and applies their permissions.

  • Static Token: Every caller shares one GitHub identity. GitHub sees every request as the token’s owner. See Authenticate with one shared token.

Where people reach their own repositories, or GitHub’s per-user permissions have to hold, choose User OAuth.

Verify the MCP server works

Test that the MCP server is correctly configured and can authenticate users.

  1. In Agentic Data Plane, find your GitHub MCP server in the MCP servers list.

  2. Click it to view details.

  3. If you tested the connection in Connections, you’re already connected and can test immediately.

  4. If you skipped the Connections test, the first time you call a tool from this server, you’ll be prompted to authorize GitHub.

    The flow is:

    1. Call a tool (for example, through a Claude Desktop integration pointing to this MCP server).

    2. The tool call fails with a message that carries an authorization URL.

    3. Open the URL to connect to GitHub.

    4. You authorize in GitHub.

    5. Call the tool again. It now succeeds.

  5. After successful authorization, subsequent tool calls use your stored GitHub token with no additional prompts (until the token expires or scopes change).

Expose GitHub data as SQL tables

The GitHub server can present its data as read-only SQL tables instead of only as tools, so an agent can filter repository data the way it would query a database. SQL exposure adds two tools:

  • list_tables: Return the table catalog. For each table, the catalog lists its columns and their types, which columns can be filtered and with which operators, whether each filter is exact, the page-size limit, and a schema fingerprint that every query response repeats so a caller can tell when the catalog changed.

  • execute_query: Run one query against a table and return a page of rows plus a cursor for the next page.

The execute_query tool reads GitHub through the server’s configured authentication, so with user-delegated OAuth a query returns only what the calling user can see, exactly as the other tools do. The list_tables tool returns the catalog, which is the same for every caller and carries no GitHub data, so a caller who hasn’t connected a GitHub account yet can still read the catalog and plan a query. Every other tool on the server, including execute_query, keeps asking for that connection, and a list_tables call routed through the server’s code-mode endpoint needs the connection too. Neither tool writes to GitHub.

The tables are:

Table Contents

repositories

Repositories of one GitHub organization. Columns: organization, full_name, description, default_branch, visibility, language, topics, archived, fork, created_at, updated_at, pushed_at, size, and html_url.

pull_requests

Pull requests of one repository, oldest first. Columns: owner, repo, number, title, state, draft, head_ref, head_sha, head_repo, base_ref, base_sha, author_login, body, labels, assignees, requested_reviewers, created_at, updated_at, merged_at, and html_url.

commits

Commits reachable from one repository’s default branch, newest first. Columns: owner, repo, sha, message, author_login, author_name, author_email, authored_at, committer_login, committer_name, committer_email, committed_at, parents, html_url, and path.

branches

Branches of one repository. Columns: owner, repo, name, commit_sha, and protected.

tags

Tags of one repository. Columns: owner, repo, name, and commit_sha.

Every table is scoped to an organization or to a single repository, so every query has to say which one:

  • A query against repositories filters on organization.

  • A query against pull_requests, commits, branches, or tags filters on both owner and repo.

Setting Restrict To Org pins that scope. The server fills in the pinned organization for you, so a query against repositories needs no filter, and a query against the other four tables only has to filter on repo. A query that names a different organization or owner is refused.

Besides the scope columns, only a few columns can be filtered:

  • On pull_requests, filter on state for open or closed, or on base_ref for a branch name.

  • On commits, filter on author_login, on committed_at with a time range, or on path to list only the commits that touched one file.

  • On branches, filter on protected.

Every other column can be returned but not filtered. A query against tags takes no filter beyond its scope.

The author_login filter and a committed_at range aren’t exact, so the list_tables catalog marks them as filters that can return extra rows. Because execute_query returns the rows GitHub sends back without re-checking them against your filters, an agent that needs exact results must re-apply those two filters to the rows it receives. Every other filter is exact.

A paged scan is best-effort. A page holds at most 100 rows, and the repository keeps changing under a multi-page scan, so a long scan can miss a row or return one twice. A cursor is bound to the query that produced it, and reusing one with different filters or against another table is refused instead of quietly starting a new scan.

A curator can also trim the catalog table by table, from the SQL exposure tab on the server’s page. The tab’s Enable SQL for this server button is the same setting as Enabled, and the tab lists the tables only while SQL is on. If the server’s page has no SQL exposure tab, narrowing isn’t enabled for your organization, and Enabled in the server’s configuration still turns the two tools on and off.

With SQL exposure on, the two tools are available to every caller of the server, including agents. Turn Enabled off on a server whose agents should only reach the curated GitHub tools.

What you accomplished

You have now:

  • Created a GitHub OAuth app with the correct callback URL

  • Registered GitHub as an OAuth provider in Agentic Data Plane

  • Tested the OAuth connection proactively

  • Created a GitHub managed MCP server with user-delegated OAuth

  • Verified that users can authenticate and call GitHub tools

You could next create an agent using this GitHub MCP server. Each user who calls tools from this MCP server will authenticate with their own GitHub account. User tokens are stored securely in Agentic Data Plane’s token vault and automatically refreshed before expiry.

Troubleshooting

Symptom Solution

redirect_uri_mismatch error during authorization

The callback URL in your GitHub OAuth app doesn’t match Agentic Data Plane’s callback. Go to GitHub Settings → Developer settings → OAuth Apps → [Your App] and verify the Authorization callback URL is exactly https://aigw.<cluster-id>.clusters.rdpa.co/oauth/v1/callback.

invalid_client error during token exchange

The Client ID or Client secret is incorrect, or the authentication method doesn’t match. Verify the Client ID in the OAuth provider matches GitHub, and that GITHUB_CLIENT_SECRET contains the correct client secret. Ensure Token endpoint authentication method is set to "Client Secret (Basic)".

invalid_scope error during consent

One of the scopes you requested isn’t valid for GitHub OAuth apps. Check the GitHub OAuth scopes documentation and remove or rename invalid scopes.

"OAuth provider not found" when creating MCP server

The provider name doesn’t match. Verify you created the provider with name github (lowercase) and are selecting the correct provider in the MCP server configuration.

Connection works in Connections but fails in MCP server

The MCP server’s required scopes might be different from what you consented to in Connections. Edit the OAuth provider to include all necessary scopes, then re-consent in Connections.

Token expired or token_expired error

GitHub tokens eventually expire or can be revoked. The user needs to re-authorize in Connections or by triggering the consent flow again on the next tool call.

Permission denied when attaching provider to MCP server

You need the dataplane_aigateway_oauthprovider_attach permission on the GitHub provider. Contact your Agentic Data Plane administrator to grant this permission.