agentic-community / agentic-community/mcp-gateway-registry
Feature request: Separate discovery/scan authentication from runtime authentication for MCP servers
- Dominant language
- Python
- Stars
- 911
- Forks
- 234
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 62
Description
## Summary
Today, registering an MCP server appears to use a single backend authentication configuration for multiple purposes:
1. Health checks
2. Tool discovery / `tools/list`
3. Security scanning
4. Runtime proxying of end-user requests
This works well for MCP servers that use a shared service credential, but it does not work cleanly for MCP servers that require **per-end-user delegated authentication**, such as Atlassian, Google, Microsoft, GitHub, Salesforce, and other SaaS providers using OAuth.
I would like to request a feature that separates:
- **Discovery / scan authentication**
- **Runtime authentication behavior**
This would allow the gateway to safely scan and enable MCP servers without accidentally reusing a registration-time credential for all end users at runtime.
## Problem
Some remote MCP servers require authentication before they expose metadata such as `initialize` or `tools/list`.
For example, an Atlassian MCP server may require the user to authenticate with Atlassian before the server allows discovery or tool execution.
In the current gateway model, if I register such a server without backend authentication:
```bash
auth_scheme=none
```
then the gateway may not be able to run the security scan or discover tools, so the server cannot be enabled.
However, if I register the server with a bearer token or API key:
```bash
auth_scheme=bearer
auth_credential=
```
then that credential becomes the backend credential used by the gateway for runtime proxying. This means the same credential could be injected for all incoming user requests.
That is not appropriate for delegated-user OAuth scenarios.
## Example scenario: Atlassian MCP server
Desired behavior:
```text
Gateway registration / scanning:
use a scan-only credential, or another discovery-specific auth method
Runtime tool invocation:
use the end user's Atlassian OAuth token
do not use the registration-time credential
do not store or rotate Atlassian user tokens in the gateway
```
Current problem:
```text
If auth_scheme=none:
security scan/tool discovery may fail
If auth_scheme=bearer:
gateway stores that bearer token and uses it for all proxied runtime requests
```
This creates a mismatch between gateway registration requirements and per-user delegated authentication.
## Requested feature
Please add support for separating **discovery authentication** from **runtime authentication**.
For example, server registration could support fields like:
```json
{
"server_name": "Atlassian",
"path": "/atlassian",
"proxy_pass_url": "https://mcp.atlassian.com/v1/mcp",
"discovery_auth": {
"scheme": "bearer",
"credential": "",
"header": "Authorization"
},
"runtime_auth": {
"mode": "pass_through",
"headers": ["Authorization"]
}
}
```
The key behavior would be:
```text
discovery_auth:
used only for health checks, tool discovery, and security scanning
runtime_auth:
controls what happens during end-user requests
```
The gateway should not automatically reuse `discovery_auth` during runtime proxying unless explicitly configured to do so.
## Proposed runtime authentication modes
### 1. `gateway_managed`
Current behavior.
The gateway stores a backend credential and injects it for all runtime requests.
Useful for shared service credentials.
```json
{
"runtime_auth": {
"mode": "gateway_managed",
"scheme": "bearer",
"credential": ""
}
}
```
### 2. `pass_through`
The gateway forwards selected headers from the client/agent to the backend MCP server.
Useful for per-user OAuth tokens managed by the client/agent.
```json
{
"runtime_auth": {
"mode": "pass_through",
"headers": ["Authorization"]
}
}
```
This would support flows such as:
```text
Client/agent -> Gateway:
X-Authorization: Bearer
Authorization: Bearer
Gateway -> MCP server:
Authorization: Bearer
```
The gateway authenticates the caller with its own token, but passes the user's upstream SaaS token to the MCP server.
### 3. `none`
The gateway does not inject or forward any backend authentication.
Useful for public MCP servers or MCP servers that handle auth out-of-band.
```json
{
"runtime_auth": {
"mode": "none"
}
}
```
### 4. Future option: `delegated_token_vault`
This could be a future mode, not necessarily part of the first implementation.
The gateway would manage per-user upstream OAuth tokens, including storage, refresh, revocation, audit, and injection.
```json
{
"runtime_auth": {
"mode": "delegated_token_vault",
"provider": "atlassian"
}
}
```
This would be more complex and would require a much larger security model.
For now, `pass_through` would be enough for clients/agents that already manage delegated OAuth tokens.
## Why this matters
Many useful MCP servers are wrappers around SaaS APIs where authorization is inherently user-specific.
Examples:
- Atlassian Jira / Confluence
- Google Drive / Gmail / Calendar
- Microsoft Graph
- GitHub
- Slack
- Salesforce
- ServiceNow
For these integrations, a single shared backend credential is often the wrong model.
The gateway needs to be able to:
1. Authenticate and authorize access to the MCP server path
2. Run health checks, tool discovery, and security scanning
3. Preserve delegated end-user authentication at runtime
4. Avoid storing third-party user tokens unless explicitly configured to do so
5. Avoid accidentally using one registration-time credential for all users
## Security considerations
This feature would improve security by making credential intent explicit.
The current single-auth model can lead to accidental misuse:
```text
A token provided for registration/scanning may unintentionally become the token used for all users at runtime.
```
With separated auth, administrators can clearly define:
```text
Discovery credential:
used by the gateway only for scanning and tool discovery
Runtime credential:
passed through from the user/agent, injected by the gateway, or omitted
```
This also supports least privilege. A discovery credential could be scan-only and unable to execute tools, while actual tool calls require user-specific delegated tokens.
## Suggested implementation
Add separate registration fields for discovery and runtime auth.
Possible shape:
```json
{
"discovery_auth_scheme": "none | bearer | api_key",
"discovery_auth_header": "Authorization",
"discovery_auth_credential": "",
"runtime_auth_mode": "none | gateway_managed | pass_through",
"runtime_auth_scheme": "none | bearer | api_key",
"runtime_auth_header": "Authorization",
"runtime_auth_credential": "",
"runtime_pass_through_headers": ["Authorization"]
}
```
Backward compatibility could be preserved by mapping the existing fields to:
```json
{
"discovery_auth": "same as existing auth_scheme/auth_credential",
"runtime_auth": {
"mode": "gateway_managed",
"credential": "same as existing auth_credential"
}
}
```
That would preserve current behavior while allowing newer registrations to opt into separated auth.
## Acceptance criteria
- A server can be registered with a credential used only for discovery/scanning.
- That discovery credential is not injected into runtime requests unless explicitly configured.
- A server can be configured to pass through selected end-user auth headers at runtime.
- Existing `auth_scheme` / `auth_credential` behavior remains backward compatible.
- Security scan, health check, and tool discovery continue to work with discovery-specific credentials.
- Runtime proxying can use a different authentication behavior from scanning.
- Documentation clearly explains the difference between:
- gateway/registry authentication
- discovery/scan authentication
- backend runtime authentication
- pass-through delegated user authentication
## Example desired Atlassian registration
```json
{
"server_name": "Atlassian",
"path": "/atlassian",
"proxy_pass_url": "https://mcp.atlassian.com/v1/mcp",
"discovery_auth": {
"scheme": "bearer",
"credential": ""
},
"runtime_auth": {
"mode": "pass_through",
"headers": ["Authorization"]
}
}
```
Runtime request:
```http
POST /atlassian/mcp HTTP/1.1
Host: gateway.example.com
X-Authorization: Bearer
Authorization: Bearer
Content-Type: application/json
```
Gateway behavior:
```text
1. Validate X-Authorization as the gateway access token.
2. Authorize the caller for /atlassian.
3. Forward Authorization to the Atlassian MCP server.
4. Do not inject the discovery credential.
5. Do not store or rotate the user's Atlassian token.
```
## Conclusion
The gateway should support a clean separation between:
```text
credential used to scan/discover/register an MCP server
```
and
```text
credential used for runtime end-user tool calls
```
This is necessary for MCP servers backed by SaaS providers that require delegated per-user authentication.
Without this separation, administrators must choose between:
1. Registering with no backend auth and failing discovery/security scanning, or
2. Registering with a credential that may then be reused for all runtime users.
A separated model would make the gateway safer, more flexible, and much easier to use with real-world OAuth-based MCP servers.
Contributor guide
Assessment
This issue has not been assessed yet.