Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Vertx

БесплатноНе проверен

A Vert.x MCP Server built on top of MCP Java SDK

GitHubEmbed

Описание

A Vert.x MCP Server built on top of MCP Java SDK

README

A Vert.x-based transport implementation for the Model Context Protocol (MCP) Java SDK. This project provides a lightweight, non-blocking transport layer that integrates MCP servers with Vert.x applications.

Overview

The Vert.x MCP Server provides:

  • Vert.x Transport: A VertxMcpTransport interface that provides a Vert.x Router for integration into your Vert.x applications
  • SSE Transport: Server-Sent Events (SSE) implementation for real-time bidirectional communication
  • Streamable HTTP Transport: New MCP 2025-06-18 Streamable HTTP transport implementation
  • Verticle Support: A ready-to-use McpVerticle for easy deployment
  • Non-blocking: Built on Vert.x for high-performance, event-driven architecture
  • Session Management: Automatic client session handling with graceful shutdown support

⚠️ Experimental Status

This project is currently in experimental status and has not been fully tested in production environments.

  • The implementation follows the MCP specification but may contain bugs or incomplete features
  • API changes are possible as the project matures
  • Performance characteristics have not been thoroughly benchmarked
  • Please report any bugs, issues, or unexpected behavior you encounter
  • Contributions and feedback are welcome to help improve the project

Installation

Maven

<dependency>
    <groupId>org.kinotic</groupId>
    <artifactId>vertx-mcp</artifactId>
    <version>4.5.1</version>
</dependency>

Gradle

dependencies {
    implementation 'org.kinotic:vertx-mcp:4.5.1'
}

Version Compatibility

  • 4.5.x versions: Compatible with Vert.x 4.5.x
  • 5.0.x versions: Will be compatible with Vert.x 5.x (not yet supported)

Quick Start

1. Create an MCP Server

First, create your MCP server using the official Java MCP SDK:

import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.ServerCapabilities;
import java.util.List;
import reactor.core.publisher.Mono;

// Create a simple calculator tool
var calculatorTool = McpServerFeatures.AsyncToolSpecification.builder()
    .tool(McpSchema.Tool.builder()
        .name("calculator")
        .description("Basic calculator")
        .inputSchema("""
            {
              "type": "object",
              "properties": {
                "operation": {"type": "string", "enum": ["add", "subtract", "multiply", "divide"]},
                "a": {"type": "number"},
                "b": {"type": "number"}
              },
              "required": ["operation", "a", "b"]
            }
            """)
        .build())
    .callHandler((exchange, toolReq) -> {
        String operation = (String) toolReq.arguments().get("operation");
        double a = ((Number) toolReq.arguments().get("a")).doubleValue();
        double b = ((Number) toolReq.arguments().get("b")).doubleValue();
        
        double result = switch (operation) {
            case "add" -> a + b;
            case "subtract" -> a - b;
            case "multiply" -> a * b;
            case "divide" -> a / b;
            default -> throw new IllegalArgumentException("Unknown operation: " + operation);
        };
        
        return Mono.just(McpSchema.CallToolResult.builder()
            .textContent(List.of(String.valueOf(result)))
            .isError(false)
            .build());
    })
    .build();

// Create the MCP server specification (don't call .build() yet)
var mcpServerSpec = McpServer.async(transportProvider)
    .serverInfo("calculator-server", "1.0.0")
    .capabilities(ServerCapabilities.builder()
        .tools(true)
        .build())
    .tools(calculatorTool);

2. Create the Vert.x Transport

Option A: Use the Legacy HTTP+SSE Transport

import io.vertx.ext.mcp.transport.VertxMcpSseServerTransportProvider;
import com.fasterxml.jackson.databind.ObjectMapper;

// Create the transport
var transport = VertxMcpSseServerTransportProvider.builder()
    .baseUrl("http://localhost:8080")
    .messageEndpoint("/mcp/message")
    .sseEndpoint("/mcp/sse")
    .keepAliveInterval(Duration.ofSeconds(30))
    .objectMapper(new ObjectMapper())
    .vertx(vertx)
    .build();

Option B: Use the New Streamable HTTP Transport

import io.vertx.ext.mcp.transport.VertxMcpStreamableServerTransportProvider;
import com.fasterxml.jackson.databind.ObjectMapper;

// Create the Streamable HTTP transport
var transport = VertxMcpStreamableServerTransportProvider.builder()
    .objectMapper(new ObjectMapper())
    .mcpEndpoint("/mcp")
    .disallowDelete(false)
    .vertx(vertx)
    .build();

3. Integrate with Your Vert.x Application

Use the provided Verticle for easy integration:

import io.vertx.ext.mcp.McpVerticle;

