CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/maven-com-embabel-agent--embabel-agent-mcpserver

Discover and Export available Agent(s) as MCP Servers

Overview
Eval results
Files

domain-types.mddocs/api/

Domain Types API

API reference for core domain models including execution modes, server information, tool specifications, capabilities, and health status.

Package

com.embabel.agent.mcpserver.domain

Overview

Domain types represent core concepts in the MCP server architecture. These immutable data classes provide type-safe access to server metadata, configuration, and runtime state.

Execution Mode

McpExecutionMode { .api }

Enum representing MCP server execution modes.

package com.embabel.agent.mcpserver.domain

enum class McpExecutionMode {
    SYNC,
    ASYNC
}

Values:

  • SYNC - Synchronous blocking mode
  • ASYNC - Asynchronous non-blocking mode

Usage:

import com.embabel.agent.mcpserver.domain.McpExecutionMode

// Check mode
val mode = serverStrategy.getExecutionMode()
when (mode) {
    McpExecutionMode.SYNC -> {
        println("Running in synchronous mode")
    }
    McpExecutionMode.ASYNC -> {
        println("Running in asynchronous mode")
    }
}

// Mode-specific logic
fun performOperation() {
    val mode = serverStrategy.getExecutionMode()

    if (mode == McpExecutionMode.ASYNC) {
        performAsyncOperation()
    } else {
        performSyncOperation()
    }
}

// String representation
val modeString = mode.toString()  // "SYNC" or "ASYNC"
val modeValue = mode.name          // "SYNC" or "ASYNC"

Comparison:

// Check for specific mode
val isSyncMode = mode == McpExecutionMode.SYNC
val isAsyncMode = mode == McpExecutionMode.ASYNC

// Pattern matching
val description = when (mode) {
    McpExecutionMode.SYNC -> "Blocking operations, simpler code"
    McpExecutionMode.ASYNC -> "Non-blocking operations, better scalability"
}

Server Information

ServerInfo { .api }

Immutable data class containing server metadata.

package com.embabel.agent.mcpserver.domain

data class ServerInfo(
    val name: String,
    val version: String,
    val executionMode: McpExecutionMode,
    val capabilities: Set<McpCapability>,
    val metadata: Map<String, String> = emptyMap()
)

Properties:

  • name: String - Application name (from spring.application.name)
  • version: String - Library version (e.g., "0.3.3")
  • executionMode: McpExecutionMode - Current execution mode
  • capabilities: Set<McpCapability> - Supported MCP capabilities
  • metadata: Map<String, String> - Additional custom metadata

Usage:

import com.embabel.agent.mcpserver.domain.ServerInfo

@Service
class ServerInfoService(
    private val serverStrategy: McpServerStrategy
) {

    fun displayServerInfo() {
        serverStrategy.getServerInfo()
            .subscribe { info ->
                println("Server Name: ${info.name}")
                println("Version: ${info.version}")
                println("Mode: ${info.executionMode}")
                println("Capabilities: ${info.capabilities}")
                println("Metadata: ${info.metadata}")
            }
    }

    fun checkCapability(capability: McpCapability): Mono<Boolean> {
        return serverStrategy.getServerInfo()
            .map { info -> info.capabilities.contains(capability) }
    }

    fun getMetadataValue(key: String): Mono<String?> {
        return serverStrategy.getServerInfo()
            .map { info -> info.metadata[key] }
    }

    fun formatServerSummary(): Mono<String> {
        return serverStrategy.getServerInfo()
            .map { info ->
                """
                ${info.name} v${info.version}
                Mode: ${info.executionMode}
                Capabilities: ${info.capabilities.size}
                """.trimIndent()
            }
    }
}

REST API:

@RestController
@RequestMapping("/api/server")
class ServerController(
    private val serverStrategy: McpServerStrategy
) {

    @GetMapping("/info")
    fun getServerInfo(): Mono<ResponseEntity<ServerInfo>> {
        return serverStrategy.getServerInfo()
            .map { ResponseEntity.ok(it) }
    }

    @GetMapping("/info/summary")
    fun getServerSummary(): Mono<ResponseEntity<ServerSummary>> {
        return serverStrategy.getServerInfo()
            .map { info ->
                ServerSummary(
                    name = info.name,
                    version = info.version,
                    mode = info.executionMode.toString()
                )
            }
            .map { ResponseEntity.ok(it) }
    }
}

