VectorMCP
Una gema de Ruby para construir servidores del Protocolo de Contexto de Modelo (MCP) que exponen herramientas, recursos y avisos a clientes LLM.
Documentación
VectorMCP
VectorMCP es una implementación en Ruby de la especificación del lado del servidor del Protocolo de Contexto de Modelos (MCP). Te proporciona un marco de trabajo para exponer herramientas, recursos, prompts, raíces, muestreo, middleware y seguridad a través del transporte HTTP transmisible de MCP.
Características destacadas
- HTTP transmisible es el transporte integrado, con gestión de sesiones, capacidad de reanudación y cumplimiento con MCP 2025-11-25
- Herramientas basadas en clases mediante
VectorMCP::Tool, además de la API original basada en bloquesregister_tool - Montaje en Rack y Rails a través de
server.rack_app - Autenticación y autorización opcionales, registro estructurado y enlaces de middleware
- Identidad con ámbito de solicitud: cada solicitud se despacha a través de su propia invocación, por lo que las solicitudes concurrentes en una sesión nunca pueden observar los encabezados o la autenticación de las demás
- Herramientas/recursos/prompts conscientes de imágenes, raíces y muestreo iniciado por el servidor
- Middleware de anonimización de campos basado en tokens para mantener los valores sensibles fuera del contexto del LLM
Requisitos
- Ruby 3.2+
Instalación
gem install vector_mcp
gem "vector_mcp"
Inicio rápido
require "vector_mcp"
class Greet < VectorMCP::Tool
description "Say hello to someone"
param :name, type: :string, desc: "Name to greet", required: true
def call(args, _session)
"Hello, #{args["name"]}!"
end
end
server = VectorMCP::Server.new(name: "MyApp", version: "1.0.0")
server.register(Greet)
server.run(port: 8080)
El DSL basado en clases es opcional. La API existente basada en bloques sigue funcionando:
server.register_tool(
name: "echo",
description: "Echo back the supplied text",
input_schema: {
type: "object",
properties: { text: { type: "string" } },
required: ["text"]
}
) { |args| args["text"] }
Rack y Rails
VectorMCP puede ejecutarse como un servidor HTTP independiente o montarse dentro de una aplicación Rack existente:
require "vector_mcp"
server = VectorMCP::Server.new(name: "MyApp", version: "1.0.0")
server.register(Greet)
MCP_APP = server.rack_app
En Rails, móntalo en config/routes.rb:
mount MCP_APP => "/mcp"
Para herramientas respaldadas por ActiveRecord, opta por VectorMCP::Rails::Tool:
require "vector_mcp/rails/tool"
class FindUser < VectorMCP::Rails::Tool
description "Find a user by id"
param :id, type: :integer, required: true
def call(args, _session)
user = find!(User, args[:id])
{ id: user.id, email: user.email }
end
end
Consulta docs/rails-setup-guide.md para obtener una guía completa de configuración.
Herramientas, Recursos y Prompts
Expón herramientas invocables:
server.register_tool(
name: "calculate",
description: "Performs basic math",
input_schema: {
type: "object",
properties: {
operation: { type: "string", enum: ["add", "subtract", "multiply"] },
a: { type: "number" },
b: { type: "number" }
},
required: ["operation", "a", "b"]
}
) do |args|
case args["operation"]
when "add" then args["a"] + args["b"]
when "subtract" then args["a"] - args["b"]
when "multiply" then args["a"] * args["b"]
end
end
Expón recursos legibles:
server.register_resource(
uri: "file://config.json",
name: "App Configuration",
description: "Current application settings"
) { File.read("config.json") }
Define plantillas de prompts:
server.register_prompt(
name: "code_review",
description: "Reviews code for best practices",
arguments: [
{ name: "language", description: "Programming language", required: true },
{ name: "code", description: "Code to review", required: true }
]
) do |args|
{
messages: [{
role: "user",
content: {
type: "text",
text: "Review this #{args["language"]} code:\n\n#{args["code"]}"
}
}]
}
end
VectorMCP::Tool también admite type: :date y type: :datetime, que se validan como cadenas en JSON Schema y se convierten a Date y Time antes de que se ejecute #call.
Los manejadores que aceptan un segundo argumento reciben la invocación por solicitud, que expone la identidad de la sesión, los encabezados/parámetros de la solicitud y el usuario autenticado en un solo lugar:
server.register_tool(
name: "whoami",
description: "Reports the caller's identity",
input_schema: { type: "object", properties: {} }
) do |_args, invocation|
{
session: invocation.id,
user: invocation.user,
api_key_header: invocation.request_header("X-API-Key")
}
end
Los manejadores de recursos reciben la misma invocación como segundo argumento (también responde a las consultas familiares user / authenticated? / can?, por lo que los manejadores escritos contra el argumento de contexto de seguridad anterior siguen funcionando sin cambios).
Seguridad y Middleware
VectorMCP mantiene la seguridad como opcional, pero los primitivos están integrados:
server.enable_authentication!(
strategy: :api_key,
keys: [ENV.fetch("MCP_API_KEY")],
rate_limit: { max_attempts: 10, window_seconds: 60 }
)
server.enable_authorization! do
authorize_tools do |user, _action, tool|
user[:role] == "admin" || !tool.name.start_with?("admin_")
end
end
La autenticación personalizada también funciona:
server.enable_authentication!(strategy: :custom) do |request|
api_key = request[:headers]["X-API-Key"]
user = User.find_by(api_key: api_key)
user ? { user_id: user.id, role: user.role } : false
end
Cuando la autenticación está habilitada, VectorMCP la aplica de forma centralizada a los manejadores de solicitudes/notificaciones integrados y personalizados. Solo initialize, ping y la notificación initialized son públicas; las transmisiones HTTP GET y las solicitudes de eliminación de sesión también requieren credenciales.
Para implementaciones públicas, habilita la limitación de fallos de autenticación con rate_limit: true (10 intentos por 60 segundos por defecto), o proporciona max_attempts, window_seconds y max_entries. Los fallos repetidos se rastrean por IP del cliente y una huella de credencial de un solo sentido; las solicitudes bloqueadas devuelven HTTP 429, JSON-RPC -32029 y Retry-After. El limitador está en proceso, por lo que las implementaciones multiproceso o distribuidas también deben aplicar un límite compartido en el proxy o la puerta de enlace. Genera claves API con al menos 256 bits de entropía—por ejemplo, ruby -rsecurerandom -e 'puts SecureRandom.hex(32)'—y cárgalas desde un gestor de secretos o una variable de entorno.
Para clientes MCP que hablan OAuth 2.1 (por ejemplo, Claude Desktop), pasa un resource_metadata_url: para activar el descubrimiento RFC 9728. Las solicitudes no autenticadas a /mcp devuelven 401 con un encabezado WWW-Authenticate que apunta al documento de metadatos configurado, y el cliente impulsa el resto del flujo OAuth automáticamente. Consulta docs/oauth_resource_server.md para la referencia de características y docs/rails_oauth_integration.md para una receta completa de Rails + Doorkeeper.
El middleware puede engancharse en eventos de herramientas, recursos, prompts, muestreo, autenticación y transporte, incluyendo before_auth, after_auth, on_auth_error, before_request, after_response y on_transport_error.
Consulta security/README.md para la guía completa de seguridad.
Anonimización de Campos
Mantén los valores de cadena sensibles fuera del contexto del LLM sustituyéndolos por tokens opacos estables. Los valores se tokenizan en los resultados de herramientas salientes y se restauran en los argumentos de herramientas entrantes, por lo que el LLM solo ve tokens mientras tus manejadores reciben los datos originales.
anonymizer = VectorMCP::Middleware::Anonymizer.new(
store: VectorMCP::TokenStore.new,
field_rules: [
{ pattern: /email/i, prefix: "EMAIL" },
{ pattern: /\bssn\b/i, prefix: "SSN" }
]
)
anonymizer.install_on(server)
Notas de Transporte
- VectorMCP incluye HTTP transmisible como su transporte integrado
POST /mcpacepta una sola solicitud, notificación o respuesta JSON-RPC; los arreglos por lotes se rechazanGET /mcpabre una transmisión SSE para mensajes iniciados por el servidorDELETE /mcptermina la sesión- El servidor anuncia el protocolo MCP
2025-11-25y acepta los encabezados2025-03-26y2024-11-05para compatibilidad - Los orígenes permitidos por defecto están restringidos a localhost y direcciones de bucle invertido
- Los cuerpos POST están limitados a 16 MiB por defecto; configura
max_body_bytes:enrunorack_appcuando sea necesario - Para aplicaciones Rack montadas, configura el mismo límite en el servidor web frontal o proxy inverso para que las solicitudes se rechacen antes del almacenamiento en búfer de Rack
Inicializa una sesión con curl:
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
Más Características
- Raíces mediante
register_rootyregister_root_from_path - Recursos de imagen y herramientas/prompts conscientes de imágenes
- Registro estructurado con registradores de componentes
- Muestreo iniciado por el servidor con soporte de transmisión/llamada a herramientas
- Modelado de solicitudes y observabilidad impulsados por middleware
Documentación
- CHANGELOG.md
- examples/
- docs/rails-setup-guide.md
- docs/rails_oauth_integration.md
- docs/oauth_resource_server.md
- docs/streamable-http-spec-compliance.md
- security/README.md
- Especificación MCP
Contribuciones
Los informes de errores y las solicitudes de extracción son bienvenidos en GitHub.
Licencia
Disponible como código abierto bajo la Licencia MIT.