vector_mcp
A server implementation for the Model Context Protocol (MCP) in Ruby.
Documentation
VectorMCP
VectorMCP is a Ruby implementation of the Model Context Protocol (MCP) server-side specification. It gives you a framework for exposing tools, resources, prompts, roots, sampling, middleware, and security over the MCP streamable HTTP transport.
Highlights
- Streamable HTTP is the built-in transport, with session management, resumability, and MCP 2025-11-25 compliance
- Class-based tools via `VectorMCP::Tool`, plus the original block-based `register_tool` API
- Rack and Rails mounting through `server.rack_app`
- Opt-in authentication and authorization, structured logging, and middleware hooks
- Request-scoped identity: every request is dispatched through its own invocation, so concurrent requests on one session can never observe each other's headers or auth
- Image-aware tools/resources/prompts, roots, and server-initiated sampling
- Token-based field anonymization middleware to keep sensitive values out of LLM context
Requirements
- Ruby 3.2+
Installation
gem install vector_mcpgem "vector_mcp"Quick Start
require "vector_mcp"
class Greet "/mcp"For ActiveRecord-backed tools, opt into `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
endSee docs/rails-setup-guide.md for a full setup guide.
Tools, Resources, and Prompts
Expose callable tools:
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
endExpose readable resources:
server.register_resource(
uri: "file://config.json",
name: "App Configuration",
description: "Current application settings"
) { File.read("config.json") }Define prompt templates:
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` also supports `type: :date` and `type: :datetime`, which are validated as strings in JSON Schema and coerced to `Date` and `Time` before `#call` runs.
Handlers that take a second argument receive the per-request invocation, which exposes session identity, the request's headers/params, and the authenticated user in one place:
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")
}
endResource handlers get the same invocation as their second argument (it also answers the familiar `user` / `authenticated?` / `can?` queries, so handlers written against the older security-context argument keep working unchanged).
Security and Middleware
VectorMCP keeps security opt-in, but the primitives are built in:
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
endCustom authentication works too:
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
endWhen authentication is enabled, VectorMCP applies it centrally to built-in and custom request/notification handlers. Only `initialize`, `ping`, and the `initialized` notification are public; HTTP GET streams and DELETE session requests also require credentials.
For public deployments, enable authentication failure limiting with `rate_limit: true` (10 attempts per 60 seconds by default), or provide `max_attempts`, `window_seconds`, and `max_entries`. Repeated failures are tracked by client IP and a one-way credential fingerprint; blocked requests return HTTP `429`, JSON-RPC `-32029`, and `Retry-After`. The limiter is in-process, so multi-process or distributed deployments should also enforce a shared limit at the proxy or gateway. Generate API keys with at least 256 bits of entropy—for example, `ruby -rsecurerandom -e 'puts SecureRandom.hex(32)'`—and load them from a secret manager or environment variable.
For MCP clients that speak OAuth 2.1 (e.g. Claude Desktop), pass a `resource_metadata_url:` to turn on RFC 9728 discovery. Unauthenticated requests to `/mcp` return `401` with a `WWW-Authenticate` header pointing at the configured metadata document, and the client drives the rest of the OAuth dance automatically. See docs/oauth_resource_server.md for the feature reference and docs/rails_oauth_integration.md for a full Rails + Doorkeeper recipe.
Middleware can hook into tool, resource, prompt, sampling, auth, and transport events, including `before_auth`, `after_auth`, `on_auth_error`, `before_request`, `after_response`, and `on_transport_error`.
See security/README.md for the full security guide.
Field Anonymization
Keep sensitive string values out of the LLM context by substituting them with stable opaque tokens. Values are tokenized on outbound tool results and restored on inbound tool arguments, so the LLM sees only tokens while your handlers receive the original data.
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)Transport Notes
- VectorMCP ships with streamable HTTP as its built-in transport
- `POST /mcp` accepts a single JSON-RPC request, notification, or response; batch arrays are rejected
- `GET /mcp` opens an SSE stream for server-initiated messages
- `DELETE /mcp` terminates the session
- The server advertises MCP protocol `2025-11-25` and accepts `2025-03-26` and `2024-11-05` headers for compatibility
- Default allowed origins are restricted to localhost and loopback addresses
- POST bodies are capped at 16 MiB by default; configure `max_body_bytes:` on `run` or `rack_app` when needed
- For mounted Rack apps, configure the same limit in the fronting web server or reverse proxy so requests are rejected before Rack buffering
Initialize a session with 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"}}}'More Features
- Roots via `register_root` and `register_root_from_path`
- Image resources and image-aware tools/prompts
- Structured logging with component loggers
- Server-initiated sampling with streaming/tool-call support
- Middleware-driven request shaping and observability
Documentation
- 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
- MCP Specification
Contributing
Bug reports and pull requests are welcome on GitHub.
License
Available as open source under the MIT License.
Frequently asked questions
What is vector_mcp?
vector_mcp is A server implementation for the Model Context Protocol (MCP) in Ruby.
How do I install vector_mcp?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is vector_mcp open source?
Yes — it is hosted on GitHub at https://github.com/sergiobayona/vector_mcp and has 13 stars.
Related MCP tools
MCP Aggregator, Orchestrator, Middleware, Gateway in one docker
A Model Context Protocol (MCP) server and CLI that provides tools for agent use when working on iOS and macOS projects.
MCP Aggregator, Orchestrator, Middleware, Gateway in one docker TypeScript-based implementation. Trusted by 1400+ developers.
A Ruby Implementation of the Model Context Protocol
🔥 Official Firecrawl MCP Server - Adds powerful web scraping and search to Cursor, Claude and any other LLM clients.
Fast and Accurate Code Search for Agents. Uses 99% fewer tokens than grep+read
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP