Changelog Entry - v0.4.0
View Source[0.4.0] - 2025-10-21
Major Release: Struct-Based API
This release introduces typed Elixir structs throughout the MCP server library, replacing the previous map-based approach. This provides better type safety, improved IDE support, and clearer error messages.
⚠️ Breaking Changes
Router List Functions Now Require conn Parameter and Return Structs
Router list functions have been renamed, now require a conn parameter, and return tuples with typed structs:
tools_list()→list_tools(conn)returns{:ok, [McpServer.Tool.t()]}prompts_list()→prompts_list(conn)returns{:ok, [McpServer.Prompt.t()]}- Resource listing functions now accept
connparameter
Migration: Add conn parameter, handle tuple return, change field access from ["field"] to .field
# Before (v0.3.x)
tools = MyRouter.tools_list()
tool_names = Enum.map(tools, & &1["name"])
# After (v0.4.0+)
{:ok, tools} = MyRouter.list_tools(conn)
tool_names = Enum.map(tools, & &1.name)Controller Functions Now Require conn Parameter
ALL controller functions now require a conn parameter as their first argument:
- Tool functions:
def tool(args)→def tool(conn, args)(arity 1 → 2) - Prompt get functions:
def get(args)→def get(conn, args)(arity 1 → 2) - Prompt complete functions:
def complete(arg, prefix)→def complete(conn, arg, prefix)(arity 2 → 3) - Resource read functions:
def read(opts)→def read(conn, opts)(arity 1 → 2) - Resource complete functions:
def complete(arg, prefix)→def complete(conn, arg, prefix)(arity 2 → 3)
Migration: Add conn as first parameter to ALL controller functions
# Before (v0.3.x) - No conn parameter
def read_file(opts) do
%{
"contents" => [
%{"name" => "file", "uri" => "...", "text" => "..."}
]
}
end
# After (v0.4.0+) - With conn parameter + return struct
def read_file(conn, opts) do
McpServer.Resource.ReadResult.new(
contents: [
content("file", "file:///path", text: "...")
]
)
endController Helpers Now Return Structs
The controller helper functions now return typed structs:
content/3returnsMcpServer.Resource.Content.t()message/3returnsMcpServer.Prompt.Message.t()completion/2returnsMcpServer.Completion.t()
New Features
Comprehensive Struct Types
Added 16 new struct types organized into 5 modules:
Schema Module (McpServer.Schema)
Schema- JSON Schema validation for tool parameters
Tool Module (McpServer.Tool)
Tool- Tool definition with metadataTool.Annotations- Behavioral hints (read_only, idempotent, etc.)
Completion Module (McpServer.Completion)
Completion- Completion suggestions for prompts and resources
Prompt Module (McpServer.Prompt)
Prompt- Prompt template definitionArgument- Prompt argument specificationMessage- Prompt message with role and contentMessageContent- Structured message content (text, image, etc.)
Resource Module (McpServer.Resource and McpServer.ResourceTemplate)
Resource- Static resource definitionResourceTemplate- Templated resource with URI variablesContent- Resource content (text or binary blob)ReadResult- Resource read response wrapper
Helper Functions
All structs include new/1 helper functions for easy construction:
McpServer.Tool.new(
name: "my_tool",
description: "Does something useful",
input_schema: schema,
annotations: annotations
)Automatic JSON Encoding
All structs implement the Jason.Encoder protocol with automatic field name conversion:
- Elixir:
snake_case→ JSON:camelCase mime_type→"mimeType"uri_template→"uriTemplate"has_more→"hasMore"nilfields automatically omitted from JSON
Compile-Time Validation
Structs use @enforce_keys to ensure required fields are provided at compile time:
# Compile error if required fields missing
McpServer.Resource.new(uri: "file:///test")
# ** (KeyError) key :name not found🔧 Improvements
- Type Safety: All return values now have proper type specifications (
@spec) - IDE Support: Better autocomplete and inline documentation
- Error Messages: Clearer errors when fields are missing or incorrect
- Consistency: Unified structure throughout the codebase
- Documentation: Comprehensive docs with examples for all structs
📚 Documentation
New documentation added:
STRUCTURES.md- Complete documentation of all 16 structuresMIGRATION_GUIDE.md- Step-by-step migration guide from v0.3.xQUICK_MIGRATION_REFERENCE.md- Quick reference card for migrationINTEGRATION_SUMMARY.md- Technical implementation detailsROUTER_UPDATE_SUMMARY.md- Router changes documentation
Backward Compatibility
While this is a breaking change in the API, the following remain unchanged:
- Router DSL syntax (
tool,prompt,resourcemacros) - Controller function signatures (still
(conn, args)) - JSON API output format (same structure)
- HTTP transport layer (no changes required)
- Validation logic and error handling
Migration Path
Estimated migration time: 10-30 minutes for most projects
- Update field access:
["field"]→.field - Use controller helpers (already return structs)
- Update test assertions
- Verify JSON output (should be identical)
See MIGRATION_GUIDE.md for detailed instructions.
Bug Fixes
- Fixed inconsistent field naming between maps and JSON
- Fixed missing field validation in controller responses
- Fixed optional field handling (now properly omits
nilvalues)
Internal Changes
- Router macro now generates structs instead of maps
- Eliminated post-processing transformations for resources
- Simplified conditional map building throughout codebase
- Improved code generation in
__before_compile__macro
Notes
This release represents a significant architectural improvement to the MCP server library. While it requires some migration effort, the benefits in type safety, developer experience, and code clarity make it worthwhile.
For questions or issues during migration, please:
- Review the MIGRATION_GUIDE.md
- Check existing tests for examples
- Open an issue on GitHub if you need help
Full Changelog: v0.3.0...v0.4.0