ruby-sdk/AGENTS.md
Koichi ITO 636e494068 Add a rake docs:preview task serving the docs site locally
## Motivation and Context

The documentation site under `docs/` had no development command: previewing a change meant hand-assembling
a Jekyll environment, since the site only builds for real when a release publishes it through
`bin/generate-gh-pages.sh` and the GitHub Pages runtime. `rake docs:preview` now builds and serves
the site at http://localhost:4000 (override with `PORT`), with watch-based rebuilds on edit.

The preview dependencies live in their own `docs/Gemfile` rather than the gem's Gemfile:
`github-pages` mirrors the runtime that builds the released site (jekyll-remote-theme,
jekyll-redirect-from, and the Jekyll version Pages actually runs), which keeps the preview faithful
but is far too heavy to impose on the gem itself. The task subshells into that bundle with
`Bundler.with_unbundled_env`, the same delegation shape the conformance tasks use for npx.
Two support pieces keep the pinned toolchain running on current Ruby. `docs/_preview/taint_shim.rb` restores
the taint API as no-ops: Liquid 4.0.3 calls `obj.tainted?` on every variable render,
ahead of its own lax-mode check (`liquid/variable.rb:124`), so on Ruby 3.2 and later,
where the taint API was removed, the first layout render dies with NoMethodError, while on Ruby 3.1
and earlier the methods still exist as deprecated no-ops and the shim is inert. The shim is loaded only into
the preview process via RUBYOPT. The former default gems the pinned Jekyll expects are listed in the docs Gemfile.
The task also regenerates `docs/_data/versions.yml` from the version tags, mirroring what `bin/generate-gh-pages.sh`
produces at deploy time, so the nav footer shows the released-gem version line exactly as it does on the published site.
Build products and the generated data file are ignored.

## How Has This Been Tested?

By running the task on a spare port and verifying the served pages, the footer's version line,
and that a SIGINT stops it cleanly with exit 0; `git status` stays clean while it runs (all build products ignored).
Verified on both Ruby 3.1.5 (shim inert) and Ruby 4.0.6, where a shimless build reproduces the NoMethodError
and the task runs green with the shim. RuboCop and the full suite are green.

## Breaking Changes

None. The task and its Gemfile are development-only additions; the gem and its dependencies are untouched.
2026-08-25 12:36:54 +09:00

5.8 KiB

AGENTS.md

Project overview

This is the official Ruby SDK for the Model Context Protocol (MCP), implementing both server and client functionality for JSON-RPC 2.0 based communication between LLM applications and context providers.

Dev environment setup

  • Ruby 3.2.0+ required to run the full test suite, including all Sorbet-related features
  • Run bundle install to install dependencies
  • Dependencies: json-schema >= 4.1 - Schema validation

Build and test commands

  • bundle install - Install dependencies
  • rake test - Run all tests
  • rake rubocop - Run linter
  • rake - Run tests and linting (default task)
  • bundle exec rake conformance - Run the MCP conformance suite (see conformance/README.md)
  • bundle exec rake docs:preview - Serve the documentation site locally at http://localhost:4000 (PORT to override)
  • ruby -I lib -I test test/path/to/specific_test.rb - Run single test file
  • gem build mcp.gemspec - Build the gem

Testing instructions

  • Test files are in test/ directory with _test.rb suffix
  • Run full test suite with rake test
  • Run individual tests with ruby -I lib -I test test/path/to/file_test.rb
  • Tests should pass before submitting PRs

Code style guidelines

  • Follow RuboCop rules (run rake rubocop)
  • Use frozen string literals
  • Follow Ruby community conventions
  • Keep dependencies minimal
  • Use lowercase HTTP response header names (e.g. mcp-session-id); the Rack 3 SPEC requires this, and the MCP spec's Mcp-Session-Id casing is prose convention only

Documentation

  • User-facing documentation lives in docs/, one page per topic, published at https://ruby.sdk.modelcontextprotocol.io (deploys only when a release is published)
  • Pages live in the docs/_server/, docs/_client/, and docs/_extensions/ collections
  • Keep README.md slim: quick start and pointers only; document features on the relevant docs page
  • Internal links are absolute and extensionless (e.g. /server/tools/); front matter is followed by a blank line before the h1
  • Callout tiers: .note (supplementary), .important (spec constraints), .warning (deprecated features)

Commit message conventions

  • Use conventional commit format when possible
  • Include clear, descriptive commit messages
  • Releases are triggered by updating version in lib/mcp/version.rb and merging to main

Release process

  • Follow Keep a Changelog format in CHANGELOG.md
  • Update CHANGELOG.md before cutting releases
  • Use git history and PR merge commits to construct changelog entries
  • Format entries as: "Terse description of the change (#nnn)"
  • Keep entries in flat list format (no nesting)
  • Git tags mark commits that cut new releases
  • Exclude maintenance PRs that don't concern end users
  • Check upstream remote for PRs if available

Architecture overview

Core Components

MCP::Server (lib/mcp/server.rb):

  • Main server class handling JSON-RPC requests and holding shared configuration (tools, prompts, resources, handlers, capabilities)
  • Implements MCP protocol methods: initialize, ping, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read
  • Supports custom method registration via define_custom_method
  • Handles instrumentation, exception reporting, and notifications
  • Uses JsonRpcHandler for request processing

MCP::ServerSession (lib/mcp/server_session.rb):

  • Per-connection state: client info, logging level
  • Created by the transport layer for each client connection
  • Delegates request handling to the shared Server

MCP::Client (lib/mcp/client.rb):

  • Client interface for communicating with MCP servers
  • Transport-agnostic design with pluggable transport layers
  • Supports tool listing and invocation

Transport Layer:

  • MCP::Server::Transports::StdioTransport - Command-line stdio transport
  • MCP::Server::Transports::StreamableHttpTransport - HTTP with streaming support
  • MCP::Client::HTTP - HTTP client transport (requires faraday gem)

Protocol Components:

  • MCP::Tool - Tool definition with input/output schemas and annotations
  • MCP::Prompt - Prompt templates with argument validation
  • MCP::Resource - Resource registration and retrieval
  • MCP::Configuration - Global configuration with exception reporting and instrumentation

Key Patterns

Three Ways to Define Components:

  1. Class inheritance (e.g., class MyTool < MCP::Tool)
  2. Define methods (e.g., MCP::Tool.define(name: "my_tool") { ... })
  3. Server registration (e.g., server.define_tool(name: "my_tool") { ... })

Schema Validation:

  • Tools support input_schema and output_schema for JSON Schema validation
  • Protocol version 2025-03-26+ supports tool annotations (destructive_hint, idempotent_hint, etc.)
  • Validation is configurable via configuration.validate_tool_call_arguments

Session Architecture:

  • Server holds shared configuration (tools, prompts, resources, handlers)
  • ServerSession holds per-connection state (client info, logging level)
  • Both StdioTransport and StreamableHTTPTransport create a ServerSession per connection, making the session model transparent across transports
  • Session-scoped notifications (notify_progress, notify_log_message) are sent only to the originating client via ServerSession
  • Server-wide notifications (notify_tools_list_changed, etc.) broadcast to all sessions via Server

Context Passing:

  • server_context hash passed through tool/prompt calls for request-specific data
  • Methods can accept server_context: keyword argument for accessing context

Integration patterns

  • Rails/Rack apps: Mount StreamableHTTPTransport as a Rack app (e.g., mount transport => "/mcp")
  • Command-line tools: Use StdioTransport.new(server).open for CLI applications
  • HTTP services: Use StreamableHTTPTransport for web-based servers