rubydex 0.2.7-aarch64-linux → 0.2.9-aarch64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/THIRD_PARTY_LICENSES.html +132 -1378
  4. data/exe/rdx +28 -2
  5. data/ext/rubydex/extconf.rb +0 -8
  6. data/ext/rubydex/graph.c +43 -29
  7. data/lib/rubydex/3.2/rubydex.so +0 -0
  8. data/lib/rubydex/3.3/rubydex.so +0 -0
  9. data/lib/rubydex/3.4/rubydex.so +0 -0
  10. data/lib/rubydex/4.0/rubydex.so +0 -0
  11. data/lib/rubydex/librubydex_sys.so +0 -0
  12. data/lib/rubydex/mcp_server/protocol.rb +156 -0
  13. data/lib/rubydex/mcp_server/tools/base_tool.rb +109 -0
  14. data/lib/rubydex/mcp_server/tools/codebase_stats_tool.rb +30 -0
  15. data/lib/rubydex/mcp_server/tools/find_constant_references_tool.rb +46 -0
  16. data/lib/rubydex/mcp_server/tools/get_declaration_tool.rb +68 -0
  17. data/lib/rubydex/mcp_server/tools/get_descendants_tool.rb +46 -0
  18. data/lib/rubydex/mcp_server/tools/get_file_declarations_tool.rb +55 -0
  19. data/lib/rubydex/mcp_server/tools/search_declarations_tool.rb +55 -0
  20. data/lib/rubydex/mcp_server.rb +219 -0
  21. data/lib/rubydex/version.rb +1 -1
  22. data/rbi/rubydex.rbi +8 -8
  23. data/rust/Cargo.lock +1 -555
  24. data/rust/Cargo.toml +0 -1
  25. data/rust/rubydex/src/config.rs +54 -34
  26. data/rust/rubydex/src/listing.rs +159 -102
  27. data/rust/rubydex/src/main.rs +148 -5
  28. data/rust/rubydex/src/model/declaration.rs +14 -14
  29. data/rust/rubydex/src/model/graph.rs +92 -9
  30. data/rust/rubydex/src/model/ids.rs +30 -0
  31. data/rust/rubydex/src/model/string_ref.rs +12 -4
  32. data/rust/rubydex/src/operation/applier.rs +0 -2
  33. data/rust/rubydex/src/query.rs +83 -15
  34. data/rust/rubydex/src/resolution.rs +196 -139
  35. data/rust/rubydex/tests/cli.rs +66 -0
  36. data/rust/rubydex-sys/src/declaration_api.rs +2 -2
  37. data/rust/rubydex-sys/src/graph_api.rs +71 -56
  38. metadata +11 -10
  39. data/exe/rubydex_mcp +0 -17
  40. data/lib/rubydex/bin/rubydex_mcp +0 -0
  41. data/rust/rubydex-mcp/Cargo.toml +0 -34
  42. data/rust/rubydex-mcp/src/main.rs +0 -48
  43. data/rust/rubydex-mcp/src/server.rs +0 -1148
  44. data/rust/rubydex-mcp/src/tools.rs +0 -49
  45. data/rust/rubydex-mcp/tests/mcp.rs +0 -302
@@ -19,6 +19,9 @@ fn prints_help() {
19
19
  .success()
20
20
  .stdout(predicate::str::contains("A Static Analysis Toolkit for Ruby"))
21
21
  .stdout(predicate::str::contains("Usage:"))
22
+ .stdout(predicate::str::contains(
23
+ "If the first path is a directory, it is used as the workspace root for rubydex.toml",
24
+ ))
22
25
  .stdout(predicate::str::contains("--stats"))
23
26
  .stdout(predicate::str::contains("--dot"))
24
27
  .stdout(predicate::str::contains("--stop-after"));
@@ -52,6 +55,69 @@ fn paths_argument_variants() {
52
55
  });
53
56
  }
54
57
 