data class ServerSummary(
    val name: String,
    val version: String,
    val mode: String
)

Tool Specification

ToolSpecification { .api }

Immutable data class describing a tool's metadata.

package com.embabel.agent.mcpserver.domain

data class ToolSpecification(
    val name: String,
    val description: String,
    val inputSchema: String?,
    val outputSchema: String?
)

Properties:

  • name: String - Tool name (unique identifier)
  • description: String - Human-readable description
  • inputSchema: String? - JSON schema for input (optional)
  • outputSchema: String? - JSON schema for output (optional)

Usage:

import com.embabel.agent.mcpserver.domain.ToolSpecification

// Create specification
val spec = ToolSpecification(
    name = "calculateSum",
    description = "Calculate sum of two numbers",
    inputSchema = """
        {
          "type": "object",
          "properties": {
            "a": {"type": "number"},
            "b": {"type": "number"}
          },
          "required": ["a", "b"]
        }
    """.trimIndent(),
    outputSchema = """
        {
          "type": "object",
          "properties": {
            "result": {"type": "number"}
          }
        }
    """.trimIndent()
)

// Query tools
@Service
class ToolSpecificationService(
    private val toolRegistry: ToolRegistry
) {

    fun getToolSpecification(toolName: String): Mono<ToolSpecification> {
        return toolRegistry.findToolCallback(toolName)
            .map { callback ->
                ToolSpecification(
                    name = callback.name,
                    description = callback.description,
                    inputSchema = callback.inputTypeSchema,
                    outputSchema = null
                )
            }
    }

    fun getAllToolSpecifications(): Mono<List<ToolSpecification>> {
        return toolRegistry.listToolCallbacks()
            .map { callbacks ->
                callbacks.map { callback ->
                    ToolSpecification(
                        name = callback.name,
                        description = callback.description,
                        inputSchema = callback.inputTypeSchema,
                        outputSchema = null
                    )
                }
            }
    }

    fun hasInputSchema(toolName: String): Mono<Boolean> {
        return getToolSpecification(toolName)
            .map { it.inputSchema != null }
            .defaultIfEmpty(false)
    }
}

MCP Capability

McpCapability { .api }

Enum representing MCP protocol capabilities.

package com.embabel.agent.mcpserver.domain

enum class McpCapability {
    TOOLS,
    RESOURCES,
    PROMPTS,
    SAMPLING
}

Values:

  • TOOLS - Tool execution support
  • RESOURCES - Resource exposure support
  • PROMPTS - Prompt definition support
  • SAMPLING - Sampling/completion support

Usage:

import com.embabel.agent.mcpserver.domain.McpCapability

@Service
class CapabilityService(
    private val serverStrategy: McpServerStrategy
) {

    fun hasCapability(capability: McpCapability): Mono<Boolean> {
        return serverStrategy.getServerInfo()
            .map { info -> info.capabilities.contains(capability) }
    }

    fun checkAllCapabilities(required: Set<McpCapability>): Mono<Boolean> {
        return serverStrategy.getServerInfo()
            .map { info -> info.capabilities.containsAll(required) }
    }

    fun listCapabilities(): Mono<Set<McpCapability>> {
        return serverStrategy.getServerInfo()
            .map { it.capabilities }
    }

    fun describeCapabilities(): Mono<Map<McpCapability, String>> {
        return serverStrategy.getServerInfo()
            .map { info ->
                info.capabilities.associateWith { capability ->
                    when (capability) {
                        McpCapability.TOOLS -> "Execute tools"
                        McpCapability.RESOURCES -> "Access resources"
                        McpCapability.PROMPTS -> "Use prompts"
                        McpCapability.SAMPLING -> "Generate completions"
                    }
                }
            }
    }
}

// Check required capabilities
@Service
class FeatureGuard(
    private val serverStrategy: McpServerStrategy
) {

    fun requireCapabilities(vararg capabilities: McpCapability): Mono<Void> {
        return serverStrategy.getServerInfo()
            .flatMap { info ->
                val hasAll = capabilities.all { it in info.capabilities }
                if (hasAll) {
                    Mono.empty()
                } else {
                    val missing = capabilities.filter { it !in info.capabilities }
                    Mono.error(
                        MissingCapabilitiesException(
                            "Missing capabilities: ${missing.joinToString()}"
                        )
                    )
                }
            }
    }
}

