{"kind":"Skill","metadata":{"namespace":"community","name":"ruby-mcp-server-generator","version":"0.1.0"},"spec":{"description":"Generate a complete Model Context Protocol server project in Ruby using the official MCP Ruby SDK gem.","files":{"SKILL.md":"---\nname: ruby-mcp-server-generator\ndescription: 'Generate a complete Model Context Protocol server project in Ruby using the official MCP Ruby SDK gem.'\n---\n\n# Ruby MCP Server Generator\n\nGenerate a complete, production-ready MCP server in Ruby using the official Ruby SDK.\n\n## Project Generation\n\nWhen asked to create a Ruby MCP server, generate a complete project with this structure:\n\n```\nmy-mcp-server/\n├── Gemfile\n├── Rakefile\n├── lib/\n│   ├── my_mcp_server.rb\n│   ├── my_mcp_server/\n│   │   ├── server.rb\n│   │   ├── tools/\n│   │   │   ├── greet_tool.rb\n│   │   │   └── calculate_tool.rb\n│   │   ├── prompts/\n│   │   │   └── code_review_prompt.rb\n│   │   └── resources/\n│   │       └── example_resource.rb\n├── bin/\n│   └── mcp-server\n├── test/\n│   ├── test_helper.rb\n│   └── tools/\n│       ├── greet_tool_test.rb\n│       └── calculate_tool_test.rb\n└── README.md\n```\n\n## Gemfile Template\n\n```ruby\nsource 'https://rubygems.org'\n\ngem 'mcp', '~\u003e 0.4.0'\n\ngroup :development, :test do\n  gem 'minitest', '~\u003e 5.0'\n  gem 'rake', '~\u003e 13.0'\n  gem 'rubocop', '~\u003e 1.50'\nend\n```\n\n## Rakefile Template\n\n```ruby\nrequire 'rake/testtask'\nrequire 'rubocop/rake_task'\n\nRake::TestTask.new(:test) do |t|\n  t.libs \u003c\u003c 'test'\n  t.libs \u003c\u003c 'lib'\n  t.test_files = FileList['test/**/*_test.rb']\nend\n\nRuboCop::RakeTask.new\n\ntask default: %i[test rubocop]\n```\n\n## lib/my_mcp_server.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nrequire 'mcp'\nrequire_relative 'my_mcp_server/server'\nrequire_relative 'my_mcp_server/tools/greet_tool'\nrequire_relative 'my_mcp_server/tools/calculate_tool'\nrequire_relative 'my_mcp_server/prompts/code_review_prompt'\nrequire_relative 'my_mcp_server/resources/example_resource'\n\nmodule MyMcpServer\n  VERSION = '1.0.0'\nend\n```\n\n## lib/my_mcp_server/server.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nmodule MyMcpServer\n  class Server\n    attr_reader :mcp_server\n    \n    def initialize(server_context: {})\n      @mcp_server = MCP::Server.new(\n        name: 'my_mcp_server',\n        version: MyMcpServer::VERSION,\n        tools: [\n          Tools::GreetTool,\n          Tools::CalculateTool\n        ],\n        prompts: [\n          Prompts::CodeReviewPrompt\n        ],\n        resources: [\n          Resources::ExampleResource.resource\n        ],\n        server_context: server_context\n      )\n      \n      setup_resource_handler\n    end\n    \n    def handle_json(json_string)\n      mcp_server.handle_json(json_string)\n    end\n    \n    def start_stdio\n      transport = MCP::Server::Transports::StdioTransport.new(mcp_server)\n      transport.open\n    end\n    \n    private\n    \n    def setup_resource_handler\n      mcp_server.resources_read_handler do |params|\n        Resources::ExampleResource.read(params[:uri])\n      end\n    end\n  end\nend\n```\n\n## lib/my_mcp_server/tools/greet_tool.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nmodule MyMcpServer\n  module Tools\n    class GreetTool \u003c MCP::Tool\n      tool_name 'greet'\n      description 'Generate a greeting message'\n      \n      input_schema(\n        properties: {\n          name: {\n            type: 'string',\n            description: 'Name to greet'\n          }\n        },\n        required: ['name']\n      )\n      \n      output_schema(\n        properties: {\n          message: { type: 'string' },\n          timestamp: { type: 'string', format: 'date-time' }\n        },\n        required: ['message', 'timestamp']\n      )\n      \n      annotations(\n        read_only_hint: true,\n        idempotent_hint: true\n      )\n      \n      def self.call(name:, server_context:)\n        timestamp = Time.now.iso8601\n        message = \"Hello, #{name}! Welcome to MCP.\"\n        \n        structured_data = {\n          message: message,\n          timestamp: timestamp\n        }\n        \n        MCP::Tool::Response.new(\n          [{ type: 'text', text: message }],\n          structured_content: structured_data\n        )\n      end\n    end\n  end\nend\n```\n\n## lib/my_mcp_server/tools/calculate_tool.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nmodule MyMcpServer\n  module Tools\n    class CalculateTool \u003c MCP::Tool\n      tool_name 'calculate'\n      description 'Perform mathematical calculations'\n      \n      input_schema(\n        properties: {\n          operation: {\n            type: 'string',\n            description: 'Operation to perform',\n            enum: ['add', 'subtract', 'multiply', 'divide']\n          },\n          a: {\n            type: 'number',\n            description: 'First operand'\n          },\n          b: {\n            type: 'number',\n            description: 'Second operand'\n          }\n        },\n        required: ['operation', 'a', 'b']\n      )\n      \n      output_schema(\n        properties: {\n          result: { type: 'number' },\n          operation: { type: 'string' }\n        },\n        required: ['result', 'operation']\n      )\n      \n      annotations(\n        read_only_hint: true,\n        idempotent_hint: true\n      )\n      \n      def self.call(operation:, a:, b:, server_context:)\n        result = case operation\n                 when 'add' then a + b\n                 when 'subtract' then a - b\n                 when 'multiply' then a * b\n                 when 'divide'\n                   return error_response('Division by zero') if b.zero?\n                   a / b.to_f\n                 else\n                   return error_response(\"Unknown operation: #{operation}\")\n                 end\n        \n        structured_data = {\n          result: result,\n          operation: operation\n        }\n        \n        MCP::Tool::Response.new(\n          [{ type: 'text', text: \"Result: #{result}\" }],\n          structured_content: structured_data\n        )\n      end\n      \n      def self.error_response(message)\n        MCP::Tool::Response.new(\n          [{ type: 'text', text: message }],\n          is_error: true\n        )\n      end\n    end\n  end\nend\n```\n\n## lib/my_mcp_server/prompts/code_review_prompt.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nmodule MyMcpServer\n  module Prompts\n    class CodeReviewPrompt \u003c MCP::Prompt\n      prompt_name 'code_review'\n      description 'Generate a code review prompt'\n      \n      arguments [\n        MCP::Prompt::Argument.new(\n          name: 'language',\n          description: 'Programming language',\n          required: true\n        ),\n        MCP::Prompt::Argument.new(\n          name: 'focus',\n          description: 'Review focus area (e.g., performance, security)',\n          required: false\n        )\n      ]\n      \n      meta(\n        version: '1.0',\n        category: 'development'\n      )\n      \n      def self.template(args, server_context:)\n        language = args['language'] || 'Ruby'\n        focus = args['focus'] || 'general quality'\n        \n        MCP::Prompt::Result.new(\n          description: \"Code review for #{language} with focus on #{focus}\",\n          messages: [\n            MCP::Prompt::Message.new(\n              role: 'user',\n              content: MCP::Content::Text.new(\n                \"Please review this #{language} code with focus on #{focus}.\"\n              )\n            ),\n            MCP::Prompt::Message.new(\n              role: 'assistant',\n              content: MCP::Content::Text.new(\n                \"I'll review the code focusing on #{focus}. Please share the code.\"\n              )\n            ),\n            MCP::Prompt::Message.new(\n              role: 'user',\n              content: MCP::Content::Text.new(\n                '[paste code here]'\n              )\n            )\n          ]\n        )\n      end\n    end\n  end\nend\n```\n\n## lib/my_mcp_server/resources/example_resource.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nmodule MyMcpServer\n  module Resources\n    class ExampleResource\n      RESOURCE_URI = 'resource://data/example'\n      \n      def self.resource\n        MCP::Resource.new(\n          uri: RESOURCE_URI,\n          name: 'example-data',\n          description: 'Example resource data',\n          mime_type: 'application/json'\n        )\n      end\n      \n      def self.read(uri)\n        return [] unless uri == RESOURCE_URI\n        \n        data = {\n          message: 'Example resource data',\n          timestamp: Time.now.iso8601,\n          version: MyMcpServer::VERSION\n        }\n        \n        [{\n          uri: uri,\n          mimeType: 'application/json',\n          text: data.to_json\n        }]\n      end\n    end\n  end\nend\n```\n\n## bin/mcp-server Template\n\n```ruby\n#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire_relative '../lib/my_mcp_server'\n\nbegin\n  server = MyMcpServer::Server.new\n  server.start_stdio\nrescue Interrupt\n  warn \"\\nShutting down server...\"\n  exit 0\nrescue StandardError =\u003e e\n  warn \"Error: #{e.message}\"\n  warn e.backtrace.join(\"\\n\")\n  exit 1\nend\n```\n\nMake the file executable:\n```bash\nchmod +x bin/mcp-server\n```\n\n## test/test_helper.rb Template\n\n```ruby\n# frozen_string_literal: true\n\n$LOAD_PATH.unshift File.expand_path('../lib', __dir__)\nrequire 'my_mcp_server'\nrequire 'minitest/autorun'\n```\n\n## test/tools/greet_tool_test.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nrequire 'test_helper'\n\nmodule MyMcpServer\n  module Tools\n    class GreetToolTest \u003c Minitest::Test\n      def test_greet_with_name\n        response = GreetTool.call(\n          name: 'Ruby',\n          server_context: {}\n        )\n        \n        refute response.is_error\n        assert_equal 1, response.content.length\n        assert_match(/Ruby/, response.content.first[:text])\n        \n        assert response.structured_content\n        assert_equal 'Hello, Ruby! Welcome to MCP.', response.structured_content[:message]\n      end\n      \n      def test_output_schema_validation\n        response = GreetTool.call(\n          name: 'Test',\n          server_context: {}\n        )\n        \n        assert response.structured_content.key?(:message)\n        assert response.structured_content.key?(:timestamp)\n      end\n    end\n  end\nend\n```\n\n## test/tools/calculate_tool_test.rb Template\n\n```ruby\n# frozen_string_literal: true\n\nrequire 'test_helper'\n\nmodule MyMcpServer\n  module Tools\n    class CalculateToolTest \u003c Minitest::Test\n      def test_addition\n        response = CalculateTool.call(\n          operation: 'add',\n          a: 5,\n          b: 3,\n          server_context: {}\n        )\n        \n        refute response.is_error\n        assert_equal 8, response.structured_content[:result]\n      end\n      \n      def test_subtraction\n        response = CalculateTool.call(\n          operation: 'subtract',\n          a: 10,\n          b: 4,\n          server_context: {}\n        )\n        \n        refute response.is_error\n        assert_equal 6, response.structured_content[:result]\n      end\n      \n      def test_multiplication\n        response = CalculateTool.call(\n          operation: 'multiply',\n          a: 6,\n          b: 7,\n          server_context: {}\n        )\n        \n        refute response.is_error\n        assert_equal 42, response.structured_content[:result]\n      end\n      \n      def test_division\n        response = CalculateTool.call(\n          operation: 'divide',\n          a: 15,\n          b: 3,\n          server_context: {}\n        )\n        \n        refute response.is_error\n        assert_equal 5.0, response.structured_content[:result]\n      end\n      \n      def test_division_by_zero\n        response = CalculateTool.call(\n          operation: 'divide',\n          a: 10,\n          b: 0,\n          server_context: {}\n        )\n        \n        assert response.is_error\n        assert_match(/Division by zero/, response.content.first[:text])\n      end\n      \n      def test_unknown_operation\n        response = CalculateTool.call(\n          operation: 'modulo',\n          a: 10,\n          b: 3,\n          server_context: {}\n        )\n        \n        assert response.is_error\n        assert_match(/Unknown operation/, response.content.first[:text])\n      end\n    end\n  end\nend\n```\n\n## README.md Template\n\n```markdown\n# My MCP Server\n\nA Model Context Protocol server built with Ruby and the official MCP Ruby SDK.\n\n## Features\n\n- ✅ Tools: greet, calculate\n- ✅ Prompts: code_review\n- ✅ Resources: example-data\n- ✅ Input/output schemas\n- ✅ Tool annotations\n- ✅ Structured content\n- ✅ Full test coverage\n\n## Requirements\n\n- Ruby 3.0 or later\n\n## Installation\n\n```bash\nbundle install\n```\n\n## Usage\n\n### Stdio Transport\n\nRun the server:\n\n```bash\nbundle exec bin/mcp-server\n```\n\nThen send JSON-RPC requests:\n\n```bash\n{\"jsonrpc\":\"2.0\",\"id\":\"1\",\"method\":\"ping\"}\n{\"jsonrpc\":\"2.0\",\"id\":\"2\",\"method\":\"tools/list\"}\n{\"jsonrpc\":\"2.0\",\"id\":\"3\",\"method\":\"tools/call\",\"params\":{\"name\":\"greet\",\"arguments\":{\"name\":\"Ruby\"}}}\n```\n\n### Rails Integration\n\nAdd to your Rails controller:\n\n```ruby\nclass McpController \u003c ApplicationController\n  def index\n    server = MyMcpServer::Server.new(\n      server_context: { user_id: current_user.id }\n    )\n    render json: server.handle_json(request.body.read)\n  end\nend\n```\n\n## Testing\n\nRun tests:\n\n```bash\nbundle exec rake test\n```\n\nRun linter:\n\n```bash\nbundle exec rake rubocop\n```\n\nRun all checks:\n\n```bash\nbundle exec rake\n```\n\n## Integration with Claude Desktop\n\nAdd to `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"my-mcp-server\": {\n      \"command\": \"bundle\",\n      \"args\": [\"exec\", \"bin/mcp-server\"],\n      \"cwd\": \"/path/to/my-mcp-server\"\n    }\n  }\n}\n```\n\n## Project Structure\n\n```\nmy-mcp-server/\n├── Gemfile              # Dependencies\n├── Rakefile             # Build tasks\n├── lib/                 # Source code\n│   ├── my_mcp_server.rb # Main entry point\n│   └── my_mcp_server/   # Module namespace\n│       ├── server.rb    # Server setup\n│       ├── tools/       # Tool implementations\n│       ├── prompts/     # Prompt templates\n│       └── resources/   # Resource handlers\n├── bin/                 # Executables\n│   └── mcp-server       # Stdio server\n├── test/                # Test suite\n│   ├── test_helper.rb   # Test configuration\n│   └── tools/           # Tool tests\n└── README.md            # This file\n```\n\n## License\n\nMIT\n```\n\n## Generation Instructions\n\n1. **Ask for project name and description**\n2. **Generate all files** with proper naming and module structure\n3. **Use classes for tools and prompts** for better organization\n4. **Include input/output schemas** for type safety\n5. **Add tool annotations** for behavior hints\n6. **Include structured content** in responses\n7. **Implement comprehensive tests** for all tools\n8. **Follow Ruby conventions** (snake_case, modules, frozen_string_literal)\n9. **Add proper error handling** with is_error flag\n10. **Provide both stdio and HTTP** usage examples\n"},"import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/tree/541b7819d8c3545c6df122491af4fa1eae415779/plugins/ruby-mcp-development/skills/ruby-mcp-server-generator"}},"content_hash":[54,91,159,185,72,131,203,50,35,9,225,158,80,225,190,128,56,39,1,23,4,4,248,18,45,227,39,214,148,34,81,202],"trust_level":"unsigned","yanked":false}
