Skip to content

Commit 810a242

Browse files
committed
Fix nested path URI resolution
1 parent c09ee67 commit 810a242

2 files changed

Lines changed: 38 additions & 4 deletions

File tree

mcp-core/src/main/java/io/modelcontextprotocol/util/Utils.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package io.modelcontextprotocol.util;
66

77
import java.net.URI;
8+
import java.net.URISyntaxException;
89
import java.util.Collection;
910
import java.util.Map;
1011

@@ -76,9 +77,40 @@ public static URI resolveUri(URI baseUrl, String endpointUrl) {
7677
if (endpointUri.isAbsolute() && !isUnderBaseUri(baseUrl, endpointUri)) {
7778
throw new IllegalArgumentException("Absolute endpoint URL does not match the base URL.");
7879
}
79-
else {
80-
return baseUrl.resolve(endpointUri);
80+
else if (endpointUri.isAbsolute()) {
81+
return endpointUri;
8182
}
83+
84+
return baseUrlWithTrailingSlash(baseUrl).resolve(removeLeadingSlash(endpointUrl));
85+
}
86+
87+
private static URI baseUrlWithTrailingSlash(URI baseUrl) {
88+
String path = baseUrl.getPath();
89+
if (path == null || path.isEmpty()) {
90+
return createUriWithPath(baseUrl, "/");
91+
}
92+
if (path.endsWith("/")) {
93+
return baseUrl;
94+
}
95+
return createUriWithPath(baseUrl, path + "/");
96+
}
97+
98+
private static URI createUriWithPath(URI baseUrl, String path) {
99+
try {
100+
return new URI(baseUrl.getScheme(), baseUrl.getAuthority(), path, baseUrl.getQuery(),
101+
baseUrl.getFragment());
102+
}
103+
catch (URISyntaxException ex) {
104+
throw new IllegalArgumentException("Invalid base URL.", ex);
105+
}
106+
}
107+
108+
private static String removeLeadingSlash(String endpointUrl) {
109+
String result = endpointUrl;
110+
while (result.startsWith("/")) {
111+
result = result.substring(1);
112+
}
113+
return result;
82114
}
83115

84116
/**

mcp-core/src/test/java/io/modelcontextprotocol/util/UtilsTests.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ void testMapIsEmpty() {
4545
@ParameterizedTest
4646
@CsvSource({
4747
// relative endpoints
48-
"http://localhost:8080/root, /api/v1, http://localhost:8080/api/v1",
48+
"http://localhost:8080/root, /api/v1, http://localhost:8080/root/api/v1",
49+
"http://localhost:8080/root, api/v1, http://localhost:8080/root/api/v1",
4950
"http://localhost:8080/root/, api, http://localhost:8080/root/api",
5051
"http://localhost:8080, /api, http://localhost:8080/api",
52+
"http://localhost:8080/root, /api/v1?key=value, http://localhost:8080/root/api/v1?key=value",
5153
// absolute endpoints matching base
5254
"http://localhost:8080/root, http://localhost:8080/root/api/v1, http://localhost:8080/root/api/v1",
5355
"http://localhost:8080/root, http://localhost:8080/root, http://localhost:8080/root" })
@@ -66,4 +68,4 @@ void testAbsoluteUriNotMatchingBase(String baseUrl, String endpoint) {
6668
.hasMessageContaining("does not match the base URL");
6769
}
6870

69-
}
71+
}

0 commit comments

Comments
 (0)