Skip to content

Commit ef4bfba

Browse files
committed
Initial Commit
1 parent 8d8e8f9 commit ef4bfba

File tree

12 files changed

+178
-0
lines changed

12 files changed

+178
-0
lines changed

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,5 @@ group :development do
5555
gem "web-console"
5656
end
5757
gem "hotwire-spark", group: :development
58+
59+
gem "fast-mcp", "~> 1.5"

Gemfile.lock

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ GEM
7272
securerandom (>= 0.3)
7373
tzinfo (~> 2.0, >= 2.0.5)
7474
uri (>= 0.13.1)
75+
addressable (2.8.7)
76+
public_suffix (>= 2.0.2, < 7.0)
7577
ast (2.4.3)
7678
base64 (0.3.0)
7779
bcrypt_pbkdf (1.1.1)
@@ -92,11 +94,47 @@ GEM
9294
reline (>= 0.3.8)
9395
dotenv (3.1.8)
9496
drb (2.2.3)
97+
dry-configurable (1.3.0)
98+
dry-core (~> 1.1)
99+
zeitwerk (~> 2.6)
100+
dry-core (1.1.0)
101+
concurrent-ruby (~> 1.0)
102+
logger
103+
zeitwerk (~> 2.6)
104+
dry-inflector (1.2.0)
105+
dry-initializer (3.2.0)
106+
dry-logic (1.6.0)
107+
bigdecimal
108+
concurrent-ruby (~> 1.0)
109+
dry-core (~> 1.1)
110+
zeitwerk (~> 2.6)
111+
dry-schema (1.14.1)
112+
concurrent-ruby (~> 1.0)
113+
dry-configurable (~> 1.0, >= 1.0.1)
114+
dry-core (~> 1.1)
115+
dry-initializer (~> 3.2)
116+
dry-logic (~> 1.5)
117+
dry-types (~> 1.8)
118+
zeitwerk (~> 2.6)
119+
dry-types (1.8.3)
120+
bigdecimal (~> 3.0)
121+
concurrent-ruby (~> 1.0)
122+
dry-core (~> 1.0)
123+
dry-inflector (~> 1.0)
124+
dry-logic (~> 1.4)
125+
zeitwerk (~> 2.6)
95126
ed25519 (1.4.0)
96127
erb (5.0.2)
97128
erubi (1.13.1)
98129
et-orbi (1.2.11)
99130
tzinfo
131+
fast-mcp (1.5.0)
132+
addressable (~> 2.8)
133+
base64
134+
dry-schema (~> 1.14)
135+
json (~> 2.0)
136+
mime-types (~> 3.4)
137+
rack (~> 3.1)
100138
ffi (1.17.2-aarch64-linux-gnu)
101139
ffi (1.17.2-aarch64-linux-musl)
102140
ffi (1.17.2-arm-linux-gnu)
@@ -151,6 +189,10 @@ GEM
151189
net-pop
152190
net-smtp
153191
marcel (1.0.4)
192+
mime-types (3.7.0)
193+
logger
194+
mime-types-data (~> 3.2025, >= 3.2025.0507)
195+
mime-types-data (3.2025.0729)
154196
mini_mime (1.1.5)
155197
minitest (5.25.5)
156198
msgpack (1.8.0)
@@ -199,6 +241,7 @@ GEM
199241
psych (5.2.6)
200242
date
201243
stringio
244+
public_suffix (6.0.2)
202245
puma (6.6.1)
203246
nio4r (~> 2.0)
204247
raabro (1.4.0)
@@ -365,6 +408,7 @@ DEPENDENCIES
365408
bootsnap
366409
brakeman
367410
debug
411+
fast-mcp (~> 1.5)
368412
hotwire-spark
369413
importmap-rails
370414
kamal

app/models/user.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class User < ApplicationRecord
2+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
class ApplicationResource < ActionResource::Base
4+
# write your custom logic to be shared across all resources here
5+
end

