From 62e4e50c676405214bb238f10250f2d20b812444 Mon Sep 17 00:00:00 2001 From: Pavel Gorgulov Date: Fri, 20 Mar 2026 15:01:58 +0100 Subject: [PATCH] docs: update AGENTS.md (#612) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve AGENTS.md ## Motivation and Context The previous AGENTS.md contained many elements contradicting [best practices](https://code.claude.com/docs/en/best-practices). AGENTS.md/CLAUDE.md is loaded into the context on every request, so a ~300+ line file is too large and fills the context window. > Keep it concise. For each line, ask: “Would removing this cause Claude to make mistakes?” If not, cut it. Bloated CLAUDE.md files cause Claude to ignore your actual instructions! > Most best practices are based on one constraint: Claude’s context window fills up fast, and performance degrades as it fills. > The over-specified CLAUDE.md. If your CLAUDE.md is too long, Claude ignores half of it because important rules get lost in the noise. Since the file is loaded on every request, it should be general-purpose rather than targeting specific use cases. > CLAUDE.md is loaded every session, so only include things that apply broadly. AI coding agents are used not only for writing tests and implementations. - AGENTS.md should not contain behavioral instructions, especially like `Tests first, always.`. This causes the agent to trigger test runs even when not required, increasing request time and token consumption significantly due to large test outputs. For example, on a simple codebase question, the agent ran the full test suite and I waited over 10 minutes for a response. - `Uphold SOLID principles` — self-evident rules, explaining what SOLID stands for is redundant since AI coding agents are already trained on this knowledge. > Exclude: "Standard language conventions Claude already knows" > Exclude: "Self-evident practices like 'write clean code'" - Mentioning specific MCP servers (jetbrains, intellij-index) can mislead the agent if they are not installed in the environment. Additionally, [Anthropic recommends](https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf) mentioning the use of MCP in skills. - The large Kotest patterns block targets a specific use case and is unnecessary for other agent interactions. Moreover, the agent already looks at neighboring test classes and can learn patterns from existing tests - The large Module documentation block covers a very rare use case. - The KDoc block — the agent can derive this information from the codebase, this should be a skill instead These and other changes follow the best practices. ## Types of changes - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] 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 ## Additional context https://code.claude.com/docs/en/best-practices https://resources.anthropic.com/hubfs/The-Complete-Guide-to-Building-Skill-for-Claude.pdf https://agents.md/#examples --- AGENTS.md | 372 +++++++++--------------------------------------------- CLAUDE.md | 2 +- 2 files changed, 61 insertions(+), 313 deletions(-) mode change 100644 => 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 1646c55..6ef38be 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,334 +1,82 @@ # AGENTS: Development Guidelines for AI Contributors -This document is for autonomous agents and AI copilots contributing code to this repository. -Follow these rules to keep changes safe, comprehensible, and easy to maintain. +This file provides guidance to AI coding agents working with code in this repository. -## Repository Layout +## Project -- `kotlin-sdk-core`: Core protocol types, transport abstractions, serialization utilities -- `kotlin-sdk-client`: Client transports (STDIO, SSE, StreamableHttp, WebSocket) -- `kotlin-sdk-server`: Server transports + Ktor integration (STDIO, SSE, WebSocket) -- `kotlin-sdk`: Umbrella module that aggregates all three above -- `test-utils`: Shared test utilities -- `integration-test`: Integration tests with TypeScript/other implementations -- `conformance-test`: Protocol conformance tests -- `samples/`: Sample projects (composite builds) -- Package structure: `io.modelcontextprotocol.kotlin.sdk.*` -- JVM 11+, Kotlin 2.2+ +Kotlin Multiplatform SDK for the [Model Context Protocol (MCP)](https://modelcontextprotocol.io). Targets JVM, Native (macOS/Linux/Windows), JS, and Wasm. Implements both MCP clients and servers with pluggable transports. -## Prime Directives - -1. **Tests first, always.** - - Before changing code, identify or add tests that express the desired behavior. - - Prefer readable, minimal tests over clever ones. Tests are documentation. -2. **Keep tests simple and explicit.** - - Arrange/Act/Assert structure; avoid hidden magic and overuse of helpers. - - Prefer concrete inputs/outputs; avoid randomness and time dependence. -3. **Uphold SOLID principles** in production code: - - Single Responsibility: each class/function should do one thing well. - - Open/Closed: extend via new code, avoid risky edits to stable code paths. - - Liskov Substitution: honor contracts; keep types substitutable. - - Interface Segregation: keep abstractions small and focused. - - Dependency Inversion: depend on abstractions, not concretions. -4. **Make the minimal change** that satisfies the tests and the issue. - Stay focused on a single concern and avoid "drive-by" changes. -5. **Never commit changes!** It's human who should verify and commit to git. -6. **Keep the build green.** Do not merge changes that break existing tests. -7. **Prefer clarity** over micro-optimizations and cleverness. -8. **Ask when uncertain.** If requirements are ambiguous, request clarification with a concise question. -9. **Write code with the quality of a Kotlin Champion.** -10. **Use MCP servers** like `jetbrains` and `intellij-index` to explore the codebase, for code navigation, analysis, - refactoring, and running tests. -11. **Use the Bash tool for terminal commands** instead of MCP terminal execution features. -12. **Suggest updates** to AGENTS.md/CLAUDE.md with best practices and guidelines. - -## Code Style - -### Kotlin - -- Avoid changing public API signatures. Run `./gradlew apiCheck` before every commit. -- **Explicit API mode** is strict: all public APIs must have explicit visibility modifiers and return types. -- Anything under an `internal` directory is not part of the public API and may change freely. -- Package structure follows: `io.modelcontextprotocol.kotlin.sdk.*` -- Follow Kotlin coding conventions -- Use the provided `.editorconfig` for consistent formatting -- Use Kotlin typesafe DSL builders where possible; prioritize fluent builder style over standard builder methods -- Prefer DSL builder style (method with lambda blocks) over constructors, if possible -- Use `val` for immutable properties and `var` for mutable; consider `lateinit var` instead of nullable types when - appropriate -- Use multi-dollar interpolation prefix for strings where applicable -- Use fully qualified imports instead of star imports -- Ensure backward compatibility when making changes - -## Testing Guidance - -### Test Organization - -- **Location**: `src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/` -- **Platform-specific**: `src/jvmTest/`, `src/jsTest/`, etc. -- **Naming**: Use function `Names with backticks`, e.g., `fun \`should return 200 OK\`()` -- **Structure**: Arrange/Act/Assert pattern -- **Documentation**: Keep tests self-documenting; don't add KDocs to tests. - -### Test Principles - -- Write comprehensive tests for new features. Always add tests for new features or bug fixes, even if not explicitly - requested. -- **Prioritize test readability** -- Avoid creating too many test methods; use parametrized tests when testing multiple similar scenarios -- When running tests on Kotlin Multiplatform projects, run JVM tests only unless asked for other platforms - -### Test Framework Stack - -- **kotlin-test**: Core test framework -- **Kotest assertions**: Use infix style (`shouldBe`, `shouldContain`) instead of `assertEquals`. - - Use `shouldMatchJson` from kotest-assertions-json for JSON validation. - - For nullable objects with nested properties, prefer `shouldNotBeNull { ... }` blocks: - ```kotlin - content.annotations shouldNotBeNull { - priority shouldBe 1.0 - } - ``` -- **mockk**: Mocking library -- **Ktor MockEngine**: For HTTP client mocking (`io.ktor:ktor-client-mock`) -- **Java tests**: Use JUnit5, Mockito, AssertJ core -- **Serialization test utilities** (`io.modelcontextprotocol.kotlin.test.utils`): - - `verifySerialization(value, json, expectedJson)` — serializes, asserts match, round-trips back; use for most serialization tests - - `verifyDeserialization(json, payload)` — deserializes from JSON, re-serializes, asserts match; returns the object for further assertions - - Always test both empty/null/omitted and non-null cases for nullable fields; `McpJson` has `explicitNulls = false` so null properties must be absent from JSON, not `null` - -### Kotest Patterns - -- Basic assertions: Use infix style (`shouldBe`, `shouldContain`) instead of `assertEquals`. - ```kotlin - result shouldBe expected - list shouldContain item - ``` -- Nullable Assertions - ```kotlin - // Preferred: lambda-style for multiple assertions - content.annotations shouldNotBeNull { - priority shouldBe 1.0 - } - ``` - -- JSON Assertions (kotest-assertions-json): - ```kotlin - // language=json - val expected = """ - { - "id": 123 - } - """.trimIndent() - actual shouldEqualJson expected - ``` - -- Soft Assertions - ```kotlin - // Use for multiple assertions on SAME subject - assertSoftly(subject) { - name shouldBe "test" - value shouldBe 42 - } - // DON'T use for different subjects or single assertions - ``` -- Clues (Use Sparingly) - ```kotlin - // Only when assertion is NOT obvious - withClue("Failed to parse response") { - result shouldNotBe null - } - ``` - -#### Avoiding `this.` in Lambda Blocks - -```kotlin -// Avoid explicit `this.` unless necessary for disambiguation -prop.shouldNotBeNull { - enum shouldHaveSize 2 // Preferred - this.enum shouldHaveSize 2 // Avoid -} -``` - -### Multiplatform Patterns - -- Use `expect`/`actual` pattern for platform-specific implementations in `utils.*` files. -- Test changes on JVM first, then verify platform-specific behavior if needed. -- Supported targets: JVM (11+), JS/Wasm, iOS, watchOS, tvOS. - -## Coding Guidance - -### Module Boundaries - -- Respect separation of concerns between modules -- Keep abstractions framework-agnostic -- Avoid leaking implementation details across module boundaries - -### Serialization - -- Use Kotlinx Serialization with explicit `@Serializable` annotations -- JSON config is defined in `jsonUtils.kt` as `McpJson` — use it consistently -- Register custom serializers in companion objects - -### Error Handling - -- Use sealed classes for result states -- Map errors to JSON-RPC error codes in protocol handlers -- Log errors using `io.github.oshai.kotlinlogging.KotlinLogging` -- Never log sensitive data (credentials, tokens) - -### Code Quality - -- Handle nullability and references as established patterns -- Keep changes small and reversible; prefer adding functions over editing many call sites -- Add focused comments **only** where intent is non-obvious -- Use `git mv` command when moving version-controlled files -- Never commit or push changes. This is a Human responsibility. - -## Workflow for AI Agents - -1. **Understand the issue** - - Summarize requirement in 1-2 sentences - - Identify affected files and tests; ask if unclear - -2. **Plan minimal changes** - - Use TaskCreate/TaskUpdate to track work, or EnterPlanMode for complex changes - - Document affected files and approach - -3. **Work with code** - - View, edit, and run tests through MCP tools - -4. **Start with tests** - - Update existing or add new tests in relevant modules - -5. **Implement the change** - - Prefer composition and small functions - - Avoid breaking public APIs without tests and discussion - -6. **Run tests locally** - ```bash - ./gradlew test - ./gradlew :kotlin-sdk-core:test # Specific module - ./gradlew :integration-test:test # Integration tests - ``` - -7. **Verify results** - - Use Kotest JSON matchers for schema validation - - Double-check the readability of code and tests - -8. **Document key decisions** - - Brief notes in markdown document, if requested - -## Build and Run Commands +## Build Commands ```bash -# Build all modules -./gradlew build - -# Run all tests -./gradlew test - -# Run specific module tests -./gradlew :kotlin-sdk-core:test -./gradlew :kotlin-sdk-client:test -./gradlew :kotlin-sdk-server:test - -# Check API compatibility (required before commit) -./gradlew apiCheck - -# Update API dump (after intentional API changes) -./gradlew apiDump - -# Platform-specific tests -./gradlew jsTest -./gradlew wasmJsTest +./gradlew ktlintCheck # Lint check +./gradlew detekt # Static analysis +./gradlew ktlintFormat # Auto-fix lint issues +./gradlew apiCheck # Check public API compatibility (run before committing) +./gradlew apiDump # Update API dump after intentional API changes +./gradlew koverLog # Print coverage summary +./gradlew koverXmlReport # Generate XML coverage report ``` -## Definition of done +Run a single test class: +```bash +./gradlew :kotlin-sdk-server:jvmTest --tests "io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransportTest" +``` -- Tests for affected functionality exist -- All tests pass across all targets -- Changes are focused on a single concern. -- Code respects module boundaries -- `./gradlew apiCheck` passes -- Documentation updated for user-facing changes +Run a single test method: +```bash +./gradlew :kotlin-sdk-core:jvmTest --tests "*.ProtocolTest.should preserve existing meta when adding progress token" +``` -## Documentation +Conformance tests (requires Node.js + npx): +```bash +./conformance-test/run-conformance.sh all # All suites sequentially +./conformance-test/run-conformance.sh server # Server suite only +./conformance-test/run-conformance.sh client # Client core suite (initialize, tools_call, elicitation, sse-retry) +./conformance-test/run-conformance.sh client-auth # Client auth suite (20 OAuth scenarios) +``` -### General Guidelines +## Module Structure -- **Never make up documentation/facts** -- Update README files when adding new features -- Document API changes in the appropriate module -- **Keep documentation concise and straight to the point** -- Always verify documentation matches code; fix discrepancies -- Write tutorials in Markdown format in README.md +``` +kotlin-sdk-core Core: protocol types, JSON-RPC, Transport abstraction, Protocol base class +kotlin-sdk-client Client: MCP client implementation (tools, prompts, resources, sampling) +kotlin-sdk-server Server: MCP server implementation (feature registries, sessions) +kotlin-sdk-testing ChannelTransport for in-memory client-server testing +kotlin-sdk Umbrella module aggregating client + server +test-utils Shared test helpers (mockk, kotest, awaitility) +conformance-test MCP specification compliance tests (external runner) +integration-test End-to-end tests +samples/ Runnable examples (servers and clients) +``` -### KDoc Guidelines +## Architecture -- Properly document interfaces and abstract classes in production code -- Avoid KDocs on override functions to reduce verbosity -- Update KDocs when API changes -- Use references: `[SendMessageRequest]` instead of `SendMessageRequest` -- Add brief code examples to KDocs -- Add links to specifications with verified URLs; never add broken links +Layered design: -### Module.md Files for Dokka +``` +Application (tools, prompts, resources) + → Client / Server (typed MCP operations, capability enforcement) + → Protocol (JSON-RPC framing, request correlation, timeouts) + → Transport (pluggable I/O: stdio, SSE, Streamable HTTP, WebSocket) +``` -Each module must have a `Module.md` file at the module root for Dokka-generated API documentation. +## Code Conventions -**Format Requirements** (per [Dokka specification](https://kotlinlang.org/docs/dokka-module-and-package-docs.html)): +- **Explicit API mode (Strict)**: all public declarations must have explicit visibility modifiers and return types +- **DSL builders**: prefer DSL builder style (lambda blocks) over direct constructors +- **Multi-dollar interpolation**: use `$$"""..."""` for strings containing literal `$` (e.g., JSON with `$ref`, `$defs`) +- **`McpJson` has `explicitNulls = false`**: null properties must be absent from JSON, not `"field": null` +- **Logging**: use `io.github.oshai.kotlinlogging.KotlinLogging` +- **Structured concurrency**: every coroutine must have a bounded scope and lifetime; always re-throw `CancellationException`; never hold `Mutex` across suspension points -- Must start with `# Module module-name` (level 1 header) -- Package documentation uses `# Package package.name` (level 1 header) -- All other content uses level 2+ headers (`##`, `###`, etc.) +## Testing -**Content Guidelines**: +- **JVM first**: run `jvmTest` instead of `test` — full multiplatform test runs are slow and rarely needed during development +- **Test naming**: use backtick syntax — `fun \`should return 200 OK\`()` +- **Frameworks**: JUnit 5 (runner) + Kotest (assertions) + MockK (mocking) + Awaitility (async waits) +- **In-memory testing**: `ChannelTransport.createLinkedPair()` connects client and server without network -- **Purpose**: Provide module-level overview in generated API docs -- **Detail level**: API documentation style (concise, focused on classes/interfaces) -- **Module section**: - - Brief module description (1-2 sentences) - - Platform support (format: "Multiplatform • Kotlin 2.2+" or "JVM only • Kotlin 2.2+") - - Key classes/components (use Dokka references like `[ClassName]`) - - Example (minimal, demonstrating primary usage) -- **Package sections**: Use `# Package package.name` headers with brief description -- **Optional sections**: Features, Limitations, Related Specifications -- **Style**: - - Use bullet points over prose - - Keep examples short (5-15 lines) - - Reference related modules using Dokka links - - Avoid duplicating README content +## Skills -**Example structure (markdown)**: - - # Module module-name - - Brief description. - - **Platform Support:** Multiplatform • Kotlin 2.2+ - - ## Key Classes - - - [MainClass] - what it does - - [HelperClass] - what it does - - ## Example - - ```kotlin - val example = MainClass() - ``` - - # Package package.name - - Package description. - - # Package another.package - - Another package description. - -## When to Ask for Help - -- Requirements conflict with existing tests or documentation -- The smallest change still requires altering core abstractions -- Unclear expected schema shape for a new feature—ask for a concrete, readable test case to anchor implementation +- `/mcp-docs` — fetches live MCP specification and docs; use when implementing or debugging MCP protocol features diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 43c994c..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -@AGENTS.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file