Repository navigation
Documentation, MCP server non-reference #8493
Description
Activity
- changed the title
[-]Documentation, MCP server non-reference documentation[/-][+]Documentation, MCP server non-reference[/+]on Aug 10, 2026 New entry added (named as
MCP Servers) on navigation pane, under Development, pointing to the new doc.- added 2 commits that reference this issue
on Aug 18, 2026 Hi @TheoGkoumas
I moved the information in the PR you created into one of my PR and merged the information.
Please check and let me know.
Draft site link:
https://draft-openlibertyio.mqj6zf7jocq.us-south.codeengine.appdomain.cloud/docs/latest/liberty-mcp-server.htmlYou can close your PR.
Regards,
Ramkumar@ramkumar-k-9286 I have directly made changes in this PR #8500. There's a new security docs page and the main mcp server page has minor content removals and rewrites
- added a commit that references this issue
on Aug 21, 2026 Hi @TheoGkoumas @IssacAX123 @Azquelt
I moved the information in the PR you #8500 into one of my PR and merged the information.
Please check and let me know.
Draft site link:You can close your PR.
Regards,
RamkumarReacted by Karen DeenThanks for pulling in the updates, I've been held up sorting out a build issue but I will review and make comments here.
Reacted by RamkumarThe PR has some changes to the main page which aren't yet reflected in the draft.
Can you make the changes to
liberty-mcp-server.adocfrom these commits, aside from the one that I've left a comment on please? https://github.com/OpenLiberty/docs/pull/8500/changes/7af6f0f0eb0cf12a0795e1ec33bd5b43c5b08d85..8b6cc66eea8c7cfc4d809fe6293d91d9ce873f47#diff-b8f19b52f8eba5d170bd3eb4d69a3ec6a6eceacea0fe0563a76945ed96295700I'll continue reviewing, assuming those changes will be made.
I think we should improve the flow of the getting started section and separate it from the more in-depth documentation about tools.
Please make the following changes:
-
At the end of the section "Enable the feature", add this as a Note:
Themcp-1.0feature is compatible with Jakarta EE 10 and EE 11 features -
Before the section "Find your MCP endpoint URL", add a new section "Register a tool":
Tools are registered by creating a public method on a CDI bean and annotating it with
@Toolimport java.time.LocalDateTime; import org.mcpjava.server.tools.Tool; import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class McpTools { @Tool(description = "Gets the current time") public String getTime() { return LocalDateTime.now().toString(); } } -
Move the section "Test with the MCP Inspector" before "Connect an AI client"
-
In "Connect an AI client", I would suggest we separate the example from the instructive text. Start a new paragraph at "For example".
-
Add a new level 2 heading "Developing tools" before the level 3 heading "Registering tools"
After these changes, the outline should look like this:
- Getting started
- Add dependencies
- Enable the feature
- Register a tool
- Find your MCP endpoint
- Test with the MCP Inspector
- Connect an AI client
- Developing tools
- Registering tools
- Providing tool arguments
- Using structured content
- Registering encoders
- Throwing exceptions
- Handling cancellation
- Writing asynchronous tools
- Programmatically registering tools
- Stateless mode
- Configuration
- Custom endpoint path
- Server description and metadata
- Async tool timeout
- EAR deployments with multiple modules
- Supported MCP protocol versions and features
- Protocol versions
- Supported features
-
Ok, I've gone through it again and picked up some more changes:
- before the "Getting started" section, add a NOTE: the MCP protocol includes various features, but the
mcp-1.0feature only supports Tools. For more information see <> - In "Add the MCP API dependency", change "The
mcp-1.0feature uses themcp-javaAPI (org.mcpjava:mcp-server-api)" to "Themcp-1.0feature uses the org.mcpjava API" - In "Add the MCP API dependency", is it possible to also include a gradle example with a tab controls, like we do for Windows/Mac/Linux command line examples in the guides here? If so I'll provide a gradle example too.
- The text "For tool methods that return a full ToolResponse, you can also signal a business-logic error to the AI without throwing an exception:" and the following example is in the wrong place, take it out of here.
- For the section "Throwing exceptions":
- Rename the section to "Handling errors"
- Reorganise the structure under "Handling errors" to
- Error responses
- An error response indicates that the tool couldn't be called. The error response is sent back to the AI agent so that it can decide what to do next. If the error indicates that the AI agent has provided invalid arguments, this gives it the opportunity to call the tool again with different arguments.
You an send an error response by returning aToolResponse. (Include the example above here)
- An error response indicates that the tool couldn't be called. The error response is sent back to the AI agent so that it can decide what to do next. If the error indicates that the AI agent has provided invalid arguments, this gives it the opportunity to call the tool again with different arguments.
- ToolCallException
- It's also possible to return an error response by throwing
ToolCallException. In this case the tool method does not need to returnToolResponse. The message of theToolCallExceptionwill be return to the client as the error message.
(ToolCallException example here)
Other exceptions can also be automatically wrapped by aToolCallExceptionby annotating the method with@WrapBusinessException. The message of the exception will still be return directly to the client as the error message, so check carefully whether the error message makes sense to the client and that it doesn't reveal any sensitive information from the server. In many cases, it may be better to catch and handle the exception yourself and create a better error message.
(WrapBusinessException example here)
- It's also possible to return an error response by throwing
- Unhandled exceptions
- If your method throws an exception that isn't converted to a
ToolCallException, then a general "Server error" response is sent to the client and details of the exception will be logged to the server log.
- If your method throws an exception that isn't converted to a
- Error responses
- In "Handling cancellation
- I think the heading would be better as just "Cancellation"
- Change
"Callcancellation.check().isRequested()periodically and throwCancellation.OperationCancelledExceptionto stop execution cleanly"
to
"Callcancellation.skipProcessingIfCancelled()periodically which will throwCancellation.OperationCancelledExceptionif the tool call has been cancelled. It's also possible to callcancellation.check()to handle cancellation yourself." - Update the example to match:
for (String chunk : dataService.getChunks(datasetId)) { // Check for cancellation before each chunk cancellation.skipProcessingIfCancelled(); results.add(process(chunk)); }
- In "Writing asynchronous tools" I need to work out a better example, the current one isn't wrong but it doesn't make sense. I'll provide this later.
- In "Writing asynchronous tools" change the NOTE to a TIP
- In "Programmatically registering tools" I'm not sure the code is quite correct, I'm testing it and may provide a new one.
- In "Stateless mode"
- put 2025-11-25 in code tags
- the NOTE here appears to just repeat the previous line? Should we remove one or the other? Should this be a CAUTION? wdyt?
- In "Configuration" every instance of
<mcpServer>needs changed to<mcp>- we changed the name of this config element in Update feature name and config element tomcp-1.0open-liberty#35365 - In "Server description and metadata" change NOTE to TIP
- In some cases we have text that is both code and a link (for example
Cancellationin the cancellation section). These render fine on github but don't render well on docs site. Unless we can get the styling changed, please change these to be just a link without code tags.
- before the "Getting started" section, add a NOTE: the MCP protocol includes various features, but the
- added a commit that references this issue
on Aug 28, 2026 Hi @Azquelt
I have incorporated the comments from the other PR as well as the previous comments mentioned in this issue.
Draft site link:
Regards,
RamkumarI have used BOB for grammar and style checks on these pages. You may find sentences that have been rephrased. FYI
Pending Items as mentioned in comments from @Azquelt
- Gradle dependency example with tab controls
- Replacement example for "Writing asynchronous tools"
- Corrected code for "Programmatically registering tools"
I had a quick read through and spotted this:
In "Securing an MCP server" - "Controlling access per tool"
@PermitAll- All authenticated callers are permitted, regardless of role.Should be
@PermitAll- All callers are permittedAnd in the following code sample
// Any authenticated user can call this toolShould be
// Any user can call this toolI'll get the updated examples to you tomorrow morning.
New example for asynchronous tools: (The old example was from our tests. It wasn't wrong, but it didn't make sense as an example because there wasn't any need or benefit from it being asynchronous. This new example uses restfulWS async client which, in principle, saves server resources by being asynchronous.)
import java.util.concurrent.CompletionStage; import org.mcpjava.server.tools.Tool; import org.mcpjava.server.tools.ToolArg; import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.core.MediaType; @ApplicationScoped public class RemoteTools { private Client client = ClientBuilder.newClient(); @Tool public CompletionStage<String> fetchWidget(@ToolArg(name = "id", description = "widget id") String id) { validateWidgetId(id); return client.target("http://example.com/api/widgets/{id}") .resolveTemplate("id", id) .request(MediaType.APPLICATION_JSON) .rx() .get(Widget.class) .thenApply(w -> createWidgetResponse(w)); } }
New example for programmatic registration: (it's the same, except it does the CDI lifecycle correctly)
import io.openliberty.mcp.tools.ToolManager; import org.mcpjava.server.tools.ToolResponse; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; import jakarta.enterprise.event.Startup; import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; @ApplicationScoped public class WeatherToolRegistrar { @Inject ToolManager toolManager; @Inject Instance<WeatherClient> weatherClientInstance; private void registerTools(@Observes Startup startup) { if (weatherClientInstance.isResolvable()) { toolManager.newTool("getForecast") .setTitle("Weather Forecast Provider") .setDescription("Get weather forecast for a location") .addArgument("latitude", "Latitude of the location", true, Double.class) .addArgument("longitude", "Longitude of the location", true, Double.class) .setHandler(args -> { WeatherClient weatherClient = weatherClientInstance.get(); try { Double lat = (Double) args.args().get("latitude"); Double lon = (Double) args.args().get("longitude"); String result = weatherClient.getForecast(lat, lon, 4, "temperature_2m,snowfall,rain,precipitation,precipitation_probability"); return ToolResponse.ofText(result); } finally { weatherClientInstance.destroy(weatherClient); } }) .register(); } } }
-
Change
Add the following dependency to your
pom.xml:to
Add the following dependency to your
pom.xmlorbuild.gradle: -
Add this gradle example for MCP Server API:
providedCompile 'org.mcpjava:mcp-server-api:1.0.0'Add this gradle example for the Liberty MCP extensions:
providedCompile 'io.openliberty.api:io.openliberty.mcp:1.0.117'
-
- added a commit that references this issue
on Sep 2, 2026 I have incorporated the comments from the other PR as well as the previous comments mentioned in this issue.
Draft site link:
Note: I have used BOB for grammar and style checks on these pages. You may find sentences that have been rephrased. FYI
Regards,
RamkumarThe maven and gradle examples are both showing together, with a dark grey box around them, rather than in tabs.
If we can't do tabs, then I think we would be better off just having them one after another without the big grey box if possible. It stands out to an extent that isn't justified by the content, unfortunately.
Alternatively, we can revert back to just the maven example if that's easier.
Other than that formatting issue, it looks good to me, so I'll tag with
developer reviewed- added a commit that references this issue
on Sep 2, 2026 Hi @Azquelt
Suggested correction done.
Please let me know if you are fine with this.
Regards,
Ramkumar@ramkumar-k-9286 Looks good, thanks
Published [26.0.0.9 release].
Feature epic details
Operating systems
Does the documentation apply to all operating systems?
Summary
Provide the ability for Open Liberty to act as an MCP Server, giving developers the ability to define Tools, Resources, Prompts for use by AI Apps.
Model Context Protocol (MCP) is an open standard that enables AI applications to interact with and utilise external systems. The
mcp-1.0feature for Open Liberty allows developers to expose the business logic of their applications, making it discoverable, understandable, and invocable by AI applications.Configuration
The
mcp-1.0feature uses the https://github.com/mcp-java/java-mcp-annotations[`mcp-java` API] (org.mcpjava:mcp-server-api), which is available on Maven Central.Add the following dependency to your
pom.xml:Some features - such as
@Schema,DefaultValueConverter,ToolManager, andToolResponseEncoder- are provided by theio.openliberty.mcpjar that ships with Liberty. To make these available on the build path, you need to add asystem-scoped dependency in yourpom.xmlthat points to this jar.First, locate the
io.openliberty.mcp_*.jarin<wlp>/dev/api/ibm/and note the version suffix (e.g.1.0.106). Then define the following properties in yourpom.xml:Then add the dependency:
=== Enable the feature
Add
mcp-1.0to yourserver.xml:Updates to existing topics
It should not update any existing topics.
Create a new topic
This documentation should act as a concise tutorial for the MCP feature.
We should discuss with the docs team to identify what documentation is expected for liberty features.
As a starting point, we should have a step-by-step guide to getting started and registering a tool, which we can then build on to explain more advanced features.
In principle, the list of actions/functionalities that need to be cover is the following:
Each entry should also note whether there are any restrictions (e.g. cancellation does not work in stateless mode, structured content only works for clients which support version
2025-06-18or later)