kotlin-sdk/conformance-test
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Pavel Gorgulov 5cb3c1de12
fix: enable DNS rebinding protection by default (#659)
Add `DnsRebindingProtection` Ktor route-scoped plugin and enable it by
default across all http transports

## Motivation and Context
DNS rebinding protection was disabled by default
(`enableDnsRebindingProtection = false`), and sse endpoints
(`Route.mcp()`) had zero protection. Same vulnerability as typescript
sdk
[GHSA-w48q-cv73-mx4w](https://github.com/modelcontextprotocol/typescript-sdk/security/advisories/GHSA-w48q-cv73-mx4w)

## How Has This Been Tested?
all tests pass

## Breaking Changes
- `Route.mcp()`, `Application.mcp()` signatures changed (new
`enableDnsRebindingProtection`, `allowedHosts`, `allowedOrigins`
params), binary incompatible on JVM
- `enableDnsRebindingProtection` default changed from `false` to `true`
on `mcpStreamableHttp`/`mcpStatelessStreamableHttp`
- Default allowed hosts: `localhost`, `127.0.0.1`, `[::1]` — opt out
with `enableDnsRebindingProtection = false`
- Host validation is now port-agnostic (matches ts sdk)
- Origin validation now allows missing `Origin` header (non-browser
clients)
- `Configuration.enableDnsRebindingProtection`, `.allowedHosts`,
`.allowedOrigins` deprecated in favor of the plugin

## Types of changes
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
2026-05-05 11:05:59 +02:00
..
src/main fix: enable DNS rebinding protection by default (#659) 2026-05-05 11:05:59 +02:00
.gitignore feat!: add mcp conformance test infra (#585); add SSE reconnection with retry support (#596) (#585) 2026-03-12 15:44:59 +02:00
build.gradle.kts feat!: add mcp conformance test infra (#585); add SSE reconnection with retry support (#596) (#585) 2026-03-12 15:44:59 +02:00
conformance-baseline.yml fix: apply elicitation schema defaults for missing fields in client response (#661) 2026-04-01 16:31:34 +02:00
README.md fix(conformance): correct SEP-1330 enum schemas in test_elicitation_sep1330_enums (#600) 2026-03-12 17:25:14 +02:00
run-conformance.sh feat: add URL mode elicitation and typed schema definitions per MCP (#660) 2026-04-01 12:20:12 +02:00

MCP Conformance Tests

Conformance tests for the Kotlin MCP SDK. Uses the external @modelcontextprotocol/conformance runner (pinned to 0.1.15) to validate compliance with the MCP specification.

Prerequisites

  • JDK 17+
  • Node.js 18+ and npx (for the conformance runner)
  • curl (used to poll server readiness)

Quick Start

Run all suites (server, client core, client auth) from the project root:

./conformance-test/run-conformance.sh all

Commands

./conformance-test/run-conformance.sh <command> [extra-args...]
Command What it does
list List scenarios available in MCP Conformance Test Framework
server Starts the Ktor conformance server, runs the server test suite against it
client Runs the client test suite (initialize, tools_call, elicitation, sse-retry)
client-auth Runs the client auth test suite (20 OAuth scenarios)
all Runs all three suites sequentially

Any [extra-args] are forwarded to the conformance runner (e.g. --verbose).

What the Script Does

  1. Builds the module via ./gradlew :conformance-test:installDist
  2. For server — starts the conformance server on localhost:3001, polls until ready
  3. Invokes npx @modelcontextprotocol/conformance@0.1.15 with the appropriate arguments
  4. Saves results to conformance-test/results/<command>/
  5. Cleans up the server process on exit
  6. Exits non-zero if any suite fails

Environment Variables

Variable Default Description
MCP_PORT 3001 Port for the conformance server

Project Structure

conformance-test/
├── run-conformance.sh            # Single entry point script
├── conformance-baseline.yml      # Expected failures for known SDK limitations
└── src/main/kotlin/.../conformance/
    ├── ConformanceServer.kt      # Ktor server entry point (StreamableHTTP, DNS rebinding, EventStore)
    ├── ConformanceClient.kt      # Scenario-based client entry point (MCP_CONFORMANCE_SCENARIO routing)
    ├── ConformanceTools.kt       # 18 tool registrations
    ├── ConformanceResources.kt   # 5 resource registrations (static, binary, template, watched, dynamic)
    ├── ConformancePrompts.kt     # 5 prompt registrations (simple, args, image, embedded, dynamic)
    ├── ConformanceCompletions.kt # completion/complete handler
    ├── InMemoryEventStore.kt     # EventStore impl for SSE resumability (SEP-1699)
    └── auth/                     # OAuth client for 20 auth scenarios
        ├── registration.kt       # Scenario handler registration
        ├── utils.kt              # Shared utilities: JSON instance, constants, extractOrigin()
        ├── discovery.kt          # Protected Resource Metadata + AS Metadata discovery
        ├── pkce.kt               # PKCE code verifier/challenge generation + AS capability check
        ├── tokenExchange.kt      # Token endpoint interaction (exchange code, error handling)
        ├── authCodeFlow.kt       # Main Authorization Code flow handler (runAuthClient + interceptor)
        ├── scopeHandling.kt      # Scope selection strategy + step-up 403 handling
        ├── clientRegistration.kt # Client registration logic (pre-reg, CIMD, dynamic)
        ├── JWTScenario.kt              # Client Credentials JWT scenario
        ├── basicScenario.kt            # Client Credentials Basic scenario
        └── crossAppAccessScenario.kt   # Cross-App Access (SEP-990) scenario

Test Suites

Server Suite

Tests the conformance server against all server scenarios:

Category Scenarios
Lifecycle initialize, ping
Tools text, image, audio, embedded, multiple, progress, logging, error, sampling, elicitation, dynamic, reconnection, JSON Schema 2020-12
Resources list, read-text, read-binary, templates, subscribe, dynamic
Prompts simple, with-args, with-image, with-embedded-resource, dynamic
Completions complete
Security DNS rebinding protection

Client Core Suite

Scenario Description
initialize Connect, list tools, close
tools_call Connect, call add_numbers(a=5, b=3), close
elicitation-sep1034-client-defaults Elicitation with applyDefaults capability
sse-retry Call test_reconnection, verify reconnection

Client Auth Suite

17 OAuth Authorization Code scenarios + 2 Client Credentials scenarios (jwt, basic) + 1 Cross-App Access scenario = 20 total.

Note

Auth scenarios are implemented using Ktor's HttpClient plugins (HttpSend interceptor, ktor-client-auth) as a standalone OAuth client. They do not use the SDK's built-in auth support.

Known SDK Limitations

Scenarios, expected to fail due to current SDK limitations, are tracked in conformance-baseline.yml. These failures reveal SDK gaps and are intentionally not fixed in this module.