4848import com .alibaba .nacos .api .PropertyKeyConst ;
4949import com .alibaba .nacos .api .ai .model .a2a .AgentCard ;
5050import com .alibaba .nacos .api .ai .model .a2a .AgentCardVersionInfo ;
51+ import com .alibaba .nacos .api .ai .model .mcp .McpEndpointInfo ;
5152import com .alibaba .nacos .api .ai .model .mcp .McpServerBasicInfo ;
5253import com .alibaba .nacos .api .ai .model .mcp .McpServerDetailInfo ;
5354import com .alibaba .nacos .api .exception .NacosException ;
6162import com .aliyun .mse20190531 .models .ListClustersResponse ;
6263import com .aliyun .mse20190531 .models .ListClustersResponseBody ;
6364import com .aliyun .teautil .models .RuntimeOptions ;
65+ import java .net .URI ;
6466import java .util .HashMap ;
6567import java .util .List ;
6668import java .util .Map ;
@@ -359,11 +361,10 @@ private MCPConfigResult buildMCPConfigResult(McpServerDetailInfo detail) {
359361 }
360362
361363 private Object buildRemoteConnectionConfig (McpServerDetailInfo detail ) {
362- List <? > backendEndpoints = detail .getBackendEndpoints ();
364+ List <McpEndpointInfo > backendEndpoints = detail .getBackendEndpoints ();
363365
364366 if (backendEndpoints != null && !backendEndpoints .isEmpty ()) {
365- Object firstEndpoint = backendEndpoints .get (0 );
366-
367+ McpEndpointInfo firstEndpoint = backendEndpoints .get (0 );
367368 Map <String , Object > connectionConfig = new HashMap <>();
368369 Map <String , Object > mcpServers = new HashMap <>();
369370 Map <String , Object > serverConfig = new HashMap <>();
@@ -386,132 +387,117 @@ private Object buildRemoteConnectionConfig(McpServerDetailInfo detail) {
386387 return basicConfig ;
387388 }
388389
389- private String extractEndpointUrl (Object endpoint ) {
390+ private String extractEndpointUrl (McpEndpointInfo endpoint ) {
390391 if (endpoint == null ) {
391392 return null ;
392393 }
393394
394- if (endpoint instanceof String ) {
395- return (String ) endpoint ;
395+ String address = endpoint .getAddress ();
396+ if (StrUtil .isBlank (address )) {
397+ return null ;
396398 }
397399
398- if (endpoint instanceof Map ) {
399- Map <?, ?> endpointMap = (Map <?, ?>) endpoint ;
400-
401- String url = getStringValue (endpointMap , "url" );
402- if (url != null ) return url ;
403-
404- String endpointUrl = getStringValue (endpointMap , "endpointUrl" );
405- if (endpointUrl != null ) return endpointUrl ;
406-
407- String host = getStringValue (endpointMap , "host" );
408- String port = getStringValue (endpointMap , "port" );
409- String path = getStringValue (endpointMap , "path" );
410-
411- if (host != null ) {
412- StringBuilder urlBuilder = new StringBuilder ();
413- String protocol = getStringValue (endpointMap , "protocol" );
414- urlBuilder .append (protocol != null ? protocol : "http" ).append ("://" );
415- urlBuilder .append (host );
416-
417- if (port != null && !port .isEmpty ()) {
418- urlBuilder .append (":" ).append (port );
419- }
400+ String protocol = StrUtil .blankToDefault (endpoint .getProtocol (), "http" );
401+ int endpointPort = endpoint .getPort () > 0 ? endpoint .getPort () : -1 ;
402+ String normalizedPath = normalizeUrlPath (endpoint .getPath ());
420403
421- if (path != null && !path .isEmpty ()) {
422- if (!path .startsWith ("/" )) {
423- urlBuilder .append ("/" );
424- }
425- urlBuilder .append (path );
404+ // If address is already a full URL, prefer it and only fill missing port/path.
405+ if (address .contains ("://" )) {
406+ try {
407+ URI uri = URI .create (address );
408+ String scheme = StrUtil .blankToDefault (uri .getScheme (), protocol );
409+ String host = uri .getHost ();
410+ int port = uri .getPort () != -1 ? uri .getPort () : endpointPort ;
411+ String path = StrUtil .isBlank (uri .getPath ()) ? normalizedPath : uri .getPath ();
412+ if (host != null ) {
413+ return new URI (scheme , null , host , port , path , null , null ).toString ();
426414 }
427-
428- return urlBuilder . toString ();
415+ } catch ( Exception ignored ) {
416+ // fall back to simple concatenation
429417 }
430- }
431-
432- if (endpoint .getClass ().getName ().contains ("McpEndpointInfo" )) {
433- return extractUrlFromMcpEndpointInfo (endpoint );
434- }
435-
436- return endpoint .toString ();
437- }
438-
439- private String getStringValue (Map <?, ?> map , String key ) {
440- Object value = map .get (key );
441- return value != null ? value .toString () : null ;
442- }
443-
444- private String extractUrlFromMcpEndpointInfo (Object endpoint ) {
445- String [] possibleFieldNames = {"url" , "endpointUrl" , "address" , "host" , "endpoint" };
446-
447- for (String fieldName : possibleFieldNames ) {
448- try {
449- java .lang .reflect .Field field = endpoint .getClass ().getDeclaredField (fieldName );
450- field .setAccessible (true );
451- Object value = field .get (endpoint );
452- if (value != null && !value .toString ().trim ().isEmpty ()) {
453- if (value .toString ().contains ("://" ) || value .toString ().contains (":" )) {
454- return value .toString ();
418+ return appendPath (address , normalizedPath );
419+ }
420+
421+ // Address might be host or host:port (IPv4/hostname). Handle simple host:port.
422+ String host = address ;
423+ int port = endpointPort ;
424+
425+ // Handle bracketed IPv6 forms like "[::1]" or "[::1]:8848".
426+ if (address .startsWith ("[" ) && address .contains ("]" )) {
427+ int endBracket = address .indexOf (']' );
428+ host = address .substring (1 , endBracket );
429+ if (port == -1 ) {
430+ String rest = address .substring (endBracket + 1 );
431+ if (rest .startsWith (":" )) {
432+ Integer parsedPort = tryParsePort (rest .substring (1 ));
433+ if (parsedPort != null ) {
434+ port = parsedPort ;
455435 }
456436 }
457- } catch (Exception e ) {
458- continue ;
459437 }
460- }
461-
462- java .lang .reflect .Field [] fields = endpoint .getClass ().getDeclaredFields ();
463-
464- String host = null ;
465- String port = null ;
466- String path = null ;
467- String protocol = null ;
468-
469- for (java .lang .reflect .Field field : fields ) {
470- try {
471- field .setAccessible (true );
472- Object value = field .get (endpoint );
473- if (value != null && !value .toString ().trim ().isEmpty ()) {
474- String fieldName = field .getName ().toLowerCase ();
475-
476- if (fieldName .contains ("host" )
477- || fieldName .contains ("ip" )
478- || fieldName .contains ("address" )) {
479- host = value .toString ();
480- } else if (fieldName .contains ("port" )) {
481- port = value .toString ();
482- } else if (fieldName .contains ("path" )
483- || fieldName .contains ("endpoint" )
484- || fieldName .contains ("uri" )) {
485- path = value .toString ();
486- } else if (fieldName .contains ("protocol" ) || fieldName .contains ("scheme" )) {
487- protocol = value .toString ();
438+ } else {
439+ int lastColon = address .lastIndexOf (':' );
440+ if (lastColon > 0 && address .indexOf (':' ) == lastColon ) {
441+ Integer parsedPort = tryParsePort (address .substring (lastColon + 1 ));
442+ if (parsedPort != null ) {
443+ host = address .substring (0 , lastColon );
444+ if (port == -1 ) {
445+ port = parsedPort ;
488446 }
489447 }
490- } catch (Exception e ) {
491- continue ;
492448 }
493449 }
494450
495- if (host != null ) {
451+ try {
452+ return new URI (protocol , null , host , port , normalizedPath , null , null ).toString ();
453+ } catch (Exception e ) {
496454 StringBuilder urlBuilder = new StringBuilder ();
497- urlBuilder .append (protocol != null ? protocol : "http" ).append ("://" );
498- urlBuilder .append (host );
499-
500- if (port != null && !port .isEmpty ()) {
455+ urlBuilder .append (protocol ).append ("://" ).append (address );
456+ if (port > 0 && !address .contains (":" )) {
501457 urlBuilder .append (":" ).append (port );
502458 }
503-
504- if (path != null && !path .isEmpty ()) {
505- if (!path .startsWith ("/" )) {
506- urlBuilder .append ("/" );
507- }
508- urlBuilder .append (path );
459+ if (normalizedPath != null ) {
460+ urlBuilder .append (normalizedPath );
509461 }
510-
511462 return urlBuilder .toString ();
512463 }
464+ }
465+
466+ private String normalizeUrlPath (String path ) {
467+ if (StrUtil .isBlank (path )) {
468+ return null ;
469+ }
470+ return path .startsWith ("/" ) ? path : "/" + path ;
471+ }
472+
473+ private Integer tryParsePort (String portStr ) {
474+ if (StrUtil .isBlank (portStr )) {
475+ return null ;
476+ }
477+ for (int i = 0 ; i < portStr .length (); i ++) {
478+ if (!Character .isDigit (portStr .charAt (i ))) {
479+ return null ;
480+ }
481+ }
482+ try {
483+ int port = Integer .parseInt (portStr );
484+ return port > 0 && port <= 65535 ? port : null ;
485+ } catch (NumberFormatException e ) {
486+ return null ;
487+ }
488+ }
513489
514- return endpoint .toString ();
490+ private String appendPath (String baseUrl , String normalizedPath ) {
491+ if (normalizedPath == null ) {
492+ return baseUrl ;
493+ }
494+ if (baseUrl .endsWith ("/" ) && normalizedPath .startsWith ("/" )) {
495+ return baseUrl + normalizedPath .substring (1 );
496+ }
497+ if (!baseUrl .endsWith ("/" ) && !normalizedPath .startsWith ("/" )) {
498+ return baseUrl + "/" + normalizedPath ;
499+ }
500+ return baseUrl + normalizedPath ;
515501 }
516502
517503 private NacosInstance findNacosInstance (String nacosId ) {
0 commit comments