58
+ #[test]
59
+ fn single_directory_argument_is_workspace_root_for_config() {
60
+ with_context(|context| {
61
+ context.write("included.rb", "class Included\nend\n");
62
+ context.write("excluded/skipped.rb", "class Skipped\nend\n");
63
+ context.write("rubydex.toml", "exclude = [\"excluded\"]\n");
64
+
65
+ rdx(&[context.absolute_path().to_str().unwrap()])
66
+ .success()
67
+ .stderr(predicate::str::is_empty())
68
+ .stdout(predicate::str::contains("Indexed 2 files"));
69
+ });
70
+ }
71
+
72
+ #[test]
73
+ fn first_directory_argument_is_workspace_root_for_config() {
74
+ with_context(|context| {
75
+ context.write("included/kept.rb", "class Included\nend\n");
76
+ context.write("excluded/skipped.rb", "class Skipped\nend\n");
77
+ context.write("rubydex.toml", "exclude = [\"excluded\"]\n");
78
+
79
+ rdx(&[
80
+ context.absolute_path().to_str().unwrap(),
81
+ context.absolute_path_to("included").to_str().unwrap(),
82
+ context.absolute_path_to("excluded").to_str().unwrap(),
83
+ ])
84
+ .success()
85
+ .stderr(predicate::str::is_empty())
86
+ .stdout(predicate::str::contains("Indexed 2 files"));
87
+ });
88
+ }
89
+
90
+ #[test]
91
+ fn single_file_argument_is_not_used_as_workspace_root() {
92
+ with_context(|context| {
93
+ context.write("included.rb", "class Included\nend\n");
94
+ context.write("excluded/skipped.rb", "class Skipped\nend\n");
95
+ context.write("rubydex.toml", "exclude = [\"excluded\"]\n");
96
+
97
+ rdx(&[context.absolute_path_to("excluded/skipped.rb").to_str().unwrap()])
98
+ .success()
99
+ .stderr(predicate::str::is_empty())
100
+ .stdout(predicate::str::contains("Indexed 2 files"));
101
+ });
102
+ }
103
+
104
+ #[test]
105
+ fn first_file_argument_is_not_used_as_workspace_root() {
106
+ with_context(|context| {
107
+ context.write("included.rb", "class Included\nend\n");
108
+ context.write("excluded/skipped.rb", "class Skipped\nend\n");
109
+ context.write("rubydex.toml", "exclude = [\"excluded\"]\n");
110
+
111
+ rdx(&[
112
+ context.absolute_path_to("included.rb").to_str().unwrap(),
113
+ context.absolute_path_to("excluded").to_str().unwrap(),
114
+ ])
115
+ .success()
116
+ .stderr(predicate::str::is_empty())
117
+ .stdout(predicate::str::contains("Indexed 3 files"));
118
+ });
119
+ }
120
+
55
121
  #[test]
