anthropics / anthropics/claude-ai-mcp
Cloude desktop does not allow to connect to custom MCP server with Entra ID authentication
- Ngôn ngữ chính
- Không có dữ liệu ngôn ngữ
- Star
- 471
- Fork
- 76
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
### MCP server URL
https://web.delightfulpond-17b3aecf.northeurope.azurecontainerapps.io/mcp
### Where does the issue occur?
When pressing the Connect button (Custom connector)
### Transport used
streamable-http
### Client registration type
OpenID Connect Discovery (OIDC)
### SSE only: Does your server return the expected status code for POST requests?
Not applicable (my server does not use SSE)
### When did you last reproduce this?
2026-08-04T10:37:07.4345684Z
### Browser and OS
Microsoft Edge - redirect not even reached
### Describe the issue
We are developing custom MCP server for our company internal use. This MCP server requires authentication (Microsoft work account needed).
Claude web and Claude desktop both does not allow to connect and does reach Microsoft login page.
### Issue details
```shell
Connect fails with message:
Couldn’t register with Overwatch MCP’s sign-in service. You can try again, or add an OAuth Client ID in the connector settings. If this persists, share this reference with support: “ofid_3f9b36d6acedb32d”
```
After specifying client ID, Claude thinks that MCP server is OAuth authority server instead of loooking at .well-known/oauth-protected-resource first:
https://web.delightfulpond-17b3aecf.northeurope.azurecontainerapps.io/authorize?response_type=code&client_id=93c60986-2f73-4c3d-bc3b-4f29f476db0c&redirect_uri=https%3A%2F%2Fclaude.ai%2Fapi%2Fmcp%2Fauth_callback&code_challenge=I3aIqaRiMy8yi7XO-e_BL6yutM56PdVXv5t5zJukZ5k&code_challenge_method=S256&state=Fh0Um1p2qb9PZFNlV8WJcBbYVNEF_94D_2kdOgVhETs
### Expected behavior
Claude should open Microsoft login page.
### Logs from your server
```shell
Not relevant.
```
### Additional context
GitHub Copilot connects to this MCP server without issue and lets user to authenticate.
Here is small proof of concept using device code auth.
```pwsh
. {
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
# could be derived from from .well-known/oauth-protected-resource, but it is better to specify this explicitly
$clientId = "93c60986-2f73-4c3d-bc3b-4f29f476db0c"
$serverUrl = "https://web.delightfulpond-17b3aecf.northeurope.azurecontainerapps.io/mcp"
$resourceUrl = "https://web.delightfulpond-17b3aecf.northeurope.azurecontainerapps.io/"
$resource = Invoke-RestMethod -Method Get -Uri "$resourceUrl/.well-known/oauth-protected-resource"
$authority = Invoke-RestMethod -Method Get -Uri ($resource.authorization_servers[0].TrimEnd('/') + '/.well-known/openid-configuration')
# Request device code
$deviceCode = Invoke-RestMethod `
-Method Post `
-Uri $authority.device_authorization_endpoint `
-ContentType "application/x-www-form-urlencoded" `
-Body @{
client_id = $clientId
scope = $resource.scopes_supported -join " "
}
Write-Host $deviceCode.message
# Poll until user completes authentication
do {
Start-Sleep -Seconds 5
try {
$token = Invoke-RestMethod `
-Method Post `
-Uri $authority.token_endpoint `
-ContentType "application/x-www-form-urlencoded" `
-Body @{
grant_type = "urn:ietf:params:oauth:grant-type:device_code"
client_id = $clientId
device_code = $deviceCode.device_code
}
$accessToken = $token.access_token
}
catch {
$response = $_.ErrorDetails.Message | ConvertFrom-Json
if ($response.error -notin @("authorization_pending", "slow_down")) {
throw
}
}
}
while (-not (Test-Path -LiteralPath 'Variable:accessToken'))
$accessToken
$token = $accessToken
$headers = @{
Authorization = "Bearer $token"
"Content-Type" = "application/json"
Accept = "application/json, text/event-stream"
"MCP-Protocol-Version" = "2025-03-26"
}
$body = @{
jsonrpc = "2.0"
id = 1
method = "initialize"
params = @{
protocolVersion = "2025-03-26"
capabilities = @{}
clientInfo = @{
name = "PowerShell"
version = "1.0"
}
}
} | ConvertTo-Json -Depth 10
Invoke-RestMethod `
-Method Post `
-Uri "$serverUrl/mcp" `
-Headers $headers `
-Body $body
$body = @{
jsonrpc = "2.0"
id = 2
method = "tools/list"
} | ConvertTo-Json
Invoke-RestMethod `
-Method Post `
-Uri "$serverUrl/mcp" `
-Headers $headers `
-Body $body
}
```
Here is output:
```
To sign in, use a web browser to open the page https://login.microsoft.com/device and enter the code DL695M69A to authenticate.
event: message
data: {"result":{"protocolVersion":"2025-03-26","capabilities":{"logging":{},"tools":{}},"serverInfo":{"name":"Overwatch.Web","version":"1.0.0.0"},"instructions":"Overwatch knows the softera-applic Cosmos DB account (app-licensing database):\r\ncontainer inventory, inferred field shapes/types/enum values, and curated\r\nhuman/agent-written insights \u2014 kept warm by a background watcher, so reads here\r\nare instant with no live Cosmos scan triggered by asking.\r\n\r\nThis server requires signing in with a company Microsoft work account \u2014 the caller\r\n(e.g. Claude Desktop\u0027s connector) handles that as part of connecting; no login step\r\nis needed from within a conversation.\r\n\r\nTo answer a question about this data:\r\n1. list_known_schemas / get_schema_overview to see what containers and fields\r\n exist and how they\u0027re shaped (get_path_detail for full stats on specific\r\n fields once you know which ones matter).\r\n2. list_insights (and any insights embedded in the schema calls above) for\r\n non-obvious context the schema alone won\u0027t tell you \u2014 e.g. localized\r\n enum values, data-quality quirks, fields that mean something different than\r\n their name suggests.\r\n3. To actually query the data: if the Azure MCP server is available to you,\r\n prefer its Cosmos tools \u2014 they\u0027re more capable. query_container here is the\r\n fallback for when it isn\u0027t (e.g. no Azure credentials for this caller) \u2014 it\r\n runs under Overwatch\u0027s own connection, so it works regardless of the caller\u0027s\r\n own Azure access. Either way, run get_schema_overview first so the query is\r\n shaped correctly."},"id":1,"jsonrpc":"2.0"}
event: message
data: {"result":{"tools":[{"name":"get_schema_overview","description":"Cheap index of one container\u0027s schema: every path with its value kinds and presence ratio only \u2014 no string/number/array stats, no examples, no enum dictionaries. Call this before writing any query, then use get_path_detail for just the fields that matter. Database defaults to \u0027app-licensing\u0027.","inputSchema":{"type":"object","properties":{"container":{"description":"Container name whose schema overview to fetch.","type":"string"},"database":{"description":"Cosmos DB database name. Omit to use \u0027app-licensing\u0027.","type":["string","null"],"default":null}},"required":["container"]}},{"name":"get_known_schema","description":"Get the full cached schema for one container in the \u0027app-licensing\u0027 database \u2014 every path found, its observed value kinds, presence ratio, first/last-seen timestamps, and \u2014 where applicable \u2014 string stats (GUID/date/enum detection), number stats (integer/float, sign constraint), or array stats. Also includes any recorded insights for that container. Instant, no live Cosmos scan. For a wide container (dozens of paths, big enum dictionaries) this can be large \u2014 prefer get_schema_overview first and drill in with get_path_detail.","inputSchema":{"type":"object","properties":{"container":{"description":"Container name whose cached schema to fetch.","type":"string"},"database":{"description":"Cosmos DB database name. Omit to use \u0027app-licensing\u0027.","type":["string","null"],"default":null}},"required":["container"]}},{"name":"add_insight","description":"Record a small markdown insight about this data that the inferred schema alone doesn\u0027t capture \u2014 why a field is always one value, what a cryptic enum means, a data-quality quirk, a relationship the schema can\u0027t express. Keep the body small: a paragraph or two, not a report. Tag it with every container it relates to (an insight can cover several) plus topical tags \u2014 good keywords are what make this useful, since other agents decide relevance from keywords alone before reading the body.","inputSchema":{"type":"object","properties":{"title":{"description":"Short, specific title.","type":"string"},"keywords":{"description":"Keywords for relevance filtering \u2014 lowercase, short. Include every container this relates to, e.g. [\u0022bf-companies\u0022,\u0022companies\u0022,\u0022localized-booleans\u0022].","type":"array","items":{"type":"string"}},"body":{"description":"Markdown body. Small \u2014 a paragraph or two.","type":"string"},"createdBy":{"description":"Who/what is recording this, e.g. an agent name. Defaults to \u0027agent\u0027 if omitted.","type":["string","null"],"default":null}},"required":["title","keywords","body"]}},{"name":"get_insight","description":"Get the full markdown text of one insight by id \u2014 ids come from list_insights or the \u0027insights\u0027 array embedded in get_known_schema.","inputSchema":{"type":"object","properties":{"insightId":{"description":"Insight id, from list_insights or get_known_schema.","type":"string"}},"required":["insightId"]}},{"name":"list_known_schemas","description":"START HERE for any question about Softera\u0027s Business Central licensing / Bankfeed usage data. Lists every container that has a cached schema \u2014 container name, documents processed, unique path count, insight count, and when it was last updated. This server covers the \u0027softera-applic\u0027 Azure Cosmos DB account, database \u0027app-licensing\u0027 (the default \u2014 you do not need to supply it). Reads only the cache kept warm by a background watcher; instant, no live Cosmos scan.","inputSchema":{"type":"object","properties":{"database":{"description":"Cosmos DB database name. Omit to use \u0027app-licensing\u0027, the only database in this account.","type":["string","null"],"default":null}}}},{"name":"get_path_detail","description":"Full stats \u2014 string/number/array detail, enum values, examples \u2014 for just the paths starting with pathPrefix. \u0022institutionAccounts\u0022 pulls back that field plus every institutionAccounts[].* child in one call; \u0022productId\u0022 pulls back just that one field. Use after get_schema_overview to avoid paying for detail on paths you don\u0027t need. Database defaults to \u0027app-licensing\u0027.","inputSchema":{"type":"object","properties":{"container":{"description":"Container name.","type":"string"},"pathPrefix":{"description":"Path or path prefix to match, e.g. \u0027institutionAccounts\u0027 or \u0027productId\u0027. Ordinal, case-sensitive, matches the start of the path.","type":"string"},"database":{"description":"Cosmos DB database name. Omit to use \u0027app-licensing\u0027.","type":["string","null"],"default":null}},"required":["container","pathPrefix"]}},{"name":"query_container","description":"Run a read-only Cosmos DB SQL query against the actual data in the \u0027softera-applic\u0027 account, database \u0027app-licensing\u0027 (the default \u2014 you need not supply it).\n\nIF THE AZURE MCP SERVER IS AVAILABLE TO YOU, PREFER ITS COSMOS TOOLS INSTEAD \u2014 they are more capable. This tool is the fallback for when it is not (e.g. the user has no Azure credentials, or Azure MCP returns 403 on this account\u0027s data plane): it runs under Overwatch\u0027s own connection, so it works regardless of the caller\u0027s own Azure access.\n\nBefore writing a query, call get_schema_overview for the container to learn the real field names, types and enum values, and check list_insights for data-quality traps the schema alone won\u0027t reveal (e.g. booleans stored as localized strings in 23 languages, test/demo companies mixed in with real ones, ids that are only unique per environment).\n\nCosmos SQL is SELECT-only, so there is no way to modify data here. Notable dialect limits: HAVING is unsupported, and DISTINCT combined with a nested subquery COUNT over the whole container is unreliable on this account \u2014 prefer GROUP BY \u003Ckey\u003E with ORDER BY \u003Csame key\u003E plus OFFSET/LIMIT, paginated. Results are capped (default 20, max 200). Only containers with a cached schema can be queried \u2014 see list_known_schemas.","inputSchema":{"type":"object","properties":{"container":{"description":"Container to query.","type":"string"},"sql":{"description":"Cosmos SQL query, e.g. \u0022SELECT c.id, c.name FROM c WHERE c.countryRegionCode = @country\u0022.","type":"string"},"parameters":{"description":"Optional JSON object of named parameters for @placeholders in sql, e.g. {\u0022country\u0022:\u0022GB\u0022}. Omit to inline values directly in sql instead.","type":["string","null"],"default":null},"maxItems":{"description":"Max rows to return (default 20, hard cap 200).","type":["integer","null"],"default":null},"database":{"description":"Cosmos DB database name. Omit to use \u0027app-licensing\u0027.","type":["string","null"],"default":null}},"required":["container","sql"]}},{"name":"list_insights","description":"List recorded insights \u2014 title, keywords, and last-updated time only, no body. An insight isn\u0027t scoped to one container: its keywords can name several containers plus topical tags (e.g. [\u0022bf-companies\u0022,\u0022companies\u0022,\u0022localized-booleans\u0022]). Scan the keyword lists to judge relevance before spending a call on get_insight. Omit keyword to see everything; pass one (typically a container name) to narrow it.","inputSchema":{"type":"object","properties":{"keyword":{"description":"Optional keyword to filter by \u2014 typically a container name. Omit to list every insight.","type":["string","null"],"default":null}}}}]},"id":2,"jsonrpc":"2.0"}
```
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Đánh giá
Issue này chưa được đánh giá.