{"record":{"id":"1186411d467c30e8","repo":"microsoft/aspire","slug":"a-discovered-toolbox-tool-did-not-have-a-name","errorCode":null,"errorMessage":"A discovered Toolbox tool did not have a name.","messagePattern":"A discovered Toolbox tool did not have a name\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReadinessProbe.cs","lineNumber":84,"sourceCode":"                {\n                    var response = await SendRequestAsync(\n                        endpoint,\n                        accessToken,\n                        initialize.SessionId,\n                        negotiatedProtocol,\n                        CreateToolsListPayload(requestId++, cursor),\n                        discoveryCancellation.Token,\n                        retryInternalServerError: true).ConfigureAwait(false);\n                    if (response.IsRetryableFailure)\n                    {\n                        retryDiscovery = true;\n                        break;\n                    }\n\n                    foreach (var tool in response.Result.GetProperty(\"tools\").EnumerateArray())\n                    {\n                        discoveredToolNames.Add(tool.GetProperty(\"name\").GetString()\n                            ?? throw new InvalidOperationException(\"A discovered Toolbox tool did not have a name.\"));\n                    }\n\n                    // MCP paginates tools/list as:\n                    //   {\"result\":{\"tools\":[...],\"nextCursor\":\"opaque continuation token\"}}\n                    cursor = response.Result.TryGetProperty(\"nextCursor\", out var nextCursor)\n                        ? nextCursor.GetString()\n                        : null;\n                }\n                while (!string.IsNullOrEmpty(cursor));\n\n                var hasRequiredTools =\n                    requiredToolNames.All(discoveredToolNames.Contains) &&\n                    requiredMcpServerLabels.All(label =>\n                        discoveredToolNames.Any(name =>\n                            name.StartsWith($\"{label}.\", StringComparison.Ordinal)));\n                var hasConfiguredExpectations =\n                    requiredToolNames.Count > 0 || requiredMcpServerLabels.Count > 0;\n                if (!retryDiscovery &&","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Foundry/Toolbox/FoundryToolboxReadinessProbe.cs#L66-L102","documentation":"Thrown while enumerating the tools array from the MCP tools/list response when a tool entry's 'name' property is null. GetProperty throws KeyNotFoundException if 'name' is absent; the ??-throw fires when the property exists but holds null, so this is an internal-shape violation of the MCP response contract.","triggerScenarios":"A tool registered in the Foundry Toolbox has no name (malformed tool registration), or the server returns a tools/list entry missing/null 'name'.","commonSituations":"A custom MCP server behind the Toolbox advertises a tool without a name; a Toolbox deployment bug or schema change returns unnamed tool entries; a partial/corrupt response from an intermediate proxy.","solutions":["Inspect the MCP server backing the Toolbox and ensure every declared tool has a non-null name.","Check the raw tools/list response (capture the JSON) to identify which tool entry is malformed.","Update or fix the MCP server/tool registration, then re-run the readiness check.","If caused by a Foundry service change, upgrade the Aspire.Hosting.Foundry package to a version matching the server's MCP schema."],"exampleFix":"// before\nserver declares: { \"description\": \"search tool\" } // no name\n// after\nserver declares: { \"name\": \"search\", \"description\": \"search tool\" }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    await probe.WaitForToolsAsync(accessToken, ct);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"did not have a name\"))\n{\n    logger.LogError(ex, \"MCP server behind the Toolbox advertised an unnamed tool; fix the tool registration.\");\n    throw;\n}","preventionTips":["Validate every tool declared by your MCP server has a non-null name before publishing it.","Add a contract test that calls tools/list and asserts each entry has a name.","Keep the MCP server schema in sync with the protocol version the Toolbox expects."],"tags":["mcp","json-rpc","schema","foundry-toolbox"],"backgroundTag":"unexpected-response-shape","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}