-
Notifications
You must be signed in to change notification settings - Fork 346
Add MCP probe to comprehensive health endpoint #3685
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5ee6e73
e21f4f0
340f6f0
e8495b0
751990d
417bc49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -136,6 +136,82 @@ | |
| } | ||
| } | ||
|
|
||
| // Executes the MCP query by sending an initialize JSON-RPC POST request to the MCP endpoint. | ||
| public async Task<string?> ExecuteMcpQueryAsync(string mcpUriSuffix, string incomingRoleHeader, string incomingRoleToken) | ||
| { | ||
| string? errorMessage = null; | ||
| try | ||
| { | ||
| if (string.IsNullOrWhiteSpace(mcpUriSuffix)) | ||
| { | ||
| const string msg = "MCP path is not configured."; | ||
| _logger.LogError(msg); | ||
| return msg; | ||
| } | ||
|
|
||
| if (_httpClient.BaseAddress is null) | ||
| { | ||
| const string msg = "Health check HTTP client BaseAddress is not configured."; | ||
| _logger.LogError(msg); | ||
| return msg; | ||
| } | ||
|
|
||
| // Ensure the configured MCP path cannot override the host (e.g. absolute URIs). | ||
| if (!Uri.TryCreate(mcpUriSuffix, UriKind.Relative, out _)) | ||
| { | ||
| _logger.LogError("Blocked outbound request due to invalid or unsafe URI."); | ||
| return "Blocked outbound request due to invalid or unsafe URI."; | ||
| } | ||
|
|
||
| Uri requestUri = new(_httpClient.BaseAddress, mcpUriSuffix); | ||
|
|
||
| if (!Program.CheckSanityOfUrl(requestUri.AbsoluteUri)) | ||
| { | ||
| _logger.LogError("Blocked outbound request due to invalid or unsafe URI."); | ||
| return "Blocked outbound request due to invalid or unsafe URI."; | ||
| } | ||
|
|
||
| string jsonPayload = Utilities.CreateHttpMcpQuery(); | ||
| HttpContent content = new StringContent(jsonPayload, Encoding.UTF8, Utilities.JSON_CONTENT_TYPE); | ||
|
|
||
| HttpRequestMessage message = new(method: HttpMethod.Post, requestUri: requestUri) | ||
| { | ||
| Content = content | ||
| } | ||
|
Check failure on line 180 in src/Service/HealthCheck/HttpUtilities.cs
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: think this is missing a semi-colon on the object initializer here. |
||
|
|
||
| // The MCP Streamable HTTP transport requires the client to accept both | ||
| // JSON and SSE responses. | ||
| message.Headers.Add("Accept", "application/json, text/event-stream"); | ||
|
|
||
| if (!string.IsNullOrEmpty(incomingRoleToken)) | ||
| { | ||
| message.Headers.Add(AuthenticationOptions.CLIENT_PRINCIPAL_HEADER, incomingRoleToken); | ||
| } | ||
|
|
||
| if (!string.IsNullOrEmpty(incomingRoleHeader)) | ||
| { | ||
| message.Headers.Add(AuthorizationResolver.CLIENT_ROLE_HEADER, incomingRoleHeader); | ||
| } | ||
|
|
||
| HttpResponseMessage response = await _httpClient.SendAsync(message); | ||
| if (response.IsSuccessStatusCode) | ||
| { | ||
| _logger.LogTrace($"The MCP HealthEndpoint query executed successfully with code {response.StatusCode}."); | ||
| } | ||
| else | ||
| { | ||
| errorMessage = $"The MCP HealthEndpoint query failed with code: {response.StatusCode}."; | ||
| } | ||
|
|
||
| return errorMessage; | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| _logger.LogError($"An exception occurred while executing the health check MCP query: {ex.Message}"); | ||
| return ex.Message; | ||
| } | ||
| } | ||
|
|
||
| // Executes the GraphQL query by sending a POST request to the API. | ||
| // Internally calls the metadata provider to fetch the column names to create the graphql payload. | ||
| public async Task<string?> ExecuteGraphQLQueryAsync(string graphqlUriSuffix, string entityName, Entity entity, string incomingRoleHeader, string incomingRoleToken) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -72,6 +72,27 @@ public static string CreateHttpRestQuery(string entityName, int first) | |
| return $"/{entityName}?$first={first}"; | ||
| } | ||
|
|
||
| public static string CreateHttpMcpQuery() | ||
| { | ||
| // Create a minimal MCP request (initialize) as a valid JSON-RPC request. | ||
| // 'initialize' is used because other methods (e.g. 'tools/list') require an active | ||
| // session in the MCP Streamable HTTP transport. | ||
| var payload = new | ||
| { | ||
| jsonrpc = "2.0", | ||
| id = 1, | ||
| method = "initialize", | ||
| @params = new | ||
| { | ||
| protocolVersion = "2025-03-26", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SHould the protocolVersion be hardcoded here or can we source this from somewhere? |
||
| capabilities = new { }, | ||
| clientInfo = new { name = "dab-health-check", version = "1.0.0" } | ||
| } | ||
| }; | ||
|
|
||
| return JsonSerializer.Serialize(payload); | ||
| } | ||
|
|
||
| public static string NormalizeConnectionString(string connectionString, DatabaseType dbType, ILogger? logger = null) | ||
| { | ||
| try | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.