Skip to content

kpavlov/tachyon

Repository files navigation

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

Ask DeepWiki

Tachyon MCP is a Java 21 Model Context Protocol (MCP) server built on Netty. Implements the 2025-11-25 Streamable HTTP transport, protocol extensions, and stateless mode.

Why Tachyon?

  1. MCP Spec Compliant β€” All official conformance tests green on the current 2025-11-25 spec; tools, resources, prompts, tasks, elicitation, sampling, and extensions (SEP-1686, SEP-2133) in one artifact.
  2. Your handlers outlive the spec β€” MCP moves fast; Tachyon's stable domain types (ToolHandler, ResourceHandler, PromptHandler, Task support) absorb protocol changes in an internal mapper layer, so version bumps don't touch your code.
  3. Write blocking code, get async runtime β€” handlers run on Java 21 virtual threads off the Netty event loop; plain synchronous logic scales without thread pools, reactive chains, or CompletableFuture gymnastics. Coroutine-first Kotlin DSL included.
  4. Serverless-ready β€” stateless by default, so each request is independent for AWS Lambda and friends; opt into full session mode (.session(s -> s.enabled(true))) for SSE resumability, Last-Event-ID replay, TTL + janitor, and a customizable session-id generator.
  5. Production-grade transport β€” Netty core with backpressure watermarks, graceful shutdown, DNS-rebinding protection, and auto-detected native transports (io_uring / epoll / kqueue) when you want the extra speed.

TL;DR

  1. Add dependency:

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

    import dev.tachyonmcp.server.TachyonServer;
    import dev.tachyonmcp.runtime.InteractionContext;
    import dev.tachyonmcp.server.features.tools.AbstractSyncToolHandler;
    import dev.tachyonmcp.server.features.tools.ToolArgs;
    import dev.tachyonmcp.server.features.tools.ToolDescriptor;
    import dev.tachyonmcp.server.features.tools.ToolResult;
    import tools.jackson.databind.node.JsonNodeFactory;
    
    void main() {
        var schema = JsonNodeFactory.instance.objectNode();
        schema.put("type", "object");
        schema.putObject("properties").putObject("city").put("type", "string");
    
        TachyonServer.builder()
            .name("weather-mcp")
            .tool(new AbstractSyncToolHandler(
                ToolDescriptor.builder("get_forecast")
                    .description("Get weather forecast")
                    .inputSchema(schema)
                    .build()) {
    
                @Override
                public ToolResult handle(InteractionContext ctx, ToolArgs args) {
                    return 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

Core Protocol (46/46 conformance tests passing)

  • JSON-RPC 2.0 β€” request/response/error/notification
  • Streamable HTTP β€” POST, GET (SSE), DELETE, OPTIONS
  • Lifecycle β€” initialize β†’ initialized β†’ ACTIVE
  • Pagination β€” cursor-based across all list methods
  • Session state machine β€” INITIALIZING β†’ ACTIVE β†’ CLOSED
  • CORS & origin validation
  • DNS rebinding protection
  • Accept header strict validation (406)
  • Pending request timeout (60s)
  • Extensions (SEP-2133)

Tools

  • tools/list β€” paginated with nextCursor
  • tools/call β€” returns CallToolResult with isError
  • outputSchema in listing
  • annotations field
  • execution.taskSupport (forbidden/optional/required)
  • Synchronous & asynchronous handler interfaces
  • Tool name validation (SEP-986)
  • notifications/tools/list_changed on add/remove
  • Inline notifications + logging during tool call
  • Input JSON Schema 2020-12 validation (SEP-1613)

Resources

  • resources/list β€” paginated
  • resources/read β€” text & blob content
  • resources/templates/list β€” URI templates
  • resources/subscribe / unsubscribe
  • notifications/resources/list_changed
  • notifications/resources/updated to subscribers
  • Dynamic content via ResourceHandler interface

Prompts

  • prompts/list β€” paginated with nextCursor
  • prompts/get β€” invokes prompt resolver
  • notifications/prompts/list_changed

Tasks

  • tasks/list, tasks/get, tasks/cancel, tasks/result
  • State machine enforcement β€” SUBMITTED β†’ WORKING β†’ INPUT_REQUIRED β†’ COMPLETED/FAILED/CANCELLED, plus REJECTED/AUTH_REQUIRED
  • notifications/tasks/status broadcast on every transition
  • Task Janitor for stale tasks
  • execution.taskSupport per tool (forbidden/optional/required)
  • TasksExtension (SEP-1686) β€” negotiable extension exposing create_task tool + task://{id} resource template
  • Extension-gated tool visibility (hidden from un-negotiated clients)

Logging & Observability

  • logging/setLevel per session
  • notifications/message emitted above threshold
  • Progress notifications

Client Communication

  • sampling/createMessage β€” server β†’ client request
  • Elicitation β€” βœ… form mode; ❌ url mode
  • notifications/cancelled β€” bidirectional
  • notifications/tasks/status from client

Transport & I/O

  • Netty 4.2
  • io_uring / epoll / kqueue / nio auto-detection
  • Platform-thread event loops + virtual-thread handlers
  • TCP_NODELAY, SO_KEEPALIVE
  • Channel writability backpressure (setAutoRead)
  • Configurable idle timeouts (reader/writer)

Session Management

  • SSE resumability via Last-Event-ID
  • Stateless mode β€” skip sessions for serverless
  • IN_MEMORY session store (ConcurrentHashMap)
  • Session Janitor β€” 5s sweep, 30s TTL
  • SSE disconnect β‰  session removal (supports reconnect)
  • Event log replay on reconnection
  • Graceful shutdown β€” drains in-flight handlers for shutdownGracePeriod (default 5s) before force-interrupt

Installation

Requirements: JDK 21+

Build from source

git clone https://github.com/kpavlov/tachyon.git
cd tachyon
mvn install -pl tachyon-server -DskipTests

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
  • Batch flushing β€” ctx.write() accumulates, single ctx.flush() on boundary
  • Minimal allocations β€” McpEndpointHandler is @Sharable, no per-request handler creation
  • Virtual threads β€” handlers offloaded from event loop, no manual thread pools
  • JSON-RPC β€” Jackson streaming codec, no ObjectMapper.

Gaps & Limitations

  • Rate limiting β€” Not yet implemented
  • 2026-07-28 draft protocol version β€” High priority
  • Stale session on re-initialize β€” 30s TTL lingering, affects reconnect only

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.

Does it support HTTP/2?

Not yet. The current transport targets HTTP/1.1.

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.

About

πŸ’« Tachyon MCP Runtime for JVM - a Java Model Context Protocol (MCP) server with Streamable HTTP, native Netty transports, tasks, resources, prompts, resumable sessions, and stateless deployment support.

Topics

Resources

License

Stars

Watchers

Forks

Contributors