SwaggerMCPTool

A Ruby gem that automatically generates MCP (Model Context Protocol) tools from Swagger/OpenAPI specifications. This gem allows you to create both HTTP and STDIO MCP servers that dynamically generate tools based on API endpoints defined in Swagger/OpenAPI documentation.

Features

  • Automatic Tool Generation: Dynamically creates MCP tools from Swagger/OpenAPI specifications
  • Dual Server Support: Both HTTP server and STDIO server implementations
  • Path Parameter Handling: Properly substitutes path parameters in API endpoints (e.g., /pet/{petId})
  • Multiple Server Types: Supports Puma and other Rack-compatible servers
  • Authentication Support: Token-based authentication with configurable headers
  • Comprehensive Logging: Detailed request/response logging with configurable levels
  • Error Handling: Robust error handling for API failures and edge cases
  • User Context: Passes user context from LLM to API calls
  • Easy Configuration: Simple Ruby-based configuration system
  • Command Line Interface: Built-in CLI for quick server startup

Dependencies

  • Ruby 3.2 or higher
  • Gems:
    • sinatra
    • sinatra-contrib
    • mcp (~> 0.1.0)
    • json
    • puma
    • rackup (~> 2.2)
    • pry (development)
    • rake (development)

Installation

From RubyGems

gem install swagger_mcp_tool

From Source

Clone the repository:

git clone https://github.com/yourusername/swagger_mcp_tool.git
cd swagger_mcp_tool

Build and install the gem:

gem build swagger_mcp_tool.gemspec
gem install swagger_mcp_tool-0.1.0.gem

Using Bundler

Add this line to your application's Gemfile:

gem 'swagger_mcp_tool'

And then execute:

bundle install

Starting the Server

Command Line Interface

The gem provides a command-line executable for quick server startup:

# Start with default settings (Petstore API)
swagger_mcp_server

# Start with custom port and Swagger URL
swagger_mcp_server --port 3001 --swagger-url https://api.example.com/swagger.json

# Show help
swagger_mcp_server --help

Use the provided example for direct integration with MCP clients like Kiro IDE:

File: examples/mcp_stdio_server.rb

#!/usr/bin/env ruby

gem install swagger_mcp_tool
# Load swagger_mcp_tool modules
require 'swagger_mcp_tool'