class MissingCapabilitiesException(message: String) : RuntimeException(message)

Server Health Status

ServerHealthStatus { .api }

Immutable data class representing server health.

package com.embabel.agent.mcpserver.domain

data class ServerHealthStatus(
    val isHealthy: Boolean,
    val message: String,
    val timestamp: Long = System.currentTimeMillis(),
    val details: Map<String, Any> = emptyMap()
)

Properties:

  • isHealthy: Boolean - Overall health status
  • message: String - Status message
  • timestamp: Long - Status check timestamp (milliseconds)
  • details: Map<String, Any> - Additional health details

Usage:

import com.embabel.agent.mcpserver.domain.ServerHealthStatus

@Service
class HealthCheckService(
    private val serverStrategy: McpServerStrategy
) {

    fun checkHealth(): Mono<ServerHealthStatus> {
        return serverStrategy.checkHealth()
            .doOnNext { status ->
                if (status.isHealthy) {
                    logger.info("Server healthy: ${status.message}")
                } else {
                    logger.warn("Server unhealthy: ${status.message}")
                }
            }
    }

    fun waitUntilHealthy(timeout: Duration): Mono<Boolean> {
        return serverStrategy.checkHealth()
            .map { it.isHealthy }
            .repeatWhenEmpty { it.delayElements(Duration.ofSeconds(1)) }
            .timeout(timeout)
            .onErrorReturn(false)
    }

    fun getHealthDetails(): Mono<Map<String, Any>> {
        return serverStrategy.checkHealth()
            .map { it.details }
    }

    fun formatHealthReport(): Mono<String> {
        return serverStrategy.checkHealth()
            .map { status ->
                buildString {
                    appendLine("Health Status: ${if (status.isHealthy) "Healthy" else "Unhealthy"}")
                    appendLine("Message: ${status.message}")
                    appendLine("Timestamp: ${status.timestamp}")
                    if (status.details.isNotEmpty()) {
                        appendLine("Details:")
                        status.details.forEach { (key, value) ->
                            appendLine("  $key: $value")
                        }
                    }
                }
            }
    }

    companion object {
        private val logger = LoggerFactory.getLogger(HealthCheckService::class.java)
    }
}

REST API:

@RestController
@RequestMapping("/api/health")
class HealthController(
    private val serverStrategy: McpServerStrategy
) {

    @GetMapping
    fun checkHealth(): Mono<ResponseEntity<ServerHealthStatus>> {
        return serverStrategy.checkHealth()
            .map { status ->
                val httpStatus = if (status.isHealthy) {
                    HttpStatus.OK
                } else {
                    HttpStatus.SERVICE_UNAVAILABLE
                }
                ResponseEntity.status(httpStatus).body(status)
            }
    }

    @GetMapping("/simple")
    fun simpleHealthCheck(): Mono<ResponseEntity<HealthResponse>> {
        return serverStrategy.checkHealth()
            .map { status ->
                HealthResponse(
                    healthy = status.isHealthy,
                    timestamp = status.timestamp
                )
            }
            .map { ResponseEntity.ok(it) }
    }

    @GetMapping("/wait")
    fun waitForHealthy(
        @RequestParam(defaultValue = "30") timeoutSeconds: Long
    ): Mono<ResponseEntity<String>> {
        val timeout = Duration.ofSeconds(timeoutSeconds)

        return serverStrategy.checkHealth()
            .map { it.isHealthy }
            .repeatWhenEmpty { it.delayElements(Duration.ofSeconds(1)) }
            .timeout(timeout)
            .map { healthy ->
                if (healthy) {
                    ResponseEntity.ok("Server is healthy")
                } else {
                    ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                        .body("Server not healthy")
                }
            }
            .onErrorResume(TimeoutException::class.java) { _ ->
                Mono.just(
                    ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT)
                        .body("Health check timeout")
                )
            }
    }
}

data class HealthResponse(
    val healthy: Boolean,
    val timestamp: Long
)

Custom Health Details:

