https://code.visualstudio.com/docs/copilot/chat/mcp-servers
Blog for the Eclipse Communication Framework Project (ECF)
The Model Context Protocol (MCP) is a new protocol for integrating AI/LLMs with existing software services. MCP Server Tools allow LLMs get additional context-relevant data, write/change remote data, and to take actions.
Most current MCP servers declare their tools statically. When the MCP server starts up it's available tools and any tool meta-data (such as text descriptions of the tool behavior provided in decorators or annotations) are made available to MCP clients that connect to an MCP server. The MCP client (LLM) can then call an available tool at the appropriate time, providing tool-specific input data, and the tool can take actions, get additional data, and provide those data to the client.
OSGi Remote Services/Remote Service Admin provides a open, standardized, multi-protocol, modular, extensible way to discover, dynamically export and import, and secure inter-process communication between services. Combining Remote Services with MCP Tool meta-data allows the creation of dynamic remote tools.
Remote Tools for MCP Servers
This README.md shows an example 'Arithmetic' service, with 'add' and 'multiply' tools defined and described via Java annotations to an ArithmeticTools service. The python MCP Server communicates with the Java Server (startup and after) to dynamically add to/update from its set of tools that it exposes to MCP Clients.
Here is a simple diagram showing the communication between and MCP client, the Python MCP Server, and a Java Arithmetic Service Server.
MCP Client (LLM) <- MCP -> Python MCP Server <- Arithmetic Service -> Java Server
The ArithmeticTools service is a simple example, but exposes a powerful and general capability, Arbitrary remote tool services may be declared and provided with the appropriate tool description meta-data, and then made dynamically available to any MCP servers created in Python, Java, or other languages. Both the MCP and RS/RSA are transport agnostic, allowing the service developer and service provider to use the remote-tool-appropriate-and-secure communication protocol.
syntax = "proto3"; package grpc.health.v1; option java_multiple_files = true; option java_outer_classname = "HealthProto"; option java_package = "io.grpc.health.v1.rx3"; message HealthCheckRequest { string message = 1; } message HealthCheckResponse { enum ServingStatus { UNKNOWN = 0; SERVING = 1; NOT_SERVING = 2; SERVICE_UNKNOWN = 3; // Used only by the Watch method. } ServingStatus status = 1; } service HealthCheck { // Unary method rpc Check(HealthCheckRequest) returns (HealthCheckResponse); // Server streaming method rpc WatchServer(HealthCheckRequest) returns (stream HealthCheckResponse); // Client streaming method rpc WatchClient(stream HealthCheckRequest) returns (HealthCheckResponse); // bidi streaming method rpc WatchBidi(stream HealthCheckRequest) returns (stream HealthCheckResponse); }
package io.grpc.health.v1.rx3; import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.core.Flowable; @javax.annotation.Generated( value = "by grpc-osgi-generator (REACTIVEX) - A protoc plugin for ECF's grpc remote services distribution provider at https://github.com/ECF/grpc-RemoteServiceSProvider ", comments = "Source: health.proto. ") public interface HealthCheckService { /** * <pre> * Unary method * </pre> */ default Single<io.grpc.health.v1.rx3.HealthCheckResponse> check(Single<io.grpc.health.v1.rx3.HealthCheckRequest> requests) { return null; } /** * <pre> * Server streaming method * </pre> */ default Flowable<io.grpc.health.v1.rx3.HealthCheckResponse> watchServer(Single<io.grpc.health.v1.rx3.HealthCheckRequest> requests) { return null; } /** * <pre> * Client streaming method * </pre> */ default Single<io.grpc.health.v1.rx3.HealthCheckResponse> watchClient(Flowable<io.grpc.health.v1.rx3.HealthCheckRequest> requests) { return null;
}
/** * <pre> * bidi streaming method * </pre> */ default Flowable<io.grpc.health.v1.rx3.HealthCheckResponse> watchBidi(Flowable<io.grpc.health.v1.rx3.HealthCheckRequest> requests) { return null; } }
Note that it uses the two ReactiveX 3 classes: io.reactivex.rxjava3.core.Single, and io.reactivex.rxjava3.core.Flowable. These two classes provide api for event-driven/reactive sending and receiving of unary (Single) and streaming (Flowable) arguments and return values.
The ReactiveX API...particularly Flowable...makes it very easy to implement both consumers and implementers of the streaming API, while maintaining ordered delivery and non-blocking communication.
For example, this is a simple implementation of the HealthCheckService. Note how the Single and flowable methods are able to express the implementation logic through methods such as Flowable.map.
Here is a simple implementation of a consumer of the HealthCheckService.
The use of the ReactiveX API simplifies both the implementation and the consumer use of both unary and streaming services. As an added bonus: the reactive-grpc library used in the ECF Distribution provider provides *flow-control* using backpressure.
In next article I'll describe how OSGi Remote Services can be easily used to export, publish, discover, and import remote services with full support for service versioning, security, and dynamics. I'll also describe one can use tools like maven or bndtools+eclipse to generate source code (as above) from a proto3 file and easily run a generated service as an OSGi Remote Service.
gRPC is a popular framework for creating high-performance remote procedure call-based microservices.
OSGi Remote Services is a transport-agnostic specification for creating dynamic, versionable, modular, remote services.
The ECF project provides an open implementation of the OSGi Remote Services spec, and has a provider implementation based-upon gRPC. What this means is that gRPC can be used to create and run as an OSGi remote service, with all the support for service dynamics (particularly important for network-based services), versioning, and other features provided by OSGi remote services.
The architectural fit between gRPC and OSGi Remote Services is very good, since gRPC is concerned with transport-level efficiency (i.e. http/2, binary serialization format), and OSGi Remote Services are completely transport-agnostic, and focuses instead upon service-level concerns (e.g. dynamics, versioning, and service discovery).
gRPC offers support for server and client-based streaming. In ECF's implementation, streaming rpcs are mapped to the reactivex api. This means that consumers and implementers of a streaming rpc can simply call methods and provide callbacks (using Flowable), and non-blocking streaming calls will be made. In addition, the use of reactivex and backpressure will result in transport-level flow control for these streaming APIs!
Another advantage of gRPC for OSGi remote services is it's polyglot nature. This means that if (for example) a gRPC remote service is run as an OSGi/Java server, clients can be easily implemented in any of the languages supported by gRPC. As well, servers written in some other language can easily created and accessed from OSGi consumers. An example of this is the ECF etcd3 discovery provider, which communicates with an etcd server (written in Go) to publish and discover OSGi remote services.
Finally, with bndtools (an Eclipse plugin for OSGi bundle development), ECF Remote Service workspace template, and it's support for generating code as part of Eclipse's incremental build, gRPC code generation can be seemlessly integrated into the Eclipse development environment so that gRPC code generation, compile, and bundle packaging can happen immediately and continuously as part of gRPC remote service development. For a video tutorial demonstrating this, please see here.
There's a new video tutorial that demonstrates using ECF Remote Services, bndtools, and Eclipse to create an OSGi Remote Service.
Bndtools has recently added the ability to run code generators as part of a bnd-based project, and with ECF's bndtools workspace template, a single proto3 file added to a project will automatically generate an entire Java remote service API and update/regenerate the API as changes are made to the proto3 file. No command-line execution of protoc needed.
Further with ECF's project templates, the generated API can be easily implemented and exported as an OSGi Remote Service.
Please watch the video here
ECF 3.14.19 has been released.
Along with the usual bug fixes, this release includes new documentation on the use of properties for discovering and importing remote services. The docs describe the use of properties files for simplifying the import of remote services.
This capability is especially useful for Eclipse RCP clients accessing Jax-RS/REST remote services.
Patrick Paulin describes a production usage his blog posting here.