Project

tsikol

0.0
The project is in a healthy, maintained state
A elegant and easy to use framework for building MCP servers with tools, resources, prompts, middleware, and more
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 2.0
~> 5.0
~> 13.0
~> 1.0

Runtime

~> 2.0
~> 3.0
~> 1.0
 Project Readme

Tsikol - Ruby MCP Framework

A elegant and easy to use framework for building Model Context Protocol (MCP) servers in Ruby.

Features

  • ๐Ÿš€ Rails-like Structure - Familiar project organization with app/tools, app/resources, app/prompts
  • ๐Ÿ”ง Flexible DSL - Define components inline or in separate files
  • ๐Ÿ”„ Full MCP Protocol Support - Tools, Resources, Prompts, Logging, Completion, Sampling
  • ๐Ÿ›ก๏ธ Middleware System - Add cross-cutting concerns like auth, rate limiting, logging
  • ๐Ÿ“Š Built-in Monitoring - Health checks, metrics, error tracking
  • ๐Ÿงช Testing Utilities - Comprehensive test helpers and mock client
  • โšก Hot Reload - Auto-discovery of components
  • ๐Ÿ” Advanced Error Handling - Circuit breakers, error recovery, detailed logging

Installation

Add to your Gemfile:

gem 'tsikol'

Or install directly:

gem install tsikol

CLI Usage

Tsikol includes a powerful CLI tool for scaffolding projects and generating components.

Create a New Project

tsikol new my-mcp-server
cd my-mcp-server
bundle install

This creates a complete project structure with:

  • server.rb - Main server file
  • Gemfile - Dependencies
  • app/ directory structure for components
  • README and .gitignore

Generate Components

The CLI can generate tools, resources, and prompts with automatic server.rb updates:

Generate a Tool

# Basic tool
tsikol generate tool calculate

# Tool with parameters (name:type format)
tsikol generate tool calculate a:number b:number operation:string

# Optional parameters use ? suffix
tsikol generate tool weather_forecast location:string days?:integer units?:string

# Short alias
tsikol g tool my_tool param1:string param2:boolean

Generate a Resource

# Basic resource
tsikol generate resource system_status

# Resource with custom URI (auto-converts underscores to slashes)
tsikol generate resource user_profile  # Creates URI: user/profile

# Short alias
tsikol g resource my_data

Generate a Prompt

# Basic prompt
tsikol generate prompt code_review

# Prompt with arguments
tsikol generate prompt code_review language:string code:string style?:string

# Short alias
tsikol g prompt chat_assistant topic:string context?:string

How the CLI Works

  1. Generates the component file in the appropriate directory:

    • Tools โ†’ app/tools/
    • Resources โ†’ app/resources/
    • Prompts โ†’ app/prompts/
  2. Updates server.rb automatically:

    • Adds the require statement
    • Registers the component in the routes
  3. Smart insertion - Components are grouped by type in server.rb

Example Workflow

# Create a new weather service
tsikol new weather-service
cd weather-service

# Generate tools
tsikol g tool get_current_weather location:string units?:string
tsikol g tool get_forecast location:string days:integer

# Generate resources
tsikol g resource weather_alerts
tsikol g resource service_status

# Generate prompts
tsikol g prompt weather_chat city:string topic:string

# Your server.rb is automatically updated with all components!
./server.rb

Quick Start

Simple Server

#!/usr/bin/env ruby
require 'tsikol'

Tsikol.server "my-server" do
  tool "greet" do |name:|
    "Hello, #{name}!"
  end
  
  resource "status" do
    "Server is running"
  end
  
  prompt "chat" do |topic:|
    "Let's discuss #{topic}"
  end
end

Rails-like Structure

# server.rb
require 'tsikol'

Tsikol.start(name: "weather-service") do
  # Direct class references
  tool GetCurrentWeather
  tool GetForecast
  resource WeatherAlerts
  prompt WeatherChat
end
# app/tools/get_current_weather.rb
class GetCurrentWeather < Tsikol::Tool
  description "Get current weather for a location"
  
  parameter :location do
    type :string
    required
    description "City name"
    
    complete do |partial|
      ["New York", "London", "Tokyo"].select { |c| c.start_with?(partial) }
    end
  end
  
  def execute(location:)
    "Currently 72ยฐF in #{location}"
  end
