back to all blogsSee all blog posts

MCP Server updates in mcpServer-1.0 for Open Liberty 26.0.0.8-beta

image of author
Ismath Badsha on Jul 28, 2026
Post available in languages:

This beta release adds several new capabilities to mcpServer-1.0, including operational metrics for monitoring throughput and session lifecycle, configurable server identity and metadata, configurable session and async tool timeouts, support for custom Java types as default values in tool arguments, and full support for multi-WAR EAR deployments.

The Open Liberty 26.0.0.8-beta includes the following beta features (along with all GA features):

MCP Server metrics

The Model Context Protocol (MCP) is an open standard that enables AI applications to access real-time data and business logic from external sources. The Liberty MCP Server feature mcpServer-1.0 allows developers to expose their application’s tools and data for use in agentic AI workflows.

The MCP Server now exports operational metrics, making it possible to monitor operation throughput, duration, and session lifecycle using Liberty’s existing observability stack. Metrics are available via JMX (monitor-1.0) and as OpenTelemetry histograms via mpTelemetry-2.0 or mpTelemetry-2.1.

Add monitor-1.0 alongside mcpServer-1.0 in your server.xml file. Optionally add mpTelemetry-2.0 (or 2.1) to export metrics to an OpenTelemetry collector:

<featureManager>
    <feature>mcpServer-1.0</feature>
    <feature>monitor-1.0</feature>
    <feature>mpTelemetry-2.0</feature>
</featureManager>

Two metrics are exported, following the OpenTelemetry semantic conventions for MCP:

mcp.server.operation.duration (Histogram, unit: seconds)

Tracks the duration of each MCP operation. A new data point is recorded per unique combination of the following attributes:

Attribute Required Description

mcp.method.name

Yes

The MCP JSON-RPC method name, for example tools/call, initialize, tools/list

error.type

Conditional

Set when an error occurs

gen_ai.tool.name

Conditional

The name of the tool; set for tools/call operations

gen_ai.prompt.name

Optional

The prompt name, if applicable

gen_ai.operation.name

Optional

The GenAI operation name

rpc.response.status_code

Optional

The JSON-RPC response status code

jsonrpc.protocol.version

Optional

The JSON-RPC protocol version

mcp.protocol.version

Optional

The MCP protocol version, for example 2025-11-25

network.protocol.name

Optional

Network protocol name, for example http

network.protocol.version

Optional

Network protocol version, for example 1.1

network.transport

Optional

Network transport, for example tcp

mcp.resource.uri

Optional

MCP resource URI, if applicable

mcp.server.session.duration (Histogram, unit: seconds)

Tracks the duration of each MCP session (stateful mode only). A new data point is recorded per unique combination of the following attributes:

Attribute Required Description

error.type

Conditional

Set when an error occurs during the session

jsonrpc.protocol.version

Optional

The JSON-RPC protocol version

mcp.protocol.version

Optional

The MCP protocol version, for example 2025-11-25

network.protocol.name

Optional

Network protocol name, for example http

network.protocol.version

Optional

Network protocol version, for example 1.1

network.transport

Optional

Network transport, for example tcp

Both metrics are also accessible via JMX through McpOperationStatsMXBean (exposes Count, CountDetails, Duration, DurationDetails) and McpSessionStatsMXBean (exposes Count, CountDetails, Duration, DurationDetails). For more information, see the MicroProfile Telemetry documentation.

Configure MCP Server description and metadata

The MCP Server now sends a meaningful serverInfo block to clients during initialization, which MCP clients may display in their UI. Previously, this was hard-coded to a placeholder value. You can now configure the name, title, version, and description using the <info> subelement within <mcpServer>:

<application location="my-app.war">
    <mcpServer>
        <info name="my-mcp-server"
              title="My MCP Server"
              version="2.5.0"
              description="Provides tools for querying customer data." />
    </mcpServer>
</application>

If the <info> subelement is not configured, the server defaults to name="mcp-server" and version="1.0.0".

Configure MCP session timeout and async tool timeout

Two previously hard-coded timeouts are now configurable via <mcpServer> attributes:

  • sessionTimeout — how long an inactive session is kept alive (default: 600s)

  • asyncTimeout — maximum execution time for an async tool call (default: 30s)

<application location="my-app.war">
    <mcpServer sessionTimeout="20m" asyncTimeout="60s"/>
</application>

Both attributes accept Liberty’s standard duration format (for example, 30s, 10m, 1h).

Custom types for default values in MCP tool arguments

