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
STDIO Server (Recommended for MCP Integration)
Use the provided example for direct integration with MCP clients like Vscode 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.}"
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.}"
@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.}"
}
}
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 = :'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
Vscode IDE Integration
To use with Vscode IDE, add the server to your MCP configuration file (.vscode/settings/mcp.json
):
{
"mcpServers": {
"swagger-mcp-tool": {
"command": "/Users/<user>/.rbenv/versions/3.2.2/bin/ruby",
"args": [
"/Users/<user>/swagger_mcp_tool/examples/mcp_stdio_server.rb"
],
"env": {
"RBENV_VERSION": "3.2.2",
"PATH": "/Users/<user>/.rbenv/versions/3.2.2/bin:/Users/aki/.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 statusgetPetById
- 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 petdeletePet
- Delete a petgetUserByName
- Get user by usernamedeleteUser
- 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
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 "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:
- STDIO Server:
examples/mcp_stdio_server.rb
- For MCP client integration - HTTP Server:
examples/start_server.rb
- For web-based integration - 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 integrationPOST /mcp
- MCP JSON-RPC requestsPOST /set_auth_token
- Set authentication tokensPOST /generate_tools
- Regenerate tools from Swagger URLGET /health
- Health check and server statusGET /logo.png
- Server logo (if available)
Testing Your Tools
With Vscode IDE
Once configured in Vscode, 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
- Path Parameter Substitution: Ensure your Swagger spec properly defines path parameters like
{petId}
- Authentication: Check that auth headers are properly configured in your config
- CORS Issues: The HTTP server includes CORS headers for web integration
- Tool Generation: Verify your Swagger URL is accessible and returns valid JSON
- 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
) - Vscode Integration: Check Vscode'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.