56
122
  fn prints_index_metrics() {
57
123
  with_context(|context| {
@@ -9,7 +9,7 @@ use crate::definition_api::{DefinitionsIter, rdx_definitions_iter_new_from_ids};
9
9
  use crate::graph_api::{GraphPointer, with_graph};
10
10
  use crate::reference_api::{CConstantReference, CMethodReference, ConstantReferencesIter, MethodReferencesIter};
11
11
  use crate::utils;
12
- use rubydex::model::ids::{DeclarationId, StringId};
12
+ use rubydex::model::ids::{DeclarationId, StringId, declaration_id_from_lookup_name};
13
13
 
14
14
  #[repr(C)]
15
15
  #[derive(Debug, Clone, Copy)]
@@ -80,7 +80,7 @@ pub(crate) unsafe fn decl_id_from_char_ptr(ptr: *const c_char) -> Option<Declara
80
80
  if s.is_empty() {
81
81
  return None;
82
82
  }
83
- Some(DeclarationId::from(s.as_str()))
83
+ Some(declaration_id_from_lookup_name(&s))
84
84
  }
85
85
 
86
86
  /// An iterator over declaration IDs
@@ -11,7 +11,7 @@ use rubydex::errors::Errors;
11
11
  use rubydex::indexing::LanguageId;
12
12
  use rubydex::model::encoding::Encoding;
13
13
  use rubydex::model::graph::Graph;
14
- use rubydex::model::ids::{DeclarationId, NameId, UriId};
14
+ use rubydex::model::ids::{DeclarationId, NameId, UriId, declaration_id_from_lookup_name};
15
15
  use rubydex::model::keywords;
16
16
  use rubydex::model::name::NameRef;
17
17
  use rubydex::model::visibility::Visibility;
@@ -58,64 +58,75 @@ where
58
58
  result
59
59
  }
60
60
 
61
- /// Searches the graph using exact substring matching
61
+ /// Searches the graph using exact substring matching, returning every declaration whose name matches any of the
62
+ /// queries.
62
63
  ///
63
64
  /// # Safety
64
65
  ///
65
- /// Expects both the graph and the query pointers to be valid
66
+ /// Expects `pointer` to be a valid graph and `c_queries` to point to an array of `count` valid, NUL-terminated C
67
+ /// strings. Returns a null pointer when `count` is zero, `c_queries` is null, or any query is not valid UTF-8.
66
68
  #[unsafe(no_mangle)]
67
69
  pub unsafe extern "C" fn rdx_graph_declarations_search(
68
70
  pointer: GraphPointer,
69
- c_query: *const c_char,
71
+ c_queries: *const *const c_char,
72
+ count: usize,
70
73
  ) -> *mut DeclarationsIter {
71
- {
72
- let Ok(query) = (unsafe { utils::convert_char_ptr_to_string(c_query) }) else {
73
- return ptr::null_mut();
74
- };
74
+ if count == 0 || c_queries.is_null() {
75
+ return ptr::null_mut();
76
+ }
75
77
 
76
- let entries = with_graph(pointer, |graph| {
77
- query::declaration_search(graph, &query, &query::MatchMode::Exact)
78
- .into_iter()
79
- .filter_map(|id| {
80
- let decl = graph.declarations().get(&id)?;
81
- Some(CDeclaration::from_declaration(id, decl))
82
- })
83
- .collect::<Vec<CDeclaration>>()
84
- .into_boxed_slice()
85
- });
78
+ let Ok(queries) = (unsafe { utils::convert_double_pointer_to_vec(c_queries, count) }) else {
79
+ return ptr::null_mut();
80
+ };
81
+ let query_refs: Vec<&str> = queries.iter().map(String::as_str).collect();
86
82
 
87
- DeclarationsIter::new(entries)
88
- }
83
+ let entries = with_graph(pointer, |graph| {
84
+ query::declaration_search(graph, &query_refs, &query::MatchMode::Exact)
85
+ .into_iter()
86
+ .filter_map(|id| {
87
+ let decl = graph.declarations().get(&id)?;
88
+ Some(CDeclaration::from_declaration(id, decl))
89
+ })
90
+ .collect::<Vec<CDeclaration>>()
91
+ .into_boxed_slice()
92
+ });
93
+
94
+ DeclarationsIter::new(entries)
89
95
  }
90
96
 
91
- /// Searches the graph using fuzzy matching
97
+ /// Searches the graph using fuzzy matching, returning every declaration whose name matches any of the queries.
92
98
  ///
93
99
  /// # Safety
94
100
  ///
95
- /// Expects both the graph and the query pointers to be valid
101
+ /// Expects `pointer` to be a valid graph and `c_queries` to point to an array of `count` valid, NUL-terminated C
102
+ /// strings. Returns a null pointer when `count` is zero, `c_queries` is null, or any query is not valid UTF-8.
96
103
  #[unsafe(no_mangle)]
97
104
  pub unsafe extern "C" fn rdx_graph_declarations_fuzzy_search(
98
105
  pointer: GraphPointer,
99
- c_query: *const c_char,
106
+ c_queries: *const *const c_char,
107
+ count: usize,
100
108
  ) -> *mut DeclarationsIter {
101
- {
102
- let Ok(query) = (unsafe { utils::convert_char_ptr_to_string(c_query) }) else {
103
- return ptr::null_mut();
104
- };
109
+ if count == 0 || c_queries.is_null() {
110
+ return ptr::null_mut();
111
+ }
105
112
 
106
- let entries = with_graph(pointer, |graph| {
107
- query::declaration_search(graph, &query, &query::MatchMode::Fuzzy)
108
- .into_iter()
109
- .filter_map(|id| {
110
- let decl = graph.declarations().get(&id)?;
111
- Some(CDeclaration::from_declaration(id, decl))
112
- })
113
- .collect::<Vec<CDeclaration>>()
114
- .into_boxed_slice()
115
- });
113
+ let Ok(queries) = (unsafe { utils::convert_double_pointer_to_vec(c_queries, count) }) else {
114
+ return ptr::null_mut();
115
+ };
116
+ let query_refs: Vec<&str> = queries.iter().map(String::as_str).collect();
116
117
 
117
- DeclarationsIter::new(entries)
118
- }
118
+ let entries = with_graph(pointer, |graph| {
119
+ query::declaration_search(graph, &query_refs, &query::MatchMode::Fuzzy)
120
+ .into_iter()
121
+ .filter_map(|id| {
122
+ let decl = graph.declarations().get(&id)?;
123
+ Some(CDeclaration::from_declaration(id, decl))
124
+ })
125
+ .collect::<Vec<CDeclaration>>()
126
+ .into_boxed_slice()
127
+ });
128
+
129
+ DeclarationsIter::new(entries)
119
130
  }
120
131
 
121
132
  /// # Panics
@@ -158,37 +169,41 @@ pub unsafe extern "C" fn rdx_graph_resolve_constant(
158
169
  })