// Creating custom health status
val healthStatus = ServerHealthStatus(
    isHealthy = true,
    message = "All systems operational",
    details = mapOf(
        "toolsRegistered" to 42,
        "resourcesAvailable" to 15,
        "uptime" to System.currentTimeMillis(),
        "memoryUsage" to "512MB / 1024MB"
    )
)

// Unhealthy status
val unhealthyStatus = ServerHealthStatus(
    isHealthy = false,
    message = "Database connection failed",
    details = mapOf(
        "error" to "Connection timeout",
        "retryAttempts" to 3,
        "lastAttempt" to System.currentTimeMillis()
    )
)

Common Patterns

Mode Detection { .api }

@Service
class ModeAwareService(
    private val serverStrategy: McpServerStrategy
) {

    fun performModeSpecificOperation(): Mono<String> {
        val mode = serverStrategy.getExecutionMode()

        return when (mode) {
            McpExecutionMode.SYNC -> {
                Mono.just("Performing synchronous operation")
            }
            McpExecutionMode.ASYNC -> {
                Mono.just("Performing asynchronous operation")
            }
        }
    }

    fun isAsyncMode(): Boolean {
        return serverStrategy.getExecutionMode() == McpExecutionMode.ASYNC
    }

    fun isSyncMode(): Boolean {
        return serverStrategy.getExecutionMode() == McpExecutionMode.SYNC
    }
}

Server Metadata Access { .api }

@Service
class MetadataService(
    private val serverStrategy: McpServerStrategy
) {

    fun getServerName(): Mono<String> {
        return serverStrategy.getServerInfo()
            .map { it.name }
    }

    fun getServerVersion(): Mono<String> {
        return serverStrategy.getServerInfo()
            .map { it.version }
    }

    fun getFullServerDescription(): Mono<String> {
        return serverStrategy.getServerInfo()
            .map { info ->
                "${info.name} v${info.version} (${info.executionMode})"
            }
    }

    fun getAllMetadata(): Mono<Map<String, Any>> {
        return serverStrategy.getServerInfo()
            .map { info ->
                mapOf(
                    "name" to info.name,
                    "version" to info.version,
                    "mode" to info.executionMode.toString(),
                    "capabilities" to info.capabilities.map { it.toString() },
                    "metadata" to info.metadata
                )
            }
    }
}

Health Monitoring { .api }

@Service
class HealthMonitor(
    private val serverStrategy: McpServerStrategy
) {

    @Scheduled(fixedRate = 60000)  // Every minute
    fun monitorHealth() {
        serverStrategy.checkHealth()
            .subscribe { status ->
                if (!status.isHealthy) {
                    logger.error("Health check failed: ${status.message}")
                    alertAdministrators(status)
                } else {
                    logger.debug("Health check passed: ${status.message}")
                }
            }
    }

    fun collectHealthHistory(): Flux<ServerHealthStatus> {
        return Flux.interval(Duration.ofSeconds(10))
            .flatMap { serverStrategy.checkHealth() }
            .take(Duration.ofMinutes(5))
    }

    private fun alertAdministrators(status: ServerHealthStatus) {
        // Send alerts
    }

    companion object {
        private val logger = LoggerFactory.getLogger(HealthMonitor::class.java)
    }
}

Best Practices

  1. Use Type-Safe Access: Leverage domain types for type safety

    val mode: McpExecutionMode = serverStrategy.getExecutionMode()
  2. Pattern Matching: Use when expressions for mode handling

    when (mode) {
        McpExecutionMode.SYNC -> handleSync()
        McpExecutionMode.ASYNC -> handleAsync()
    }
  3. Capability Checking: Verify capabilities before operations

    serverInfo.capabilities.contains(McpCapability.TOOLS)
  4. Health Monitoring: Regularly check health status

    @Scheduled(fixedRate = 60000)
    fun checkHealth() { /* ... */ }
  5. Immutability: Domain types are immutable; use copy for modifications

    val updated = serverInfo.copy(metadata = newMetadata)

See Also

  • Server Strategy API - Strategy interface operations
  • Execution Modes Guide - Mode selection
  • Configuration API - Configuration details
  • Tool Registry API - Tool management
tessl i tessl/maven-com-embabel-agent--embabel-agent-mcpserver@0.3.1

docs

index.md

tile.json