File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 11#!/usr/bin/env ruby
22# frozen_string_literal: true
33
4- require "rbconfig"
4+ $LOAD_PATH . unshift ( File . expand_path ( "../lib" , __dir__ ) )
55
6- host_os = RbConfig ::CONFIG . fetch ( "host_os" )
7- executable = host_os . match? ( /mswin|mingw|cygwin/ ) ? "rubydex_mcp.exe" : "rubydex_mcp"
8- binary = File . expand_path ( "../lib/rubydex/bin/#{ executable } " , __dir__ )
6+ require "rubydex/mcp_server_launcher"
97
10- unless File . executable? ( binary )
11- abort ( <<~MESSAGE . chomp )
12- rubydex_mcp is not available at #{ binary } .
13- Install a precompiled rubydex gem, or reinstall rubydex with Cargo available so the MCP executable can be built locally.
14- MESSAGE
15- end
16-
17- exec ( binary , *ARGV )
8+ Rubydex ::MCPServerLauncher . exec_server ( ARGV )
Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+
3+ require "rbconfig"
4+
5+ module Rubydex
6+ # Launcher-only helpers for `exe/rubydex_mcp`.
7+ #
8+ # Do not require this file from `lib/rubydex.rb`. It exists only so the Ruby executable wrapper can handle
9+ # host-specific process launch details before it execs the Rust MCP server.
10+ module MCPServerLauncher
11+ extend self
12+
13+ def windows?
14+ RbConfig ::CONFIG . fetch ( "host_os" ) . match? ( /mswin|mingw|cygwin/ )
15+ end
16+
17+ def executable_name
18+ windows? ? "rubydex_mcp.exe" : "rubydex_mcp"
19+ end
20+
21+ def binary_path
22+ File . expand_path ( "bin/#{ executable_name } " , __dir__ )
23+ end
24+
25+ def host_loader ( maps_path = "/proc/self/maps" )
26+ File . foreach ( maps_path ) do |line |
27+ path = line . split . last
28+ next unless path &.start_with? ( "/" )
29+
30+ return path if File . basename ( path ) . match? ( /\A ld-.*\. so/ )
31+ end
32+
33+ nil
34+ rescue Errno ::ENOENT
35+ nil
36+ end
37+
38+ def exec_server ( argv )
39+ binary = binary_path
40+
41+ unless File . executable? ( binary )
42+ abort ( <<~MESSAGE . chomp )
43+ rubydex_mcp is not available at #{ binary } .
44+ Install a precompiled rubydex gem, or reinstall rubydex with Cargo available so the MCP executable can be built locally.
45+ MESSAGE
46+ end
47+
48+ exec ( binary , *argv )
49+ rescue Errno ::ENOENT
50+ raise if windows?
51+
52+ loader = host_loader
53+ raise unless loader && File . exist? ( loader )
54+
55+ exec ( loader , binary , *argv )
56+ end
57+ end
58+ end
Original file line number Diff line number Diff line change 1+ # frozen_string_literal: true
2+
3+ require_relative "test_helper"
4+
5+ require "tempfile"
6+ require "rubydex/mcp_server_launcher"
7+
8+ class MCPServerExecutableTest < Minitest ::Test
9+ def test_host_loader_reads_loader_from_maps
10+ maps = Tempfile . new ( "maps" )
11+ maps . write ( <<~MAPS )
12+ 7f3d10000000-7f3d10022000 r--p 00000000 00:00 0 [heap]
13+ 7f3d20000000-7f3d20022000 r-xp 00000000 00:00 0 /nix/store/glibc/lib/ld-linux-x86-64.so.2
14+ MAPS
15+ maps . close
16+
17+ assert_equal ( "/nix/store/glibc/lib/ld-linux-x86-64.so.2" , Rubydex ::MCPServerLauncher . host_loader ( maps . path ) )
18+ ensure
19+ maps &.unlink
20+ end
21+
22+ def test_host_loader_returns_nil_when_maps_file_is_missing
23+ assert_nil ( Rubydex ::MCPServerLauncher . host_loader ( "/missing/proc/self/maps" ) )
24+ end
25+
26+ def test_host_loader_returns_existing_linux_loader
27+ skip ( "Linux-only" ) unless File . file? ( "/proc/self/maps" )
28+
29+ loader = Rubydex ::MCPServerLauncher . host_loader
30+
31+ refute_nil ( loader )
32+ assert_path_exists ( loader )
33+ assert_match ( /\A ld-.*\. so/ , File . basename ( loader ) )
34+ end
35+ end
You can’t perform that action at this time.
0 commit comments