159
170
  }
160
171
 
161
- /// Adds paths to exclude from file discovery during indexing.
172
+ /// Adds glob patterns to exclude from file discovery during indexing.
162
173
  ///
163
174
  /// # Panics
164
175
  ///
165
- /// Will panic if the given array of C string paths cannot be converted to a `Vec<String>`.
176
+ /// Will panic if the given array of C string patterns cannot be converted to a `Vec<String>`.
166
177
  ///
167
178
  /// # Safety
168
179
  ///
169
180
  /// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
170
- /// - `paths` must be an array of `count` valid, null-terminated UTF-8 strings.
181
+ /// - `patterns` must be an array of `count` valid, null-terminated UTF-8 strings.
171
182
  #[unsafe(no_mangle)]
172
- pub unsafe extern "C" fn rdx_graph_exclude_paths(pointer: GraphPointer, paths: *const *const c_char, count: usize) {
173
- let paths: Vec<String> = unsafe { utils::convert_double_pointer_to_vec(paths, count).unwrap() };
174
- let path_bufs: Vec<PathBuf> = paths.into_iter().map(PathBuf::from).collect();
175
- with_mut_graph(pointer, |graph| graph.exclude_paths(path_bufs));
183
+ pub unsafe extern "C" fn rdx_graph_exclude_patterns(
184
+ pointer: GraphPointer,
185
+ patterns: *const *const c_char,
186
+ count: usize,
187
+ ) {
188
+ let patterns: Vec<String> = unsafe { utils::convert_double_pointer_to_vec(patterns, count).unwrap() };
189
+ let entries: Vec<Box<str>> = patterns.into_iter().map(String::into_boxed_str).collect();
190
+ with_mut_graph(pointer, |graph| graph.exclude_patterns(entries));
176
191
  }
177
192
 
178
- /// Returns the currently excluded paths as an array of C strings. Writes the count to `out_count`. Returns NULL if no
179
- /// paths are excluded. Caller must free with `free_c_string_array`.
193
+ /// Returns the currently excluded glob patterns as an array of C strings. Writes the count to `out_count`. Returns NULL
194
+ /// if no patterns are excluded. Caller must free with `free_c_string_array`.
180
195
  ///
181
196
  /// # Safety
182
197
  ///
183
198
  /// - `pointer` must be a valid `GraphPointer` previously returned by this crate.
184
199
  /// - `out_count` must be a valid, writable pointer.
185
200
  #[unsafe(no_mangle)]
186
- pub unsafe extern "C" fn rdx_graph_excluded_paths(
201
+ pub unsafe extern "C" fn rdx_graph_excluded_patterns(
187
202
  pointer: GraphPointer,
188
203
  out_count: *mut usize,
189
204
  ) -> *const *const c_char {
190
205
  with_graph(pointer, |graph| {
191
- let excluded = graph.excluded_paths();
206
+ let excluded = graph.excluded_patterns();
192
207
 
193
208
  if excluded.is_empty() {
194
209
  unsafe { *out_count = 0 };
@@ -202,7 +217,7 @@ pub unsafe extern "C" fn rdx_graph_excluded_paths(
202
217
  // on Windows if a configuration file is using forward slashes. For example:
203
218
  //
204
219
  // C:\project/vendor/bundle
205
- let normalized = path.to_string_lossy().replace(std::path::MAIN_SEPARATOR, "/");
220
+ let normalized = path.replace(std::path::MAIN_SEPARATOR, "/");
206
221
 
207
222
  CString::new(normalized)
208
223
  .ok()
@@ -302,7 +317,7 @@ pub unsafe extern "C" fn rdx_index_all(
302
317
  let file_paths: Vec<String> = unsafe { utils::convert_double_pointer_to_vec(file_paths, count).unwrap() };
303
318
 
304
319
  with_mut_graph(pointer, |graph| {
305
- let (file_paths, listing_errors) = listing::collect_file_paths(file_paths, &graph.excluded_paths());
320
+ let (file_paths, listing_errors) = listing::collect_file_paths(file_paths, &graph.excluded_patterns());
306
321
  let indexing_errors = indexing::index_files(graph, file_paths, indexing::IndexerBackend::RubyIndexer);
307
322
 
308
323
  let all_errors: Vec<String> = listing_errors
@@ -498,7 +513,7 @@ pub unsafe extern "C" fn rdx_graph_get_declaration(pointer: GraphPointer, name:
498
513
  };
499
514
 
500
515
  with_graph(pointer, |graph| {
501
- let decl_id = DeclarationId::from(name_str.as_str());
516
+ let decl_id = declaration_id_from_lookup_name(&name_str);
502
517
 
503
518
  if let Some(decl) = graph.declarations().get(&decl_id) {
504
519
  Box::into_raw(Box::new(CDeclaration::from_declaration(decl_id, decl))).cast_const()
@@ -917,7 +932,7 @@ pub unsafe extern "C" fn rdx_graph_complete_namespace_access(
917
932
  graph,
918
933
  CompletionReceiver::NamespaceAccess {
919
934
  self_decl_id,
920
- namespace_decl_id: DeclarationId::from(name_str.as_str()),
935
+ namespace_decl_id: declaration_id_from_lookup_name(&name_str),
921
936
  },
922
937
  Vec::new(),
923
938
  )
@@ -951,7 +966,7 @@ pub unsafe extern "C" fn rdx_graph_complete_method_call(
951
966
  graph,
952
967
  CompletionReceiver::MethodCall {
953
968
  self_decl_id,
954
- receiver_decl_id: DeclarationId::from(name_str.as_str()),
969
+ receiver_decl_id: declaration_id_from_lookup_name(&name_str),
955
970
  },
956
971
  Vec::new(),
957
972
  )
@@ -995,7 +1010,7 @@ pub unsafe extern "C" fn rdx_graph_complete_method_argument(
995
1010
  CompletionReceiver::MethodArgument {
996
1011
  self_decl_id,
997
1012
  nesting_name_id,
998
- method_decl_id: DeclarationId::from(name_str.as_str()),
1013
+ method_decl_id: declaration_id_from_lookup_name(&name_str),
999
1014
  },
1000
1015
  names_to_untrack,
1001
1016
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubydex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.9
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-06-30 00:00:00.000000000 Z
11
+ date: 2026-07-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A high-performance static analysis suite for Ruby, built in Rust with
14
14
  Ruby APIs
@@ -16,7 +16,6 @@ email:
16
16
  - ruby@shopify.com
17
17
  executables:
18
18
  - rdx
19
- - rubydex_mcp
20
19
  extensions: []
21
20
  extra_rdoc_files: []
22
21
  files:
@@ -24,7 +23,6 @@ files:
24
23
  - README.md
25
24
  - THIRD_PARTY_LICENSES.html
26
25
  - exe/rdx
27
- - exe/rubydex_mcp
28
26
  - ext/rubydex/declaration.c
29
27
  - ext/rubydex/declaration.h
30
28
  - ext/rubydex/definition.c
@@ -51,7 +49,6 @@ files:
51
49
  - lib/rubydex/3.3/rubydex.so
52
50
  - lib/rubydex/3.4/rubydex.so
53
51
  - lib/rubydex/4.0/rubydex.so
54
- - lib/rubydex/bin/rubydex_mcp
55
52
  - lib/rubydex/comment.rb
56
53
  - lib/rubydex/declaration.rb
57
54
  - lib/rubydex/diagnostic.rb
@@ -62,6 +59,15 @@ files:
62
59
  - lib/rubydex/keyword_parameter.rb
63
60
  - lib/rubydex/librubydex_sys.so
64
61
  - lib/rubydex/location.rb
62
+ - lib/rubydex/mcp_server.rb
63
+ - lib/rubydex/mcp_server/protocol.rb
64
+ - lib/rubydex/mcp_server/tools/base_tool.rb
65
+ - lib/rubydex/mcp_server/tools/codebase_stats_tool.rb
66
+ - lib/rubydex/mcp_server/tools/find_constant_references_tool.rb
67
+ - lib/rubydex/mcp_server/tools/get_declaration_tool.rb
68
+ - lib/rubydex/mcp_server/tools/get_descendants_tool.rb
69
+ - lib/rubydex/mcp_server/tools/get_file_declarations_tool.rb
70
+ - lib/rubydex/mcp_server/tools/search_declarations_tool.rb
65
71
  - lib/rubydex/mixin.rb
66
72
  - lib/rubydex/reference.rb
67
73
  - lib/rubydex/signature.rb
@@ -72,11 +78,6 @@ files:
72
78
  - rust/about.toml
73
79
  - rust/about_templates/about.hbs
74
80
  - rust/about_templates/mingw_licenses.hbs
75
- - rust/rubydex-mcp/Cargo.toml
76
- - rust/rubydex-mcp/src/main.rs
77
- - rust/rubydex-mcp/src/server.rs
78
- - rust/rubydex-mcp/src/tools.rs
79
- - rust/rubydex-mcp/tests/mcp.rs
80
81
  - rust/rubydex-sys/Cargo.toml
81
82
  - rust/rubydex-sys/build.rs
82
83
  - rust/rubydex-sys/cbindgen.toml
data/exe/rubydex_mcp DELETED
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require "rbconfig"
5
-
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__)
9
-
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)
Binary file
@@ -1,34 +0,0 @@
1
- [package]
2
- name = "rubydex-mcp"
3
- version = "0.2.6"
4
- edition = "2024"
5
- rust-version = "1.89.0"
6
- license = "MIT"
7
- description = "MCP server exposing Rubydex semantic Ruby code intelligence tools."
8
- homepage = "https://github.com/Shopify/rubydex"
9
- repository = "https://github.com/Shopify/rubydex"
10
- readme = "README.md"
11
- keywords = ["ruby", "mcp", "static-analysis"]
12
- categories = ["development-tools"]
13
-
14
- [[bin]]
15
- name = "rubydex_mcp"
16
- path = "src/main.rs"
17
-
18
- [dependencies]
19
- rubydex = { version = "0.2.6", path = "../rubydex" }
20
- clap = { version = "4.5.16", features = ["derive"] }
21
- rmcp = { version = "1.4", features = ["server", "macros", "transport-io", "schemars"] }
22
- tokio = { version = "1", features = ["macros", "rt", "io-std"] }
23
- serde = { version = "1", features = ["derive"] }
24
- serde_json = "1"
25
- schemars = "1"
26
- url = "2"
27
-
28
- [dev-dependencies]
29
- rubydex = { version = "0.2.6", path = "../rubydex", features = ["test_utils"] }
30
- assert_cmd = "2.0"
31
- serde_json = "1"
32
-
33
- [lints]
34
- workspace = true
@@ -1,48 +0,0 @@
1
- use clap::Parser;
2
-
3
- mod server;
4
- mod tools;
5
-
6
- #[derive(Parser, Debug)]
7
- #[command(
8
- name = "rubydex_mcp",
9
- about = "Rubydex MCP server for AI-assisted Ruby code intelligence",
10
- version
11
- )]
12
- struct Args {
13
- #[arg(value_name = "PATH", default_value = ".")]
14
- path: String,
15
- }
16
-
17
- fn main() {
18
- let args = Args::parse();
19
-
20
- let root = match std::fs::canonicalize(&args.path) {
21
- Ok(p) => p
22
- .into_os_string()
23
- .into_string()
24
- .expect("Project path is not valid UTF-8"),
25
- Err(e) => {
26
- eprintln!("Warning: failed to canonicalize '{}': {e}", args.path);
27
- args.path
28
- }
29
- };
30
-
31
- // Create the server and start indexing in the background.
32
- let server = server::RubydexServer::new(root.clone());
33
- server.spawn_indexer(root);
34
-
35
- // Serve MCP over stdio immediately while indexing runs.
36
- // We need to do this because Claude Code's default MCP server timeout is 30 seconds,
37
- // And in big codebases it's possible to exceed that and Claude Code would just consider
38
- // the server fail to connect.
39
- let rt = tokio::runtime::Builder::new_current_thread()
40
- .enable_all()
41
- .build()
42
- .expect("Failed to build tokio runtime");
43
-
44
- if let Err(e) = rt.block_on(server.serve()) {
45
- eprintln!("MCP server error: {e}");
46
- std::process::exit(1);
47
- }
48
- }