end

Core Concepts

Tools

Tools are functions that can be called by the MCP client:

# Inline definition
tool "calculate" do |a:, b:, operation: "add"|
  case operation
  when "add" then a + b
  when "subtract" then a - b
  when "multiply" then a * b
  when "divide" then b.zero? ? "Error: Division by zero" : a.to_f / b
  end
end

# Class-based definition
class Calculate < Tsikol::Tool
  description "Perform calculations"
  
  parameter :a do
    type :number
    required
    description "First number"
  end
  
  parameter :b do
    type :number
    required
    description "Second number"
  end
  
  parameter :operation do
    type :string
    optional
    default "add"
    enum ["add", "subtract", "multiply", "divide"]
  end
  
  def execute(a:, b:, operation: "add")
    # Implementation
  end
end

Resources

Resources provide data that can be read by the client:

# Inline definition
resource "config/database" do
  {
    host: ENV['DB_HOST'],
    port: ENV['DB_PORT'],
    name: ENV['DB_NAME']
  }.to_json
end

# Class-based definition
class DatabaseConfig < Tsikol::Resource
  uri "config/database"
  description "Database configuration"
  
  def read
    # Return content
  end
end

Prompts

Prompts generate messages for AI interactions:

# Inline definition
prompt "code_review" do |language:, code:|
  "Review this #{language} code:\n```#{language}\n#{code}\n```"
end

# Class-based definition
class CodeReview < Tsikol::Prompt
  name "code_review"
  description "Generate code review prompt"
  
  argument :language do
    type :string
    required
    complete do |partial|
      ["ruby", "python", "javascript"].select { |l| l.start_with?(partial) }
    end
  end
  
  def get_messages(language:, code:)
    [{
      role: "user",
      content: {
        type: "text",
        text: "Review this #{language} code:\n```#{language}\n#{code}\n```"
      }
    }]
  end
end

Completion (Autocomplete)

Provide intelligent autocomplete suggestions for tool parameters and prompt arguments:

# Tool with parameter completion
class SearchFiles < Tsikol::Tool
  description "Search for files in the project"
  
  parameter :file_type do
    type :string
    required
    description "Type of file to search for"
    
    complete do |partial|
      # Return suggestions based on partial input
      extensions = ["rb", "js", "py", "md", "yml", "json", "xml"]
      extensions.select { |ext| ext.start_with?(partial) }
    end
  end
  
  parameter :directory do
    type :string
    optional
    description "Directory to search in"
    
    complete do |partial|
      # Dynamic completion based on filesystem
      Dir.glob("#{partial}*").select { |f| File.directory?(f) }
    end
  end
  
  def execute(file_type:, directory: ".")
    Dir.glob("#{directory}/**/*.#{file_type}")
  end
end

# Inline completion for tools
tool "database_query" do |table:, operation:|
  "Executing #{operation} on #{table}"
end

# Define completions separately
completion_for "tool", "database_query", "table" do |partial|
  # List available tables
  ["users", "posts", "comments", "tags"].select { |t| t.start_with?(partial) }
end

completion_for "tool", "database_query", "operation" do |partial|
  ["select", "insert", "update", "delete"].select { |op| op.start_with?(partial) }
end

Advanced Features

Middleware

Add cross-cutting concerns with middleware:

Tsikol.server "my-server" do
  # Built-in middleware
  use Tsikol::LoggingMiddleware
  use Tsikol::RateLimitMiddleware, max_requests: 100, window: 60
  use Tsikol::ValidationMiddleware
  
  # Custom middleware
  use AuthMiddleware, api_keys: ["secret-key"]
  
  # Tools, resources, prompts...
end

Lifecycle Hooks

Tsikol.server "my-server" do
  before_start do
    log :info, "Initializing connections..."
    # Setup code
  end
  
  after_start do
    log :info, "Server ready!"
  end
  
  before_stop do
    log :info, "Cleaning up..."
    # Cleanup code
  end
  
  # Tool-specific hooks
  before_tool "critical_operation" do |params|
    log :warning, "About to run critical operation", data: params
  end
  
  after_tool "critical_operation" do |params, result|
    log :info, "Critical operation completed", data: { result: result }
  end
end

Sampling (AI Assistance)

