{"record":{"id":"aa89541f1f399fb6","repo":"apache/shenyu","slug":"openapi-document-is-missing-the-top-level-servers-field","errorCode":null,"errorMessage":"OpenAPI document is missing the top-level 'servers' field, which is required for MCP import. Please add a servers section, e.g.: servers: [{ url: 'http://localhost:8080' }]","messagePattern":"OpenAPI document is missing the top-level 'servers' field, which is required for MCP import\\. Please add a servers section, e\\.g\\.: servers: \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SwaggerImportServiceImpl.java","lineNumber":215,"sourceCode":"                shenyuMcpRequestConfig.setBodyToJson(\"false\");\n                tool.setRequestConfig(shenyuMcpRequestConfig);\n                tool.setToolName(operation.getOperationId());\n                tool.setEnable(true);\n                PathItem.HttpMethod httpMethod = opEntry.getKey();\n                tool.setMethod(httpMethod.name().toLowerCase());\n\n                toolMap.put(fullPath, tool);\n            }\n            maps.add(toolMap);\n        }\n        return result;\n    }\n\n    private MetaDataRegisterDTO buildMetaDataRegisterDTO(final OpenAPI openapi, final String selectorName,\n                                                         final ShenyuMcpTool shenyuMcpTool, final String contentPath,\n                                                         final String namespaceId) {\n        if (Objects.isNull(openapi.getServers()) || openapi.getServers().isEmpty()) {\n            throw new IllegalArgumentException(\"OpenAPI document is missing the top-level 'servers' field, which is required for MCP import. \"\n                + \"Please add a servers section, e.g.: servers: [{ url: 'http://localhost:8080' }]\");\n        }\n        String urlString = openapi.getServers().get(0).getUrl();\n        URL url;\n        try {\n            url = new URL(urlString);\n        } catch (MalformedURLException e) {\n            LOG.error(\"url error\");\n            throw new RuntimeException(e);\n        }\n        String host = url.getHost();\n        int port = url.getPort();\n        Operation operation = shenyuMcpTool.getOperation();\n        String parameterTypes = Objects.isNull(operation.getParameters())\n                ? \"\"\n                : operation.getParameters()\n                        .stream()\n                        .map(Parameter::getIn)","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/SwaggerImportServiceImpl.java#L197-L233","documentation":"buildMetaDataRegisterDTO() throws IllegalArgumentException when the parsed OpenAPI document has no top-level 'servers' array (or it is empty). The servers field supplies the base URL used to build MCP tool metadata; without it the gateway cannot construct the upstream target. The message includes an example servers section to guide the user.","triggerScenarios":"Importing an MCP config whose swagger/OpenAPI JSON lacks `servers: [{url: ...}]` at the document root — the code checks openapi.getServers() for null/empty before reading servers.get(0).getUrl().","commonSituations":"OpenAPI documents generated for documentation only (no server info); swagger files copied from specs where servers were stripped; specs using relative server URLs or relying on host/basePath from Swagger 2.0 instead of OpenAPI 3.0 servers.","solutions":["Add a top-level servers array to the OpenAPI document, e.g. servers: [{url: 'http://localhost:8080'}], with the real backend address.","Regenerate/export the spec from the source tool with server information included.","If migrating from Swagger 2.0, convert host/basePath into an OpenAPI 3.0 servers entry."],"exampleFix":"// before (openapi.json)\n{\n  \"openapi\": \"3.0.1\",\n  \"info\": { \"title\": \"api\", \"version\": \"1.0\" }\n}\n// after\n{\n  \"openapi\": \"3.0.1\",\n  \"info\": { \"title\": \"api\", \"version\": \"1.0\" },\n  \"servers\": [{ \"url\": \"http://localhost:8080\" }]\n}","handlingStrategy":"validation","validationCode":"JsonElement root = JsonParser.parseString(swaggerJson).getAsJsonObject();\nif (!root.has(\"servers\") || !root.getAsJsonArray(\"servers\").iterator().hasNext()) {\n    throw new IllegalArgumentException(\"openapi doc needs servers: [{url: ...}] before MCP import\");\n}","typeGuard":"boolean hasServers(OpenAPI api) {\n    return api != null && api.getServers() != null && !api.getServers().isEmpty()\n        && api.getServers().get(0).getUrl() != null && !api.getServers().get(0).getUrl().isBlank();\n}","tryCatchPattern":"try {\n    service.importMcpConfig(request);\n} catch (IllegalArgumentException e) {\n    return ResponseEntity.badRequest().body(\"Fix your OpenAPI doc: \" + e.getMessage());\n}","preventionTips":["Always include a servers array when exporting OpenAPI specs used for MCP import.","Lint specs in CI to require non-empty servers when targeting MCP registration.","Convert Swagger 2.0 host/basePath to OpenAPI 3.0 servers when migrating specs.","Use absolute URLs in servers rather than relative paths."],"tags":["openapi","validation","mcp","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}