Fast MCP Server Tutorial¶
fast-mcp exposes Fast's Ruby AST search and rewrite primitives as MCP tools over stdio. It is best when an LLM host can register an MCP server and call tools directly instead of parsing CLI text output.
What the server exposes¶
The current server exposes five tools:
search_ruby_astruby_method_sourceruby_class_sourcerewrite_rubyrewrite_ruby_filerun_fast_experiment
These are MCP tools, not MCP resources. If your host lists resources/templates and shows nothing, that does not mean the server is broken. It means the host has not connected to the server's tool interface.
When MCP is better than CLI¶
Use MCP when:
- Your host supports MCP server registration and tool calling.
- You want structured JSON results without asking the model to parse CLI text.
- You want the host to decide when to call
ruby_method_sourceorsearch_ruby_astas a first-class tool.
Use the CLI when:
- Your host cannot register MCP servers.
- You only need ad hoc terminal searches.
- You want the simplest possible integration surface.
In practice, CLI is the easiest integration to get working. MCP is the better long-term interface for LLM agents because it preserves typed arguments and structured responses.
Security warning¶
fast-mcp must be treated as a trusted local development tool.
Register it only with hosts you trust with the same level of access you would grant to a local shell session in the repository. The server can:
- read and return source code from files under the paths you provide
- rewrite files in place through
rewrite_ruby_file - execute Ruby and shell commands through
run_fast_experiment
Because of that, do not expose bin/fast-mcp to untrusted remote clients, browser-accessible services, shared multi-tenant environments, or arbitrary third-party prompts.
If your use case only needs search and inspection, the CLI is the safer integration surface because it avoids registering a long-lived tool server with write and command-execution capabilities.
Testing it locally with JSON-RPC¶
The server speaks JSON-RPC 2.0 over stdio through bin/fast-mcp.
1. List the tools¶
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
| ruby -Ilib bin/fast-mcp
2. Extract a specific method¶
printf '%s\n' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ruby_method_source","arguments":{"method_name":"search_all","paths":["lib"]}}}' \
| ruby -Ilib bin/fast-mcp
This returns a JSON payload whose result.content[0].text is itself a JSON array of matches. Each match includes file, line_start, line_end, and the trimmed code snippet.
3. Extract a method from a known class¶
printf '%s\n' \
'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"ruby_method_source","arguments":{"method_name":"run","class_name":"McpServer","paths":["lib"]}}}' \
| ruby -Ilib bin/fast-mcp
This is often more token-efficient than returning the full class body.
4. Search with a raw AST pattern¶
printf '%s\n' \
'{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"search_ruby_ast","arguments":{"pattern":"(send nil :require (str _))","paths":["lib/fast/mcp_server.rb"]}}}' \
| ruby -Ilib bin/fast-mcp
Set "show_ast": true only when you need the s-expression too.
5. Preview a rewrite without touching disk¶
printf '%s\n' \
'{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"rewrite_ruby","arguments":{"source":"def foo; puts 1; end","pattern":"(send nil :puts (int 1))","replacement":"logger.info('\''hello'\'')"}}}' \
| ruby -Ilib bin/fast-mcp
Fast validates the rewritten Ruby before returning it. That matters for LLM workflows because a bad replacement fails early instead of feeding invalid code back into the next tool call.
6. Rewrite a file in place¶
printf '%s\n' \
'{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"rewrite_ruby_file","arguments":{"file":"lib/fast/mcp_server.rb","pattern":"(send nil :require (str \"json\"))","replacement":"require '\''json'\''"}}}' \
| ruby -Ilib bin/fast-mcp
Prefer rewrite_ruby first to preview the change.
7. Run an automated experiment to validate a refactoring hypothesis¶
The run_fast_experiment tool allows you to safely test refactoring hypotheses across an entire folder. It uses Fast's internal divide-and-conquer testing algorithm. The mutation is only applied if the policy block executes successfully (e.g. your tests pass).
This tool is intentionally powerful and should be considered high trust. It evaluates the edit expression and executes the policy command as the current user.
printf '%s\n' \
'{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"run_fast_experiment","arguments":{"name":"RSpec/UseBuildStubbed","lookup":"spec","search":"(send nil :create)","edit":"replace(node.loc.expression, \"build_stubbed\")","policy":"bin/spring rspec --fail-fast {file}"}}}' \
| ruby -Ilib bin/fast-mcp
This is particularly useful for agents that need to introduce large-scale replacements or code refactoring across a codebase, such as:
- Replacing FactoryBot.create with build_stubbed.
- Migrating deprecated test assertions (e.g. expect(a).to eq(true) to expect(a).to be(true)).
- Automatically dropping useless before and after blocks.
- Exploring any global Search-and-Replace ideas that need automated validation.
Error behavior¶
- Missing paths return MCP error
-32603with the underlying file error. - Invalid AST patterns currently return an empty result array
[]. - Invalid rewrite output returns MCP error
-32603with parser diagnostics, andrewrite_ruby_filedoes not modify the file. - Unknown tool names return MCP error
-32603.
Current limitations¶
ruby_method_sourcewithclass_namefilters by file membership, not lexical scope. If a file defines the class anywhere, matching methods in that file can pass the filter.ruby_class_sourcereturns the full class body, which can still be large for token-sensitive workflows.- Hosts must register the server explicitly. A raw MCP resource list will stay empty because this server does not publish resources.
Best practices¶
- Start with
ruby_method_sourcewhen you know the method name. - Use
search_ruby_astfor call sites and structural queries. - Prefer method-level extraction over class-level extraction to save tokens.
- Fall back to the CLI for hosts that cannot call MCP tools yet.
- Avoid
run_fast_experimentunless the host and prompt are fully trusted.