class WorkingSwaggerMCPStdioServer
  include SwaggerMCPTool::Logging
  include SwaggerMCPTool::Helpers::ToolRegister

  def initialize
    @logger = Logger.new($stderr)
    @logger.level = Logger::INFO
    @logger.info 'Initializing WorkingSwaggerMCPStdioServer with swagger_mcp_tool'

    # Configure the swagger_mcp_tool
    @config = SwaggerMCPTool.configure do |config|
      # to switch to other swagger documentation just change url here
      config.swagger_url = 'https://petstore.swagger.io/v2/swagger.json'
      config.mcp_name = 'swagger_api_tools12'
      config.mcp_name_for_human = 'Swagger API Tools'
      config.mcp_description_for_human = 'Tools for interacting with APIs via Swagger/OpenAPI specifications'
      config.mcp_description_for_model = 'This MCP server provides tools for interacting with APIs via Swagger/OpenAPI specifications.'

        # Add default prompts

    end
    setup_tool_registry
    initialize_tools


    @logger.info 'Configuration set, generating tools using swagger_mcp_tool components'

    # Generate tools using the swagger_mcp_tool components directly
    @tools = tool_registry.dynamic_tools
    @logger.info "Generated #{@tools.size} tools from Swagger specification"

    # Log all tool names
    @tools.each { |tool| @logger.info "Available tool: #{tool.name}" }
  end

  def start_stdio_server
    @logger.info "Starting MCP stdio server with #{@tools.size} tools"

    # Create MCP server with our dynamically generated tools
    mcp_server = MCP::Server.new(
      name: 'swagger_api_tools',
      tools: @tools,
      server_context: { user_id: 1 }
    )

    @logger.info 'MCP server created, starting stdio loop'

    # Handle stdio communication
    $stdin.each_line do |line|
      line = line.strip
      next if line.empty?

      @logger.debug "Received: #{line}"

      # Validate JSON-RPC request format
      begin
        request_data = JSON.parse(line)
        unless request_data.is_a?(Hash) && request_data['jsonrpc'] && request_data['method']
          @logger.error "Invalid JSON-RPC request format: #{line}"
          next
        end
      rescue JSON::ParserError => e
        @logger.error "Invalid JSON in request: #{e.message}"
        next
      end

      # Process the JSON-RPC request
      @logger.info "Processing JSON-RPC request: #{request_data['method']}"
      response = mcp_server.handle_json(line)

      @logger.info "Generated response for method: #{request_data['method']}"

      # Send response to stdout
      puts response
      $stdout.flush
    rescue StandardError => e
      @logger.error "Error processing request: #{e.message}"
      @logger.error "Error class: #{e.class}"
      @logger.error e.backtrace.join("\n")

      # Extract request ID if possible
      request_id = nil
      begin
        parsed_request = JSON.parse(line)
        request_id = parsed_request['id']
      rescue StandardError
        # Ignore parsing errors for error response
      end

      # Send error response
      error_response = {
        jsonrpc: '2.0',
        id: request_id,
        error: {
          code: -32_603,
          message: "Internal error: #{e.message}"
        }
      }

      error_json = error_response.to_json
      @logger.debug "Sending error response: #{error_json}"
      puts error_json
      $stdout.flush
    end
  end
end

# Start the server if this file is executed directly
if __FILE__ == $0
  server = WorkingSwaggerMCPStdioServer.new
  server.start_stdio_server
end

Run the STDIO server:

ruby examples/mcp_stdio_server.rb

HTTP Server

Use the provided example for HTTP-based integration:

File: examples/start_server.rb

#!/usr/bin/env ruby

gem install swagger_mcp_tool


require 'swagger_mcp_tool'
SwaggerMCPTool.configure do |config|
  # Server settings
  config.server_port = 3001
  config.server_bind = '0.0.0.0'

  # Swagger settings
  config.swagger_url = 'https://petstore.swagger.io/v2/swagger.json'

  # MCP settings
  config.mcp_name = 'my_company_api'
  config.mcp_name_for_human = 'My Company API'
  config.mcp_description_for_human = "Tools for interacting with My Company's API"
  config.auth_header_name = :'X-Auth-Token'
end

# Start the server
SwaggerMCPTool.start_server

Run the HTTP server:

ruby examples/start_server.rb

Configuration

The gem uses a singleton Config class for configuration. You can configure it using a block:

SwaggerMCPTool.configure do |config|
  # Server settings
  config.server_port = 3001
  config.server_bind = '0.0.0.0'
  config.server_type = :puma
  config.log_level = Logger::INFO
  config.log_file = 'mcp_server.log'

  # Swagger settings
  config.swagger_url = "https://petstore.swagger.io/v2/swagger.json"

  # MCP settings
  config.mcp_name = "swagger_api_tools"
  config.mcp_name_for_human = "Swagger API Tools"
  config.mcp_description_for_human = "Tools for interacting with APIs via Swagger/OpenAPI specifications"
  config.mcp_description_for_model = "This MCP server provides tools for interacting with APIs via Swagger/OpenAPI specifications."

  # Auth settings
  config.auth_type = "none"  # or "bearer", "basic", etc.
  config.auth_header_name = "Token"  # Default header name for auth
  config.default_token = nil
  config.prompts = []
  config.resources = []
end

Configuration Options

