|
Important
|
Experimental
This feature is currently experimental. |
When you run a Quarkus application in dev mode, you can expose a Model Context Protocol (MCP) server. It presents the methods used by the DevUI MCP tools (methods you can call) and the data exposed by MCP resources.
The recommended way to connect an AI coding agent to your Quarkus application is the Quarkus Agent MCP server. It manages the application lifecycle, proxies Dev MCP tools, provides documentation search, and delivers extension-specific coding skills.
The Quarkus Agent MCP server requires JBang. Make sure JBang is installed before configuring your agent:
jbang versionIf JBang is not installed, you can install it with curl -Ls https://sh.jbang.dev | bash or sdk install jbang.
Most coding agents use stdio transport — for example, with Claude Code:
claude mcp add quarkus-agent -- jbang quarkus-agent-mcp@quarkusioOpen the Dev UI settings dialog and select the Dev MCP tab to see configuration snippets for all supported agents and IDEs (Claude Code, Cursor, VS Code, Claude Desktop, Cline, Goose, Windsurf, Zed, and JetBrains IDEs).
Alternatively to connecting through the Quarkus Agent, you can connect an MCP client directly to the Dev MCP endpoint on the running application.
Open the Dev UI settings dialog, select the Dev MCP tab, and enable Dev MCP.
The connection details (default http://localhost:8080/q/dev-mcp) and per-agent configuration snippets are available under the Direct connection section.
Any MCP client that supports the Streamable Protocol, version 2025‑03‑26 can connect using that URL. After a client connects, it will appear on the tab.
Extensions can contribute additional tools and resources to the Dev MCP server. The integration is similar to contributing to the Dev UI, but descriptions are mandatory. A single JSON‑RPC service can be used for both Dev UI and Dev MCP; methods without a description only show up in Dev UI, while methods with a description appear in both.
Extensions can ship a quarkus-skill.md file to provide AI coding agents with extension-specific coding guidelines, testing patterns, and common pitfalls. During the Quarkus build, all skill files are automatically discovered, composed with extension metadata (name, description, guide URL), and aggregated into a single io.quarkus:quarkus-extension-skills JAR following the Agent Skills specification. This JAR is published to Maven Central with each Quarkus release and is compatible with SkillsJars.
Place a quarkus-skill.md file in your extension’s deployment module at:
my-extension/deployment/src/main/resources/META-INF/quarkus-skill.mdThat’s it. No pom.xml changes are needed. The Quarkus build automatically discovers all quarkus-skill.md files across all extensions and aggregates them into the quarkus-extension-skills artifact.
If your extension’s runtime module has a description field in META-INF/quarkus-extension.yaml, it will be included in the composed skill’s YAML frontmatter to help AI agents discover and understand your extension. While optional, providing a description is recommended:
name: "My Extension"
description: "A concise description of what this extension does"
artifact: ${project.groupId}:${project.artifactId}:${project.version}
metadata:
guide: "https://quarkus.io/guides/my-extension"The file should contain concise, actionable Markdown content. Focus on what an AI agent needs to know to use your extension correctly:
-
Key patterns — how to use the main APIs, annotations, and CDI beans.
-
Testing — how to write tests using
@QuarkusTest, Dev Services, and extension-specific test utilities. -
Common pitfalls — mistakes that agents (and developers) frequently make.
Example for a hypothetical extension:
### Data Access
- Inject `MyClient` with `@Inject` — it is an `@ApplicationScoped` CDI bean.
- Use `client.query("...")` for read operations.
- Always wrap write operations in `@Transactional`.
### Testing
- Use `@QuarkusTest` — Dev Services starts a backing service automatically.
- Inject `MyClient` in tests for direct assertions.
### Common Pitfalls
- Do NOT create `MyClient` manually with `new` — always let CDI inject it.
- Do NOT set the connection URL without a `%prod.` profile prefix — this disables Dev Services.The skill file content is not shipped as-is. During the Quarkus build, the aggregate-skills goal scans the source tree for all quarkus-skill.md files and composes each one with extension metadata to produce a SKILL.md file at META-INF/skills/{extension-name}/SKILL.md inside the aggregated JAR. The composed document follows the Agent Skills specification and includes:
-
YAML frontmatter — the skill name, extension description from
quarkus-extension.yaml, license, and guide URL as structured metadata for agent discovery. -
Skill body — the patterns, testing guidelines, and pitfalls authored by the extension developer.
-
Dev MCP tools — the skill is automatically enriched with an "Available Dev MCP Tools" section listing each MCP tool the extension enables by default, including tool names, descriptions, and parameters. Tools are discovered from runtime methods annotated with both
@JsonRpcDescriptionand@DevMCPEnableByDefault, and from deployment processor classes annotated with@DevMcpBuildTimeTool.
Example of a composed SKILL.md:
---
name: quarkus-my-extension
description: "A brief description of the extension from quarkus-extension.yaml"
license: Apache-2.0
metadata:
guide: https://quarkus.io/guides/my-extension
---
### Data Access
...
### Available Dev MCP Tools
| Tool | Description | Parameters |
|------|-------------|------------|
| `quarkus-my-extension_getData` | Get current status | — |
| `quarkus-my-extension_updateValue` | Update a value | `name` (required): The name, `value` (required): The new value |The Dev MCP tools section is appended during the Quarkus build by the aggregate-skills Maven goal. Only tools that are enabled by default are included. All modules are scanned via Jandex on compiled classes. The enriched skills are baked into the quarkus-extension-skills JAR published with each Quarkus release.
For runtime methods, add both @JsonRpcDescription and @DevMCPEnableByDefault annotations on the method (see MCP Tools against the Runtime classpath).
For deployment build-time actions, annotate the processor class with @DevMcpBuildTimeTool:
@DevMcpBuildTimeTool(name = "updateProperty", // (1)
description = "Update a configuration property", // (2)
params = {
@DevMcpParam(name = "name", description = "The property name"), // (3)
@DevMcpParam(name = "value", description = "The new value")
})
public class ConfigurationProcessor {
// ...
}-
The tool name, matching the
methodNamein the builder chain. -
A human-readable description of what this tool does.
-
Parameter descriptions. Use
required = falsefor optional parameters.
The annotation is repeatable — add one per tool on the same class. This is the deployment-classpath counterpart of @JsonRpcDescription + @DevMCPEnableByDefault used on runtime methods.
-
Extension description or guide links — these are automatically added from
quarkus-extension.yaml. -
Configuration properties — reference the guide instead. A link is auto-generated.
-
Obvious instructions — focus on Quarkus-specific patterns and gotchas, not generic advice.
A tool corresponds to a method that a client can call. Any JSON‑RPC method can be exposed as a tool by supplying descriptions on the method and its parameters. Tools can run on either the runtime or deployment classpath.
To expose runtime information or actions (for example, changing log levels), define a JSON‑RPC service in your runtime or runtime‑dev module and annotate the methods and parameters with @JsonRpcDescription:
public class MyExtensionRPCService {
@JsonRpcDescription("Update a specific logger's level in this Quarkus application") // (1)
public JsonObject updateLogLevel(
@JsonRpcDescription("The logger name as defined in the logging implementation") String loggerName,
@JsonRpcDescription("The new log level") String levelValue) { // (2)
// implementation…
}
}-
Description of the method.
-
Description of each parameter.
By default this tool will be disabled, and the user has to enable it in Dev UI. You can change this default by adding the @DevMCPEnableByDefault annotation on the method.
You must register the JSON‑RPC service in the deployment module:
@BuildStep
JsonRPCProvidersBuildItem registerRpcService() { // (1)
return new JsonRPCProvidersBuildItem(MyExtensionRPCService.class); // (2)
}-
Produce a
JsonRPCProvidersBuildItem. -
Specify the class in your runtime or runtime‑dev module that contains the methods.
@JsonRpcDescription is mandatory for Dev MCP; without it the method is only available in the Dev UI.
The method can return primitives, String, JsonObject, JsonArray, or any POJO that can be serialised to JSON.
Asynchronous methods (Uni, CompletionStage or methods annotated with @NonBlocking) are also supported.
Sometimes you need to run actions on the deployment classpath (for example, writing configuration files). In that case you do not create a JSON‑RPC service; instead you provide a supplier via a BuildTimeActionBuildItem:
@BuildStep(onlyIf = IsLocalDevelopment.class)
BuildTimeActionBuildItem createBuildTimeActions() {
BuildTimeActionBuildItem actions = new BuildTimeActionBuildItem();
actions.actionBuilder()
.methodName("updateProperty")
.description("Update a configuration/property in the Quarkus application") // (1)
.parameter("name", "The name of the configuration/property to update") // (2)
.parameter("value", "The new value for the configuration/property")
.function(map -> {
Map<String, String> values = Collections.singletonMap(
map.get("name"), map.get("value"));
updateConfig(values);
return true;
})
.build();
return actions;
}-
Description of the method.
-
Description of each parameter.
The code in the function runs on the deployment classpath. The function can return a plain value, a CompletionStage or CompletableFuture for asynchronous work.
By default this tool will be disabled, and the user has to enable it in Dev UI. You can change this default by adding .enableMcpFunctionByDefault() in the builder method.
A resource is data exposed by your extension. There are two ways to create a resource.
Build‑time data that is already exposed to the Dev UI can also be made available to Dev MCP. Provide a description when calling addBuildTimeData():
footerPageBuildItem.addBuildTimeData(
"jokes",
jokesBuildItem.getJokes(),
"Some funny jokes that the user might enjoy"
);The extra description argument is new: without it the data only appears in the Dev UI. Once supplied, the jokes data becomes an MCP resource, however, by default this resource will be disabled. You can change the default by passing in true as another parameter after description, that will change this default to be enabled. Users can change this in Dev UI anyway, so this is just a sensible default.
footerPageBuildItem.addBuildTimeData(
"jokes",
jokesBuildItem.getJokes(),
"Some funny jokes that the user might enjoy",
true
);To expose recorded values (data produced at runtime by a recorder) as an MCP resource, define a build‑time action in the deployment module. The action must include a description:
@BuildStep(onlyIf = IsLocalDevelopment.class)
BuildTimeActionBuildItem createBuildTimeActions() {
BuildTimeActionBuildItem item = new BuildTimeActionBuildItem(); //(1)
item.actionBuilder() //(2)
.methodName("getMyRecordedValue")
.description("A well‑thought‑out description") //(3)
.runtime(runtimeValue) //(4)
.build();
return item;
}-
Return or produce a
BuildTimeActionBuildItem. -
Use the builder to configure the action.
-
Set a human‑readable description.
-
Provide the runtime value returned by your recorder.
By default this resource will be disabled, and the user has to enable it in Dev UI. You can change this default by adding .enableMcpFunctionByDefault() in the builder method.
