Java implementation of the Model Context Protocol (MCP) client for the LangChain4j framework, enabling integration with MCP servers for tools, resources, and prompts
The data models package provides classes representing MCP protocol entities including resources, prompts, roots, and their associated content types. These classes are primarily immutable data structures that map to the MCP protocol schema.
// Resources
McpResource resource = new McpResource("file:///path", "name", "description", "text/plain");
McpResourceTemplate template = new McpResourceTemplate("user:///{id}", "User Profile", "...", "application/json");
McpReadResourceResult result = client.readResource("file:///path");
// Resource Contents
for (McpResourceContents contents : result.contents()) {
switch (contents) {
case McpTextResourceContents text -> System.out.println(text.text());
case McpBlobResourceContents blob -> System.out.println(blob.blob());
}
}
// Prompts
McpPrompt prompt = new McpPrompt("name", "description", List.of(argument));
McpGetPromptResult promptResult = client.getPrompt("name", args);
ChatMessage chatMessage = promptResult.messages().get(0).toChatMessage();
// Roots
McpRoot root = new McpRoot("workspace", "file:///home/user/workspace");
client.setRoots(List.of(root));// Resources
import dev.langchain4j.mcp.client.McpResource;
import dev.langchain4j.mcp.client.McpResourceTemplate;
import dev.langchain4j.mcp.client.McpReadResourceResult;
import dev.langchain4j.mcp.client.McpResourceContents;
import dev.langchain4j.mcp.client.McpTextResourceContents;
import dev.langchain4j.mcp.client.McpBlobResourceContents;
// Prompts
import dev.langchain4j.mcp.client.McpPrompt;
import dev.langchain4j.mcp.client.McpPromptArgument;
import dev.langchain4j.mcp.client.McpGetPromptResult;
import dev.langchain4j.mcp.client.McpPromptMessage;
import dev.langchain4j.mcp.client.McpRole;
// Prompt Content
import dev.langchain4j.mcp.client.McpPromptContent;
import dev.langchain4j.mcp.client.McpTextContent;
import dev.langchain4j.mcp.client.McpImageContent;
import dev.langchain4j.mcp.client.McpEmbeddedResource;
// Other
import dev.langchain4j.mcp.client.McpRoot;
import dev.langchain4j.mcp.client.McpCallContext;
// LangChain4j integration
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.Content;
import dev.langchain4j.invocation.InvocationContext;Represents a static resource with a fixed URI.
record McpResource(String uri, String name, String description, String mimeType) {}Constructor Parameters:
uri (String, required, never null) - The URI identifying this resourcename (String, required, never null) - Human-readable resource namedescription (String, nullable) - Description of the resourcemimeType (String, nullable) - MIME type of the resource contentMethods: uri(), name(), description(), mimeType()
Example:
McpResource resource = new McpResource(
"file:///config.json",
"Application Configuration",
"Main application configuration file",
"application/json"
);Represents a dynamic resource template with URI pattern containing placeholders.
record McpResourceTemplate(String uriTemplate, String name, String description, String mimeType) {}Constructor Parameters:
uriTemplate (String, required, never null) - URI template with placeholders (e.g., "user:///{userId}")name (String, required, never null) - Human-readable template namedescription (String, nullable) - Description of the templatemimeType (String, nullable) - MIME type of resources from this templateMethods: uriTemplate(), name(), description(), mimeType()
Template Patterns:
user:///{userId} - Single placeholderdata:///{category}/{id} - Multiple placeholders{name} syntaxExample:
McpResourceTemplate template = new McpResourceTemplate(
"user:///{userId}/profile",
"User Profile",
"User profile by ID",
"application/json"
);
// To read: substitute placeholders
McpReadResourceResult result = client.readResource("user:///12345/profile");Result of reading a resource from an MCP server.
record McpReadResourceResult(List<McpResourceContents> contents) {}Constructor Parameters:
contents (List<McpResourceContents>, required, never null) - List of content items (may be empty)Methods: contents()
Sealed interface representing resource content. Can be either text or binary (blob).
sealed interface McpResourceContents permits McpTextResourceContents, McpBlobResourceContents {
Type type();
enum Type {
TEXT, // Text content
BLOB // Binary content (base64-encoded)
}
}Implementations:
McpTextResourceContents - Text contentMcpBlobResourceContents - Binary content (base64-encoded)Pattern Matching:
for (McpResourceContents contents : result.contents()) {
switch (contents) {
case McpTextResourceContents text ->
System.out.println("Text: " + text.text());
case McpBlobResourceContents blob ->
System.out.println("Binary data length: " + blob.blob().length());
}
}Text content for a resource.
final record McpTextResourceContents(String uri, String text, String mimeType)
implements McpResourceContents {
Type type();
}Constructor Parameters:
uri (String, required, never null) - Resource URItext (String, required, never null) - Text contentmimeType (String, nullable) - MIME typeMethods: type() (returns Type.TEXT), uri(), text(), mimeType()
Binary content for a resource, base64-encoded.
record McpBlobResourceContents(String uri, String blob, String mimeType)
implements McpResourceContents {
static McpBlobResourceContents create(String uri, String blob);
static McpBlobResourceContents create(String uri, byte[] blob);
Type type();
}Constructor Parameters:
uri (String, required, never null) - Resource URIblob (String, required, never null) - Base64-encoded binary contentmimeType (String, nullable) - MIME typeStatic Factory Methods:
Creates from already base64-encoded string.
Parameters: uri, blob (base64-encoded string)
Returns: McpBlobResourceContents
Creates from byte array, automatically base64-encodes.
Parameters: uri, blob (byte array)
Returns: McpBlobResourceContents
Example:
// From byte array (auto-encodes)
byte[] imageData = Files.readAllBytes(Path.of("image.png"));
McpBlobResourceContents blobFromBytes =
McpBlobResourceContents.create("file:///image.png", imageData);
// From base64 string
String base64Data = "SGVsbG8gV29ybGQ=";
McpBlobResourceContents blobFromString =
McpBlobResourceContents.create("file:///data.bin", base64Data);Represents a prompt template declaration. Contains metadata but not the actual rendered content.
record McpPrompt(String name, String description, List<McpPromptArgument> arguments) {}Constructor Parameters:
name (String, required, never null) - Prompt namedescription (String, nullable) - Prompt descriptionarguments (List<McpPromptArgument>, nullable) - List of prompt arguments (may be null or empty)Methods: name(), description(), arguments()
Example:
McpPrompt prompt = new McpPrompt(
"essay_prompt",
"Generates an essay prompt",
List.of(
new McpPromptArgument("topic", "Essay topic", true),
new McpPromptArgument("length", "Desired length", false)
)
);Represents an argument for a prompt template.
record McpPromptArgument(String name, String description, boolean required) {}Constructor Parameters:
name (String, required, never null) - Argument namedescription (String, nullable) - Argument descriptionrequired (boolean) - Whether this argument is requiredMethods: name(), description(), required()
Result of rendering a prompt with arguments. Contains the rendered messages.
record McpGetPromptResult(String description, List<McpPromptMessage> messages) {}Constructor Parameters:
description (String, nullable) - Prompt descriptionmessages (List<McpPromptMessage>, required, never null) - Rendered prompt messages (may be empty)Methods: description(), messages()
Represents a message in a prompt, with a role and content.
record McpPromptMessage(McpRole role, McpPromptContent content) {
ChatMessage toChatMessage();
}Constructor Parameters:
role (McpRole, required, never null) - Message role (USER or ASSISTANT)content (McpPromptContent, required, never null) - Message contentMethods: role(), content(), toChatMessage()
Converts this MCP prompt message to a LangChain4j ChatMessage.
Returns: ChatMessage (UserMessage or AiMessage)
Throws: UnsupportedOperationException - If role is ASSISTANT and content is not text
Use Case: Convert MCP prompts to LangChain4j chat format
Example:
McpGetPromptResult promptResult = client.getPrompt("essay_prompt", args);
List<ChatMessage> chatMessages = new ArrayList<>();
for (McpPromptMessage message : promptResult.messages()) {
try {
chatMessages.add(message.toChatMessage());
} catch (UnsupportedOperationException e) {
logger.warn("Cannot convert message: {}", e.getMessage());
}
}Enumeration of message roles in prompts.
enum McpRole {
ASSISTANT, // AI assistant message
USER; // User message
static McpRole fromString(String key);
}Constants:
ASSISTANT - Represents an AI assistant messageUSER - Represents a user messageMethods:
Parses a role from a string (case-insensitive).
Parameters: key (String) - Role string
Returns: McpRole or null if unknown
Sealed interface for prompt content types.
sealed interface McpPromptContent
permits McpTextContent, McpEmbeddedResource, McpImageContent {
Type type();
Content toContent();
String getType();
enum Type {
TEXT, // Text content
RESOURCE, // Embedded resource
IMAGE // Image content
}
}Implementations:
McpTextContent - Text contentMcpImageContent - Image content (base64-encoded)McpEmbeddedResource - Embedded resource contentMethods:
type() - Returns the content typetoContent() - Converts to LangChain4j ContentgetType() - Returns type as lowercase stringText content for prompts.
record McpTextContent(String text) implements McpPromptContent {
Type type();
Content toContent();
}Constructor Parameters:
text (String, required, never null) - Text contentMethods: type() (returns Type.TEXT), toContent(), text()
Image content for prompts, with base64-encoded data.
record McpImageContent(String data, String mimeType) implements McpPromptContent {
Type type();
Content toContent();
}Constructor Parameters:
data (String, required, never null) - Base64-encoded image datamimeType (String, required, never null) - Image MIME typeMethods: type() (returns Type.IMAGE), toContent(), data(), mimeType()
Embedded resource content for prompts.
record McpEmbeddedResource(McpResourceContents resource) implements McpPromptContent {
Type type();
Content toContent();
}Constructor Parameters:
resource (McpResourceContents, required, never null) - Resource contentsMethods: type() (returns Type.RESOURCE), toContent(), resource()
Limitations: toContent() only supports text resources, throws UnsupportedOperationException for binary
Represents a root directory or location made available to an MCP server.
record McpRoot(String name, String uri) {}Constructor Parameters:
name (String, required, never null) - Root name identifieruri (String, required, never null) - Root URI (typically file:// scheme)Methods: name(), uri()
Example:
List<McpRoot> roots = List.of(
new McpRoot("workspace", "file:///home/user/workspace"),
new McpRoot("documents", "file:///home/user/documents"),
new McpRoot("config", "file:///etc/myapp")
);
client.setRoots(roots);Context information for MCP operation calls, including invocation context for tracing.
record McpCallContext(InvocationContext invocationContext, McpClientMessage message) {}Constructor Parameters:
invocationContext (InvocationContext, nullable) - AI service invocation context for tracingmessage (McpClientMessage, required, never null) - The MCP protocol message being sentMethods: invocationContext(), message()
Use Cases:
// List static resources
List<McpResource> resources = client.listResources();
for (McpResource resource : resources) {
System.out.println("Resource: " + resource.name());
System.out.println(" URI: " + resource.uri());
System.out.println(" Description: " + resource.description());
System.out.println(" MIME Type: " + resource.mimeType());
}
// List resource templates
List<McpResourceTemplate> templates = client.listResourceTemplates();
for (McpResourceTemplate template : templates) {
System.out.println("Template: " + template.name());
System.out.println(" URI Pattern: " + template.uriTemplate());
}
// Read a static resource
McpReadResourceResult result = client.readResource("file:///config.json");
for (McpResourceContents contents : result.contents()) {
if (contents instanceof McpTextResourceContents text) {
System.out.println("Text: " + text.text());
System.out.println("MIME Type: " + text.mimeType());
} else if (contents instanceof McpBlobResourceContents blob) {
System.out.println("Binary data (base64): " + blob.blob());
System.out.println("MIME Type: " + blob.mimeType());
}
}
// Read using template (substitute placeholders)
McpReadResourceResult templatedResult = client.readResource("user:///12345/profile");// List available prompts
List<McpPrompt> prompts = client.listPrompts();
for (McpPrompt prompt : prompts) {
System.out.println("Prompt: " + prompt.name());
System.out.println("Description: " + prompt.description());
if (prompt.arguments() != null) {
for (McpPromptArgument arg : prompt.arguments()) {
System.out.println(" Argument: " + arg.name());
System.out.println(" Description: " + arg.description());
System.out.println(" Required: " + arg.required());
}
}
}
// Render a prompt with arguments
Map<String, Object> args = Map.of(
"topic", "artificial intelligence",
"length", "short",
"style", "formal"
);
McpGetPromptResult promptResult = client.getPrompt("essay_prompt", args);
System.out.println("Prompt description: " + promptResult.description());
for (McpPromptMessage message : promptResult.messages()) {
System.out.println("Role: " + message.role());
if (message.content() instanceof McpTextContent textContent) {
System.out.println("Content: " + textContent.text());
}
}// Convert prompt messages to chat messages
McpGetPromptResult promptResult = client.getPrompt("essay_prompt", args);
List<ChatMessage> chatMessages = new ArrayList<>();
for (McpPromptMessage message : promptResult.messages()) {
try {
ChatMessage chatMessage = message.toChatMessage();
chatMessages.add(chatMessage);
} catch (UnsupportedOperationException e) {
logger.warn("Cannot convert message: {}", e.getMessage());
}
}
// Use with LangChain4j
ChatLanguageModel model = /* ... */;
AiMessage response = model.generate(chatMessages).content();// Resource contents
for (McpResourceContents contents : result.contents()) {
switch (contents) {
case McpTextResourceContents text ->
System.out.println("Text: " + text.text());
case McpBlobResourceContents blob -> {
byte[] data = Base64.getDecoder().decode(blob.blob());
System.out.println("Binary data size: " + data.length);
}
}
}
// Prompt content
McpPromptContent content = message.content();
switch (content) {
case McpTextContent text ->
System.out.println("Text: " + text.text());
case McpImageContent image ->
System.out.println("Image: " + image.mimeType());
case McpEmbeddedResource resource ->
System.out.println("Resource: " + resource.resource());
}// From byte array (auto-encodes to base64)
byte[] imageData = Files.readAllBytes(Path.of("image.png"));
McpBlobResourceContents blobFromBytes =
McpBlobResourceContents.create("file:///image.png", imageData);
// From base64 string
String base64Data = "SGVsbG8gV29ybGQ=";
McpBlobResourceContents blobFromString =
McpBlobResourceContents.create("file:///data.bin", base64Data);
// Full constructor with MIME type
McpBlobResourceContents blobWithMime =
new McpBlobResourceContents("file:///image.png", base64Data, "image/png");
// Decode base64 to byte array
byte[] decoded = Base64.getDecoder().decode(blobWithMime.blob());McpGetPromptResult complexPrompt = client.getPrompt("multi_modal_prompt", args);
for (McpPromptMessage message : complexPrompt.messages()) {
System.out.println("Role: " + message.role());
McpPromptContent content = message.content();
switch (content.type()) {
case TEXT -> {
McpTextContent text = (McpTextContent) content;
System.out.println("Text: " + text.text());
}
case IMAGE -> {
McpImageContent image = (McpImageContent) content;
System.out.println("Image MIME: " + image.mimeType());
byte[] imageData = Base64.getDecoder().decode(image.data());
System.out.println("Image size: " + imageData.length);
}
case RESOURCE -> {
McpEmbeddedResource resource = (McpEmbeddedResource) content;
System.out.println("Embedded resource: " + resource.resource());
}
}
}McpResource: uri(), name()McpResourceTemplate: uriTemplate(), name()McpReadResourceResult: contents() (list itself, may be empty)McpTextResourceContents: uri(), text()McpBlobResourceContents: uri(), blob()McpPrompt: name()McpPromptArgument: name(), required()McpGetPromptResult: messages() (list itself)McpPromptMessage: role(), content()McpTextContent: text()McpImageContent: data(), mimeType()McpEmbeddedResource: resource()McpRoot: name(), uri()McpCallContext: message()McpResource: description(), mimeType()McpResourceTemplate: description(), mimeType()McpTextResourceContents: mimeType()McpBlobResourceContents: mimeType()McpPrompt: description(), arguments()McpPromptArgument: description()McpGetPromptResult: description()McpCallContext: invocationContext()All data model classes are immutable:
Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-mcp