trackmcp
Back to directory
sergiobayona

vector_mcp

View on GitHub

A server implementation for the Model Context Protocol (MCP) in Ruby.

13 stars RubyOthers Updated Aug 17, 2026
mcpmcp-sdkmcp-servermcp-serversmodel-context-protocolmodel-context-protocol-serversruby-gemmodel-context-protocol-sdkruby

Documentation

VectorMCP

Gem Version
Docs
Build Status
Maintainability
License: MIT

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

bash
gem install vector_mcp
ruby
gem "vector_mcp"

Quick Start

ruby
require "vector_mcp"

class Greet  "/mcp"

For ActiveRecord-backed tools, opt into `VectorMCP::Rails::Tool`:

ruby
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

See docs/rails-setup-guide.md for a full setup guide.

Tools, Resources, and Prompts

Expose callable tools:

ruby
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

Expose readable resources:

ruby
server.register_resource(
  uri: "file://config.json",
  name: "App Configuration",
  description: "Current application settings"
) { File.read("config.json") }

Define prompt templates:

ruby
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:

ruby
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

Resource 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:

ruby
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

Custom authentication works too:

ruby
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

When 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.

ruby
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:

bash
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

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

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP