En este artículo te voy a explicar cómo implementar un servidor MCP en un proyecto Ruby con Sinatra.
Estas son las herramientas que vas a necesitar:
| Herramienta | Descripción | Enlace |
|---|---|---|
| Fast MCP | Gema Ruby para implementar un servidor MCP tanto en Rails como en cualquier solución Rack como Sinatra | https://github.com/yjacquin/fast-mcp |
| MCP Inspector | Es una herramienta que te permite explorar las tools y resources definidas en tu aplicación | https://modelcontextprotocol.io/docs/tools/inspector |
| MCP Remote | Permite configurar Cursor y Claude Desktop con un servidor MCP remoto, usando HTTP y Headers de autorización. Es la forma de tenerlo integrado. | https://www.npmjs.com/package/mcp-remote |
Fast MCP
Es una gema de Ruby que te permite crear un servidor MCP que puedas servir desde tu aplicación Rails o Sinatra.
El objetivo era crear una tool que permitiera interactuar con nuestro dominio de negocio. Queríamos ver cómo podíamos definirla y cómo podíamos hacer que se conectase con la base de datos. Tener una base a partir de la cual pudiéramos construir herramientas más complejas.
class FindCustomerTool < FastMcp::Tool
description 'Busca un cliente por su NIF o pasaporte'
arguments do
required(:document_id).filled(:string).description('El NIF o pasaporte del cliente a buscar')
end
def call(document_id:)
# Create the required services
self.create_services
# Find the customer
customer = @customer_repository.first(conditions: {document_id: document_id})
# Return the customer data
if customer
return { name: customer.name,
surname: customer.surname,
email: customer.email,
phone: customer.phone_number}
else
return nil
end
end
private
def create_services
@customer_repository = Repository::CustomerRepository.new
end
endPara poder publicar la tool necesitamos crear un servidor MCP, registrar la tool y configurar el middleware para la comunicación.
require 'fast_mcp'
# Crea el servidor MCP
mcp_server = FastMcp::Server.new(name: 'my-mcp-server',
version: '1.0.0')
# Registra la tool
mcp_server.register_tool(::FindCustomerTool)
# Configura el middlware
use FastMcp::Transports::AuthenticatedRackTransport, mcp_server, {allowed_origins: [],
localhost_only: false,
auth_token: ENV['MCP_AUTH_TOKEN'],
logger: Infraestructure::Logger.instance.logger}¿Cómo funciona?
FastMcp habilita 2 rutas, GET /mcp/see y POST /mcp/messages.
GET /mcp/see
Utiliza HTTP SSE y permite responder a los clientes. Es un canal de sólo escritura, desde la aplicación se comunica con los clientes.
POST /mcp/messages
Permite descubrir las tools y los resources que ofrece el servidor MCP y hacer llamadas. Utiliza JSON RCP 2.0.
Con esta llamada, mensaje en el BODY, se pueden descubrir todas las rutas disponible.
{
"jsonrpc": "2.0",
"method": "tools/list",
"id": "1"
}Con esta llamada, mensaje en el BODY, se puede ejecutar la tool que hemos creado previamente
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {"name": "FindCustomerTool", "arguments": {"document_id": "55555555K"}},
"id": "1"
}Al hacer estas llamadas con Postman o con curl no recibiremos la respuesta, porque esta se envía a través de SSE por la ruta que se abrirá previamente en /mcp/see.
$ curl -v http://mbcanalysis.test/mcp/sse \ -H "Authorization: 9oFRcMWZPo3JWFmDGC6r23209409f09s09HlgTGBHUeGsb"
$ curl -v http://mbcanalysis.test/mcp/sse \ -H "Authorization: 9oFRcMWZPo3JWFmDGC6r23209409f09s09HlgTGBHUeGsb" * Trying 127.0.0.1:80... * Connected to mbcanalysis.test (127.0.0.1) port 80 (#0) > GET /mcp/sse HTTP/1.1 > Host: mbcanalysis.test > User-Agent: curl/8.1.2 > Accept: */* > Authorization: 9oFRcMWZPo3JWFmDGC6r23209409f09s09HlgTGBHUeGsb > < HTTP/1.1 200 OK < Access-Control-Allow-Headers: Content-Type < Access-Control-Allow-Methods: GET, OPTIONS < Access-Control-Allow-Origin: * < Access-Control-Max-Age: 86400 < Cache-Control: no-cache, no-store, must-revalidate < Content-Type: text/event-stream < Expires: 0 < Pragma: no-cache < X-Accel-Buffering: no < Date: Mon, 12 May 2025 12:13:07 GMT < Transfer-Encoding: chunked < : SSE connection established event: endpoint data: /mcp/messages
Cuando hagamos la llamada a /tools/list desde Postman, observaremos en la sesión abierta de mcp/see lo siguiente:
: keep-alive 49
data: {"jsonrpc":"2.0","id":"1","result":{"tools":[{"name":"FindCustomerTool","description":"Busca un cliente por su NIF o pasaporte","inputSchema":{"type":"object","properties":{"document_id":{"type":"string","description":"El NIF o pasaporte del cliente a buscar"}},"required":["document_id"]}}]}}
: keep-alive 50Conclusiones
La capa de transporte Rack, incluyendo la capa con autenticación, no está preparada para una aplicación en producción. Menos, con las características de nuestra aplicación. Creo que tendremos que escribir nuestra propia capa de transporte. La definición de tools … ha sido correcta.
MCP Inspector
Interactuar con Postman y con el terminal no es cómo. Hay una herramienta que nos permite interactuar con nuestro servidor MCP, listar y usar las tools. Puedes ejecutarlo usando npx sin la necesidad de instalarlo.
$ npx @modelcontextprotocol/inspector
Te has de conectar con una interfaz web desde la que podrás interactuar con servidores MCP, explorar los resources y las tools. Podrás ejecutar estas últimas facilitando los parámetros que defina. Incluso puedes configurar la autenticación con un header Authorization o API-KEY


Integrar las Tools en Claude Desktop o Cursor
Una vez que has conseguido interactuar con tu servidor, viene cómo puedo integrar estas tools para que puedan usarlas agentes. Ahora veremos cómo integrarlas con Claude Desktop o con Cursor.
Si tu servidor MCP está disponible a través de HTTPS no podrás conectar desde Claude Desktop. Además, si tu servidor MCP usa headers para la autenticación, tampoco podrás conectar desde Cursor.
Para resolver este problema, tienes mcp-remote que actúa como un proxy y permite conectarse con tu servidor MCP.
Has de tener en cuenta que si usas nvm para gestionar las diferentes versiones de node, no puedes usar npx como se indicar en los ejemplos sino que has de instalar el paquete y referenciar directamente con la ruta.
Por lo tanto, necesitas instalar mcp-remote, conocer la ruta de node y del programa instalado.
Este comando te permite instalar mcp-remote de forma global
$ npm install -g mcp-remote
Este comando te permite conocer la ubicación de node
$ which node /Users/jgil/.nvm/versions/node/v22.15.0/bin/node
Este comando te permite conocer la ubicación los paquetes instalados por npm
$ npm root -g /Users/jgil/.nvm/versions/node/v22.15.0/lib/node_modules
Con esto podemos preparar este archivo que se usa en Cursor y Claude Desktop para configurar el servidor MCP. Ten en cuenta que has de reemplazar http://mbcanalysis.test/mcp/sse por la ruta en la que está disponible tu servidor mcp.
{
"mcpServers": {
"mybooking": {
"command": "/Users/jgil/.nvm/versions/node/v22.15.0/bin/node",
"args": [
"/Users/jgil/.nvm/versions/node/v22.15.0/lib/node_modules/mcp-remote/dist/proxy.js",
"http://mbcanalysis.test/mcp/sse",
"--allow-http",
"--header",
"Authorization:9oFRcMWZPo3JWFmDGC6r23209409f09s09HlgTGBHUeGsb"
]
}
}
}Probando desde Claude Desktop
Una vez tengas configurado el servidor MCP puedes comprobar si se ha cargado correctamente y las tools que está disponibles.

Cuando hagas una pregunta el propio sistema comprobará si hay alguna tool que pueda dar respuesta a la pregunta y te preguntará si quieres usar una integración externa.

El sistema interactuará con la herramienta a través del servidor MCP para responder.

Problemas con Claude Desktop
No funcionan bien las tools con :: en su nombre. Si usas namespaces y tu herramienta es Mcp::Tool::FindCustomerTool no te funcionará. Dará un error al iniciar claude y el cliente no conectará con el servidor. Hemos de utilizar clases sin namespace. En Cursor no hay problema con ésto.
Referencias
Todos estos artículos me han ayudado a poder llevar a cabo este ejemplo
- https://stanko.io/adding-mcp-to-a-rails-app-NG9zkX3dyPq1
- https://learnitnow.medium.com/bridging-the-gap-connecting-python-ai-agents-to-ruby-apps-with-mcp-614977012399
- https://chanmeng666.medium.com/solution-for-mcp-servers-connection-issues-with-nvm-npm-5529b905e54a
- https://www.reddit.com/r/ruby/comments/1ji41cr/introducing_fastmcp_a_lightweight_ruby/?show=original