// Deploy the MCP verticle (pass transport and server specification)
vertx.deployVerticle(new McpVerticle(8080, transport, mcpServerSpec), ar -> {
    if (ar.succeeded()) {
        System.out.println("MCP Verticle deployed successfully");
    } else {
        System.err.println("Failed to deploy MCP Verticle: " + ar.cause());
    }
});

4. Complete Examples

Example A: Legacy HTTP+SSE Transport

Here's a complete working example using the legacy HTTP+SSE transport:

import io.vertx.core.Vertx;
import io.vertx.ext.mcp.McpVerticle;
import io.vertx.ext.mcp.transport.VertxMcpSseServerTransportProvider;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.ServerCapabilities;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
import java.util.List;
import reactor.core.publisher.Mono;

public class LegacyMcpServerExample {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        
        // Create MCP server with a simple calculator tool
        var calculatorTool = McpServerFeatures.AsyncToolSpecification.builder()
            .tool(McpSchema.Tool.builder()
                .name("calculator")
                .description("Basic calculator")
                .inputSchema("""
                    {
                      "type": "object",
                      "properties": {
                        "operation": {"type": "string", "enum": ["add", "subtract", "multiply", "divide"]},
                        "a": {"type": "number"},
                        "b": {"type": "number"}
                      },
                      "required": ["operation", "a", "b"]
                    }
                    """)
                .build())
            .callHandler((exchange, toolReq) -> {
                String operation = (String) toolReq.arguments().get("operation");
                double a = ((Number) toolReq.arguments().get("a")).doubleValue();
                double b = ((Number) toolReq.arguments().get("b")).doubleValue();
                
                double result = switch (operation) {
                    case "add" -> a + b;
                    case "subtract" -> a - b;
                    case "multiply" -> a * b;
                    case "divide" -> a / b;
                    default -> throw new IllegalArgumentException("Unknown operation: " + operation);
                };
                
                return Mono.just(McpSchema.CallToolResult.builder()
                    .textContent(List.of(String.valueOf(result)))
                    .isError(false)
                    .build());
            })
            .build();

        // Create legacy HTTP+SSE transport
        var transport = VertxMcpSseServerTransportProvider.builder()
            .baseUrl("http://localhost:8080")
            .messageEndpoint("/mcp/message")
            .sseEndpoint("/mcp/sse")
            .keepAliveInterval(Duration.ofSeconds(30))
            .objectMapper(new ObjectMapper())
            .vertx(vertx)
            .build();

        // Create MCP server specification (don't call .build() yet)
        var mcpServerSpec = McpServer.async(transport)
            .serverInfo("calculator-server", "1.0.0")
            .capabilities(ServerCapabilities.builder()
                .tools(true)
                .build())
            .tools(calculatorTool);

        // Deploy the MCP verticle (pass transport and server specification)
        vertx.deployVerticle(new McpVerticle(8080, transport, mcpServerSpec), ar -> {
            if (ar.succeeded()) {
                System.out.println("MCP Server started on port 8080");
                System.out.println("SSE endpoint: http://localhost:8080/mcp/sse");
                System.out.println("Message endpoint: http://localhost:8080/mcp/message");
            } else {
                System.err.println("Failed to start MCP Server: " + ar.cause());
            }
        });
    }
}

Example B: New Streamable HTTP Transport

Here's a complete working example using the new MCP 2025-06-18 Streamable HTTP transport:

import io.vertx.core.Vertx;
import io.vertx.ext.mcp.McpVerticle;
import io.vertx.ext.mcp.transport.VertxMcpStreamableServerTransportProvider;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.ServerCapabilities;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
import java.util.List;
import reactor.core.publisher.Mono;

public class StreamableMcpServerExample {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        
        // Create MCP server with a simple calculator tool
        var calculatorTool = McpServerFeatures.AsyncToolSpecification.builder()
            .tool(McpSchema.Tool.builder()
                .name("calculator")
                .description("Basic calculator")
                .inputSchema("""
                    {
                      "type": "object",
                      "properties": {
                        "operation": {"type": "string", "enum": ["add", "subtract", "multiply", "divide"]},
                        "a": {"type": "number"},
                        "b": {"type": "number"}
                      },
                      "required": ["operation", "a", "b"]
                    }
                    """)
                .build())
            .callHandler((exchange, toolReq) -> {
                String operation = (String) toolReq.arguments().get("operation");
                double a = ((Number) toolReq.arguments().get("a")).doubleValue();
                double b = ((Number) toolReq.arguments().get("b")).doubleValue();
                
                double result = switch (operation) {
                    case "add" -> a + b;
                    case "subtract" -> a - b;
                    case "multiply" -> a * b;
                    case "divide" -> a / b;
                    default -> throw new IllegalArgumentException("Unknown operation: " + operation);
                };
                
                return Mono.just(McpSchema.CallToolResult.builder()
                    .textContent(List.of(String.valueOf(result)))
                    .isError(false)
                    .build());
            })
            .build();

