@@ -28,10 +28,18 @@ jest.mock("@modelcontextprotocol/sdk/client/index.js", () => ({
2828} ) ) ;
2929
3030jest . mock ( "@modelcontextprotocol/sdk/client/sse.js" , ( ) => ( {
31- SSEClientTransport : jest . fn ( ) ,
31+ SSEClientTransport : jest . fn ( ( url ) => ( {
32+ toString : ( ) => url ,
33+ } ) ) ,
3234 SseError : jest . fn ( ) ,
3335} ) ) ;
3436
37+ jest . mock ( "@modelcontextprotocol/sdk/client/streamableHttp.js" , ( ) => ( {
38+ StreamableHTTPClientTransport : jest . fn ( ( url ) => ( {
39+ toString : ( ) => url ,
40+ } ) ) ,
41+ } ) ) ;
42+
3543jest . mock ( "@modelcontextprotocol/sdk/client/auth.js" , ( ) => ( {
3644 auth : jest . fn ( ) . mockResolvedValue ( "AUTHORIZED" ) ,
3745} ) ) ;
@@ -163,4 +171,92 @@ describe("useConnection", () => {
163171 result . current . makeRequest ( mockRequest , mockSchema ) ,
164172 ) . rejects . toThrow ( "MCP client not connected" ) ;
165173 } ) ;
174+
175+ describe ( "URL Port Handling" , ( ) => {
176+ const SSEClientTransport = jest . requireMock (
177+ "@modelcontextprotocol/sdk/client/sse.js" ,
178+ ) . SSEClientTransport ;
179+ const StreamableHTTPClientTransport = jest . requireMock (
180+ "@modelcontextprotocol/sdk/client/streamableHttp.js" ,
181+ ) . StreamableHTTPClientTransport ;
182+
183+ beforeEach ( ( ) => {
184+ jest . clearAllMocks ( ) ;
185+ } ) ;
186+
187+ test ( "preserves HTTPS port number when connecting" , async ( ) => {
188+ const props = {
189+ ...defaultProps ,
190+ sseUrl : "https://example.com:8443/api" ,
191+ transportType : "sse" as const ,
192+ } ;
193+
194+ const { result } = renderHook ( ( ) => useConnection ( props ) ) ;
195+
196+ await act ( async ( ) => {
197+ await result . current . connect ( ) ;
198+ } ) ;
199+
200+ const call = SSEClientTransport . mock . calls [ 0 ] [ 0 ] ;
201+ expect ( call . toString ( ) ) . toContain (
202+ "url=https%3A%2F%2Fexample.com%3A8443%2Fapi" ,
203+ ) ;
204+ } ) ;
205+
206+ test ( "preserves HTTP port number when connecting" , async ( ) => {
207+ const props = {
208+ ...defaultProps ,
209+ sseUrl : "http://localhost:3000/api" ,
210+ transportType : "sse" as const ,
211+ } ;
212+
213+ const { result } = renderHook ( ( ) => useConnection ( props ) ) ;
214+
215+ await act ( async ( ) => {
216+ await result . current . connect ( ) ;
217+ } ) ;
218+
219+ const call = SSEClientTransport . mock . calls [ 0 ] [ 0 ] ;
220+ expect ( call . toString ( ) ) . toContain (
221+ "url=http%3A%2F%2Flocalhost%3A3000%2Fapi" ,
222+ ) ;
223+ } ) ;
224+
225+ test ( "uses default port for HTTPS when not specified" , async ( ) => {
226+ const props = {
227+ ...defaultProps ,
228+ sseUrl : "https://example.com/api" ,
229+ transportType : "sse" as const ,
230+ } ;
231+
232+ const { result } = renderHook ( ( ) => useConnection ( props ) ) ;
233+
234+ await act ( async ( ) => {
235+ await result . current . connect ( ) ;
236+ } ) ;
237+
238+ const call = SSEClientTransport . mock . calls [ 0 ] [ 0 ] ;
239+ expect ( call . toString ( ) ) . toContain ( "url=https%3A%2F%2Fexample.com%2Fapi" ) ;
240+ expect ( call . toString ( ) ) . not . toContain ( "%3A443" ) ;
241+ } ) ;
242+
243+ test ( "preserves port number in streamable-http transport" , async ( ) => {
244+ const props = {
245+ ...defaultProps ,
246+ sseUrl : "https://example.com:8443/api" ,
247+ transportType : "streamable-http" as const ,
248+ } ;
249+
250+ const { result } = renderHook ( ( ) => useConnection ( props ) ) ;
251+
252+ await act ( async ( ) => {
253+ await result . current . connect ( ) ;
254+ } ) ;
255+
256+ const call = StreamableHTTPClientTransport . mock . calls [ 0 ] [ 0 ] ;
257+ expect ( call . toString ( ) ) . toContain (
258+ "url=https%3A%2F%2Fexample.com%3A8443%2Fapi" ,
259+ ) ;
260+ } ) ;
261+ } ) ;
166262} ) ;
0 commit comments