Discover and Export available Agent(s) as MCP Servers
Complete walkthrough for setting up and using embabel-agent-mcpserver in your project.
Add to your pom.xml:
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-mcpserver</artifactId>
<version>0.3.3</version>
</dependency>Add to your build.gradle.kts:
implementation("com.embabel.agent:embabel-agent-mcpserver:0.3.3")Create or update application.properties:
# Choose execution mode (SYNC is default)
spring.ai.mcp.server.type=SYNC
# Set application name (optional)
spring.application.name=my-agent-apiModes:
SYNC: Synchronous operations (blocking, simpler)ASYNC: Asynchronous operations (non-blocking, scalable)See Execution Modes Guide for detailed comparison.
Tool publishers expose functionality as MCP tools. Create a Spring service:
import com.embabel.agent.mcpserver.McpExportToolCallbackPublisher
import org.springframework.ai.tool.ToolCallback
import org.springframework.stereotype.Service
@Service
class HelloWorldPublisher : McpExportToolCallbackPublisher {
override val toolCallbacks: List<ToolCallback>
get() = listOf(createHelloTool())
override fun infoString(verbose: Boolean?, indent: Int): String {
return "HelloWorldPublisher: ${toolCallbacks.size} tools"
}
private fun createHelloTool(): ToolCallback {
// Implementation depends on your tool framework
// See Tool Export Guide for details
TODO("Create your ToolCallback implementation")
}
}Start your Spring Boot application:
./mvnw spring-boot:runOr with Gradle:
./gradlew bootRunThe MCP server automatically:
Check server initialization in logs:
[main] INFO - Embabel Agent MCP SYNC Server
[main] INFO - Version: 0.3.3
[main] INFO - Registered tools: helloBanner, ...The helloBanner tool is automatically available and displays server information.
If you have Embabel ToolObject instances:
import com.embabel.agent.mcpserver.McpToolExport
import com.embabel.agent.api.common.ToolObject
@Service
class MyToolsPublisher : McpExportToolCallbackPublisher {
override val toolCallbacks: List<ToolCallback>
get() {
val toolObject = ToolObject(
objects = listOf(myTool1, myTool2),
namingStrategy = { "myapp_$it" }
)
return McpToolExport.fromToolObject(toolObject).toolCallbacks
}
override fun infoString(verbose: Boolean?, indent: Int): String =
"MyToolsPublisher: ${toolCallbacks.size} tools"
}See Exporting Tools Guide for detailed examples.
Expose static or dynamic resources:
import com.embabel.agent.mcpserver.sync.McpResourcePublisher
import com.embabel.agent.mcpserver.sync.SyncResourceSpecificationFactory
import io.modelcontextprotocol.server.McpServerFeatures
import org.springframework.stereotype.Service
@Service
class DocsPublisher : McpResourcePublisher {
override fun resources(): List<McpServerFeatures.SyncResourceSpecification> {
return listOf(
SyncResourceSpecificationFactory.staticSyncResourceSpecification(
uri = "app://docs/readme",
name = "README",
description = "Application documentation",
content = "# My Application\n\nWelcome!",
mimeType = "text/markdown"
)
)
}
override fun infoString(verbose: Boolean?, indent: Int): String =
"DocsPublisher: ${resources().size} resources"
}See Resources and Prompts Guide for more examples.
Create prompts for AI clients:
import com.embabel.agent.mcpserver.sync.McpPromptPublisher
import com.embabel.agent.mcpserver.sync.McpPromptFactory
import com.embabel.common.core.types.Named
import com.embabel.common.core.types.Described
import io.modelcontextprotocol.server.McpServerFeatures
import org.springframework.stereotype.Service
@Service
class TaskPromptsPublisher : McpPromptPublisher {
private val factory = McpPromptFactory()
override fun prompts(): List<McpServerFeatures.SyncPromptSpecification> {
val goal = object : Named, Described {
override val name = "createTask"
override val description = "Create a new task"
}
return listOf(
factory.syncPromptSpecificationForType(
goal = goal,
inputType = TaskInput::class.java
)
)
}
override fun infoString(verbose: Boolean?, indent: Int): String =
"TaskPromptsPublisher: ${prompts().size} prompts"
}
data class TaskInput(
val title: String,
val description: String,
val priority: Int
)See Resources and Prompts Guide for prompt creation details.
Create separate publishers for different concerns:
@Service
class ApiToolsPublisher : McpExportToolCallbackPublisher { /* API tools */ }
@Service
class UtilityToolsPublisher : McpExportToolCallbackPublisher { /* Utility tools */ }
@Service
class ResourcesPublisher : McpResourcePublisher { /* Resources */ }
@Service
class PromptsPublisher : McpPromptPublisher { /* Prompts */ }All publishers are automatically discovered and registered.
Activate publishers based on profiles or properties:
@Service
@Profile("development")
class DevToolsPublisher : McpExportToolCallbackPublisher {
// Only active in development profile
}
@Service
@ConditionalOnProperty("features.experimental.enabled")
class ExperimentalPublisher : McpExportToolCallbackPublisher {
// Only active when feature flag is enabled
}Publishers for specific execution modes:
// Sync mode only (default)
@Service
@ConditionalOnProperty(
value = ["spring.ai.mcp.server.type"],
havingValue = "SYNC",
matchIfMissing = true
)
class SyncPublisher : McpResourcePublisher { /* ... */ }
// Async mode only
@Service
@ConditionalOnProperty(
value = ["spring.ai.mcp.server.type"],
havingValue = "ASYNC"
)
class AsyncPublisher : McpAsyncResourcePublisher { /* ... */ }Symptom: Server starts but no tools appear (except helloBanner)
Solutions:
@Service or @ComponenttoolCallbacks property returns non-empty listSymptom: Publishers not activating or wrong publisher types
Solutions:
spring.ai.mcp.server.type property valueMcpResourcePublisher, McpPromptPublisherMcpAsyncResourcePublisher, McpAsyncPromptPublisherSymptom: Errors during tool registration
Solutions:
Symptom: MCP clients cannot connect
Solutions:
See Integration Patterns Guide for complete working examples: