0

Phát triển MCP cục bộ với Ruby và Gemini CLI

Thời đại này, biết sử dụng AI thôi chưa đủ; cái "chất" thực sự nằm ở việc bạn biết cách tự xây dựng Giao thức Ngữ cảnh Mô hình (MCP) cho riêng mình.

Python từ lâu đã thống trị lĩnh vực AI và học máy. Tuy nhiên, một ưu điểm lớn của Giao thức Ngữ cảnh Mô hình (MCP) là các chi tiết triển khai của nó không phụ thuộc vào ngôn ngữ lập trình. Không phải dự án nào cũng dựa trên Python, và MCP cho phép các nhà phát triển sử dụng ngôn ngữ quen thuộc của họ để kết nối với các năng lực AI mới nhất.

image.png

Mục tiêu của bài viết này là xây dựng một máy chủ Ruby MCP Stdio tối thiểu và tương tác cục bộ với nó thông qua Gemini CLI.

Tại sao chọn Ruby?

Ruby là một ngôn ngữ lập trình động, đa năng, nổi tiếng với sự chú trọng vào tính đơn giản và năng suất phát triển. Đây là một ngôn ngữ hướng đối tượng mã nguồn mở, được thiết kế với cú pháp thanh lịch, đọc tự nhiên và viết dễ dàng. Thông qua MCP, mã Ruby có thể kết nối liền mạch với các Mô hình Ngôn ngữ Lớn (LLM), đóng vai trò là cầu nối giữa dữ liệu cục bộ và AI.

Quản lý phiên bản Ruby

Do Ruby được triển khai rộng rãi, việc quản lý phiên bản ngôn ngữ trên các nền tảng khác nhau và bảo trì các phiên bản được hỗ trợ có thể gặp nhiều khó khăn. Thông thường, các nhà phát triển sử dụng các công cụ quản lý phiên bản như RVM hoặc rbenv.

Tuy nhiên, quá trình cài đặt các công cụ này thường liên quan đến các bước phức tạp như xác minh khóa GPG và biên dịch mã nguồn. Đối với người mới bắt đầu hoặc các nhà phát triển muốn bắt tay vào làm ngay, đây thường là rào cản đầu tiên.

Sử dụng ServBay để quản lý môi trường Ruby

Để bỏ qua các bước biên dịch và cấu hình tẻ nhạt, mình khuyên dùng ServBay. ServBay là một công cụ quản lý môi trường phát triển tích hợp, đi kèm với môi trường Ruby đã được biên dịch sẵn và bảo trì tốt.

image.png

Với ServBay, bạn không cần phải xử lý các tập lệnh cài đặt phức tạp. Chỉ cần tải xuống và cài đặt ServBay, sau đó kích hoạt module Ruby trong phần "Packages" (Gói).

Kiểm tra xem môi trường Ruby đã sẵn sàng chưa trong terminal:

# Xác minh phiên bản Ruby
ruby -v

image.png

Chỉ đơn giản vậy thôi, một môi trường Ruby đã sẵn sàng.

Gemini CLI

Gemini CLI là công cụ dòng lệnh do Google cung cấp để tương tác với các tệp nguồn và cung cấp hỗ trợ thời gian thực. Trong phát triển MCP, nó đóng vai trò là client (máy khách).

Quản lý phiên bản Node

Gemini CLI phụ thuộc vào môi trường Node.js. Ở đây, chúng ta cũng sử dụng ServBay để quản lý phiên bản Node.js.

image.png

ServBay cũng tích hợp sẵn một môi trường Node.js tiêu chuẩn, giúp việc cài đặt các công cụ dựa trên Node trở nên rất trực tiếp. Chúng ta không cần cài đặt thêm NVM, mà có thể sử dụng trực tiếp npm do ServBay cung cấp.

Đảm bảo ServBay đang chạy và module Node đã được kích hoạt, sau đó cài đặt Gemini CLI:

npm install -g @google/gemini-cli

image.png

Kiểm tra môi trường Gemini CLI