app/resources/sample_resource.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
class SampleResource < ApplicationResource
4+
uri "examples/users"
5+
resource_name "Users"
6+
description "A user resource for demonstration"
7+
mime_type "application/json"
8+
9+
def content
10+
JSON.generate(User.all.as_json)
11+
end
12+
end

app/tools/application_tool.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
class ApplicationTool < ActionTool::Base
4+
# write your custom logic to be shared across all tools here
5+
end

app/tools/sample_tool.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
class SampleTool < ApplicationTool
4+
description "Greet a user"
5+
6+
arguments do
7+
required(:id).filled(:integer).description("ID of the user to greet")
8+
optional(:prefix).filled(:string).description("Prefix to add to the greeting")
9+
end
10+
11+
def call(id:, prefix: "Hey")
12+
user = User.find(id)
13+
14+
"#{prefix} #{user.name} !"
15+
end
16+
end

app/tools/users_create_tool.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
class UsersCreateTool < ApplicationTool
4+
description "Create a user"
5+
6+
arguments do
7+
required(:name).filled(:string).description("Name of the user")
8+
required(:email).filled(:string).description("Email of the user")
9+
required(:age).filled(:integer).description("Age of the user")
10+
end
11+
12+
def call(name:, email:, age:)
13+
user = User.create!(name: name, email: email, age: age)
14+
15+
"User created: #{user.inspect}"
16+
end
17+
end

config/application.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,6 @@ class Application < Rails::Application
4444
g.test_framework nil
4545
g.jbuilder false
4646
end
47+
config.hosts << "b69340af24ec.ngrok-free.app"
4748
end
4849
end

config/initializers/fast_mcp.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
# FastMcp - Model Context Protocol for Rails
4+
# This initializer sets up the MCP middleware in your Rails application.
5+
#
6+
# In Rails applications, you can use:
7+
# - ActionTool::Base as an alias for FastMcp::Tool
8+
# - ActionResource::Base as an alias for FastMcp::Resource
9+
#
10+
# All your tools should inherit from ApplicationTool which already uses ActionTool::Base,
11+
# and all your resources should inherit from ApplicationResource which uses ActionResource::Base.
12+
13+
# Mount the MCP middleware in your Rails application
14+
# You can customize the options below to fit your needs.
15+
require "fast_mcp"
16+
17+
FastMcp.mount_in_rails(
18+
Rails.application,
19+
name: Rails.application.class.module_parent_name.underscore.dasherize,
20+
version: "1.0.0",
21+
path_prefix: "/mcp", # This is the default path prefix
22+
messages_route: "messages", # This is the default route for the messages endpoint
23+
sse_route: "sse", # This is the default route for the SSE endpoint
24+
# Add allowed origins below, it defaults to Rails.application.config.hosts
25+
allowed_origins: [ "localhost", "127.0.0.1", "[::1]", "b69340af24ec.ngrok-free.app", /.*\.example\.com/ ],
26+
localhost_only: false, # Set to false to allow connections from other hosts
27+
# whitelist specific ips to if you want to run on localhost and allow connections from other IPs
28+
# allowed_ips: ['127.0.0.1', '::1']
29+
# authenticate: true, # Uncomment to enable authentication
30+
# auth_token: 'your-token', # Required if authenticate: true
31+
) do |server|
32+
Rails.application.config.after_initialize do
33+
# FastMcp will automatically discover and register:
34+
# - All classes that inherit from ApplicationTool (which uses ActionTool::Base)
35+
# - All classes that inherit from ApplicationResource (which uses ActionResource::Base)
36+
server.register_tools(*ApplicationTool.descendants)
37+
server.register_resources(*ApplicationResource.descendants)
38+
# alternatively, you can register tools and resources manually:
39+
# server.register_tool(MyTool)
40+
# server.register_resource(MyResource)
41+
end
42+
end

0 commit comments

Comments
 (0)