Skip to content

feat(ws): adds ws transport client #139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Aliaksie
Copy link
Contributor

This pull request introduces the initial implementation for a WebSocket (WS) client transport in the system. It focuses on enabling communication over WebSocket for MCP client-side transport, laying the foundation for future enhancements such as adding a WebSocket server provider.

Motivation and Context

How Has This Been Tested?

This functionality has been tested in a local environment using WebSocket server containers.

Breaking Changes

NO

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

This pull request introduces the first implementation for the ws client transport. The ws server provider is planned for future implementation. Further improvements and features will be added in subsequent PRs.

let me know if i missed something and need to add or if these changes don't make sense no problem just close this pr :-)

@Aliaksie Aliaksie changed the title feat(ws): add ws transport client feat(ws): adds ws transport client Apr 10, 2025
Copy link

@edwardcapriolo edwardcapriolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nits and opinions.

.version(HttpClient.Version.HTTP_1_1)
.connectTimeout(Duration.ofSeconds(10));

private ObjectMapper objectMapper = new ObjectMapper();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of object mappers defined in lots of files. It would seem like it might be time to build a Jackson module and lock in on one that can be used across the code base.


public Mono<Void> connect(final Function<Mono<McpSchema.JSONRPCMessage>, Mono<McpSchema.JSONRPCMessage>> handler) {
if (!state.compareAndSet(TransportState.DISCONNECTED, TransportState.CONNECTING)) {
return Mono.error(new IllegalStateException("WebSocket is already connecting or connected"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better to point the actual state in the exception. I always hate error messages like "its either this or that", instead tell me what it was.

fullMessage);
handler.apply(Mono.just(msg)).subscribe();
}
catch (Exception e) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed this in #156. It would be nice to merge that and then we can stop catch Exception use a more fine grained type.

WebSocket webSocket = webSocketRef.getAndSet(null);
if (webSocket != null && state.get() == TransportState.CONNECTED) {
state.set(TransportState.CLOSED);
return Mono.fromFuture(webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "Closing")).then();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A constant here would be better possibly.

String json = objectMapper.writeValueAsString(message);
return Mono.fromFuture(ws.sendText(json, true)).then();
}
catch (Exception e) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UncheckedIOException seems nice here.

catch (Exception e) {
return Mono.error(e);
}
}).retryWhen(Retry.backoff(3, Duration.ofSeconds(3)).filter(err -> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Externalize or at least put in constants.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants