Standaard webforJ-installatie
De standaardconfiguratie maakt de MCP-server, registreert zijn servlet en installeert de webforJ-ondersteuning zelf.
Gebruik de standaard servlet-configuratie wanneer de app geen gebruik maakt van Spring Boot. Voor Spring Boot-apps, gebruik de Spring Boot configuratie, die automatisch gerouteerde weergaven publiceert via Spring AI.
MCP-apps hebben controle over de servletcontext van de app nodig om de cross-origin filter, cookie-instellingen, OAuth 2.0 discover-handling en de andere embed-ondersteuning te installeren die de host nodig heeft. Een app die wordt gedeployd via BBj Services kan die servlet-configuratie niet initiëren. Deploy de app in een servletcontainer die de app controleert in plaats daarvan.
Voeg de MCP-server afhankelijkheden toe
Voeg de MCP Apps module toe naast de bestaande webforJ afhankelijkheid. Het biedt de webforJ-bijdrage en de MCP SDK die wordt gebruikt om de server samen te stellen.
De initializer implementeert ook ServletContainerInitializer en gebruikt andere Jakarta Servlet-typen. Voeg de Servlet API toe met provided scope zodat die typen beschikbaar zijn tijdens de compileertijd zonder een tweede servletimplementatie te verpakken. De servletcontainer, zoals Jetty, levert ze tijdens runtime.
<properties>
<webforj.version>26.02</webforj.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.webforj</groupId>
<artifactId>webforj-bom</artifactId>
<version>${webforj.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.webforj</groupId>
<artifactId>webforj-mcp-apps</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
Voeg de initializer toe
De initializer scant het pakket met gerouteerde weergaven, draagt hun tools en UI-bronnen bij aan een MCP-server en monteert Streamable HTTP op /mcp.
package com.example.inventory;
import com.webforj.mcp.McpAppContribution;
import com.webforj.mcp.McpAppOptions;
import com.webforj.mcp.McpAppServletPath;
import io.modelcontextprotocol.common.McpTransportContext;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.HttpServletStreamableServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema.ServerCapabilities;
import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.ServletRegistration;
import java.util.Set;
public class InventoryMcpServerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> classes, ServletContext context) {
McpAppOptions options = McpAppOptions.load();
McpAppContribution contribution = McpAppContribution.ofPackages(
new String[] {"com.example.inventory"}, McpAppServletPath.of(context));
contribution.getOrigin().configure(options.getOrigin());
HttpServletStreamableServerTransportProvider transport =
HttpServletStreamableServerTransportProvider.builder().mcpEndpoint("/mcp")
.contextExtractor(request -> {
contribution.getOrigin().observe(request);
return McpTransportContext.EMPTY;
}).build();
McpSyncServer server = McpServer.sync(transport)
.serverInfo("inventory", "1.0.0")
.capabilities(ServerCapabilities.builder().tools(true).resources(false, true).build())
.tools(contribution.getToolSpecifications())
.resources(contribution.getResourceSpecifications())
.build();
ServletRegistration.Dynamic registration = context.addServlet("mcpServlet", transport);
registration.setAsyncSupported(true);
registration.addMapping("/mcp/*");
context.addListener(new ServletContextListener() {
@Override
public void contextDestroyed(ServletContextEvent event) {
server.close();
}
});
contribution.install(context, options);
}
}
McpAppContribution.ofPackages maakt beide collecties die op de server zijn geregistreerd. getToolSpecifications() bevat de tools die zijn gegenereerd vanuit de gerouteerde @McpApp-weergaven. getResourceSpecifications() bevat de gegenereerde ui://webforj/... bronnen die MCP-clients lezen om die weergaven weer te geven. Registreren van de tools zonder hun UI-bronnen blootlegt oproepen die de client niet kan weergeven.
De request context extractor laat webforJ de openbare oorsprong observeren wanneer webforj.origin niet is ingesteld. De laatste install-aanroep voegt het app-resourcebeleid, cross-origin handling, sessie-cookie-instellingen, OAuth 2.0 discover-handling, en favicon-ondersteuning toe. Een server die de tools publiceert maar deze aanroep overslaat, kan een bron blootleggen die de client niet correct kan uitvoeren.
Registreer de initializer
Registreer de initializer met de service loader van Java in src/main/resources/META-INF/services/jakarta.servlet.ServletContainerInitializer:
com.example.inventory.InventoryMcpServerInitializer
De servletcontainer laadt deze klasse tijdens de opstart van de app. Houd de volledig gekwalificeerde klasnaam in het servicebestand gesynchroniseerd met het initializer-pakket.
Configureer de implementatie
Standaardimplementaties lezen MCP App-instellingen vanuit webforj.conf. Bijvoorbeeld:
webforj.origin = "https://app.example.com"
webforj.mcp.allowed-origins = ["https://assistant.example.com"]
De minimale server kan nu worden gecontroleerd met een van de clients die zijn beschreven in Test een MCP App. MCP App configuratie legt publieke en cliënt-oorsprongen uit wanneer de implementatie meer nodig heeft dan de lokale standaardinstellingen.