Sau khi cài đặt và đảm bảo bạn có đúng phiên bản Node.js, hãy kiểm tra việc khởi động Gemini CLI. Bạn sẽ cần API Key hoặc tài khoản Google để xác thực:

gemini auth

Sau khi đăng nhập thành công, chạy lệnh gemini sẽ đưa bạn vào chế độ tương tác.

Bắt đầu từ đâu?

Chiến lược phát triển MCP áp dụng phương pháp tiếp cận từng bước:

  1. Thiết lập: Cấu hình môi trường phát triển cơ bản, thiết lập các biến hệ thống cần thiết và đảm bảo Gemini CLI hoạt động.
  2. Xây dựng: Tạo một máy chủ Ruby MCP tối thiểu theo phong cách "Hello World" với chức năng truyền tải stdio.
  3. Xác minh: Kiểm tra kết nối giữa Gemini CLI và tiến trình cục bộ thông qua MCP.
  4. Mở rộng: Mở rộng máy chủ MCP cơ bản bằng cách thêm các công cụ thực tế hơn.

Hello World sử dụng giao thức vận chuyển STDIO

Một chức năng chính của thư viện MCP là trừu tượng hóa các phương thức vận chuyển (transport methods) khác nhau. Bất kể client MCP sử dụng kênh vận chuyển cấp thấp nào để kết nối với máy chủ MCP, việc triển khai các công cụ cấp cao vẫn giống nhau.

Phương thức vận chuyển đơn giản nhất được SDK hỗ trợ là stdio (Đầu vào/Đầu ra chuẩn), kết nối các tiến trình đang chạy cục bộ. Client MCP và máy chủ MCP phải chạy trong cùng một môi trường.

Logic code để thiết lập kết nối như sau:

# Ví dụ mã
logger.info "Đang khởi động MCP Server..."
transport = MCP::Server::Transports::Stdio.new
server.run(transport)

Cấu hình dự án (Gemfile)

Tạo file Gemfile trong thư mục dự án để khai báo MCP SDK và thư viện logger:

# frozen_string_literal: true

source 'https://rubygems.org'

# Sử dụng phiên bản Ruby do ServBay cung cấp
ruby '3.2.0'

gem 'logger'
gem 'mcp-sdk' # Lưu ý: Điều chỉnh tên gem này dựa trên gem thực tế có sẵn

Chạy lệnh cài đặt:

bundle install

Viết mã Ruby

Tạo một tệp tên là server.rb trong thư mục dự án. Đoạn mã này sẽ khởi tạo máy chủ, đăng ký các công cụ và bắt đầu lắng nghe.

require 'mcp'
require 'logger'
require 'json'

# Đặt log output ra standard error (stderr), vì stdout bị giao thức chiếm dụng
$logger = Logger.new($stderr)
$logger.level = Logger::INFO

class SimpleRubyServer
  def initialize
    @mcp_server = MCP::Server.new("MyLocalRubyServer", "1.0.0")
    register_capabilities
  end

  def register_capabilities
    # Đăng ký một công cụ chào hỏi đơn giản
    @mcp_server.register_tool("say_hello", "Gửi lời chào đến người dùng", {
      type: "object",
      properties: {
        username: { type: "string", description: "Tên người dùng" }
      },
      required: ["username"]
    }) do |params|
      execute_hello(params)
    end
  end

  def execute_hello(params)
    user = params['username'] || "Anonymous"
    $logger.info "Nhận được yêu cầu chào hỏi cho: #{user}"
    
    # Trả về phản hồi theo định dạng giao thức MCP
    { 
      content: [
        { 
          type: "text", 
          text: "Xin chào, #{user}! Đây là máy chủ Ruby MCP đang chạy cục bộ." 
        }
      ] 
    }
  end

  def start
    $logger.info "Máy chủ sẵn sàng, đang lắng nghe trên Stdio..."
    # Khởi tạo lớp vận chuyển Stdio và chạy
    transport = MCP::Server::Transports::Stdio.new
    @mcp_server.run(transport)
  rescue => e
    $logger.error "Lỗi vận hành máy chủ: #{e.message}"
  end
