mcprotocol
forked from nobodywasishere/mcprotocolMCProtocol
A Crystal implementation of Anthropic's Model Context Protocol (MCP), providing type-safe bindings for building MCP servers and clients.
What is the Model Context Protocol?
The Model Context Protocol (MCP) is an open standard that enables AI applications to securely connect to various data sources and tools. Think of MCP as a "USB-C port for AI" - it provides a standardized way to connect AI models to:
- Resources: Files, databases, APIs, and other data sources
- Tools: Functions that AI models can execute
- Prompts: Templated interactions and workflows
Features
- Type-Safe: Auto-generated Crystal classes from the official MCP JSON schema
- Complete Protocol Support: All MCP message types, capabilities, and features
- Server & Client Support: Build both MCP servers and clients
- JSON-RPC 2.0: Full compliance with the underlying JSON-RPC protocol
- SSE Compatible: Ready for Server-Sent Events implementations
- Extensible: Easy to extend with custom capabilities
Installation
-
Add the dependency to your
shard.yml
:dependencies: mcprotocol: github: nobodywasishere/mcprotocol
-
Run
shards install
Quick Start
Basic Usage
require "mcprotocol"
# Parse an MCP message
message_data = %{{"method": "initialize", "params": {...}}}
request = MCProtocol.parse_message(message_data)
# Create MCP objects
capabilities = MCProtocol::ServerCapabilities.new(
tools: MCProtocol::ServerCapabilitiesTools.new(listChanged: true),
resources: MCProtocol::ServerCapabilitiesResources.new(subscribe: true)
)
# Handle different message types
case request
when MCProtocol::InitializeRequest
# Handle initialization
when MCProtocol::CallToolRequest
# Handle tool calls
end
Building an MCP Server
require "mcprotocol"
require "json"
class SimpleMCPServer
def initialize
@tools = [
MCProtocol::Tool.new(
name: "echo",
description: "Echo back the input",
inputSchema: MCProtocol::ToolInputSchema.new(
properties: JSON::Any.new({
"message" => JSON::Any.new({
"type" => JSON::Any.new("string"),
"description" => JSON::Any.new("Message to echo")
})
})
)
)
]
end
def handle_initialize(request : MCProtocol::InitializeRequest)
# Return server capabilities
MCProtocol::InitializeResult.new(
protocolVersion: "2024-11-05",
capabilities: MCProtocol::ServerCapabilities.new(
tools: MCProtocol::ServerCapabilitiesTools.new(listChanged: true)
),
serverInfo: MCProtocol::Implementation.new(
name: "simple-server",
version: "1.0.0"
)
)
end
def handle_list_tools(request : MCProtocol::ListToolsRequest)
MCProtocol::ListToolsResult.new(tools: @tools)
end
def handle_call_tool(request : MCProtocol::CallToolRequest)
case request.params.name
when "echo"
message = request.params.arguments.try(&.["message"]?)
MCProtocol::CallToolResult.new(
content: [
MCProtocol::TextContent.new(
type: "text",
text: "Echo: #{message}"
)
]
)
else
raise "Unknown tool: #{request.params.name}"
end
end
end
Server-Sent Events (SSE) Implementation
For SSE-based MCP servers, you can use Crystal's HTTP server:
require "http/server"
require "mcprotocol"
class SSEMCPServer
def initialize(@port : Int32 = 8080)
@server = HTTP::Server.new do |context|
if context.request.path == "/mcp"
handle_mcp_connection(context)
else
context.response.status = HTTP::Status::NOT_FOUND
context.response.print "Not Found"
end
end
end
def start
puts "Starting MCP SSE server on port #{@port}"
@server.bind_tcp(@port)
@server.listen
end
private def handle_mcp_connection(context)
# Set SSE headers
context.response.headers["Content-Type"] = "text/event-stream"
context.response.headers["Cache-Control"] = "no-cache"
context.response.headers["Connection"] = "keep-alive"
context.response.headers["Access-Control-Allow-Origin"] = "*"
# Handle the MCP session
loop do
begin
# Read JSON-RPC messages from the request body or WebSocket
# Parse using MCProtocol.parse_message
# Send responses as SSE events
break if context.response.closed?
rescue ex
puts "Connection error: #{ex.message}"
break
end
end
end
private def send_sse_message(context, data : String, event : String? = nil)
if event
context.response.print "event: #{event}\n"
end
context.response.print "data: #{data}\n\n"
context.response.flush
end
end
# Start the server
server = SSEMCPServer.new
server.start
Protocol Messages
The library includes all MCP protocol message types:
Requests (Client → Server)
InitializeRequest
- Begin connection and capability negotiationListToolsRequest
- Get available toolsCallToolRequest
- Execute a toolListResourcesRequest
- Get available resourcesReadResourceRequest
- Read resource contentListPromptsRequest
- Get available promptsGetPromptRequest
- Get prompt content
Responses (Server → Client)
InitializeResult
- Server capabilities and infoListToolsResult
- Available toolsCallToolResult
- Tool execution resultListResourcesResult
- Available resourcesReadResourceResult
- Resource contentListPromptsResult
- Available promptsGetPromptResult
- Prompt content
Notifications (Bidirectional)
InitializedNotification
- Client ready for requestsProgressNotification
- Progress updatesLoggingMessageNotification
- Log messagesCancelledNotification
- Request cancellation
Available Message Types
The library supports all MCP protocol methods through the METHOD_TYPES
constant:
MCProtocol::METHOD_TYPES.keys
# => ["initialize", "ping", "resources/list", "tools/call", ...]
Architecture
┌─────────────────┐ JSON-RPC 2.0 ┌─────────────────┐
│ MCP Client │ ◄─────────────────► │ MCP Server │
│ (AI Application)│ │ (Your Service) │
└─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ MCProtocol │ │ MCProtocol │
│ Crystal Lib │ │ Crystal Lib │
└─────────────────┘ └─────────────────┘
Key Classes
Core Protocol
MCProtocol::ClientRequest
- Union type for all client requestsMCProtocol::ServerResult
- Union type for all server responsesMCProtocol::ClientNotification
- Union type for client notificationsMCProtocol::ServerNotification
- Union type for server notifications
Capabilities
MCProtocol::ClientCapabilities
- What the client supportsMCProtocol::ServerCapabilities
- What the server provides
Data Types
MCProtocol::Tool
- Tool definitionsMCProtocol::Resource
- Resource definitionsMCProtocol::Prompt
- Prompt templatesMCProtocol::TextContent
- Text contentMCProtocol::ImageContent
- Image content
Error Handling
begin
request = MCProtocol.parse_message(invalid_json)
rescue MCProtocol::ParseError => ex
puts "Failed to parse MCP message: #{ex.message}"
end
Security Considerations
When implementing MCP servers:
- Validate all inputs - Never trust client-provided data
- Implement proper authentication - Use OAuth 2.0 for remote servers
- Limit resource access - Only expose necessary data and tools
- Log security events - Monitor for suspicious activity
- Handle errors gracefully - Don't leak sensitive information
Examples
See the examples/
directory for complete working examples:
- Basic Server: Simple tool and resource server
- SSE Server: Server-Sent Events implementation
- File System Server: Access local files and directories
- Database Server: Query databases through MCP
Development
To regenerate the protocol classes from the schema:
make generate
This runs the code generator using the official MCP JSON schema.
Testing
crystal spec
Contributing
- Fork it (https://github.com/nobodywasishere/mcprotocol/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
License
MIT License - see LICENSE for details.
Related Projects
Contributors
- Margret Riegert - creator and maintainer
mcprotocol
- 0
- 0
- 0
- 0
- 1
- 9 days ago
- May 1, 2025
MIT License
Mon, 02 Jun 2025 10:04:52 GMT