The @ToolArg(defaultValue = "…​") annotation previously only worked with String, primitives, and enums. You can now handle any custom Java type by implementing DefaultValueConverter<T> as a CDI bean. Liberty automatically discovers and calls the converter when a default value string needs to be converted to your custom type.

import io.openliberty.mcp.annotations.DefaultValueConverter;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class DateRangeConverter implements DefaultValueConverter<DateRange> {
    @Override
    public DateRange convert(String defaultValue) {
        String[] parts = defaultValue.split("/");
        return new DateRange(LocalDate.parse(parts[0]), LocalDate.parse(parts[1]));
    }
}
@Tool(description = "Generate a report for a date range")
public String generateReport(
        @ToolArg(description = "Date range (YYYY-MM-DD/YYYY-MM-DD)",
                 defaultValue = "2024-01-01/2024-12-31")
        DateRange range) {
    return "Report from " + range.start + " to " + range.end;
}

If multiple converters exist for the same type, the one with the highest @jakarta.annotation.Priority value is called. Converters without @Priority default to priority 0.

Multi-module MCP applications

Liberty now fully supports deploying MCP applications as an EAR with multiple WAR modules. Each WAR module that contains MCP tools gets its own independent MCP server endpoint:

  • Tools declared in one WAR module are only available at that module’s endpoint — they are not visible to other modules.

  • ContentEncoder and ToolResponseEncoder beans from one module are not invoked for requests to another module’s endpoint.

  • Sessions and request tracking are isolated per module.

Configure separate endpoints for each WAR module using the moduleName attribute (the WAR file name within the EAR):

<application location="my-app.ear">
    <mcpServer path="/custom-mcp" moduleName="war1"/>
    <mcpServer path="/custom-mcp-for-war-2" moduleName="war2"/>
</application>

This creates two independent MCP endpoints:

  • http://localhost:9080/war1/custom-mcp

  • http://localhost:9080/war2/custom-mcp-for-war-2

Bug fixes

Cancelling a tool call no longer logs an error

Previously, when a client cancelled a running tool call, the server incorrectly logged an ERROR for the expected OperationCancellationException. The client still receives the correct cancellation response, but the error is no longer logged.

@Priority on encoder CDI beans now resolved correctly

When sorting ContentEncoder or ToolResponseEncoder beans by @Priority, the priority was sometimes read from a CDI proxy rather than the actual bean class, causing non-deterministic ordering. The priority is now always resolved from the real bean class at CDI extension time.

Try it now

To try out these features, update your build tools to pull the Open Liberty All Beta Features package instead of the main release. The beta works with Java SE 21, Java SE 17, Java SE 11, and Java SE 8.

If you’re using Maven, you can install the All Beta Features package using:

<plugin>
    <groupId>io.openliberty.tools</groupId>
    <artifactId>liberty-maven-plugin</artifactId>
    <version>3.12.1</version>
    <configuration>
        <runtimeArtifact>
          <groupId>io.openliberty.beta</groupId>
          <artifactId>openliberty-runtime</artifactId>
          <version>26.0.0.8-beta</version>
          <type>zip</type>
        </runtimeArtifact>
    </configuration>
</plugin>

You must also add dependencies to your pom.xml file for the beta version of the APIs that are associated with the beta features that you want to try. For example, the following block adds dependencies for two example beta APIs:

<dependency>
    <groupId>org.example.spec</groupId>
    <artifactId>exampleApi</artifactId>
    <version>7.0</version>
    <type>pom</type>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>example.platform</groupId>
    <artifactId>example.example-api</artifactId>
    <version>11.0.0</version>
    <scope>provided</scope>
</dependency>

Or for Gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'io.openliberty.tools:liberty-gradle-plugin:4.0.0'
    }
}
apply plugin: 'liberty'
dependencies {
    libertyRuntime group: 'io.openliberty.beta', name: 'openliberty-runtime', version: '[26.0.0.8-beta,)'
}

Or if you’re using container images:

FROM icr.io/appcafe/open-liberty:beta

Or take a look at our Downloads page.

If you’re using IntelliJ IDEA, Visual Studio Code or Eclipse IDE, you can also take advantage of our open source Liberty developer tools to enable effective development, testing, debugging and application management all from within your IDE.

For more information on using a beta release, refer to the Installing Open Liberty beta releases documentation.

We welcome your feedback

Let us know what you think on our mailing list. If you hit a problem, post a question on StackOverflow. If you hit a bug, please raise an issue.