end

# Điểm nhập (Entry point)
if __FILE__ == $0
  SimpleRubyServer.new.start
end

Chạy thử nghiệm

Trước khi kết nối với Gemini, hãy thử chạy tập lệnh để đảm bảo không có lỗi cú pháp:

ruby server.rb

Chương trình sẽ treo và chờ đầu vào sau khi khởi động, đây là hành vi bình thường.

Cấu hình Gemini CLI (settings.json)

Gemini CLI cần biết cách khởi động máy chủ Ruby của chúng ta. Sửa đổi tệp cấu hình của Gemini:

{
  "mcpServers": {
    "ruby-demo": {
      "command": "ruby",
      "args": [
        "/đường/dẫn/tuyệt/đối/tới/dự/án/của/bạn/server.rb"
      ]
    }
  }
}

Review dự án với Gemini CLI

Khởi chạy Gemini CLI; nó sẽ đọc cấu hình và cố gắng kết nối với máy chủ.

gemini

image.png Trong giao diện tương tác, chúng ta có thể kiểm tra trạng thái máy chủ:

> /mcp list

Configured MCP servers:
🟢 ruby-demo - Ready (1 tool)
  Tools:
  - say_hello

Xác minh và Tương tác

Bây giờ, hãy tương tác với mã Ruby thông qua Gemini CLI.

Nhập lệnh:

Hãy dùng server ruby-demo để chào "ServBay Developer".

Gemini sẽ phân tích yêu cầu, gọi tiến trình Ruby cục bộ và xuất kết quả:

✦ I will call the say_hello tool with the username "ServBay Developer".

╭──────────────────────────────────────────────────────────────────╮
│ ✓  say_hello (ruby-demo MCP Server) {"username":"ServBay Developer"} │
│                                                                  │
│ Xin chào, ServBay Developer! Đây là máy chủ Ruby MCP đang chạy cục bộ. │
╰──────────────────────────────────────────────────────────────────╯

Mở rộng máy chủ Ruby MCP

Chức năng MCP cơ bản đã được xác minh qua Gemini CLI. Tiếp theo, chúng ta có thể mở rộng máy chủ bằng cách thêm một công cụ để lấy thông tin hệ thống.

Thêm công cụ mới vào phương thức register_capabilities trong server.rb:

    # Đăng ký công cụ thông tin hệ thống
    @mcp_server.register_tool("system_specs", "Lấy thông tin Ruby và hệ thống của môi trường hiện tại", {}) do |_|
      get_specs
    end

Và thêm phương thức xử lý tương ứng:

  def get_specs
    specs = {
      ruby_v: RUBY_VERSION,
      platform: RUBY_PLATFORM,
      servbay_env: ENV['SERVBAY_ROOT'] ? "Detected" : "Not Detected",
      time: Time.now.to_s
    }
    { content: [{ type: "text", text: JSON.pretty_generate(specs) }] }
  end

Sau khi khởi động lại Gemini CLI, công cụ mới có thể được gọi.

Lấy thông tin về môi trường Ruby của hệ thống hiện tại.

Gemini sẽ trả về dữ liệu JSON chứa phiên bản Ruby và kết quả phát hiện môi trường ServBay, sau đó trả lời câu hỏi của bạn dựa trên dữ liệu đó.

Tổng kết

Thông qua phương pháp tiếp cận từng bước, chúng ta đã xác minh tính khả thi của việc phát triển MCP bằng Ruby và Gemini CLI.

Nhờ ServBay, chúng ta đã tránh được quá trình phức tạp khi cấu hình môi trường Rubymôi trường Node.js, cho phép tập trung trực tiếp vào việc viết mã. Bằng cách xây dựng một máy chủ vận chuyển Stdio tối thiểu, chúng ta đã kết nối thành công mã Ruby cục bộ với Mô hình Lớn Gemini. Phương pháp này có thể được mở rộng thêm để tận dụng hệ sinh thái phong phú của Ruby nhằm xử lý các tác vụ cục bộ phức tạp hơn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí