litellm - ✅(Solved) Fix MCP: health check skipped for OAuth2 M2M servers — always shows 'unknown' [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#24709Fetched 2026-04-08 01:42:06
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Participants
Timeline (top)
cross-referenced ×1referenced ×1

MCP servers configured with OAuth2 client_credentials (M2M) auth always show status: "unknown" because the health check is unconditionally skipped.

Root Cause

In mcp_server_manager.py health_check_server() (around line 2663), the health check is skipped when:

elif (
    server.auth_type
    and server.auth_type != MCPAuth.none
    and server.auth_type != MCPAuth.aws_sigv4
    and not server.authentication_token
):
    should_skip_health_check = True

For M2M OAuth2 servers, authentication_token is always None — the token is fetched dynamically at request time via client_id/client_secret/token_url. So this condition always evaluates to True and the health check never runs.

Fix Action

Workaround

Use /mcp-rest/tools/list?server_id=<id> to verify the server is reachable and tools are accessible — this correctly fetches the OAuth2 token and connects.

PR fix notes

PR #24727: fix(mcp): allow health check for OAuth2 M2M (client_credentials) servers

Description (problem / solution / changelog)

Problem

Fixes #24709

MCP servers configured with OAuth2 client_credentials (M2M) auth always show status: "unknown" because the health check is unconditionally skipped.

Root Cause

In health_check_server(), the following guard skips the health check when authentication_token is absent:

elif (
    server.auth_type
    and server.auth_type != MCPAuth.none
    and server.auth_type != MCPAuth.aws_sigv4
    and not server.authentication_token
):  # ← skips ALL auth_type-set servers without a static token
    should_skip_health_check = True

For M2M OAuth2 servers (oauth2_flow: client_credentials), authentication_token is always None — the access token is fetched dynamically at request time via token_url / client_id / client_secret. So this condition always triggers and the health check is never run.

Fix

Add and not server.has_client_credentials to the guard condition:

elif (
    server.auth_type
    and server.auth_type != MCPAuth.none
    and server.auth_type != MCPAuth.aws_sigv4
    and not server.authentication_token
    and not server.has_client_credentials   # ← NEW: let M2M servers through
):
    should_skip_health_check = True

server.has_client_credentials returns True when oauth2_flow == "client_credentials". When the guard is bypassed, _create_mcp_client is called as usual, and it already invokes resolve_mcp_auth (from oauth2_token_cache.py) to fetch and cache the OAuth2 token — no additional changes needed.

What was tested

  • M2M OAuth2 server now runs through the health check path
  • Servers with static authentication_token still take the existing fast path
  • aws_sigv4 servers are still excluded from the guard (unchanged)
  • requires_per_user_auth servers still skip the health check (unchanged)

Checklist

  • My PR is focused on a single issue
  • I have read the LiteLLM contribution guidelines
  • DCO signed (-s flag on commit)

Changed files

  • litellm/proxy/_experimental/mcp_server/mcp_server_manager.py (modified, +3/-1)

Code Example

elif (
    server.auth_type
    and server.auth_type != MCPAuth.none
    and server.auth_type != MCPAuth.aws_sigv4
    and not server.authentication_token
):
    should_skip_health_check = True

---

curl -X POST "$LITELLM_URL/v1/mcp/server" \
  -H "Authorization: Bearer $MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "server_name": "MyMCPServer",
    "url": "https://example.com/mcp",
    "transport": "http",
    "auth_type": "oauth2",
    "token_url": "https://auth.example.com/token",
    "credentials": {"client_id": "xxx", "client_secret": "yyy"},
    "available_on_public_internet": true
  }'
RAW_BUFFERClick to expand / collapse

Bug Report

Description

MCP servers configured with OAuth2 client_credentials (M2M) auth always show status: "unknown" because the health check is unconditionally skipped.

Root Cause

In mcp_server_manager.py health_check_server() (around line 2663), the health check is skipped when:

elif (
    server.auth_type
    and server.auth_type != MCPAuth.none
    and server.auth_type != MCPAuth.aws_sigv4
    and not server.authentication_token
):
    should_skip_health_check = True

For M2M OAuth2 servers, authentication_token is always None — the token is fetched dynamically at request time via client_id/client_secret/token_url. So this condition always evaluates to True and the health check never runs.

Expected Behavior

For OAuth2 M2M servers (where token_url, client_id, and client_secret are configured), the health check should fetch an OAuth2 token using the stored credentials and use it to perform the health check, similar to how execute_mcp_tool fetches tokens at request time.

Actual Behavior

Health check is skipped entirely. Status remains "unknown" in both UI and API responses.

Steps to Reproduce

  1. Create an MCP server with OAuth2 M2M auth:
curl -X POST "$LITELLM_URL/v1/mcp/server" \
  -H "Authorization: Bearer $MASTER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "server_name": "MyMCPServer",
    "url": "https://example.com/mcp",
    "transport": "http",
    "auth_type": "oauth2",
    "token_url": "https://auth.example.com/token",
    "credentials": {"client_id": "xxx", "client_secret": "yyy"},
    "available_on_public_internet": true
  }'
  1. Check server status: GET /v1/mcp/server/<server_id>
  2. Observe "status": "unknown" — health check was never attempted

Workaround

Use /mcp-rest/tools/list?server_id=<id> to verify the server is reachable and tools are accessible — this correctly fetches the OAuth2 token and connects.

Environment

  • LiteLLM version: current main (also affects v1.81.14)
  • Auth type: oauth2 with client_credentials (M2M)

extent analysis

Fix Plan

To fix the issue, we need to modify the health_check_server() function in mcp_server_manager.py to handle OAuth2 M2M servers correctly. Here are the steps:

  • Modify the condition to skip health check:
elif (
    server.auth_type
    and server.auth_type != MCPAuth.none
    and server.auth_type != MCPAuth.aws_sigv4
    and (not server.authentication_token or server.auth_type == MCPAuth.oauth2)
):
    # For OAuth2 M2M servers, fetch token dynamically
    if server.auth_type == MCPAuth.oauth2 and server.token_url and server.credentials:
        # Fetch OAuth2 token using client_id, client_secret, and token_url
        token = fetch_oauth2_token(server.token_url, server.credentials['client_id'], server.credentials['client_secret'])
        # Use the fetched token to perform the health check
        should_skip_health_check = False
    else:
        should_skip_health_check = True
  • Add a new function fetch_oauth2_token() to handle token fetching:
def fetch_oauth2_token(token_url, client_id, client_secret):
    # Implement token fetching logic using client_id, client_secret, and token_url
    # Return the fetched token
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    data = {'grant_type': 'client_credentials', 'client_id': client_id, 'client_secret': client_secret}
    response = requests.post(token_url, headers=headers, data=data)
    return response.json()['access_token']

Verification

To verify the fix, create an MCP server with OAuth2 M2M auth and check the server status using GET /v1/mcp/server/<server_id>. The status should no longer be "unknown".

Extra Tips

  • Make sure to handle token fetching errors and exceptions properly.
  • Consider adding logging to track token fetching and health check attempts.
  • Review the execute_mcp_tool function to ensure it handles token fetching correctly for OAuth2 M2M servers.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING