Skip to content

SDK 0.7.4: Empty POST response causing 'Cannot read Json element' error" #356

@dusskapark

Description

@dusskapark

MCP Kotlin SDK 0.7.4 Bug Report: Empty POST Response causing "Cannot read Json element" Error

Summary

MCP Kotlin SDK 0.7.4 successfully establishes SSE connections and starts transport, but returns empty responses to POST requests from MCP clients (specifically Cursor), causing JSON parsing errors and preventing successful MCP communication.

Environment

  • SDK Version: io.modelcontextprotocol:kotlin-sdk:0.7.4
  • Ktor Version: 3.0.2
  • Ktor Engine: CIO
  • JVM: Amazon Corretto 21
  • OS: macOS 24.6.0
  • Client: Cursor (Anthropic MCP Client)
  • Date: October 31, 2025

Description

When connecting an MCP client (Cursor) to a server built with MCP Kotlin SDK 0.7.4, the following sequence occurs:

  1. SSE connection establishes successfully - Server logs show: New SSE connection established and stored with sessionId
  2. Tools and resources register - Server logs show: Registering tool: xxx
  3. Transport starts - Server logs show: Starting transport
  4. POST message handling fails - Client receives empty HTTP 400 response body

Client Error:

Error POSTing to endpoint (HTTP 400): 
Error handling message : Cannot read Json element because of unexpected end of the input at path: $
JSON input: 
(empty)

Reproduction Steps

Minimal Test Server

Created a minimal Hello World MCP server based on official documentation:

package kr.co.metadata.mcp.test

import io.ktor.server.application.*
import io.ktor.server.cio.*
import io.ktor.server.engine.*
import io.modelcontextprotocol.kotlin.sdk.*
import io.modelcontextprotocol.kotlin.sdk.server.*

fun main() {
    embeddedServer(CIO, port = 3057, host = "127.0.0.1") {
        // MCP at Application level (routing doesn't work!)
        mcp {
            Server(
                serverInfo = Implementation(
                    name = "hello-world-test-server",
                    version = "1.0.0"
                ),
                options = ServerOptions(
                    capabilities = ServerCapabilities(
                        tools = ServerCapabilities.Tools(listChanged = true),
                        resources = ServerCapabilities.Resources(subscribe = true, listChanged = true),
                        prompts = ServerCapabilities.Prompts(listChanged = true)
                    )
                )
            ) {
                "This is a simple Hello World MCP test server"
            }.apply {
                // Add a simple hello_world tool
                addTool(
                    name = "hello_world",
                    description = "Returns a hello world message",
                    inputSchema = Tool.Input()
                ) { _ ->
                    CallToolResult(
                        content = listOf(
                            TextContent(
                                text = "Hello, World from MCP Test Server!"
                            )
                        ),
                        isError = false
                    )
                }
            }
        }
    }.start(wait = true)
}

MCP Client Configuration (mcp.json)

{
  "mcpServers": {
    "HelloWorldTest": {
      "url": "http://127.0.0.1:3057/"
    }
  }
}

Expected Behavior

  1. Client connects to SSE endpoint at http://127.0.0.1:3057/
  2. Client receives sessionId via SSE (✅ Works)
  3. Client sends POST request with initialize message
  4. Server responds with proper JSON containing server info and capabilities
  5. Client displays available tools (e.g., hello_world)

Actual Behavior

  1. Client connects to SSE endpoint ✅
  2. Client receives sessionId
  3. Client sends POST request with initialize message ✅
  4. Server responds with HTTP 400 and EMPTY body
  5. Client fails to parse empty JSON and shows error ❌
  6. No tools are displayed in client ❌

Server Logs (Success until POST handling)

