Quarkus build-time deployment extension for Model Context Protocol (MCP) client integration, handling configuration processing, synthetic bean generation, and framework integration
Build-time API for Quarkus extension developers extending or integrating with the MCP deployment module.
The MCP deployment module provides build items and build processors that operate during Quarkus build phase. Extension developers can consume these build items or contribute additional functionality.
Build items communicate information between build steps in the Quarkus build pipeline.
Represents parsed contents of a Claude Desktop configuration file.
package io.quarkiverse.langchain4j.mcp.deployment;
import io.quarkus.builder.item.SimpleBuildItem;
import io.quarkiverse.langchain4j.mcp.runtime.config.LocalLaunchParams;
import java.util.Map;
/**
* Build item containing parsed MCP server configurations from Claude Desktop config file.
* Produced when quarkus.langchain4j.mcp.config-file is specified.
*/
public final class McpConfigFileContentsBuildItem extends SimpleBuildItem {
/**
* Constructs build item with parsed configuration contents.
*
* @param contents Map of server name to launch parameters
*/
public McpConfigFileContentsBuildItem(Map<String, LocalLaunchParams> contents);
/**
* Returns the parsed MCP server configurations.
* Key: Server name (used as MCP client name)
* Value: Launch parameters (command and environment)
*
* @return Map of server configurations
*/
public Map<String, LocalLaunchParams> getContents();
}Usage Example:
import io.quarkiverse.langchain4j.mcp.deployment.McpConfigFileContentsBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import java.util.Optional;
class CustomExtensionProcessor {
@BuildStep
void consumeClaudeConfig(Optional<McpConfigFileContentsBuildItem> configItem) {
if (configItem.isPresent()) {
var contents = configItem.get().getContents();
contents.forEach((serverName, params) -> {
// Access server name and launch parameters
var command = params.command();
var envVars = params.envVars();
// Custom processing logic
});
}
}
}Build processors contain @BuildStep methods that execute during the build phase.
Main build processor for the MCP extension. Located in io.quarkiverse.langchain4j.mcp.deployment package.
Note: This class is package-private and not intended for direct extension. Extensions should consume produced build items instead.
Parses Claude Desktop configuration file from classpath.
@BuildStep
void generateMcpConfigFileContents(
McpBuildTimeConfiguration mcpBuildTimeConfiguration,
BuildProducer<McpConfigFileContentsBuildItem> producer
);Behavior:
mcpBuildTimeConfiguration.configFile()mcpServers sectionLocalLaunchParams for each server entryMcpConfigFileContentsBuildItem if file existsError Handling: Throws RuntimeException if file cannot be read or parsed
Records configuration file contents for runtime access.
@BuildStep
@Record(ExecutionTime.STATIC_INIT)
void recordConfigFile(
Optional<McpConfigFileContentsBuildItem> maybeMcpConfigFileContents,
McpRecorder recorder
);Behavior:
McpConfigFileContentsBuildItem is presentGenerates synthetic CDI beans for MCP clients and optional ToolProvider.
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void registerMcpClients(
McpBuildTimeConfiguration mcpBuildTimeConfiguration,
Optional<McpConfigFileContentsBuildItem> maybeMcpConfigFileContents,
BuildProducer<SyntheticBeanBuildItem> beanProducer,
BuildProducer<HealthBuildItem> healthBuildItems,
ShutdownContextBuildItem shutdown,
Capabilities capabilities,
Optional<MetricsCapabilityBuildItem> metricsCapability,
CoreVertxBuildItem vertxBuildItem,
BuildProducer<RuntimeInitializedClassBuildItem> runtimeInitializedClasses,
McpRecorder recorder
);Behavior:
@McpClientName qualifier annotationSyntheticBeanBuildItem for McpClient bean@ApplicationScopedgenerateToolProvider is enabled:
SyntheticBeanBuildItem for ToolProvider beanTracer if availableHealthBuildItem for McpClientHealthCheckRuntimeInitializedClassBuildItem for MetricsMcpListenerGenerates synthetic CDI beans for MCP registry clients.
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void registerRegistryClients(
McpBuildTimeConfiguration mcpBuildTimeConfiguration,
BuildProducer<SyntheticBeanBuildItem> beanProducer,
McpRecorder recorder
);Behavior:
@McpRegistryClientName qualifier annotationSyntheticBeanBuildItem for McpRegistryClient bean@ApplicationScopedIndexes the langchain4j-mcp dependency for reflection.
@BuildStep
void indexMcpClientDependency(BuildProducer<IndexDependencyBuildItem> index);Behavior:
IndexDependencyBuildItem for dev.langchain4j:langchain4j-mcpRegisters MCP protocol classes for reflection (native compilation support).
@BuildStep
void reflectionRegistrations(
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
CombinedIndexBuildItem indexBuildItem
);Behavior:
dev\.langchain4j\.mcp\.protocol\..+ReflectiveClassBuildItem with fields and methods enabledMarks authentication provider beans as unremovable.
@BuildStep
void addMcpAuthProvider(BuildProducer<UnremovableBeanBuildItem> unremovableProducer);Behavior:
UnremovableBeanBuildItem for McpClientAuthProvider interfaceBuild processor for DevUI integration. Located in io.quarkiverse.langchain4j.mcp.deployment.devui package.
Note: This class is package-private and not intended for direct extension.
Registers MCP clients card in Quarkus DevUI.
@BuildStep(onlyIf = IsDevelopment.class)
CardPageBuildItem cardPage();Behavior:
qwc-mcp-clients.jsRegisters JSON-RPC service for DevUI backend.
@BuildStep
void jsonRpcService(BuildProducer<JsonRPCProvidersBuildItem> producers);Behavior:
JsonRPCProvidersBuildItem for McpClientsJsonRpcServiceRecorders generate bytecode for runtime initialization.
Bytecode recorder for MCP runtime initialization.
package io.quarkiverse.langchain4j.mcp.runtime;
import io.quarkus.runtime.annotations.Recorder;
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.Map;
import java.util.Set;
/**
* Recorder for generating runtime initialization code.
* Used by build processors to create suppliers for synthetic beans.
*/
@Recorder
public class McpRecorder {
/**
* Records Claude Desktop configuration contents for static initialization.
*
* @param contents Parsed configuration map
*/
public void claudeConfigContents(Map<String, LocalLaunchParams> contents);
/**
* Creates supplier for MCP client synthetic bean.
*
* @param clientName Client name for identification and logging
* @param transportType Transport protocol type
* @param shutdown Shutdown context for cleanup
* @param vertx Vert.x instance for async operations
* @param metricsEnabled Whether to enable Micrometer metrics
* @return Supplier creating McpClient instance
*/
public Supplier<McpClient> mcpClientSupplier(
String clientName,
McpTransportType transportType,
ShutdownContextBuildItem shutdown,
Vertx vertx,
boolean metricsEnabled
);
/**
* Creates function for ToolProvider synthetic bean.
*
* @param mcpClientNames Set of MCP client names to aggregate
* @return Function creating QuarkusMcpToolProvider instance
*/
public Function<SyntheticCreationalContext<ToolProvider>, ToolProvider>
toolProviderFunction(Set<String> mcpClientNames);
/**
* Creates supplier for MCP registry client synthetic bean.
*
* @param key Registry client name
* @return Supplier creating McpRegistryClient instance
*/
public Supplier<McpRegistryClient> mcpRegistryClientSupplier(String key);
}Usage: Called by build processors; not directly used by application code.
Extensions can access MCP client configuration:
import io.quarkiverse.langchain4j.mcp.deployment.McpConfigFileContentsBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
class CustomProcessor {
@BuildStep
void processConfig(
Optional<McpConfigFileContentsBuildItem> configItem,
BuildProducer<CustomBuildItem> producer
) {
configItem.ifPresent(item -> {
item.getContents().forEach((name, params) -> {
// Custom processing based on MCP configuration
producer.produce(new CustomBuildItem(name, params));
});
});
}
}Extensions can add logic after MCP clients are registered:
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Consume;
class EnhancedMcpProcessor {
@BuildStep
@Consume(SyntheticBeanBuildItem.class)
void afterMcpClientsRegistered() {
// Custom logic that runs after MCP clients are generated
// Guaranteed to execute after synthetic beans are produced
}
}Extensions can generate beans that depend on MCP clients:
import dev.langchain4j.mcp.client.McpClient;
import io.quarkiverse.langchain4j.mcp.runtime.McpClientName;
import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.Record;
import org.jboss.jandex.AnnotationInstance;
class CustomMcpBeanProcessor {
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void produceCustomBean(
BuildProducer<SyntheticBeanBuildItem> producer,
CustomRecorder recorder
) {
AnnotationInstance qualifier = AnnotationInstance.builder(
DotName.createSimple(McpClientName.class.getName())
).add("value", "github").build();
producer.produce(SyntheticBeanBuildItem
.configure(CustomService.class)
.setRuntimeInit()
.scope(ApplicationScoped.class)
.addInjectionPoint(ClassType.create(McpClient.class), qualifier)
.supplier(recorder.createCustomService())
.done()
);
}
}When building native images:
Use @QuarkusTest to test build-time behavior:
import io.quarkus.test.QuarkusUnitTest;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class McpBuildTimeTest {
@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class))
.withConfigurationResource("test-application.properties");
@Test
void testMcpClientGeneration() {
// Test that MCP clients are generated correctly
// Inject and verify beans
}
}Extensions may also interact with standard Quarkus build items:
SyntheticBeanBuildItem - Generated CDI beansHealthBuildItem - Health check registrationReflectiveClassBuildItem - Native compilation reflectionUnremovableBeanBuildItem - Bean removal protectionRuntimeInitializedClassBuildItem - Runtime initialization controlIndexDependencyBuildItem - Jandex indexingJsonRPCProvidersBuildItem - DevUI backend servicesCardPageBuildItem - DevUI frontend pagesInstall with Tessl CLI
npx tessl i tessl/maven-io-quarkiverse-langchain4j--quarkus-langchain4j-mcp-deployment@1.7.0