Enable AI-assisted content generation where the MCP server can request help from the AI client:

Tsikol.server "my-server" do
  # Enable sampling and define handler
  on_sampling do |request|
    # The request contains:
    # - messages: Array of conversation messages
    # - model_preferences: Hints about which model to use
    # - system_prompt: Optional system instructions
    # - max_tokens: Maximum response length
    
    # In production, the MCP client (e.g., Claude) handles this
    # For testing, you can simulate responses:
    {
      role: "assistant",
      content: {
        type: "text",
        text: "AI-generated response based on: #{request[:messages].last}"
      }
    }
  end
  
  # Tool that uses AI assistance
  tool "write_documentation" do |code:, style: "technical"|
    # In a real MCP client, this would trigger a sampling request
    prompt = case style
    when "technical"
      "Write technical documentation for this code"
    when "tutorial"
      "Write a beginner-friendly tutorial for this code"
    when "api"
      "Write API reference documentation"
    end
    
    # The actual AI response would come from the client
    "#{prompt}:\n\n```ruby\n#{code}\n```"
  end
  
  # Advanced example with context
  tool "refactor_code" do |code:, goal:|
    # Build conversation for AI
    messages = [
      {
        role: "system",
        content: "You are an expert Ruby developer focused on clean code."
      },
      {
        role: "user",
        content: "Refactor this code to #{goal}:\n\n```ruby\n#{code}\n```"
      }
    ]
    
    # In production, this would send a sampling request
    # with the messages to the MCP client
    "Refactored code would appear here"
  end
end

# Class-based tool with sampling
class CodeGenerator < Tsikol::Tool
  description "Generate code using AI assistance"
  
  parameter :description do
    type :string
    required
    description "What code to generate"
  end
  
  parameter :language do
    type :string
    optional
    default "ruby"
    enum ["ruby", "python", "javascript", "go"]
  end
  
  def execute(description:, language: "ruby")
    # Build sampling request
    sampling_request = {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: "Generate #{language} code that: #{description}"
          }
        }
      ],
      model_preferences: {
        hints: [{ name: "claude-3-sonnet" }],
        temperature: 0.7
      },
      max_tokens: 2000
    }
    
    # This would be sent to the MCP client
    # Response would contain AI-generated code
    "Generated #{language} code for: #{description}"
  end
end

Health Monitoring

Built-in health endpoints are automatically added:

  • resource "health" - Basic health status
  • resource "health/detailed" - Detailed health with metrics
  • resource "metrics" - Raw metrics data

Error Handling

Advanced error handling with circuit breakers:

tool "external_api" do
  # Automatically wrapped with circuit breaker
  # After 5 failures, circuit opens for 60 seconds
  call_external_service
end

Testing

Tsikol includes comprehensive testing utilities:

require 'tsikol/test_helpers'

class MyServerTest < Minitest::Test
  include Tsikol::TestHelpers::Assertions
  
  def setup
    @server = create_my_server
    @client = Tsikol::TestHelpers::TestClient.new(@server)
  end
  
  def test_echo_tool
    @client.initialize_connection
    assert_tool_result(@client, "echo", { "msg" => "Hi" }, "Echo: Hi")
  end
  
  def test_error_handling
    response = @client.call_tool("failing_tool")
    assert_error_response(response, -32603, /Internal error/)
  end
end

Project Structure

my-mcp-server/
โ”œโ”€โ”€ server.rb           # Main entry point
โ”œโ”€โ”€ Gemfile
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ tools/         # Tool classes
โ”‚   โ”œโ”€โ”€ resources/     # Resource classes
โ”‚   โ””โ”€โ”€ prompts/       # Prompt classes
โ”œโ”€โ”€ config/
โ”‚   โ””โ”€โ”€ tsikol.yml     # Configuration (optional)
โ””โ”€โ”€ test/
    โ””โ”€โ”€ server_test.rb # Tests

Examples

See the examples/ directory for complete examples:

  • basic.rb - Simple inline server
  • weather-service/ - Full Rails-like project
  • middleware_example.rb - Middleware demonstration
  • sampling_example.rb - AI assistance
  • advanced_features.rb - All features combined

License

MIT License - see LICENSE file for details.

Acknowledgments

Built for the Model Context Protocol (MCP) by Anthropic.