shared_tools 0.4.4 → 0.7.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +211 -7
- data/lib/shared_tools/apply_patch_tool.rb +4 -0
- data/lib/shared_tools/bash_tool.rb +4 -0
- data/lib/shared_tools/bundle_tool.rb +4 -0
- data/lib/shared_tools/command_guard.rb +35 -0
- data/lib/shared_tools/csv_read_tool.rb +4 -0
- data/lib/shared_tools/csv_write_tool.rb +4 -0
- data/lib/shared_tools/data_path.rb +52 -0
- data/lib/shared_tools/diff_tool.rb +4 -0
- data/lib/shared_tools/download_file_tool.rb +4 -0
- data/lib/shared_tools/gem_tool.rb +4 -0
- data/lib/shared_tools/git_tool.rb +5 -0
- data/lib/shared_tools/glob_tool.rb +4 -0
- data/lib/shared_tools/http_request_tool.rb +4 -0
- data/lib/shared_tools/json_query_tool.rb +4 -0
- data/lib/shared_tools/lint_tool.rb +4 -0
- data/lib/shared_tools/mcp/brave_search_client.rb +18 -16
- data/lib/shared_tools/mcp/chart_client.rb +18 -15
- data/lib/shared_tools/mcp/client_support.rb +103 -0
- data/lib/shared_tools/mcp/github_client.rb +23 -19
- data/lib/shared_tools/mcp/hugging_face_client.rb +22 -22
- data/lib/shared_tools/mcp/memory_client.rb +20 -15
- data/lib/shared_tools/mcp/notion_client.rb +21 -19
- data/lib/shared_tools/mcp/playwright_client.rb +19 -15
- data/lib/shared_tools/mcp/sequential_thinking_client.rb +17 -14
- data/lib/shared_tools/mcp/slack_client.rb +30 -25
- data/lib/shared_tools/mcp/tavily_client.rb +21 -21
- data/lib/shared_tools/mcp.rb +32 -41
- data/lib/shared_tools/multi_edit_tool.rb +4 -0
- data/lib/shared_tools/parse_ruby_tool.rb +4 -0
- data/lib/shared_tools/process_kill_tool.rb +4 -0
- data/lib/shared_tools/process_list_tool.rb +4 -0
- data/lib/shared_tools/process_output_tool.rb +4 -0
- data/lib/shared_tools/process_registry.rb +224 -0
- data/lib/shared_tools/process_runner.rb +69 -0
- data/lib/shared_tools/process_start_tool.rb +4 -0
- data/lib/shared_tools/python_tests_tool.rb +4 -0
- data/lib/shared_tools/replace_in_files_tool.rb +4 -0
- data/lib/shared_tools/ruby_outline.rb +207 -0
- data/lib/shared_tools/run_tests_tool.rb +4 -0
- data/lib/shared_tools/text_diff.rb +80 -0
- data/lib/shared_tools/todo_write_tool.rb +4 -0
- data/lib/shared_tools/toml_parser.rb +409 -0
- data/lib/shared_tools/toml_query_tool.rb +4 -0
- data/lib/shared_tools/tools/apply_patch_tool.rb +122 -0
- data/lib/shared_tools/tools/bash_tool.rb +102 -0
- data/lib/shared_tools/tools/browser/click_tool.rb +2 -2
- data/lib/shared_tools/tools/browser/inspect_tool.rb +2 -2
- data/lib/shared_tools/tools/browser/page_inspect_tool.rb +2 -2
- data/lib/shared_tools/tools/browser/page_screenshot_tool.rb +2 -2
- data/lib/shared_tools/tools/browser/selector_inspect_tool.rb +2 -2
- data/lib/shared_tools/tools/browser/text_field_area_set_tool.rb +2 -2
- data/lib/shared_tools/tools/browser/visit_tool.rb +2 -2
- data/lib/shared_tools/tools/browser_tool.rb +2 -2
- data/lib/shared_tools/tools/bundle_tool.rb +96 -0
- data/lib/shared_tools/tools/calculator_tool.rb +2 -2
- data/lib/shared_tools/tools/clipboard_tool.rb +2 -2
- data/lib/shared_tools/tools/composite_analysis_tool.rb +2 -2
- data/lib/shared_tools/tools/computer_tool.rb +2 -2
- data/lib/shared_tools/tools/cron_tool.rb +2 -2
- data/lib/shared_tools/tools/csv_read_tool.rb +82 -0
- data/lib/shared_tools/tools/csv_write_tool.rb +67 -0
- data/lib/shared_tools/tools/current_date_time_tool.rb +3 -3
- data/lib/shared_tools/tools/data_science_kit.rb +2 -2
- data/lib/shared_tools/tools/database_query_tool.rb +2 -2
- data/lib/shared_tools/tools/database_tool.rb +2 -2
- data/lib/shared_tools/tools/diff_tool.rb +48 -0
- data/lib/shared_tools/tools/disk/directory_create_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/directory_delete_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/directory_list_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/directory_move_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/file_create_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/file_delete_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/file_move_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/file_read_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/file_replace_tool.rb +2 -2
- data/lib/shared_tools/tools/disk/file_write_tool.rb +2 -2
- data/lib/shared_tools/tools/disk_tool.rb +2 -2
- data/lib/shared_tools/tools/dns_tool.rb +2 -2
- data/lib/shared_tools/tools/doc/docx_reader_tool.rb +2 -2
- data/lib/shared_tools/tools/doc/pdf_reader_tool.rb +2 -2
- data/lib/shared_tools/tools/doc/spreadsheet_reader_tool.rb +2 -2
- data/lib/shared_tools/tools/doc/text_reader_tool.rb +2 -2
- data/lib/shared_tools/tools/doc_tool.rb +2 -2
- data/lib/shared_tools/tools/docker/compose_run_tool.rb +2 -2
- data/lib/shared_tools/tools/download_file_tool.rb +87 -0
- data/lib/shared_tools/tools/enabler.rb +2 -2
- data/lib/shared_tools/tools/error_handling_tool.rb +2 -2
- data/lib/shared_tools/tools/eval/python_eval_tool.rb +2 -2
- data/lib/shared_tools/tools/eval/ruby_eval_tool.rb +2 -2
- data/lib/shared_tools/tools/eval/shell_eval_tool.rb +2 -2
- data/lib/shared_tools/tools/eval_tool.rb +2 -2
- data/lib/shared_tools/tools/gem_tool.rb +157 -0
- data/lib/shared_tools/tools/git/add_tool.rb +73 -0
- data/lib/shared_tools/tools/git/blame_tool.rb +77 -0
- data/lib/shared_tools/tools/git/branch_tool.rb +55 -0
- data/lib/shared_tools/tools/git/checkout_tool.rb +69 -0
- data/lib/shared_tools/tools/git/commit_tool.rb +73 -0
- data/lib/shared_tools/tools/git/diff_tool.rb +69 -0
- data/lib/shared_tools/tools/git/grep_tool.rb +82 -0
- data/lib/shared_tools/tools/git/helpers.rb +70 -0
- data/lib/shared_tools/tools/git/log_tool.rb +71 -0
- data/lib/shared_tools/tools/git/show_tool.rb +66 -0
- data/lib/shared_tools/tools/git/status_tool.rb +46 -0
- data/lib/shared_tools/tools/git.rb +18 -0
- data/lib/shared_tools/tools/git_tool.rb +148 -0
- data/lib/shared_tools/tools/glob_tool.rb +75 -0
- data/lib/shared_tools/tools/http_helpers.rb +119 -0
- data/lib/shared_tools/tools/http_request_tool.rb +91 -0
- data/lib/shared_tools/tools/json_query_tool.rb +81 -0
- data/lib/shared_tools/tools/lint_tool.rb +93 -0
- data/lib/shared_tools/tools/multi_edit_tool.rb +134 -0
- data/lib/shared_tools/tools/notification_tool.rb +2 -2
- data/lib/shared_tools/tools/parse_ruby_tool.rb +127 -0
- data/lib/shared_tools/tools/process_kill_tool.rb +55 -0
- data/lib/shared_tools/tools/process_list_tool.rb +41 -0
- data/lib/shared_tools/tools/process_output_tool.rb +69 -0
- data/lib/shared_tools/tools/process_start_tool.rb +0 -0
- data/lib/shared_tools/tools/python_tests_tool.rb +105 -0
- data/lib/shared_tools/tools/replace_in_files_tool.rb +166 -0
- data/lib/shared_tools/tools/run_tests_tool.rb +108 -0
- data/lib/shared_tools/tools/search_codebase_tool.rb +182 -51
- data/lib/shared_tools/tools/secure_tool_template.rb +2 -2
- data/lib/shared_tools/tools/system_info_tool.rb +2 -2
- data/lib/shared_tools/tools/todo_write_tool.rb +81 -0
- data/lib/shared_tools/tools/toml_query_tool.rb +81 -0
- data/lib/shared_tools/tools/toolchain_helpers.rb +64 -0
- data/lib/shared_tools/tools/tree_tool.rb +100 -0
- data/lib/shared_tools/tools/weather_tool.rb +2 -2
- data/lib/shared_tools/tools/web_fetch_tool.rb +85 -0
- data/lib/shared_tools/tools/workflow_manager_tool.rb +2 -2
- data/lib/shared_tools/tools/yaml_query_tool.rb +86 -0
- data/lib/shared_tools/tree_tool.rb +4 -0
- data/lib/shared_tools/url_guard.rb +106 -0
- data/lib/shared_tools/utilities.rb +2 -2
- data/lib/shared_tools/version.rb +1 -1
- data/lib/shared_tools/web_fetch_tool.rb +4 -0
- data/lib/shared_tools/yaml_query_tool.rb +4 -0
- data/lib/shared_tools.rb +1 -1
- metadata +532 -409
- data/lib/shared_tools/mcp/streamable_http_patch.rb +0 -42
- data/lib/shared_tools/tools/version.rb +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 95941947776da1920fb3f5d5a5c0a1866d2170810e23cbcfb53e55e79ee32847
|
|
4
|
+
data.tar.gz: be6b46bce0292f7c0092146fe85b09d6572ea1c2fbd0daf8268cfb6e417d3ea3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28c25227c7fa22fe93e56c48136855edb59193dbcc3ea3ca7236e1de4e9512d76f70256dd6d00f47386243fed9aa2589a9d98ba57703cd68f7c8c4139f0588e3
|
|
7
|
+
data.tar.gz: ca6d285368be559a1642e344c4909a05b44fa143ce5d76ebc21471a347912ff3553ec866b416b560b3bacc56672fb275427426d87a52f538e493b4b447cbb8b0
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
#### ruby_llm 2.1 migration (breaking)
|
|
6
|
+
- **Breaking:** Requires `ruby_llm >= 2.1.1, < 3`. Under ruby_llm 2.x every tool that used the 1.x `params do ... end` macro raised `NoMethodError` inside its class body; the constant already existed, so a half-built class loaded without `#execute`, and calling the tool failed with `NotImplementedError: Subclasses must implement #execute`. All 81 tool files now use `parameters do ... end` (same block DSL, now provided by `schematist`), and `Tools::Enabler`'s `param :tool, desc:` is now `parameter :tool, description:`. The generated argument schemas are unchanged apart from the top-level `"strict": true` marker that ruby_llm 1.x added and 2.x does not. Read a tool's schema with `tool.parameters_schema` (was `params_schema`).
|
|
7
|
+
- **Breaking:** Dropped the `ruby_llm-mcp` dependency; it cannot be loaded alongside ruby_llm 2.1's built-in `RubyLLM::MCP`, which has no `add_client` / `clients` registry. Each MCP client in `lib/shared_tools/mcp/` is now a `RubyLLM::MCP` subclass that describes one server with the class DSL (`command`, `env`, `url`, `bearer_token`, `timeout`): `SharedTools::MCP::GitHub`, `Notion`, `Slack`, `HuggingFace`, `Tavily`, `Memory`, `SequentialThinking`, `Chart`, `BraveSearch`, `Playwright`. Pass the class to a chat or robot (`RubyLLM.chat.with_mcp(SharedTools::MCP::GitHub)`, `RobotLab.build(mcp: [SharedTools::MCP::GitHub])`) instead of looking it up with `RubyLLM::MCP.clients["github"]`.
|
|
8
|
+
- **Breaking:** Requiring a client file no longer has side effects. It does not check environment variables, does not run `brew`/`apt`/`dnf`, and does not connect; environment variables are read when the server process starts. Use `Klass.available?` / `missing_envars` / `verify!` (raises `LoadError` like before) and `Klass.install_packages!`. `require 'shared_tools/mcp'` loads every definition, records availability for `SharedTools.mcp_status`, and `SharedTools::MCP.available` lists the usable classes.
|
|
9
|
+
- **Breaking:** MCP server names are now symbol-friendly: `brave-search` → `brave_search`, `hugging-face` → `hugging_face`, `sequential-thinking` → `sequential_thinking` (others unchanged). These are the names in `SharedTools.mcp_status` and `chat.mcp[...]`.
|
|
10
|
+
- Removed `lib/shared_tools/mcp/streamable_http_patch.rb`; it patched a `ruby_llm-mcp` internal. ruby_llm 2.1's spec-compliant SSE parser already handles mixed CRLF/LF line endings.
|
|
11
|
+
- Added `test/shared_tools/tool_classes_test.rb`: every shipped `RubyLLM::Tool` subclass must define its own `#execute`, expose an object `parameters_schema` whose properties `#execute` accepts, and no 1.x `params do` / `param :` may remain in `lib/`. It also calls `current_date_time`, `system_info` and `dns` (used by aia's demo 18) through `Tool#call` and checks the data they return. Added `test/shared_tools/mcp/clients_test.rb` (class-level only; no servers are started).
|
|
12
|
+
- Updated the MCP examples, `lib/shared_tools/mcp/README.md`, `README.md` and `docs/` for the new MCP classes.
|
|
13
|
+
|
|
14
|
+
#### Tools
|
|
15
|
+
- Added Git tools, ported from `ruby_llm-toolbox`: `SharedTools::Tools::Git::StatusTool`, `DiffTool`, `LogTool`, `ShowTool`, `BlameTool`, `BranchTool`, and `GrepTool` (read-only), plus `AddTool`, `CommitTool`, and `CheckoutTool` (mutating, require `SharedTools.execute?` authorization). All shell out to `git` with `core.fsmonitor` disabled and `--no-ext-diff --no-textconv`, so an untrusted checkout can't turn a read into command execution; refs are validated against option injection and paths are confined to `repo_root`. Also added `SharedTools::Tools::GitTool`, a facade dispatching on `action`.
|
|
16
|
+
- Added `SharedTools::Tools::JsonQueryTool`, `YamlQueryTool`, and `TomlQueryTool` — query JSON/YAML/TOML (from a file or inline string) with a dot/bracket path expression (`users[0].name`, `services[].image`), or pretty-print with no query. YAML uses `safe_load`; TOML is parsed with a new dependency-free `SharedTools::TomlParser`, also ported from `ruby_llm-toolbox`. Path traversal is shared via a new `SharedTools::DataPath` module.
|
|
17
|
+
- Added `SharedTools::Tools::CsvReadTool` (read-only) and `SharedTools::Tools::CsvWriteTool` (mutating, requires authorization).
|
|
18
|
+
- Added `SharedTools::Tools::DiffTool`, ported from `ruby_llm-toolbox` — compares two in-memory blocks of text and returns a readable unified diff, via a new dependency-free `SharedTools::TextDiff` module. Read-only, no filesystem access.
|
|
19
|
+
- Added `SharedTools::Tools::MultiEditTool` — applies several find/replace edits to one file atomically; each edit's `old_string` must match exactly once (or `replace_all`) or the whole batch is rejected and nothing is written. Mutating, requires `SharedTools.execute?` authorization.
|
|
20
|
+
- Added `SharedTools::Tools::ApplyPatchTool` — applies a unified diff via `git apply`, validated with `--check` first; every touched path is confined to `root`. Set `check: true` for a dry run. Mutating, requires authorization.
|
|
21
|
+
- Added `SharedTools::Tools::GlobTool`, ported from `ruby_llm-toolbox` — finds files matching a glob pattern (`**/*.rb`), returns sorted paths relative to `base`. Read-only, in-process.
|
|
22
|
+
- Added `SharedTools::Tools::TreeTool`, ported from `ruby_llm-toolbox` — renders a depth-limited directory tree, skipping `.git`/`node_modules`/hidden entries by default. Read-only, in-process.
|
|
23
|
+
- **Breaking:** Replaced `SharedTools::Tools::SearchCodebaseTool`'s implementation with a pure-Ruby scanner ported from `ruby_llm-toolbox`'s `grep_files`, dropping the `rg`/`grep` shell-out dependency entirely. The regex is compiled with a per-match timeout so a malicious pattern can't hang the process (ReDoS guard), and `context`/`before`/`after` params add grep-style context lines around matches. **Param changes:** `term:` → `pattern:` (already treated as a regex by `rg`/`grep`, now explicit and validated), `extension:` → `glob:` (a filename glob like `"*.rb"` instead of a bare extension like `"rb"`). `max_results:` is unchanged. `result[:tool]` now always reports `"ruby"` instead of `"rg"`/`"grep"`.
|
|
24
|
+
- Added `SharedTools::Tools::ReplaceInFilesTool` — batch find/replace across files matching a glob (literal or regex, ReDoS-guarded), with `dry_run` preview. Mutating, requires authorization.
|
|
25
|
+
- Added Ruby dev tools, ported from `ruby_llm-toolbox`: `SharedTools::Tools::GemTool` (read-only RubyGems.org metadata lookup), `BundleTool` (Bundler install/update/outdated/check/lock/add), `LintTool` (RuboCop/Standard, auto-detected), and `ParseRubyTool` (structural outline of a Ruby file via a new `SharedTools::RubyOutline` module — Prism on Ruby 3.3+, Ripper stdlib fallback otherwise). Bundle/Lint require authorization; Gem/ParseRuby are read-only.
|
|
26
|
+
- Added background process management, ported from `ruby_llm-toolbox`: `SharedTools::Tools::ProcessStartTool`, `ProcessListTool`, `ProcessOutputTool`, and `ProcessKillTool`, backed by new `SharedTools::ProcessRegistry`/`ManagedProcess` support (thread-safe registry, bounded output buffers, SIGTERM→SIGKILL escalation across the whole process group, all processes cleaned up at exit). `ProcessStartTool` requires an executable on `allowed_commands` (empty by default) via a new `SharedTools::CommandGuard`, and requires authorization. `ProcessKillTool` requires no authorization — always available so a runaway can be stopped.
|
|
27
|
+
- Added guarded network tools, ported from `ruby_llm-toolbox`: `SharedTools::Tools::WebFetchTool` (fetch a URL, HTML stripped to text; read-only), `HttpRequestTool` (general HTTP client; GET/HEAD read-only, POST/PUT/PATCH/DELETE require authorization), and `DownloadFileTool` (download a URL to a file within `root`; requires authorization). All three go through a new `SharedTools::UrlGuard` (SSRF protection: http/https only, no embedded credentials, blocks private/loopback/link-local/cloud-metadata addresses, and pins the connection to the vetted IP to close the DNS-rebinding window).
|
|
28
|
+
- Added `SharedTools::Tools::TodoWriteTool` — maintains a replace-the-whole-list task tracker for multi-step work. Read-only (in-memory only), no authorization needed.
|
|
29
|
+
- Added `SharedTools::Tools::BashTool` — runs one allowlisted executable with argv-only arguments (no shell, so no pipes/redirects/globs/injection surface). `allowed_commands` is empty by default. Requires authorization.
|
|
30
|
+
- Added `SharedTools::Tools::RunTestsTool` (RSpec/Minitest, auto-detected) and `SharedTools::Tools::PythonTestsTool` (pytest/unittest), both via a new `SharedTools::Tools::ToolchainHelpers` module shared with BundleTool/LintTool. Both require authorization.
|
|
31
|
+
- **Scope note:** `ruby_llm-toolbox`'s `run_rust`/`run_python`/`run_ruby` (Docker-sandboxed code execution) were intentionally not ported — they depend on a much larger Docker sandbox subsystem this gem doesn't have. Also dropped: the toolbox's `allow_unsafe`/operator-override escape hatches on `bash_tool`, `process_start`, `http_request`, and `web_fetch` — shared_tools has no equivalent global-override concept, so commands/URLs are simply allowed or refused.
|
|
32
|
+
|
|
33
|
+
#### Tests
|
|
34
|
+
- Added `test/shared_tools/tools/git/*_tool_test.rb` (10 files) and `test/shared_tools/tools/git_tool_test.rb` covering all git tools, including ref-injection and path-jail rejection.
|
|
35
|
+
- Added `test/shared_tools/tools/{json,yaml,toml,csv}_*_tool_test.rb` covering the structured-data tools.
|
|
36
|
+
- Added `test/shared_tools/tools/{diff,multi_edit,apply_patch,replace_in_files}_tool_test.rb` covering the file-editing tools, including atomicity-on-failure and path-jail rejection.
|
|
37
|
+
- Added `test/shared_tools/tools/{glob,tree}_tool_test.rb` and rewrote `test/shared_tools/tools/search_codebase_tool_test.rb` for the new `pattern:`/`glob:` params, context blocks, and regex-error handling.
|
|
38
|
+
- Added `test/shared_tools/tools/{gem,bundle,lint,parse_ruby}_tool_test.rb` covering the Ruby dev tools.
|
|
39
|
+
- Added `test/shared_tools/tools/process_{start,list,output,kill}_tool_test.rb` covering the process-management tools, including allowlist rejection, the concurrency limit, and full start/list/output/kill lifecycles.
|
|
40
|
+
- Added `test/shared_tools/tools/{web_fetch,http_request,download_file}_tool_test.rb` covering the network tools, including live SSRF-block assertions against loopback and cloud-metadata addresses.
|
|
41
|
+
- Added `test/shared_tools/url_guard_test.rb` and `test/shared_tools/command_guard_test.rb` covering the new security modules directly.
|
|
42
|
+
- Added `test/shared_tools/tools/{todo_write,bash,run_tests,python_tests}_tool_test.rb`.
|
|
43
|
+
- Added `init_git_repo` / `git_commit_all` test helpers to `test/test_helper.rb`.
|
|
44
|
+
|
|
5
45
|
### [0.4.4] - 2026-06-06
|
|
6
46
|
|
|
7
47
|
#### Tools
|
data/README.md
CHANGED
|
@@ -16,7 +16,7 @@ SharedTools is a comprehensive collection of production-ready tools designed for
|
|
|
16
16
|
|
|
17
17
|
### Key Features
|
|
18
18
|
|
|
19
|
-
- 🔧 **
|
|
19
|
+
- 🔧 **45+ Production Tools** — Browser automation, file discovery and editing (glob/tree/diff/multi-edit/patch/replace), git, structured data (JSON/YAML/TOML/CSV), Ruby dev tooling (gem/bundle/lint/parse), background process management, guarded HTTP (fetch/request/download), database queries, code evaluation, document processing, DNS and WHOIS lookups, IP geolocation, data science, weather data, workflow management, system utilities, notifications, and more
|
|
20
20
|
- 🔒 **Human-in-the-Loop Authorization** — Built-in safety system for sensitive operations
|
|
21
21
|
- 🎯 **Facade Pattern** — Simplified interfaces with complex capabilities under the hood
|
|
22
22
|
- 🔌 **Pluggable Drivers** — Swap implementations for testing or different backends
|
|
@@ -120,6 +120,148 @@ content = disk.execute(action: "file_read", path: "./report.txt")
|
|
|
120
120
|
|
|
121
121
|
---
|
|
122
122
|
|
|
123
|
+
### 🔍 File Discovery Tools
|
|
124
|
+
|
|
125
|
+
Find files and content without shelling out to `rg`/`grep`/`find`. Pure Ruby, no external binary dependency.
|
|
126
|
+
|
|
127
|
+
- **`GlobTool`** — finds files matching a glob pattern (`**/*.rb`, `app/models/*.rb`), returns sorted paths relative to `base`.
|
|
128
|
+
- **`TreeTool`** — renders a depth-limited directory tree, skipping `.git`/`node_modules`/hidden entries by default.
|
|
129
|
+
- **`SearchCodebaseTool`** — searches file contents for a regular expression, returning `path:line: text` hits (or context blocks with `context`/`before`/`after`). ReDoS-guarded with a per-match regex timeout, and caps results at `max_results` (default 50, max 500).
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
glob = SharedTools::Tools::GlobTool.new
|
|
133
|
+
glob.execute(pattern: "**/*.rb", base: "./lib")
|
|
134
|
+
|
|
135
|
+
tree = SharedTools::Tools::TreeTool.new
|
|
136
|
+
tree.execute(path: "./lib", max_depth: 2)
|
|
137
|
+
|
|
138
|
+
search = SharedTools::Tools::SearchCodebaseTool.new
|
|
139
|
+
search.execute(pattern: "def execute", glob: "*.rb")
|
|
140
|
+
search.execute(pattern: "TODO", context: 2) # 2 lines of context around each match
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> **Note:** `SearchCodebaseTool`'s implementation changed from shelling out to `rg`/`grep` to a pure-Ruby, ReDoS-guarded scanner. The `term:` and `extension:` params were renamed to `pattern:` (a regex) and `glob:` (a filename glob, e.g. `"*.rb"` instead of `"rb"`); `max_results:` is unchanged. The `tool:` result key now always reports `"ruby"`.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
### ✂️ File Editing Tools
|
|
148
|
+
|
|
149
|
+
Precise, deterministic text editing that complements `DiskTool` and `GitTool` — an alternative to `Disk::FileReplaceTool`'s single global replace for coding-agent workflows.
|
|
150
|
+
|
|
151
|
+
- **`DiffTool`** — compares two in-memory blocks of text and returns a readable unified diff. Read-only, no filesystem access.
|
|
152
|
+
- **`MultiEditTool`** — applies several find/replace edits to one file atomically. Each edit's `old_string` must match exactly once (add context or set `replace_all`) or the whole batch is rejected and nothing is written. Requires authorization.
|
|
153
|
+
- **`ApplyPatchTool`** — applies a unified diff (as produced by `git diff`, `DiffTool`, or `diff -u`) via `git apply`, validating with `--check` first. Every touched path is confined to `root`. Set `check: true` for a dry run. Requires authorization.
|
|
154
|
+
- **`ReplaceInFilesTool`** — batch find/replace across every file in `root` matching a glob (default `**/*`). Literal by default; set `regex: true` for a pattern with `\1`-style backreferences. ReDoS-guarded, skips binary files and ignored directories. Set `dry_run: true` to preview without writing. Requires authorization (dry runs don't).
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
diff = SharedTools::Tools::DiffTool.new
|
|
158
|
+
diff.execute(old: old_text, new: new_text)
|
|
159
|
+
|
|
160
|
+
multi_edit = SharedTools::Tools::MultiEditTool.new(root: "./my-project")
|
|
161
|
+
multi_edit.execute(path: "lib/foo.rb", edits: [
|
|
162
|
+
{ old_string: "def bar", new_string: "def baz" },
|
|
163
|
+
{ old_string: "BAR", new_string: "BAZ", replace_all: true }
|
|
164
|
+
])
|
|
165
|
+
|
|
166
|
+
apply_patch = SharedTools::Tools::ApplyPatchTool.new(root: "./my-project")
|
|
167
|
+
apply_patch.execute(patch: unified_diff_text, check: true) # dry run
|
|
168
|
+
apply_patch.execute(patch: unified_diff_text)
|
|
169
|
+
|
|
170
|
+
replace = SharedTools::Tools::ReplaceInFilesTool.new(root: "./my-project")
|
|
171
|
+
replace.execute(pattern: "OldClassName", replacement: "NewClassName", glob: "**/*.rb")
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 🔀 Git Tools
|
|
177
|
+
|
|
178
|
+
Read a repository's history and working-tree state, and make basic mutating changes. Read-only actions (`status`, `diff`, `log`, `show`, `blame`, `branch`, `grep`) require no authorization; mutating actions (`add`, `commit`, `checkout`) require user authorization. External diff drivers, textconv filters, and `core.fsmonitor` are disabled so an untrusted checkout can't turn a read into command execution.
|
|
179
|
+
|
|
180
|
+
**Actions:** `status`, `diff`, `log`, `show`, `blame`, `branch`, `grep`, `add`, `commit`, `checkout`
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
git = SharedTools::Tools::GitTool.new(repo_root: "./my-project")
|
|
184
|
+
git.execute(action: "status")
|
|
185
|
+
git.execute(action: "diff", staged: true)
|
|
186
|
+
git.execute(action: "log", count: 10, path: "lib/foo.rb")
|
|
187
|
+
git.execute(action: "blame", path: "lib/foo.rb", start_line: 10, end_line: 20)
|
|
188
|
+
git.execute(action: "commit", message: "Fix the thing", all: true)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Each action is also available as a standalone tool, e.g. `SharedTools::Tools::Git::StatusTool`, `SharedTools::Tools::Git::DiffTool`, `SharedTools::Tools::Git::CommitTool`.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### 💎 Ruby Dev Tools
|
|
196
|
+
|
|
197
|
+
Tooling for working on a Ruby project: gem metadata, Bundler, linting, and structural code navigation.
|
|
198
|
+
|
|
199
|
+
- **`GemTool`** — read-only RubyGems.org metadata lookup (`info`, `version`, `dependencies`, `search`). No authorization needed.
|
|
200
|
+
- **`BundleTool`** — runs Bundler (`install`, `update`, `outdated`, `check`, `lock`, `add`) in a project. Requires a Gemfile and authorization.
|
|
201
|
+
- **`LintTool`** — runs RuboCop or Standard, auto-detected (Standard if `.standard.yml` is present) or forced explicitly. Uses `bundle exec` when a Gemfile exists. Offenses are a normal result, not an error; `autocorrect: true` rewrites files in place. Requires authorization.
|
|
202
|
+
- **`ParseRubyTool`** — outlines a Ruby file's structure (classes, modules, methods, constants with line numbers) via Prism (Ruby 3.3+) or the Ripper stdlib fallback — parses, never executes. Filter with `query`/`kind` to locate a specific definition. Read-only.
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
gem = SharedTools::Tools::GemTool.new
|
|
206
|
+
gem.execute(name: "ruby_llm", action: "version")
|
|
207
|
+
|
|
208
|
+
bundle = SharedTools::Tools::BundleTool.new(root: "./my-project")
|
|
209
|
+
bundle.execute(action: "add", gem: "rack")
|
|
210
|
+
|
|
211
|
+
lint = SharedTools::Tools::LintTool.new(root: "./my-project")
|
|
212
|
+
lint.execute(path: "lib/foo.rb", autocorrect: true)
|
|
213
|
+
|
|
214
|
+
parse = SharedTools::Tools::ParseRubyTool.new
|
|
215
|
+
parse.execute(path: "./lib/foo.rb")
|
|
216
|
+
parse.execute(path: "./lib/foo.rb", kind: "method", query: "initialize")
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
### ⚙️ Process Management Tools
|
|
222
|
+
|
|
223
|
+
Start, monitor, and stop long-running background processes (dev servers, watchers, log tails) without blocking the caller.
|
|
224
|
+
|
|
225
|
+
- **`ProcessStartTool`** — starts a command as a background process and returns its id immediately. The executable must be on `allowed_commands` (empty by default — nothing is allowed until configured); argv only, no shell. Runs in its own process group. Requires authorization.
|
|
226
|
+
- **`ProcessListTool`** — lists background processes: id, status, pid, age, command. Read-only.
|
|
227
|
+
- **`ProcessOutputTool`** — reads new stdout/stderr since the last read (poll it to follow output), plus status and exit code. Read-only.
|
|
228
|
+
- **`ProcessKillTool`** — SIGTERM the process group, escalating to SIGKILL if it doesn't exit, then returns final output. Always available with no authorization prompt, so a runaway process can always be stopped.
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
start = SharedTools::Tools::ProcessStartTool.new(allowed_commands: ["rackup"])
|
|
232
|
+
started = start.execute(command: "rackup", args: ["-p", "9292"], name: "web server")
|
|
233
|
+
id = started[/proc_\d+/]
|
|
234
|
+
|
|
235
|
+
output = SharedTools::Tools::ProcessOutputTool.new
|
|
236
|
+
output.execute(id: id) # poll this in a loop to stream output
|
|
237
|
+
|
|
238
|
+
SharedTools::Tools::ProcessListTool.new.execute
|
|
239
|
+
SharedTools::Tools::ProcessKillTool.new.execute(id: id)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### 🌐 Network Tools
|
|
245
|
+
|
|
246
|
+
Guarded HTTP — every request and redirect hop is checked against SSRF (server-side request forgery): only http/https, no embedded credentials, and the resolved IP is rejected (and the connection pinned to it) if it's private, loopback, link-local, cloud-metadata, or otherwise reserved.
|
|
247
|
+
|
|
248
|
+
- **`WebFetchTool`** — fetches a URL and returns readable text (HTML is stripped to text). Read-only, no authorization needed.
|
|
249
|
+
- **`HttpRequestTool`** — a general HTTP client returning status, key headers, and body. GET/HEAD need no authorization; POST/PUT/PATCH/DELETE require it.
|
|
250
|
+
- **`DownloadFileTool`** — downloads a URL to a file within `root`, size-capped. Requires authorization.
|
|
251
|
+
|
|
252
|
+
```ruby
|
|
253
|
+
fetch = SharedTools::Tools::WebFetchTool.new
|
|
254
|
+
fetch.execute(url: "https://example.com")
|
|
255
|
+
|
|
256
|
+
request = SharedTools::Tools::HttpRequestTool.new
|
|
257
|
+
request.execute(url: "https://api.example.com/items", method: "POST", body: '{"name":"x"}')
|
|
258
|
+
|
|
259
|
+
download = SharedTools::Tools::DownloadFileTool.new(root: "./downloads")
|
|
260
|
+
download.execute(url: "https://example.com/release.zip", path: "release.zip")
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
123
265
|
### 🗄️ Database Tools
|
|
124
266
|
|
|
125
267
|
Execute SQL operations on databases.
|
|
@@ -162,6 +304,39 @@ output = eval_tool.execute(language: "shell", code: "ls -la")
|
|
|
162
304
|
|
|
163
305
|
---
|
|
164
306
|
|
|
307
|
+
### 🖥️ Bash & Test Runner Tools
|
|
308
|
+
|
|
309
|
+
- **`BashTool`** — runs ONE allowlisted executable with arguments. Deliberately not a shell: no pipes, redirects, globs, or variable expansion, so OS command injection has no surface to exploit. `allowed_commands` is empty by default — nothing runs until configured. Requires authorization.
|
|
310
|
+
- **`RunTestsTool`** — runs a Ruby project's test suite (RSpec or Minitest, auto-detected). A failing suite is a normal result, not a tool error. Requires authorization.
|
|
311
|
+
- **`PythonTestsTool`** — runs a Python project's tests (pytest or unittest). Requires authorization.
|
|
312
|
+
|
|
313
|
+
```ruby
|
|
314
|
+
bash = SharedTools::Tools::BashTool.new(allowed_commands: ["ls", "cat"])
|
|
315
|
+
bash.execute(command: "ls", args: ["-la"])
|
|
316
|
+
|
|
317
|
+
tests = SharedTools::Tools::RunTestsTool.new(root: "./my-project")
|
|
318
|
+
tests.execute(path: "spec/models/user_spec.rb")
|
|
319
|
+
|
|
320
|
+
py_tests = SharedTools::Tools::PythonTestsTool.new(root: "./my-project")
|
|
321
|
+
py_tests.execute(framework: "unittest")
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### ✅ Task Tracking
|
|
327
|
+
|
|
328
|
+
**`TodoWriteTool`** maintains a task list for multi-step work. Each call replaces the whole list and renders it back; state lives on the tool instance for the duration of a chat session. No authorization needed.
|
|
329
|
+
|
|
330
|
+
```ruby
|
|
331
|
+
todo = SharedTools::Tools::TodoWriteTool.new
|
|
332
|
+
todo.execute(todos: [
|
|
333
|
+
{ content: "Write the tool", status: "completed" },
|
|
334
|
+
{ content: "Write the tests", status: "in_progress" }
|
|
335
|
+
])
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
165
340
|
### 📄 Doc Tools
|
|
166
341
|
|
|
167
342
|
Read and reason over documents in any format.
|
|
@@ -208,6 +383,31 @@ dns.execute(action: "ip_location", host: "8.8.8.8") # geolocate any IP
|
|
|
208
383
|
|
|
209
384
|
---
|
|
210
385
|
|
|
386
|
+
### 🧩 Structured Data Tools
|
|
387
|
+
|
|
388
|
+
Query and edit JSON, YAML, TOML, and CSV without writing a parser. Each query tool accepts either a file path or an inline string, and supports a dot/bracket path expression to extract a value (`users[0].name`, `services[].image`, `dependencies.serde.version`) — omit the query to pretty-print the whole document. YAML is loaded with `safe_load` (no arbitrary object deserialization) and TOML is parsed with a small dependency-free parser.
|
|
389
|
+
|
|
390
|
+
```ruby
|
|
391
|
+
json = SharedTools::Tools::JsonQueryTool.new
|
|
392
|
+
json.execute(path: "./config.json", query: "servers[0].host")
|
|
393
|
+
|
|
394
|
+
yaml = SharedTools::Tools::YamlQueryTool.new
|
|
395
|
+
yaml.execute(path: "./docker-compose.yml", query: "services[].image")
|
|
396
|
+
|
|
397
|
+
toml = SharedTools::Tools::TomlQueryTool.new
|
|
398
|
+
toml.execute(path: "./Cargo.toml", query: "dependencies.serde.version")
|
|
399
|
+
|
|
400
|
+
csv_read = SharedTools::Tools::CsvReadTool.new
|
|
401
|
+
csv_read.execute(path: "./sales.csv", limit: 20)
|
|
402
|
+
|
|
403
|
+
csv_write = SharedTools::Tools::CsvWriteTool.new
|
|
404
|
+
csv_write.execute(path: "./out.csv", headers: ["name", "age"], rows: [["Alice", "30"]])
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
`CsvWriteTool` is mutating and requires user authorization (see [Authorization System](#authorization-system)); the query tools and `CsvReadTool` are read-only.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
211
411
|
### 🌤️ Weather Tool
|
|
212
412
|
|
|
213
413
|
Real-time weather data from OpenWeatherMap API. Combine with DnsTool for automatic local forecasts.
|
|
@@ -440,14 +640,16 @@ SharedTools bundles [Model Context Protocol](https://modelcontextprotocol.io) cl
|
|
|
440
640
|
| `require 'shared_tools/mcp/playwright_client'` | Browser automation: navigate, click, fill, screenshot, extract |
|
|
441
641
|
|
|
442
642
|
```ruby
|
|
443
|
-
#
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
# Or load a specific client
|
|
643
|
+
# Each client is a RubyLLM::MCP subclass (ruby_llm >= 2.1). Defining it starts
|
|
644
|
+
# nothing; the server is launched/connected when its tools are first requested.
|
|
447
645
|
require 'shared_tools/mcp/notion_client'
|
|
448
|
-
|
|
449
|
-
chat = RubyLLM.chat.with_tools(*client.tools)
|
|
646
|
+
chat = RubyLLM.chat.with_mcp(SharedTools::MCP::Notion)
|
|
450
647
|
chat.ask("Find my project planning pages and summarise what's in them")
|
|
648
|
+
|
|
649
|
+
# Load every definition; .available skips those whose env vars are missing
|
|
650
|
+
require 'shared_tools/mcp'
|
|
651
|
+
chat = RubyLLM.chat.with_mcp(*SharedTools::MCP.available)
|
|
652
|
+
robot = RobotLab.build(name: "helper", mcp: SharedTools::MCP.available)
|
|
451
653
|
```
|
|
452
654
|
|
|
453
655
|
See [MCP Clients README](lib/shared_tools/mcp/README.md) for full configuration details.
|
|
@@ -596,6 +798,8 @@ This gem is available as open source under the terms of the [MIT License](LICENS
|
|
|
596
798
|
|
|
597
799
|
This gem was originally inspired by Kevin Sylvestre's [omniai-tools](https://github.com/ksylvest/omniai-tools) gem. SharedTools has since evolved to focus exclusively on RubyLLM support with enhanced features and comprehensive documentation.
|
|
598
800
|
|
|
801
|
+
Also checkout the wonderful ruby gem [ruby_llm-toolbox](https://rubygems.org/gems/ruby_llm-toolbox)
|
|
802
|
+
|
|
599
803
|
## Links
|
|
600
804
|
|
|
601
805
|
- **Documentation**: [madbomber.github.io/shared_tools](https://madbomber.github.io/shared_tools)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SharedTools
|
|
4
|
+
# Validates the executable name for BashTool and ProcessStartTool. The
|
|
5
|
+
# actual execution path uses array-form spawning (no shell), so this guard
|
|
6
|
+
# only has to ensure the program itself is on the allowlist and isn't
|
|
7
|
+
# smuggling a path or shell metacharacters. Arguments are passed verbatim as
|
|
8
|
+
# argv and are therefore inert — there is no shell to interpret them.
|
|
9
|
+
class CommandGuard
|
|
10
|
+
class Blocked < StandardError; end
|
|
11
|
+
|
|
12
|
+
SHELL_META = /[;&|<>`$(){}\[\]*?!#~\n\r]/
|
|
13
|
+
PATH_SEP = %r{[/\\]}
|
|
14
|
+
|
|
15
|
+
def initialize(allowed)
|
|
16
|
+
@allowed = Array(allowed).map(&:to_s)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Returns the validated executable name, or raises Blocked.
|
|
20
|
+
def check!(command)
|
|
21
|
+
cmd = command.to_s
|
|
22
|
+
raise Blocked, "no command given" if cmd.empty?
|
|
23
|
+
|
|
24
|
+
raise Blocked, "executable name may not contain a path: #{cmd.inspect}" if cmd.match?(PATH_SEP)
|
|
25
|
+
raise Blocked, "executable name may not contain shell metacharacters: #{cmd.inspect}" if cmd.match?(SHELL_META)
|
|
26
|
+
|
|
27
|
+
unless @allowed.include?(cmd)
|
|
28
|
+
raise Blocked, "command not allowed: #{cmd.inspect} " \
|
|
29
|
+
"(allowed: #{@allowed.empty? ? '(none)' : @allowed.join(', ')})"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
cmd
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SharedTools
|
|
4
|
+
# Shared path-navigation for the structured-data query tools (JsonQueryTool,
|
|
5
|
+
# YamlQueryTool, TomlQueryTool). Path syntax: dot-separated keys, [n] for
|
|
6
|
+
# array indices, and [] to map a field across an array. Examples:
|
|
7
|
+
# users[0].name users[].email config.server.port
|
|
8
|
+
module DataPath
|
|
9
|
+
class Error < StandardError; end
|
|
10
|
+
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def query(data, path)
|
|
14
|
+
apply(data, parse(path))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def parse(path)
|
|
18
|
+
cleaned = path.to_s.strip.sub(/\A\$?\.?/, "")
|
|
19
|
+
tokens = []
|
|
20
|
+
cleaned.scan(/[^.\[\]]+|\[\d+\]|\[\]/) do |match|
|
|
21
|
+
tokens << case match
|
|
22
|
+
when "[]" then :map
|
|
23
|
+
when /\A\[(\d+)\]\z/ then Regexp.last_match(1).to_i
|
|
24
|
+
else match
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
raise Error, "could not parse path: #{path.inspect}" if tokens.empty?
|
|
28
|
+
|
|
29
|
+
tokens
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def apply(data, tokens)
|
|
33
|
+
return data if tokens.empty? || data.nil?
|
|
34
|
+
|
|
35
|
+
token, *rest = tokens
|
|
36
|
+
case token
|
|
37
|
+
when :map
|
|
38
|
+
raise Error, "[] expects an array, got #{data.class}" unless data.is_a?(Array)
|
|
39
|
+
|
|
40
|
+
data.map { |element| apply(element, rest) }
|
|
41
|
+
when Integer
|
|
42
|
+
raise Error, "index [#{token}] expects an array, got #{data.class}" unless data.is_a?(Array)
|
|
43
|
+
|
|
44
|
+
apply(data[token], rest)
|
|
45
|
+
else
|
|
46
|
+
raise Error, "key '#{token}' expects an object, got #{data.class}" unless data.is_a?(Hash)
|
|
47
|
+
|
|
48
|
+
apply(data[token], rest)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# shared_tools/mcp/brave_search_client.rb
|
|
2
4
|
#
|
|
3
5
|
# Brave Search MCP Server — npx auto-download (no pre-installation required)
|
|
@@ -8,30 +10,30 @@
|
|
|
8
10
|
# - Node.js and npx (https://nodejs.org)
|
|
9
11
|
# - A Brave Search API key (free tier available at https://brave.com/search/api/)
|
|
10
12
|
# The @modelcontextprotocol/server-brave-search package is downloaded
|
|
11
|
-
# automatically
|
|
13
|
+
# automatically the first time the server is started, via `npx -y`.
|
|
12
14
|
#
|
|
13
15
|
# Configuration:
|
|
14
16
|
# export BRAVE_API_KEY=your_api_key_here
|
|
15
17
|
#
|
|
16
18
|
# Usage:
|
|
17
19
|
# require 'shared_tools/mcp/brave_search_client'
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
+
# chat = RubyLLM.chat.with_mcp(SharedTools::MCP::BraveSearch)
|
|
21
|
+
# robot = RobotLab.build(name: "researcher", mcp: [SharedTools::MCP::BraveSearch])
|
|
20
22
|
#
|
|
21
|
-
#
|
|
23
|
+
# Requires ruby_llm >= 2.1 (built-in RubyLLM::MCP). Nothing starts until the
|
|
24
|
+
# server's tools are first requested.
|
|
22
25
|
|
|
23
|
-
require_relative "
|
|
26
|
+
require_relative "client_support"
|
|
24
27
|
|
|
25
|
-
SharedTools
|
|
28
|
+
module SharedTools
|
|
29
|
+
module MCP
|
|
30
|
+
class BraveSearch < ::RubyLLM::MCP
|
|
31
|
+
extend ClientSupport
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
requires_envars "BRAVE_API_KEY"
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
args: ["-y", "@modelcontextprotocol/server-brave-search"],
|
|
35
|
-
env: { "BRAVE_API_KEY" => ENV.fetch("BRAVE_API_KEY", "") },
|
|
36
|
-
},
|
|
37
|
-
)
|
|
35
|
+
command "npx", "-y", "@modelcontextprotocol/server-brave-search"
|
|
36
|
+
env "BRAVE_API_KEY" => env_from("BRAVE_API_KEY")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# shared_tools/mcp/chart_client.rb
|
|
2
4
|
#
|
|
3
5
|
# AntV Chart MCP Server — npx auto-download (no pre-installation required)
|
|
@@ -7,26 +9,27 @@
|
|
|
7
9
|
#
|
|
8
10
|
# Prerequisites:
|
|
9
11
|
# - Node.js and npx (https://nodejs.org)
|
|
10
|
-
# The @antv/mcp-server-chart package is downloaded automatically
|
|
11
|
-
# via `npx -y`.
|
|
12
|
+
# The @antv/mcp-server-chart package is downloaded automatically the first
|
|
13
|
+
# time the server is started, via `npx -y`.
|
|
12
14
|
#
|
|
13
15
|
# No API key required.
|
|
14
16
|
#
|
|
15
17
|
# Usage:
|
|
16
18
|
# require 'shared_tools/mcp/chart_client'
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
+
# chat = RubyLLM.chat.with_mcp(SharedTools::MCP::Chart)
|
|
20
|
+
# robot = RobotLab.build(name: "analyst", mcp: [SharedTools::MCP::Chart])
|
|
19
21
|
#
|
|
20
|
-
#
|
|
22
|
+
# Requires ruby_llm >= 2.1 (built-in RubyLLM::MCP). Nothing starts until the
|
|
23
|
+
# server's tools are first requested.
|
|
24
|
+
|
|
25
|
+
require_relative "client_support"
|
|
21
26
|
|
|
22
|
-
|
|
27
|
+
module SharedTools
|
|
28
|
+
module MCP
|
|
29
|
+
class Chart < ::RubyLLM::MCP
|
|
30
|
+
extend ClientSupport
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
command: "npx",
|
|
29
|
-
args: ["-y", "@antv/mcp-server-chart"],
|
|
30
|
-
env: {},
|
|
31
|
-
},
|
|
32
|
-
)
|
|
32
|
+
command "npx", "-y", "@antv/mcp-server-chart"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|