Discover and Export available Agent(s) as MCP Servers
API reference for McpToolExport interface and factory methods for converting Embabel components into MCP-compatible tool exports.
com.embabel.agent.mcpserverPrimary interface for tool export operations.
interface McpToolExport {
val toolCallbacks: List<ToolCallback>
companion object {
fun fromToolObject(toolObject: ToolObject): McpToolExport
fun fromToolObjects(
toolObjects: List<ToolObject>,
namingStrategy: StringTransformer? = null
): McpToolExport
fun fromLlmReference(
llmReference: LlmReference,
namingStrategy: StringTransformer? = null
): McpToolExport
fun fromLlmReferences(
llmReferences: List<LlmReference>,
namingStrategy: StringTransformer? = null
): McpToolExport
}
}Properties:
toolCallbacks: List<ToolCallback> - List of Spring AI ToolCallback instances ready for MCP registrationCreate export from a single ToolObject.
fun fromToolObject(toolObject: ToolObject): McpToolExportParameters:
toolObject: ToolObject - Embabel ToolObject containing tool instancesReturns: McpToolExport with exported tool callbacks
Usage:
import com.embabel.agent.mcpserver.McpToolExport
import com.embabel.agent.api.common.ToolObject
val toolObject = ToolObject(
objects = listOf(calculatorTool, weatherTool),
namingStrategy = { "api_$it" }
)
val export = McpToolExport.fromToolObject(toolObject)
val callbacks = export.toolCallbacks // List of ToolCallbackNaming Strategy:
ToolObject's namingStrategy parameter transforms tool names:
// Add prefix
ToolObject(
objects = listOf(myTool),
namingStrategy = { "myapp_$it" }
)
// Transform to uppercase
ToolObject(
objects = listOf(myTool),
namingStrategy = { it.uppercase() }
)
// No transformation
ToolObject(
objects = listOf(myTool),
namingStrategy = StringTransformer.IDENTITY
)Create export from multiple ToolObjects with optional global naming strategy.
fun fromToolObjects(
toolObjects: List<ToolObject>,
namingStrategy: StringTransformer? = null
): McpToolExportParameters:
toolObjects: List<ToolObject> - List of ToolObject instancesnamingStrategy: StringTransformer? - Optional global naming transformation applied after individual strategiesReturns: McpToolExport with all tools from all objects
Usage:
val apiTools = ToolObject(
objects = listOf(getTool, postTool),
namingStrategy = { "api_$it" }
)
val utilTools = ToolObject(
objects = listOf(formatTool, validateTool),
namingStrategy = { "util_$it" }
)
// Export both with global prefix
val export = McpToolExport.fromToolObjects(
toolObjects = listOf(apiTools, utilTools),
namingStrategy = { "v1_$it" }
)
// Results in: "v1_api_getTool", "v1_util_formatTool", etc.Naming Strategy Composition:
Individual ToolObject strategies are applied first, then global strategy:
ToolObject(namingStrategy = { "api_$it" }) // First
↓
Global namingStrategy = { "v2_$it" } // Second
↓
Result: "v2_api_toolName"Create export from LlmReference with automatic prefix from reference name.
fun fromLlmReference(
llmReference: LlmReference,
namingStrategy: StringTransformer? = null
): McpToolExportParameters:
llmReference: LlmReference - Embabel LlmReference containing agent definitionsnamingStrategy: StringTransformer? - Optional additional naming transformationReturns: McpToolExport with tools from the reference
Usage:
import com.embabel.agent.api.common.LlmReference
val llmRef: LlmReference = // Obtain from Embabel framework
// Basic export (uses reference name as prefix automatically)
val export = McpToolExport.fromLlmReference(llmRef)
// With additional strategy
val export = McpToolExport.fromLlmReference(
llmReference = llmRef,
namingStrategy = { "v2_$it" }
)Built-in Prefixing:
LlmReference includes its own naming strategy based on reference name:
Create export from multiple LlmReferences.
fun fromLlmReferences(
llmReferences: List<LlmReference>,
namingStrategy: StringTransformer? = null
): McpToolExportParameters:
llmReferences: List<LlmReference> - List of LlmReference instancesnamingStrategy: StringTransformer? - Optional global naming transformationReturns: McpToolExport with tools from all references
Usage:
val authRef: LlmReference = // Authentication reference
val dataRef: LlmReference = // Data access reference
val export = McpToolExport.fromLlmReferences(
llmReferences = listOf(authRef, dataRef),
namingStrategy = { "service_$it" }
)
// Each reference gets its own prefix plus "service_"Filter tools before export using ToolObject's filter parameter:
ToolObject(
objects: List<Any>,
namingStrategy: StringTransformer? = null,
filter: ((String) -> Boolean)? = null
)Usage:
// Only tools with specific prefix
val toolObject = ToolObject(
objects = listOf(publicTool, privateTool, internalTool),
filter = { toolName -> toolName.startsWith("public_") }
)
// Exclude deprecated tools
val toolObject = ToolObject(
objects = allTools,
filter = { toolName -> !toolName.contains("deprecated") }
)
// Whitelist specific tools
val allowedTools = setOf("getTool", "postTool", "deleteTool")
val toolObject = ToolObject(
objects = allTools,
filter = { toolName -> toolName in allowedTools }
)
// Complex filtering
val toolObject = ToolObject(
objects = allTools,
filter = { toolName ->
toolName.length <= 50 &&
!toolName.startsWith("_") &&
toolName.matches(Regex("[a-zA-Z0-9_]+"))
}
)Tools with identical names (after all transformations) are automatically deduplicated. Only the first occurrence is retained.
val tools1 = ToolObject(
objects = listOf(tool1),
namingStrategy = { "api_getData" }
)
val tools2 = ToolObject(
objects = listOf(tool2),
namingStrategy = { "api_getData" } // Same name
)
val export = McpToolExport.fromToolObjects(
toolObjects = listOf(tools1, tools2)
)
// Only one "api_getData" tool is exportedimport com.embabel.agent.mcpserver.McpExportToolCallbackPublisher
import org.springframework.stereotype.Service
@Service
class MyToolPublisher : McpExportToolCallbackPublisher {
override val toolCallbacks: List<ToolCallback>
get() {
val toolObject = ToolObject(
objects = listOf(tool1, tool2, tool3),
namingStrategy = { "myapp_$it" }
)
return McpToolExport.fromToolObject(toolObject).toolCallbacks
}
override fun infoString(verbose: Boolean?, indent: Int): String {
return "MyToolPublisher: ${toolCallbacks.size} tools"
}
}@Service
class CombinedPublisher : McpExportToolCallbackPublisher {
override val toolCallbacks: List<ToolCallback>
get() {
// Export from ToolObject
val toolObjectExport = McpToolExport.fromToolObject(
ToolObject(
objects = listOf(customTool1, customTool2),
namingStrategy = { "custom_$it" }
)
)
// Export from LlmReference
val llmRefExport = McpToolExport.fromLlmReference(
llmReference = myLlmReference,
namingStrategy = { "llm_$it" }
)
// Combine all callbacks
return toolObjectExport.toolCallbacks + llmRefExport.toolCallbacks
}
override fun infoString(verbose: Boolean?, indent: Int): String {
return "CombinedPublisher: ${toolCallbacks.size} tools"
}
}@Service
class ModularPublisher : McpExportToolCallbackPublisher {
override val toolCallbacks: List<ToolCallback>
get() {
val modules = mapOf(
"auth" to authTools,
"data" to dataTools,
"report" to reportTools
)
return modules.flatMap { (moduleName, tools) ->
McpToolExport.fromToolObject(
ToolObject(
objects = tools,
namingStrategy = { "${moduleName}_$it" }
)
).toolCallbacks
}
}
override fun infoString(verbose: Boolean?, indent: Int): String {
return "ModularPublisher: ${toolCallbacks.size} tools"
}
private val authTools = listOf(/* auth tool instances */)
private val dataTools = listOf(/* data tool instances */)
private val reportTools = listOf(/* report tool instances */)
}Functional interface for name transformation.
fun interface StringTransformer {
fun transform(input: String): String
companion object {
val IDENTITY: StringTransformer = StringTransformer { it }
}
}Usage:
// Lambda
val prefixer = StringTransformer { "api_$it" }
// Method reference
val uppercaser = StringTransformer(String::uppercase)
// Identity (no transformation)
val identity = StringTransformer.IDENTITY
// Custom implementation
class VersionTransformer(private val version: String) : StringTransformer {
override fun transform(input: String): String {
return "${version}_$input"
}
}Spring AI interface for tool execution (provided by Spring AI, not this library).
interface ToolCallback {
fun getName(): String
fun getDescription(): String
fun call(functionArguments: String): String
fun getInputTypeSchema(): String?
}All tool exports are logged at INFO level:
[INFO] McpToolExport - Exporting tool: myapp_api_getData
[INFO] McpToolExport - Exporting tool: myapp_api_postData
[INFO] McpToolExport - Exporting tool: myapp_util_formatData
[INFO] McpToolExport - Total tools exported: 3Enable DEBUG logging for detailed information:
logging.level.com.embabel.agent.mcpserver=DEBUGUse Descriptive Prefixes: Choose clear namespace prefixes to avoid collisions
namingStrategy = { "payment_api_$it" } // Good
namingStrategy = { "pa_$it" } // AvoidFilter Early: Apply filters at ToolObject level for efficiency
ToolObject(
objects = allTools,
filter = { !it.startsWith("_") }
)Compose Strategies: Use multiple levels of naming for organization
ToolObject(namingStrategy = { "api_$it" }) // Module level
↓
fromToolObjects(namingStrategy = { "v2_$it" }) // Version level
↓
Result: "v2_api_toolName"Handle Empty Results: Check for empty tool lists in publishers
override val toolCallbacks: List<ToolCallback>
get() {
val export = McpToolExport.fromToolObject(toolObject)
if (export.toolCallbacks.isEmpty()) {
logger.warn("No tools exported from publisher")
}
return export.toolCallbacks
}Document Naming Conventions: Comment naming strategy rationale
/**
* Exports API tools with "api_" prefix to avoid conflicts
* with utility tools from other publishers.
*/
override val toolCallbacks: List<ToolCallback>
get() = McpToolExport.fromToolObject(
ToolObject(
objects = apiTools,
namingStrategy = { "api_$it" }
)
).toolCallbacks