Option Default Description
server_port 3001 HTTP server port
server_bind '0.0.0.0' Server bind address
server_type :puma Server type (Puma, etc.)
log_level Logger::INFO Logging level
log_file 'mcp_server.log' Log file path
swagger_url Petstore demo Swagger/OpenAPI spec URL
mcp_name 'swagger_api_tools' MCP server name
auth_type 'none' Authentication type
auth_header_name 'Token' Auth header name

Working with Prompts

Add Prompts

The gem comes with some built-in prompts that you can use:

SwaggerMCPTool.configure do |config|
  # Add built-in prompts
  config.prompts = ['prompt1', 'prompt2']
end

Adding Resources

You can add resources that will be passed to the MCP server:

SwaggerMCPTool.configure do |config|
  # Add a simple text resource
  config.resources = ['resource1', 'resouce2']
end

MCP Integration

Kiro IDE Integration

To use with Kiro IDE, add the server to your MCP configuration file (.kiro/settings/mcp.json):

{
  "mcpServers": {
    "swagger-mcp-tool": {
      "command": "/Users/ankit/.rbenv/versions/3.2.2/bin/ruby",
      "args": [
        "/Users/ankit/projects/dummy/swagger_mcp_tool/examples/mcp_stdio_server.rb"
      ],
      "env": {
        "RBENV_VERSION": "3.2.2",
        "PATH": "/Users/ankit/.rbenv/versions/3.2.2/bin:/Users/ankit/.rbenv/shims:/usr/local/bin:/usr/bin:/bin"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}

Note: Update the paths to match your Ruby installation and project location.

Generated Tools

The server automatically generates MCP tools based on your Swagger specification. For example, with the Petstore API:

  • getInventory - Get pet inventory by status
  • getPetById - Find pet by ID (handles path parameters)
  • findPetsByStatus - Find pets by status (handles query parameters)
  • addPet - Add a new pet (handles request body)
  • updatePet - Update an existing pet
  • deletePet - Delete a pet
  • getUserByName - Get user by username
  • deleteUser - Delete user

Tool Features

  • Path Parameters: Automatically substitutes {petId} with actual values
  • Query Parameters: Handles array and single-value query parameters
  • Request Bodies: Processes JSON request bodies for POST/PUT operations
  • Error Handling: Returns proper error responses for 404, 400, etc.
  • Type Validation: Validates parameter types based on Swagger schema

Authentication

Setting an Auth Token (HTTP Server)

You can set an auth token for a user by making a POST request to the /set_auth_token endpoint:

curl -X POST http://localhost:3001/set_auth_token \
  -H "Content-Type: application/json" \
  -d '{"user_id": "user123", "auth_token": "Bearer token123"}'

Passing User Context (HTTP Server)

When making requests to the HTTP MCP server, you can pass user context in the headers:

curl -X POST http://localhost:3001/mcp \
  -H "Content-Type: application/json" \
  -H "X-User-ID: user123" \
  -H "X-Username: John Doe" \
  -H "X-Email: [email protected]" \
  -H "X-Auth-Token: Bearer token123" \
  -d '{"jsonrpc":"2.0","id":"1","method":"tools/list"}'

Usage Examples

Using the Examples

The gem includes working examples in the examples/ directory:

  1. STDIO Server: examples/mcp_stdio_server.rb - For MCP client integration
  2. HTTP Server: examples/start_server.rb - For web-based integration
  3. CLI Tool: bin/swagger_mcp_server - Command-line interface

Customizing for Your API

To use with your own API, modify the Swagger URL in the examples:

# In examples/mcp_stdio_server.rb or examples/start_server.rb
SwaggerMCPTool.configure do |config|
  config.swagger_url = 'https://your-api.com/swagger.json'  # Change this
  config.mcp_name = 'your_api_tools'
  config.mcp_name_for_human = 'Your API Tools'
  # ... other configuration
end

Available Endpoints (HTTP Server)

When running the HTTP server, the following endpoints are available:

  • GET /mcp/manifest - MCP manifest for integration
  • POST /mcp - MCP JSON-RPC requests
  • POST /set_auth_token - Set authentication tokens
  • POST /generate_tools - Regenerate tools from Swagger URL
  • GET /health - Health check and server status
  • GET /logo.png - Server logo (if available)

Testing Your Tools

With Kiro IDE

Once configured in Kiro, you can test tools directly:

# Test getInventory (no parameters)
Use the getInventory tool

# Test getPetById (path parameter) 
Use getPetById with petId: 1

# Test findPetsByStatus (query parameter)
Use findPetsByStatus with status: ["available"]

# Test addPet (request body)
Use addPet with name: "Fluffy", photoUrls: ["http://example.com/photo.jpg"], status: "available"

With HTTP Server

Test tools via HTTP requests:

# List available tools
curl -X POST http://localhost:3001/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":"1","method":"tools/list"}'

# Call a tool
curl -X POST http://localhost:3001/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":"1",
    "method":"tools/call",
    "params":{
      "name":"getInventory",
      "arguments":{}
    }
  }'

Expected Tool Output

For the Petstore API, you'll see tools like:

  • getInventory: Returns inventory counts by status

    {
    "available": 487,
    "pending": 10,
    "sold": 22
    }
    
  • getPetById: Returns pet details

    {
    "id": 1,
    "name": "Fluffy",
    "status": "available",
    "photoUrls": ["http://example.com/photo.jpg"]
    }
    

Troubleshooting

Common Issues

  1. Path Parameter Substitution: Ensure your Swagger spec properly defines path parameters like {petId}
  2. Authentication: Check that auth headers are properly configured in your config
  3. CORS Issues: The HTTP server includes CORS headers for web integration
  4. Tool Generation: Verify your Swagger URL is accessible and returns valid JSON
  5. Ruby Version: Ensure you're using Ruby 3.2 or higher

Debug Mode

Enable debug logging in your configuration:

SwaggerMCPTool.configure do |config|
  config.log_level = Logger::DEBUG
end

Checking Logs

  • STDIO Server: Logs go to stderr, check your terminal output
  • HTTP Server: Logs go to the configured log file (default: mcp_server.log)
  • Kiro Integration: Check Kiro's MCP server logs in the IDE

Verifying Tool Generation

Check if tools are being generated correctly:

# Run the STDIO server and check stderr output
ruby examples/mcp_stdio_server.rb

# Look for messages like:
# "Generated 15 tools from Swagger specification"
# "Available tool: getInventory"
# "Available tool: getPetById"

Testing Swagger URL

Verify your Swagger URL is accessible:

curl -s https://petstore.swagger.io/v2/swagger.json | jq .info.title
# Should return: "Swagger Petstore"

Vs code config for stdio

{
  "mcpServers": {
    "fetch": {
      "command": "uvx",
      "args": [
        "mcp-server-fetch"
      ],
      "env": {},
      "disabled": false,
      "autoApprove": []
    },
    "swagger-api-tools": {
      "command": "/Users/<user>/.rbenv/shims/ruby",
      "args": [
        "< absolute path to mcp_stdio_server.rb >"
      ],
      "disabled": false,
      "autoApprove": [
        "getInventory",
        "getPetById",
        "findPetsByStatus"
      ]
    }
  }
}

Architecture

The gem consists of several key components:

  • Config: Singleton configuration management
  • SwaggerClient: Fetches and parses Swagger/OpenAPI specifications
  • ToolGenerator: Converts Swagger operations to tool definitions
  • ApiClient: Handles HTTP requests with proper parameter substitution
  • ToolRegistry: Manages dynamic tool registration
  • Server: HTTP server implementation
  • STDIO Server: Direct MCP integration server

Development

After checking out the repo, run bundle install to install dependencies.

To install this gem onto your local machine, run bundle exec rake install.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/yourusername/swagger_mcp_tool.

License

The gem is available as open source under the terms of the MIT License.