Skip to content

Commit ccdddc1

Browse files
author
zoey
authored
chore: update documentation, simplify, more storytelling (#168)
## Problem The documentation was overly complex with 13+ scattered technical pages, making it difficult for users to get started. Internal implementation details were exposed through verbose moduledocs, creating an unnecessarily complex API surface. ## Solution - Consolidated documentation into 5 user-focused pages: home (quick start), building guides, recipes, and reference - Added @\moduledoc false to internal modules (Client.Base, Server.Component, supervisors, registries) - Restructured docs from implementation-focused to goal-oriented (building a client/server) - Enhanced example project READMEs with better explanations ## Rationale Progressive disclosure pattern improves developer experience - simple examples first, then focused guides, finally technical reference. Hiding internal modules reduces cognitive load while maintaining functionality. The new structure prioritizes getting developers productive in minutes rather than explaining implementation details upfront.
1 parent 33f32de commit ccdddc1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1919
-2675
lines changed

.prettierignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/_build/
2+
/deps/
3+
/node_modules/
4+
5+
/priv/dev/upcase/_build/
6+
/priv/dev/upcase/deps/
7+
8+
/priv/dev/ascii/_build/
9+
/priv/dev/ascii/deps/
10+
11+
/priv/dev/echo-elixir/_build/
12+
/priv/dev/echo-elixir/deps/
13+
14+
/priv/dev/client/_build/
15+
/priv/dev/client/deps/

CHANGELOG.md

Lines changed: 69 additions & 73 deletions
Large diffs are not rendered by default.

CLAUDE.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# Hermes MCP Development Guide
22

33
## Build & Test Commands
4+
45
```bash
56
# Setup dependencies
67
mix deps.get
78

8-
# Compile code
9+
# Compile code
910
mix compile --force --warnings-as-errors
1011

1112
# Run all tests
@@ -30,6 +31,7 @@ mix docs
3031
## Core Architecture & Design Patterns
3132

3233
### MCP Protocol Handling
34+
3335
- **Message Processing**: ALWAYS use `Hermes.MCP.Message` for all MCP/JSON-RPC message encoding/decoding
3436
- Use `Message.decode/1` to parse incoming messages
3537
- Use `Message.encode_request/2`, `Message.encode_response/2`, `Message.encode_notification/1`, `Message.encode_error/2`
@@ -40,6 +42,7 @@ mix docs
4042
- Convert between JSON-RPC: `Error.from_json_rpc/1`, `Error.to_json_rpc!/2`
4143

4244
### Transport Layer Architecture
45+
4346
- **Transport Behaviour**: All transports implement `Hermes.Transport.Behaviour`
4447
- Required callbacks: `start_link/1`, `send_message/2`, `shutdown/1`
4548
- Transport modules: `Hermes.Transport.STDIO`, `Hermes.Transport.SSE`, `Hermes.Transport.WebSocket`, `Hermes.Transport.StreamableHTTP`
@@ -48,6 +51,7 @@ mix docs
4851
- Send messages via `transport.layer.send_message(transport.name, data)`
4952

5053
### Client Architecture Patterns
54+
5155
- **State Management**: Use `Hermes.Client.State` for all client state operations
5256
- Create state: `State.new/1`
5357
- Request tracking: `State.add_request_from_operation/3`, `State.remove_request/2`
@@ -59,6 +63,7 @@ mix docs
5963
- ID generation, timing, caller reference management
6064

6165
### Server Architecture Patterns
66+
6267
- **Base Server**: Use `Hermes.Server.Base` as foundation for all MCP servers
6368
- Implement `Hermes.Server.Behaviour` callbacks in your server module
6469
- Required: `init/1`, `handle_request/2`, `handle_notification/2`, `server_info/0`
@@ -68,32 +73,37 @@ mix docs
6873
- Use `Hermes.Server.Transport.STDIO`, `Hermes.Server.Transport.StreamableHTTP`
6974

7075
### OTP Compliance & GenServer Patterns
76+
7177
- **Process Structure**: All core components are GenServers with proper OTP supervision
7278
- **GenServer Naming**: Use `Hermes.genserver_name/1` validator with Peri schemas
73-
- **State Immutability**: Always return updated state from handle_* callbacks
79+
- **State Immutability**: Always return updated state from handle\_\* callbacks
7480
- **Hibernation**: Use `:hibernate` for reduced memory footprint in init
7581
- **Graceful Shutdown**: Implement proper `terminate/2` callbacks with cleanup
7682

7783
### Validation & Schema Patterns
84+
7885
- **Peri Integration**: Use `import Peri` and `defschema` for all validation
7986
- **Option Parsing**: Use `parse_options!/1` pattern for GenServer initialization
8087
- **Schema Definitions**: Define validation schemas as module attributes
8188
- **Custom Validators**: Use `{:custom, &validator_function/1}` for complex validation
8289

8390
### ID Generation & Request Tracking
91+
8492
- **Unique IDs**: Use `Hermes.MCP.ID` for generating request/response IDs
8593
- `ID.generate_request_id/0`, `ID.generate_error_id/0`
8694
- **Timer Management**: Use `Process.send_after/3` for request timeouts
8795
- **Request Lifecycle**: Track requests with timers, cleanup on completion/timeout
8896

8997
### Telemetry & Observability
98+
9099
- **Event Emission**: Use `Hermes.Telemetry` for consistent telemetry events
91100
- Client events: `event_client_init/0`, `event_client_request/0`, `event_client_response/0`
92101
- Server events: `event_server_init/0`, `event_server_request/0`, `event_server_response/0`
93102
- **Logging**: Use `Hermes.Logging` for structured logging
94103
- `client_event/2`, `server_event/2`, `message/4` for protocol message logging
95104

96105
### Testing Patterns
106+
97107
- **MCP Framework**: Use `Hermes.MCP.Case` for comprehensive MCP protocol testing
98108
- Provides builders, setup functions, helpers, and domain-specific assertions
99109
- Reduces test boilerplate by ~90% while maintaining flexibility
@@ -111,16 +121,18 @@ mix docs
111121
- `assert_success/2`, `assert_resources/2`, `assert_tools/2`
112122

113123
## Code Style Guidelines
124+
114125
- **Code Comments**: Only add code comments if strictly necessary, avoid it generally
115126
- **Formatting**: Follow .formatter.exs rules with Peri imports
116127
- **Types**: Use @type/@spec for all public functions
117128
- **Naming**: snake_case for functions, PascalCase modules
118129
- **Imports**: Group imports at top, organize by category (Elixir stdlib, deps, project modules)
119130
- **Documentation**: Include @moduledoc and @doc with examples
120-
- **Error Handling**: Pattern match with {:ok, _} and {:error, reason}
131+
- **Error Handling**: Pattern match with {:ok, \_} and {:error, reason}
121132
- **Testing**: Descriptive test blocks
122-
- **Constants**: Define defaults as module attributes (@default_*)
133+
- **Constants**: Define defaults as module attributes (@default\_\*)
123134
- **Module Structure**: Follow pattern: moduledoc, types, constants, public API, GenServer callbacks, private helpers
124135

125136
### Testing Guidelines
137+
126138
- Always implement test helper modules in @test/support/ context, analyzing if there aren't any existing ones that could be used

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ Firstly, have sure to follow the official MCP (Model Context Protocol) [specific
1717
### Getting Started
1818

1919
1. Clone the repository
20+
2021
```bash
2122
git clone https://github.com/cloudwalk/hermes-mcp.git
2223
cd hermes-mcp
2324
```
2425

2526
2. Install dependencies
27+
2628
```bash
2729
mix setup
2830
```
@@ -74,13 +76,15 @@ mix test
7476
## Submitting Contributions
7577

7678
1. Create a new branch for your feature or bugfix
79+
7780
```bash
7881
git checkout -b feature/your-feature-name
7982
```
8083

8184
2. Make your changes and commit them with clear, descriptive messages
8285

8386
3. Push your branch to GitHub
87+
8488
```bash
8589
git push origin feature/your-feature-name
8690
```

README.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ end
2727
```elixir
2828
# Define a server with tools capabilities
2929
defmodule MyApp.MCPServer do
30-
use Hermes.Server,
31-
name: "My Server",
32-
version: "1.0.0",
30+
use Hermes.Server,
31+
name: "My Server",
32+
version: "1.0.0",
3333
capabilities: [:tools]
3434

3535
@impl true
@@ -65,7 +65,7 @@ forward "/mcp", Hermes.Server.Transport.StreamableHTTP.Plug, server: MyApp.MCPSe
6565

6666
Now you can achieve your MCP server on `http://localhost:<port>/mcp`
6767

68-
### Client
68+
### Client
6969

7070
```elixir
7171
# Define a client module
@@ -78,13 +78,12 @@ end
7878

7979
# Add to your application supervisor
8080
children = [
81-
{MyApp.AnthropicClient,
81+
{MyApp.MCPClient,
8282
transport: {:streamable_http, base_url: "http://localhost:4000"}}
8383
]
8484

8585
# Use the client
86-
{:ok, tools} = MyApp.MCPClient.list_tools()
87-
{:ok, result} = MyApp.MCPClient.call_tool("search", %{query: "elixir"})
86+
{:ok, result} = MyApp.MCPClient.call_tool("echo", %{text: "this will be echoed!"})
8887
```
8988

9089
## Why Hermes?
@@ -95,6 +94,14 @@ Named after Hermes, the Greek god of boundaries and communication, this library
9594

9695
For detailed guides and examples, visit the [official documentation](https://hexdocs.pm/hermes_mcp).
9796

97+
## Examples
98+
99+
We have build some elixir implementation examples using `plug` based and `phoenix` apps:
100+
101+
1. [upcase-server](/priv/dev/upcase/README.md): `plug` based MCP server using streamable_http
102+
2. [echo-elixir](/priv/dev/echo-elixir/README.md): `phoenix` based MCP server using sse
103+
3. [ascii-server](/priv/dev/ascii/README.md): `phoenix_live_view` based MCP server using streamable_http and UI
104+
98105
## License
99106

100107
MIT License. See [LICENSE](./LICENSE) for details.

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
devShells = forAllSystems (pkgs: {
3737
default = pkgs.mkShell {
3838
name = "hermes-mcp-dev";
39-
buildInputs = with pkgs; [
39+
packages = with pkgs; [
4040
elixir-bin."1.19.0-rc.0"
4141
erlang
4242
uv

lib/hermes/client/base.ex

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,5 @@
11
defmodule Hermes.Client.Base do
2-
@moduledoc """
3-
A GenServer implementation of an MCP (Model Context Protocol) client.
4-
5-
This module handles the client-side implementation of the MCP protocol,
6-
including initialization, request/response handling, and maintaining
7-
protocol state.
8-
9-
> ## Notes {: .info}
10-
>
11-
> For initialization and setup, check our [Installation & Setup](./installation.html) and
12-
> the [Client Usage](./client_usage.html) guides for reference.
13-
"""
2+
@moduledoc false
143

154
use GenServer
165
use Hermes.Logging

lib/hermes/client/request.ex

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
11
defmodule Hermes.Client.Request do
2-
@moduledoc """
3-
Represents a pending request in the MCP client.
4-
5-
This struct encapsulates all information about an in-progress request:
6-
- `id` - The unique request ID
7-
- `method` - The MCP method being called
8-
- `from` - The GenServer caller reference
9-
- `timer_ref` - Reference to the request-specific timeout timer
10-
- `start_time` - When the request started (monotonic time in milliseconds)
11-
- `batch_id` - The batch ID if this request is part of a batch (nil for single requests)
12-
"""
2+
@moduledoc false
133

144
@type t :: %__MODULE__{
155
id: String.t(),

lib/hermes/client/supervisor.ex

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,5 @@
11
defmodule Hermes.Client.Supervisor do
2-
@moduledoc """
3-
Supervisor for MCP client processes.
4-
5-
This module manages the lifecycle of both the MCP client and its associated
6-
transport process. It uses a `:one_for_all` strategy, meaning if either the
7-
client or transport crashes, both are restarted together to maintain consistency.
8-
9-
The supervisor automatically:
10-
- Starts the appropriate transport based on configuration
11-
- Starts the client with a reference to the transport
12-
- Ensures proper initialization order (transport first, then client)
13-
- Handles process naming for both client and transport
14-
15-
## Process Naming
16-
17-
- Client process: Uses the module name or custom `:name` option
18-
- Transport process: Named as `Module.concat(ClientName, "Transport")`
19-
20-
## Transport Configuration
21-
22-
Supports all Hermes transport types:
23-
- `:stdio` - For command-line MCP servers
24-
- `:sse` - For Server-Sent Events transports
25-
- `:websocket` - For WebSocket connections
26-
- `:streamable_http` - For streaming HTTP transports
27-
"""
2+
@moduledoc false
283

294
use Supervisor
305

lib/hermes/protocol.ex

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,5 @@
11
defmodule Hermes.Protocol do
2-
@moduledoc """
3-
Protocol version management and feature validation for MCP.
4-
5-
This module handles protocol version compatibility, feature detection,
6-
and transport validation following the MCP specification.
7-
8-
## Protocol Versions
9-
10-
- `2024-11-05`: Initial stable release with SSE and basic features
11-
- `2025-03-26`: Enhanced version with Streamable HTTP, authorization, batching, and extended features
12-
13-
## Examples
14-
15-
iex> Hermes.Protocol.validate_transport("2024-11-05", Hermes.Transport.SSE)
16-
:ok
17-
18-
iex> Hermes.Protocol.validate_transport("2024-11-05", Hermes.Transport.StreamableHTTP)
19-
{:error, %Hermes.MCP.Error{reason: :incompatible_transport}}
20-
21-
iex> Hermes.Protocol.supports_feature?("2025-03-26", :json_rpc_batching)
22-
true
23-
"""
2+
@moduledoc false
243

254
alias Hermes.MCP.Error
265

0 commit comments

Comments
 (0)