01:11:15.975 INFO  [main] io.ktor.server.Application               | Autoreload is disabled because the development mode is off.
01:11:16.001 INFO  [main] io.ktor.server.Application               | Application started in 0.108 seconds.
01:11:16.012 INFO  [DefaultDispatcher-worker-2] io.ktor.server.Application               | Responding at http://127.0.0.1:3057
01:11:22.995 INFO  [DefaultDispatcher-worker-1] i.m.kotlin.sdk.server.KtorServer         | New SSE connection established and stored with sessionId: b421d2a3-ad4d-4f83-b190-2542e52c099b
01:11:22.999 INFO  [DefaultDispatcher-worker-1] i.m.kotlin.sdk.server.Server             | Registering tool: hello_world
01:11:23.000 INFO  [DefaultDispatcher-worker-1] i.m.kotlin.sdk.server.Server             | Registering resource: Hello Resource (test://hello)
✅ Hello World MCP server configured with 1 tool and 1 resource
01:11:23.013 INFO  [DefaultDispatcher-worker-1] i.m.kotlin.sdk.shared.Protocol           | Starting transport

Client Logs (Cursor)

2025-10-31 01:12:07.900 [info] Handling CreateClient action
2025-10-31 01:12:07.900 [info] Creating streamableHttp transport
2025-10-31 01:12:07.900 [info] Connecting to streamableHttp server
2025-10-31 01:12:07.908 [info] No stored tokens found
2025-10-31 01:12:07.917 [error] Client error for command Error POSTing to endpoint (HTTP 400): sessionId query parameter is not provided
2025-10-31 01:12:07.917 [info] Client closed for command
2025-10-31 01:12:07.917 [error] Error connecting to streamableHttp server, falling back to SSE: Error POSTing to endpoint (HTTP 400): sessionId query parameter is not provided
2025-10-31 01:12:07.917 [error] Error connecting to streamableHttp server, falling back to SSE: Error POSTing to endpoint (HTTP 400): sessionId query parameter is not provided
2025-10-31 01:12:07.917 [info] Connecting to SSE server
2025-10-31 01:12:07.924 [info] No stored tokens found
2025-10-31 01:12:07.932 [info] No stored tokens found
2025-10-31 01:12:07.935 [error] Client error for command Error POSTing to endpoint (HTTP 400): Error handling message : Cannot read Json element because of unexpected end of the input at path: $
JSON input: 
2025-10-31 01:12:07.935 [info] Client closed for command
2025-10-31 01:12:07.935 [error] Error connecting to SSE server after fallback: Error POSTing to endpoint (HTTP 400): Error handling message : Cannot read Json element because of unexpected end of the input at path: $
JSON input: 
2025-10-31 01:12:07.943 [info] Handling ListOfferings action, server stored: false
2025-10-31 01:12:07.943 [error] No server info found

Additional Issue: Routing Documentation Incorrect

The official README shows this example for custom routing:

fun Application.module() {
    install(SSE)

    routing {
        route("myRoute") {
            mcp {
                Server(...)
            }
        }
    }
}

This does NOT work. Testing shows:

  • mcp {} at Application level (root /): 200 OK
  • mcp {} inside route("/sse"): 404 Not Found

The mcp {} function appears to be an Application extension, not a Route extension, contradicting the documentation.

Manual Testing Results

# SSE endpoint works - returns sessionId
$ curl http://127.0.0.1:3057/ -N -H "Accept: text/event-stream"
event: endpoint
data: ?sessionId=038c4917-a740-4bec-9bc9-c4946e77294c

# POST with sessionId returns "Session not found" (expected for invalid session, but proves endpoint responds)
$ curl -X POST "http://127.0.0.1:3057/?sessionId=test-session" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
Session not found%

Impact

This bug makes MCP Kotlin SDK 0.7.4 completely unusable with MCP clients:

  • No tools can be registered or called
  • No resources can be accessed
  • No prompts can be used
  • Clients show "Error" status and "No server info found"

Workaround

We suspect SDK 0.6.0 may work correctly based on the release notes showing that 0.7.0 introduced significant changes to SSE handling. We have not tested this yet.

Request

  1. Fix the empty POST response issue - The SDK should return proper JSON responses to client messages
  2. Clarify routing documentation - Either fix route() support or update docs to show it only works at Application level
  3. Add integration tests - Test with actual MCP clients (Cursor, Claude Desktop, etc.) to catch these issues

Full Source Code

Available at: https://github.com/[your-repo]/MCP-Magic (can provide if needed)


Thank you for maintaining this SDK! We're building production applications on top of MCP and would love to help resolve this critical issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions