VectorMCP
Uma gem Ruby para construir servidores Model Context Protocol (MCP) que expõem ferramentas, recursos e prompts para clientes LLM.
Documentação
VectorMCP
O VectorMCP é uma implementação em Ruby da especificação do lado do servidor do Model Context Protocol (MCP). Ele fornece uma estrutura para expor ferramentas, recursos, prompts, raízes, amostragem, middleware e segurança sobre o transporte HTTP streamable do MCP.
Destaques
- HTTP streamable é o transporte integrado, com gerenciamento de sessão, retomabilidade e conformidade com MCP 2025-11-25
- Ferramentas baseadas em classes via
VectorMCP::Tool, além da API original baseada em blocosregister_tool - Montagem em Rack e Rails através de
server.rack_app - Autenticação e autorização opcionais, registro estruturado e hooks de middleware
- Identidade com escopo de requisição: cada requisição é despachada por meio de sua própria invocação, então requisições concorrentes em uma mesma sessão nunca podem observar os cabeçalhos ou a autenticação umas das outras
- Ferramentas/recursos/prompts com suporte a imagens, raízes e amostragem iniciada pelo servidor
- Middleware de anonimização de campos baseado em tokens para manter valores sensíveis fora do contexto do LLM
Requisitos
- Ruby 3.2+
Instalação
gem install vector_mcp
gem "vector_mcp"
Início 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)
O DSL baseado em classes é opcional. A API existente baseada em blocos ainda funciona:
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 e Rails
O VectorMCP pode ser executado como um servidor HTTP autônomo ou montado dentro de um aplicativo Rack existente:
require "vector_mcp"
server = VectorMCP::Server.new(name: "MyApp", version: "1.0.0")
server.register(Greet)
MCP_APP = server.rack_app
No Rails, monte-o em config/routes.rb:
mount MCP_APP => "/mcp"
Para ferramentas com suporte a ActiveRecord, opte 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
Consulte docs/rails-setup-guide.md para um guia completo de configuração.
Ferramentas, Recursos e Prompts
Exponha ferramentas chamáveis:
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
Exponha recursos legíveis:
server.register_resource(
uri: "file://config.json",
name: "App Configuration",
description: "Current application settings"
) { File.read("config.json") }
Defina modelos de prompt:
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 também suporta type: :date e type: :datetime, que são validados como strings no JSON Schema e convertidos para Date e Time antes de #call ser executado.
Handlers que recebem um segundo argumento recebem a invocação por requisição, que expõe a identidade da sessão, os cabeçalhos/parâmetros da requisição e o usuário autenticado em um só 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
Handlers de recursos recebem a mesma invocação como segundo argumento (ela também responde às consultas familiares user / authenticated? / can?, então handlers escritos para o argumento de contexto de segurança mais antigo continuam funcionando sem alterações).
Segurança e Middleware
O VectorMCP mantém a segurança como opcional, mas os primitivos são 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
Autenticação personalizada também 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
Quando a autenticação está habilitada, o VectorMCP a aplica centralmente a handlers de requisição/notificação integrados e personalizados. Apenas initialize, ping e a notificação initialized são públicos; streams HTTP GET e requisições de exclusão de sessão também exigem credenciais.
Para implantações públicas, habilite a limitação de falhas de autenticação com rate_limit: true (10 tentativas por 60 segundos por padrão), ou forneça max_attempts, window_seconds e max_entries. Falhas repetidas são rastreadas por IP do cliente e uma impressão digital unidirecional de credenciais; requisições bloqueadas retornam HTTP 429, JSON-RPC -32029 e Retry-After. O limitador é em processo, então implantações multiprocesso ou distribuídas também devem impor um limite compartilhado no proxy ou gateway. Gere chaves de API com pelo menos 256 bits de entropia—por exemplo, ruby -rsecurerandom -e 'puts SecureRandom.hex(32)'—e carregue-as de um gerenciador de segredos ou variável de ambiente.
Para clientes MCP que falam OAuth 2.1 (por exemplo, Claude Desktop), passe um resource_metadata_url: para ativar a descoberta RFC 9728. Requisições não autenticadas para /mcp retornam 401 com um cabeçalho WWW-Authenticate apontando para o documento de metadados configurado, e o cliente conduz o restante do fluxo OAuth automaticamente. Consulte docs/oauth_resource_server.md para a referência de recursos e docs/rails_oauth_integration.md para uma receita completa de Rails + Doorkeeper.
O middleware pode se conectar a eventos de ferramenta, recurso, prompt, amostragem, autenticação e transporte, incluindo before_auth, after_auth, on_auth_error, before_request, after_response e on_transport_error.
Consulte security/README.md para o guia completo de segurança.
Anonimização de Campos
Mantenha valores de string sensíveis fora do contexto do LLM substituindo-os por tokens opacos estáveis. Os valores são tokenizados em resultados de ferramentas de saída e restaurados em argumentos de ferramentas de entrada, então o LLM vê apenas tokens enquanto seus handlers recebem os dados originais.
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
- O VectorMCP vem com HTTP streamable como transporte integrado
POST /mcpaceita uma única requisição, notificação ou resposta JSON-RPC; arrays em lote são rejeitadosGET /mcpabre um stream SSE para mensagens iniciadas pelo servidorDELETE /mcpencerra a sessão- O servidor anuncia o protocolo MCP
2025-11-25e aceita cabeçalhos2025-03-26e2024-11-05para compatibilidade - Origens permitidas por padrão são restritas a localhost e endereços de loopback
- Corpos POST são limitados a 16 MiB por padrão; configure
max_body_bytes:emrunourack_appquando necessário - Para aplicativos Rack montados, configure o mesmo limite no servidor web frontal ou proxy reverso para que requisições sejam rejeitadas antes do buffer do Rack
Inicialize uma sessão com 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"}}}'
Mais Recursos
- Raízes via
register_rooteregister_root_from_path - Recursos de imagem e ferramentas/prompts com suporte a imagens
- Registro estruturado com loggers de componentes
- Amostragem iniciada pelo servidor com suporte a streaming/chamada de ferramenta
- Modelagem de requisições e observabilidade orientadas por middleware
Documentação
- 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
- Especificação MCP
Contribuindo
Relatórios de bugs e pull requests são bem-vindos no GitHub.
Licença
Disponível como código aberto sob a Licença MIT.