        // Create Streamable HTTP transport
        var transport = VertxMcpStreamableServerTransportProvider.builder()
            .objectMapper(new ObjectMapper())
            .mcpEndpoint("/mcp")
            .disallowDelete(false)
            .vertx(vertx)
            .keepAliveInterval(Duration.ofSeconds(30))
            .build();

        // Create MCP server specification (don't call .build() yet)
        var mcpServerSpec = McpServer.async(transport)
            .serverInfo("calculator-server", "1.0.0")
            .capabilities(ServerCapabilities.builder()
                .tools(true)
                .build())
            .tools(calculatorTool);

        // Deploy the MCP verticle (pass transport and server specification)
        vertx.deployVerticle(new McpVerticle(8080, transport, mcpServerSpec), ar -> {
            if (ar.succeeded()) {
                System.out.println("MCP Server started on port 8080");
                System.out.println("Streamable HTTP endpoint: http://localhost:8080/mcp");
                System.out.println("Supports: GET (SSE), POST (messages), DELETE (sessions)");
            } else {
                System.err.println("Failed to start MCP Server: " + ar.cause());
            }
        });
    }
}

Configuration Options

Legacy HTTP+SSE Transport

The VertxMcpSseServerTransportProvider supports several configuration options:

  • baseUrl: Base URL for your server (required)
  • messageEndpoint: Endpoint for receiving JSON-RPC messages (default: /message)
  • sseEndpoint: Endpoint for SSE connections (default: /sse)
  • keepAliveInterval: Interval for keep-alive ping messages (default: 30 seconds)
  • objectMapper: Jackson ObjectMapper for JSON serialization
  • vertx: Vert.x instance

Streamable HTTP Transport

The VertxMcpStreamableServerTransportProvider supports:

  • objectMapper: Jackson ObjectMapper for JSON processing (required)
  • mcpEndpoint: The MCP endpoint path (default: /mcp)
  • disallowDelete: Whether to disable session deletion (default: false)
  • vertx: Vert.x instance (required)
  • keepAliveInterval: Interval for keep-alive ping messages (default: 30 seconds)

Architecture

Legacy HTTP+SSE Transport

The transport implements the MCP protocol using:

  1. SSE Connection (/sse): Establishes Server-Sent Events connection for server-to-client communication
  2. Message Endpoint (/message): Receives JSON-RPC messages from clients
  3. Session Management: Automatically manages client sessions and cleanup
  4. Keep-alive: Sends periodic ping messages to prevent connection timeouts

Streamable HTTP Transport

The new Streamable HTTP transport follows the MCP 2025-06-18 specification:

  1. Single Endpoint (/mcp): Handles all HTTP methods (GET, POST, DELETE)
  2. Session Management: Uses MCP SDK session management with unique session IDs
  3. Stream Resumption: Supports resuming broken connections via Last-Event-ID headers
  4. Protocol Compliance: Full compliance with the latest MCP specification

Testing

You can test your MCP server using any MCP client:

Legacy Transport

  • SSE endpoint: http://localhost:8080/mcp/sse for establishing connections
  • Message endpoint: http://localhost:8080/mcp/message?sessionId=<id> for sending requests

Streamable Transport

  • Single endpoint: http://localhost:8080/mcp for all operations
  • GET: Establish SSE listening streams
  • POST: Send JSON-RPC messages
  • DELETE: Terminate sessions

Graceful Shutdown

The transport supports graceful shutdown:

// Close the transport gracefully
transport.closeGracefully()
    .doOnSuccess(v -> System.out.println("Transport closed successfully"))
    .doOnError(e -> System.err.println("Error closing transport: " + e))
    .subscribe();

Roadmap

The following features are planned for future releases:

Vert.x 5 Support

Support for Vert.x 5.x versions, including:

  • Compatibility with Vert.x 5.x APIs
  • Updated transport implementations for Vert.x 5
  • Performance improvements leveraging new Vert.x 5 features

Authorization Support

Implementation of MCP Authorization capabilities including:

  • OAuth 2.1 compliant authorization flow
  • Dynamic client registration
  • Access token validation and audience binding
  • Resource parameter support for secure token issuance

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

License

This project is licensed under the Apache License, Version 2.0.

from github.com/kinotic-ai/vertx-mcp

Установка Vertx

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/kinotic-ai/vertx-mcp

FAQ

Vertx MCP бесплатный?

Да, Vertx MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Vertx?

Нет, Vertx работает без API-ключей и переменных окружения.

Vertx — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Vertx в Claude Desktop, Claude Code или Cursor?

Открой Vertx на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Vertx with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development