Maven Central Java 21+ Build Conformance: v0.1.16 codecov Docs Ask DeepWiki

Tachyon MCP is a Java 21 Model Context Protocol (MCP) server built on Netty. It implements the MCP 2025-11-25 and partially MCP 2026-07-28 Streamable HTTP transport and runs stateless by default. It passes all official conformance tests for the latest protocol version and partially passes conformance tests for the Draft protocol.

πŸ’« Why Tachyon?

🧡 Synchronous code, asynchronous runtime β€” write blocking handlers; Java 21 virtual threads run them off the Netty event loop. No thread pools, reactive pipelines, or CompletableFuture boilerplate. Coroutine-first Kotlin DSL included.

πŸ›‘οΈ Stable APIs across spec changes β€” domain types (ToolHandler, ResourceHandler, PromptHandler, tasks) sit behind an internal protocol mapper. Spec upgrades change the mapper, not your handlers.

☁️ Serverless by default β€” stateless request handling works out of the box on AWS Lambda and similar. Opt into sessions (.session(s -> s.enabled(true))) for SSE resumability, Last-Event-ID replay, and TTL cleanup.

πŸš„ Production transport β€” Netty with backpressure, graceful shutdown, DNS rebinding protection, and native transport auto-detection (io_uring β†’ epoll β†’ kqueue β†’ NIO).

TL;DR

  1. Add dependency:

    <dependency>
        <groupId>dev.tachyonmcp</groupId>
        <artifactId>tachyon-server</artifactId>
        <version>1.0.0-beta.11</version>
    </dependency>
    
  2. Create MCP server:

    import dev.tachyonmcp.server.TachyonServer;
    import dev.tachyonmcp.server.features.tools.ToolHandler;
    import dev.tachyonmcp.server.features.tools.ToolResult;
    
    public class WeatherMcpServer {
        public static void main(String... args) {
            TachyonServer.builder()
                .name("weather-mcp")
                .tool(ToolHandler.of(
                    b -> b.name("get_forecast")
                        .description("Get weather forecast")
                        .inputSchema("""
                        {"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}
                        """),
                    (ctx, args) -> ToolResult.text("β˜€οΈ 22Β°C")))
                .port(8080)
                .start();
        }
    }
    

Documentation

Guide Description
Quickstart Build a working server in 5 minutes
Configuration Network, I/O engine (native transports), sessions, CORS
Tools Sync/async handlers, input schema, ToolResult
Resources Static URIs, dynamic handlers, URI templates
Tasks Long-running operations, state machine, TasksExtension
Extensions Custom protocol extensions, negotiation
Kotlin DSL Coroutine-first DSL, TachyonServer { }, scope reference
Kotlin module tachyon-server-kotlin module overview

Agent Skill

Add agent skill to write better code using this SDK:

npx skills add kpavlov/tachyon --skill tachyon-mcp

The skill includes compilable Java and Kotlin example sources under .agents/skills/tachyon-mcp/resources/. They are compiled as extra source roots of the e2e module during mvn test to keep them valid.

Check out Skills CLI for more options.

Features

Full 2025-11-25 MCP surface over Streamable HTTP, verified by the official conformance suite:

Area What you get
Tools Sync & async handlers, JSON Schema 2020-12 input/output validation, outputSchema, annotations, per-tool taskSupport, list_changed
Resources Static + dynamic handlers, URI templates, subscribe/unsubscribe with updated notifications, text & blob content
Prompts List/get with resolver handlers, input-required (MRTR) flow, list_changed
Tasks Full tasks/* lifecycle with enforced state machine, status broadcast, stale-task janitor, TasksExtension (SEP-1686)
Client calls sampling/createMessage, elicitation (form and URL modes), client-initiated cancelled
Sessions Stateless by default; opt-in SSE resumability, Last-Event-ID replay, TTL janitor, pluggable store/ID generator
Transport Native transport auto-detect, backpressure watermarks, graceful drain-on-shutdown, CORS + origin/DNS-rebinding protection
Extensions Negotiable protocol extensions (SEP-2133) with extension-gated tool visibility

Core β€” JSON-RPC 2.0; Streamable HTTP (POST/GET-SSE/DELETE/OPTIONS); lifecycle initialize β†’ initialized β†’ ACTIVE; cursor pagination on all list methods; strict Accept validation (406); pending-request timeout.

Tools β€” tools/list (paginated), tools/call (isError), outputSchema + annotations, sync/async handlers, name validation (SEP-986), inline notifications/logging mid-call, JSON Schema 2020-12 validation (SEP-1613), notifications/tools/list_changed.

Resources β€” resources/list, resources/read (text & blob), resources/templates/list, subscribe/unsubscribe, list_changed + updated notifications, dynamic ResourceHandler.

Prompts β€” prompts/list (paginated), prompts/get, input-required flow, list_changed.

Tasks β€” tasks/list|get|cancel|result; state machine SUBMITTED β†’ WORKING β†’ INPUT_REQUIRED β†’ COMPLETED/FAILED/CANCELLED (+ REJECTED/AUTH_REQUIRED); notifications/tasks/status on every transition; stale-task janitor; per-tool execution.taskSupport; TasksExtension (SEP-1686) exposing create_task + task://{id}, hidden from clients that don't negotiate it.

Logging & client calls β€” logging/setLevel per session, notifications/message above threshold, progress notifications; sampling/createMessage; elicitation form + URL modes; client-initiated notifications/cancelled.

Transport & sessions β€” Netty 4.2, io_uring/epoll/kqueue/NIO auto-detect, platform-thread event loops + virtual-thread handlers, writability backpressure, configurable idle timeouts; stateless or in-memory sessions, 5s janitor / 30s TTL, SSE disconnect survives (event-log replay on reconnect), graceful drain (shutdownGracePeriod, default 5s) before force-interrupt.


Quick Start

See docs/quickstart.md for a full walkthrough with Java and Kotlin examples, curl test, and next-step links.

TasksExtension (SEP-1686)

var handle = TachyonServer.builder()
    .extension(TasksExtension.instance())  // exposes create_task tool + task://{id} resource
    .port(8080)
    .start();

Clients that include "extensions": {"io.modelcontextprotocol/tasks": {}} in their initialize capabilities receive the extension's tool and resource template. Clients that don't negotiate it see standard tasks/* methods. See docs/tasks.md.

Protocol isolation

Handler interfaces (ToolHandler, ResourceHandler, PromptHandler) and descriptor types use stable domain types. When Tachyon upgrades to a new protocol version, only the internal mapper layer changes; handler implementations are unaffected. Domain types track the 2026-07-28 spec shape where it improves on 2025-11-25 (e.g. Annotations.lastModified, ResourceLink in ContentBlock).

Performance

  • Native transports β€” io_uring β†’ epoll β†’ kqueue β†’ NIO auto-detect
  • Write-buffer watermarks β€” 32 KB low / 128 KB high, backpressure wired end to end
  • Batch flushing β€” ctx.write() accumulates, one ctx.flush() per boundary
  • Sharable handlers β€” @Sharable pipeline handlers, no per-request allocation
  • Virtual threads β€” handlers offloaded from the event loop, no manual pools
  • Streaming JSON-RPC β€” Jackson streaming codec, no or limited ObjectMapper tree round-trips

Not yet supported

  • HTTP/2 β€” transport is HTTP/1.1
  • Rate limiting
  • 2026-07-28 protocol version β€” domain types already track its shape; negotiation pending

FAQ

Can I deploy to AWS Lambda?

Yes. Servers are stateless by default, so each invocation processes one request independently. Enable sessions with .session(cfg -> cfg.enabled(true)) when you need SSE resumability or replay.

How do I write a tool?

See docs/tools.md β€” covers lambda and class-based handlers, input schema, and ToolResult factories.

How do I expose a resource?

See docs/resources.md β€” covers static URIs, dynamic handlers, URI templates, and subscriptions.

License

Tachyon MCP is available under the terms of the Apache 2.0.