fast-mcp 1.4.0 → 1.6.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 +69 -5
- data/README.md +78 -22
- data/lib/fast_mcp.rb +3 -14
- data/lib/generators/fast_mcp/install/templates/fast_mcp_initializer.rb +2 -2
- data/lib/generators/fast_mcp/install/templates/sample_tool.rb +7 -0
- data/lib/mcp/railtie.rb +4 -0
- data/lib/mcp/resource.rb +86 -29
- data/lib/mcp/server.rb +107 -75
- data/lib/mcp/server_filtering.rb +80 -0
- data/lib/mcp/tool.rb +218 -632
- data/lib/mcp/transports/base_transport.rb +2 -2
- data/lib/mcp/transports/rack_transport.rb +148 -62
- data/lib/mcp/version.rb +1 -1
- metadata +27 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37917d61ab02f9d3a42e8980b9007bdb0003f2b91847b5cfe6e6a5f0043550cd
|
4
|
+
data.tar.gz: 476fa4ea8a2c022c255edcf3e5b3d101748fddaa8643569d2bc999ef8ec74eee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f12f0d7bf4a4f36b4a5d6c642160c01ccf40d5b799020cbc2c16646c7332b51083bc525c867f38cd2d5a68b3757f51f2fb0f632c35e004c7fcd7a8cb0f571cdf
|
7
|
+
data.tar.gz: 559edc8f334fcf49c16b001c8e36e4ea7aa664b2f53e2fa5f83edd171442dfe927cdd42cbbfaeb5572a174347729b193ec6b000f6b43ffd6850021365967f913
|
data/CHANGELOG.md
CHANGED
@@ -5,50 +5,109 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [1.6.0] - 2025-09-28
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- Tool annotations support for providing hints about tool behavior (readOnlyHint, destructiveHint, etc.) [#96 @pauloarruda](https://github.com/yjacquin/fast-mcp/pull/96)
|
13
|
+
- GitHub Discussions link in README [#139 @jeznicholson](https://github.com/yjacquin/fast-mcp/pull/139)
|
14
|
+
- GitHub Sponsors funding configuration [#3d5a7e5 @yjacquin](https://github.com/yjacquin/fast-mcp/commit/3d5a7e5)
|
15
|
+
- Server hook `on_error_result` for handling tool execution errors [#129 @yannickutard](https://github.com/yjacquin/fast-mcp/pull/129)
|
16
|
+
- Support for transport option in rack_middleware [#149 @josevalim](https://github.com/yjacquin/fast-mcp/pull/149)
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
|
20
|
+
- Tool name validation and override for invalid names [#100 @abdelrahmanothman](https://github.com/yjacquin/fast-mcp/pull/100)
|
21
|
+
- Typo fixes in sinatra_integration.md [#131 @ilyakamenko](https://github.com/yjacquin/fast-mcp/pull/131) [#102 @anton](https://github.com/yjacquin/fast-mcp/pull/102)
|
22
|
+
- Add trailing comma to generated initializer template for better Ruby style [#123 @zachhaitz](https://github.com/yjacquin/fast-mcp/pull/123)
|
23
|
+
- Fix missing commas for params hash [#121 @FanaHOVA](https://github.com/yjacquin/fast-mcp/pull/121)
|
24
|
+
- RuboCop linting issues resolution [fa6af0b @yjacquin](https://github.com/yjacquin/fast-mcp/commit/fa6af0b)
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
|
28
|
+
- Updated GitHub Actions dependencies: checkout v4→v5, download-artifact v4→v5 [#141 #142 @dependabot](https://github.com/yjacquin/fast-mcp/pull/141)
|
29
|
+
- Relax Rack version requirements for better compatibility (>= 2.0, < 4.0) [#133 @eproulx](https://github.com/yjacquin/fast-mcp/pull/133)
|
30
|
+
- Load generators only when necessary for improved performance [#153 @josevalim](https://github.com/yjacquin/fast-mcp/pull/153)
|
31
|
+
- Drop schema compiler to use Dry's built-in functionality [#152 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/152), thanks @redox for the help !
|
32
|
+
|
33
|
+
## [1.5.0] - 2025-06-01
|
34
|
+
|
35
|
+
### Added
|
36
|
+
|
37
|
+
- Handle filtering tools and resources [#85 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/85)
|
38
|
+
- Support for resource templates 🥳 Big thanks to @danielcooper for the contribution [#84 co-authored by @danielcooper and @yjacquin](https://github.com/yjacquin/fast-mcp/pull/84)
|
39
|
+
- Possibility to authorize requests before tool calls [#79 @EuanEdgar](https://github.com/yjacquin/fast-mcp/pull/79)
|
40
|
+
- Possibility to read request headers in tool calls [#78 @EuanEdgar](https://github.com/yjacquin/fast-mcp/pull/78)
|
41
|
+
|
42
|
+
### Changed
|
43
|
+
|
44
|
+
- Bump Dependencies [#86 @aothelal](https://github.com/yjacquin/fast-mcp/pull/86)
|
45
|
+
- ⚠️ Resources are now stateless, meaning that in-memory resources won't work anymore, they require an external data source such as database, file to read and write too, etc. This was needed for a refactoring of the resource class for the [resource template PR](https://github.com/yjacquin/fast-mcp/pull/84)
|
46
|
+
|
47
|
+
### Fixed
|
48
|
+
|
49
|
+
- Stop overriding log level to info [#91 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/91)
|
50
|
+
- Properly handle ping request responses from clients [#89 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/89)
|
51
|
+
- Add Thread Safety to RackTransport sse_clients [#82 @Kevin-K](https://github.com/yjacquin/fast-mcp/pull/82)
|
52
|
+
|
8
53
|
## [1.4.0] - 2025-05-10
|
54
|
+
|
9
55
|
### Added
|
56
|
+
|
10
57
|
- Conditionnally hidden properties for tool calls (#70) [#70 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/70)
|
11
58
|
- Metadata to tool call results (#69) [#69 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/69)
|
12
59
|
- Link to official Discord Server in README.md
|
13
60
|
|
14
61
|
## [1.3.2] - 2025-05-08
|
62
|
+
|
15
63
|
### Changed
|
64
|
+
|
16
65
|
- Logs are now less verbose by default [#64 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/64)
|
66
|
+
|
17
67
|
### Fixed
|
68
|
+
|
18
69
|
- Fix undefined method `call' for an instance of String error log [#61 @radwo](https://github.com/yjacquin/fast-mcp/pull/61)
|
19
70
|
|
20
71
|
## [1.3.1] - 2025-04-30
|
72
|
+
|
21
73
|
### Fixed
|
22
|
-
|
23
|
-
-
|
24
|
-
-
|
74
|
+
|
75
|
+
- Allow ipv4 mapped to ipv6 (#56) [#56 @josevalim](https://github.com/yjacquin/fast-mcp/pull/56)
|
76
|
+
- Add items to array (#55) [#55 @josevalim](https://github.com/yjacquin/fast-mcp/pull/56)
|
77
|
+
- Ping is a regular message event (#54) [#56 @josevalim](https://github.com/yjacquin/fast-mcp/pull/56)
|
25
78
|
|
26
79
|
## [1.3.0] - 2025-04-28
|
80
|
+
|
27
81
|
### Added
|
82
|
+
|
28
83
|
- Added automatic forwarding of query params from to the messages endpoint [@yjacquin](https://github.com/yjacquin/fast-mcp/commit/011d968ac982d0b0084f7753dcac5789f66339ee)
|
29
84
|
|
30
85
|
### Fixed
|
86
|
+
|
31
87
|
- Declare rack as an explicit dependency [#49 @subelsky](https://github.com/yjacquin/fast-mcp/pull/49)
|
32
88
|
- Fix notifications/initialized response [#51 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/51)
|
33
89
|
|
34
90
|
## [1.2.0] - 2025-04-21
|
91
|
+
|
35
92
|
### Added
|
93
|
+
|
36
94
|
- Security enhancement: Bing only to localhost by default [#44 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/44)
|
37
95
|
- Prevent AuthenticatedRackMiddleware from blocking other rails routes[#35 @JulianPasquale](https://github.com/yjacquin/fast-mcp/pull/35)
|
38
96
|
- Stop Forcing reconnections after 30 pings [#42 @zoedsoupe](https://github.com/yjacquin/fast-mcp/pull/42)
|
39
97
|
|
40
|
-
|
41
98
|
## [1.1.0] - 2025-04-13
|
99
|
+
|
42
100
|
### Added
|
101
|
+
|
43
102
|
- Security enhancement: Added DNS rebinding protection by validating Origin headers [#32 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/32/files)
|
44
103
|
- Added configuration options for allowed origins in rack middleware [#32 @yjacquin](https://github.com/yjacquin/fast-mcp/pull/32/files)
|
45
104
|
- Allow to change the SSE and Messages route [#23 @pedrofurtado](https://github.com/yjacquin/fast-mcp/pull/23)
|
46
105
|
- Fix invalid return value when processing notifications/initialized request [#31 @abMatGit](https://github.com/yjacquin/fast-mcp/pull/31)
|
47
106
|
|
48
|
-
|
49
107
|
## [1.0.0] - 2025-03-30
|
50
108
|
|
51
109
|
### Added
|
110
|
+
|
52
111
|
- Rails integration improvements via enhanced Railtie support
|
53
112
|
- Automatic tool and resource registration in Rails applications
|
54
113
|
- Extended Rails autoload paths for tools and resources directories
|
@@ -59,6 +118,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
59
118
|
- Automated Github Releases through Github Workflow
|
60
119
|
|
61
120
|
### Fixed
|
121
|
+
|
62
122
|
- Fixed bug with Rack middlewares not being initialized properly.
|
63
123
|
- Fixed bug with STDIO logging preventing a proper connection with clients [# 11 @cs3b](https://github.com/yjacquin/fast-mcp/issues/11)
|
64
124
|
- Fixed Rails SSE streaming detection and handling
|
@@ -66,9 +126,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
66
126
|
- Namespace consistency correction (FastMCP -> FastMcp) throughout the codebase
|
67
127
|
|
68
128
|
### Improved
|
129
|
+
|
69
130
|
- ⚠️ [Breaking] Resource content declaration changes
|
131
|
+
|
70
132
|
- Now resources implement `content` over `default_content`
|
71
133
|
- `content` is dynamically called when calling a resource, this implies we can declare dynamic resource contents like:
|
134
|
+
|
72
135
|
```ruby
|
73
136
|
class HighestScoringUsersResource < FastMcp::Resource
|
74
137
|
...
|
@@ -77,6 +140,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
77
140
|
end
|
78
141
|
end
|
79
142
|
```
|
143
|
+
|
80
144
|
- More robust SSE connection lifecycle management
|
81
145
|
- Optimized test suite with faster execution times
|
82
146
|
- Better logging for debugging connection issues
|
data/README.md
CHANGED
@@ -10,10 +10,10 @@
|
|
10
10
|
<a href="https://github.com/yjacquin/fast-mcp/workflows/CI/badge.svg"><img src="https://github.com/yjacquin/fast-mcp/workflows/CI/badge.svg" alt="CI Status" /></a>
|
11
11
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" /></a>
|
12
12
|
<a href="code_of_conduct.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg" alt="Contributor Covenant" /></a>
|
13
|
-
<a href="https://discord.gg/
|
13
|
+
<a href="https://discord.gg/9HHfAtY3HF"><img src = "https://dcbadge.limes.pink/api/server/https://discord.gg/9HHfAtY3HF?style=flat" alt="Discord invite link" /></a>
|
14
14
|
</p>
|
15
15
|
|
16
|
-
## 🌟 Interface your Servers with LLMs in minutes
|
16
|
+
## 🌟 Interface your Servers with LLMs in minutes
|
17
17
|
|
18
18
|
AI models are powerful, but they need to interact with your applications to be truly useful. Traditional approaches mean wrestling with:
|
19
19
|
|
@@ -32,9 +32,10 @@ Fast MCP solves all these problems by providing a clean, Ruby-focused implementa
|
|
32
32
|
- 🧩 **Framework Integration** - Works seamlessly with Rails, Sinatra or any Rack app.
|
33
33
|
- 🔒 **Authentication Support** - Secure your AI-powered endpoints with ease
|
34
34
|
- 🚀 **Real-time Updates** - Subscribe to changes for interactive applications
|
35
|
-
|
35
|
+
- 🎯 **Dynamic Filtering** - Control tool/resource access based on request context (permissions, API versions, etc.)
|
36
36
|
|
37
37
|
## 💎 What Makes FastMCP Great
|
38
|
+
|
38
39
|
```ruby
|
39
40
|
# Define tools for AI models to use
|
40
41
|
server = FastMcp::Server.new(name: 'popular-users', version: '1.0.0')
|
@@ -48,10 +49,10 @@ class CreateUserTool < FastMcp::Tool
|
|
48
49
|
arguments do
|
49
50
|
required(:first_name).filled(:string).description("First name of the user")
|
50
51
|
optional(:age).filled(:integer).description("Age of the user")
|
51
|
-
required(:address).hash do
|
52
|
-
|
53
|
-
optional(:city).filled(:string)
|
54
|
-
optional(:zipcode).
|
52
|
+
required(:address).description("The shipping address").hash do
|
53
|
+
required(:street).filled(:string).description("Street address")
|
54
|
+
optional(:city).filled(:string).description("City name")
|
55
|
+
optional(:zipcode).maybe(:string).description("Postal code")
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -65,7 +66,7 @@ server.register_tool(CreateUserTool)
|
|
65
66
|
|
66
67
|
# Share data resources with AI models by inheriting from FastMcp::Resource
|
67
68
|
class PopularUsers < FastMcp::Resource
|
68
|
-
uri "
|
69
|
+
uri "myapp:///users/popular"
|
69
70
|
resource_name "Popular Users"
|
70
71
|
mime_type "application/json"
|
71
72
|
|
@@ -74,17 +75,63 @@ class PopularUsers < FastMcp::Resource
|
|
74
75
|
end
|
75
76
|
end
|
76
77
|
|
78
|
+
class User < FastMcp::Resource
|
79
|
+
uri "myapp:///users/{id}" # This is a resource template
|
80
|
+
resource_name "user"
|
81
|
+
mime_type "application/json"
|
82
|
+
|
83
|
+
def content
|
84
|
+
id = params[:id] # params are computed from the uri pattern
|
85
|
+
|
86
|
+
JSON.generate(User.find(id).as_json)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
77
90
|
# Register the resource with the server
|
78
|
-
server.
|
91
|
+
server.register_resources(PopularUsers, User)
|
79
92
|
|
80
93
|
# Accessing the resource through the server
|
81
94
|
server.read_resource(PopularUsers.uri)
|
82
95
|
|
83
96
|
# Notify the resource content has been updated to clients
|
84
|
-
server.notify_resource_updated(PopularUsers.
|
97
|
+
server.notify_resource_updated(PopularUsers.variabilized_uri)
|
98
|
+
|
99
|
+
# Notifiy the content of a resource from a template has been updated to clients
|
100
|
+
server.notify_resource_updated(User.variabilized_uri(id: 1))
|
101
|
+
```
|
102
|
+
|
103
|
+
### 🎯 Dynamic Tool Filtering
|
104
|
+
|
105
|
+
Control which tools and resources are available based on request context:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
# Tag your tools for easy filtering
|
109
|
+
class AdminTool < FastMcp::Tool
|
110
|
+
tags :admin, :dangerous
|
111
|
+
description "Perform admin operations"
|
112
|
+
|
113
|
+
def call
|
114
|
+
# Admin only functionality
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Filter tools based on user permissions
|
119
|
+
server.filter_tools do |request, tools|
|
120
|
+
user_role = request.params['role']
|
121
|
+
|
122
|
+
case user_role
|
123
|
+
when 'admin'
|
124
|
+
tools # Admins see all tools
|
125
|
+
when 'user'
|
126
|
+
tools.reject { |t| t.tags.include?(:admin) }
|
127
|
+
else
|
128
|
+
tools.select { |t| t.tags.include?(:public) }
|
129
|
+
end
|
130
|
+
end
|
85
131
|
```
|
86
132
|
|
87
133
|
### 🚂 Fast Ruby on Rails implementation
|
134
|
+
|
88
135
|
```shell
|
89
136
|
bundle add fast-mcp
|
90
137
|
bin/rails generate fast_mcp:install
|
@@ -122,7 +169,9 @@ FastMcp.mount_in_rails(
|
|
122
169
|
end
|
123
170
|
end
|
124
171
|
```
|
172
|
+
|
125
173
|
The install script will also:
|
174
|
+
|
126
175
|
- add app/resources folder
|
127
176
|
- add app/tools folder
|
128
177
|
- add app/tools/sample_tool.rb
|
@@ -174,6 +223,7 @@ end
|
|
174
223
|
```
|
175
224
|
|
176
225
|
### Easy Sinatra setup
|
226
|
+
|
177
227
|
I'll let you check out the dedicated [sinatra integration docs](./docs/sinatra_integration.md).
|
178
228
|
|
179
229
|
## 🚀 Quick Start
|
@@ -236,17 +286,21 @@ Clone this project, then give it a go !
|
|
236
286
|
```shell
|
237
287
|
npx @modelcontextprotocol/inspector examples/server_with_stdio_transport.rb
|
238
288
|
```
|
289
|
+
|
239
290
|
Or to test with an SSE transport using a rack middleware:
|
291
|
+
|
240
292
|
```shell
|
241
293
|
npx @modelcontextprotocol/inspector examples/rack_middleware.rb
|
242
294
|
```
|
243
295
|
|
244
296
|
Or to test over SSE with an authenticated rack middleware:
|
297
|
+
|
245
298
|
```shell
|
246
299
|
npx @modelcontextprotocol/inspector examples/authenticated_rack_middleware.rb
|
247
300
|
```
|
248
301
|
|
249
302
|
You can test your custom implementation with the official MCP inspector by using:
|
303
|
+
|
250
304
|
```shell
|
251
305
|
# Test with a stdio transport:
|
252
306
|
npx @modelcontextprotocol/inspector path/to/your_ruby_file.rb
|
@@ -275,6 +329,7 @@ end
|
|
275
329
|
### Integrating with Claude Desktop
|
276
330
|
|
277
331
|
Add your server to your Claude Desktop configuration at:
|
332
|
+
|
278
333
|
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
279
334
|
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
280
335
|
|
@@ -283,28 +338,27 @@ Add your server to your Claude Desktop configuration at:
|
|
283
338
|
"mcpServers": {
|
284
339
|
"my-great-server": {
|
285
340
|
"command": "ruby",
|
286
|
-
"args": [
|
287
|
-
"/Users/path/to/your/awesome/fast-mcp/server.rb"
|
288
|
-
]
|
341
|
+
"args": ["/Users/path/to/your/awesome/fast-mcp/server.rb"]
|
289
342
|
}
|
290
343
|
}
|
291
344
|
}
|
292
345
|
```
|
293
346
|
|
294
347
|
## How to add a MCP server to Claude, Cursor, or other MCP clients?
|
348
|
+
|
295
349
|
Please refer to [configuring_mcp_clients](docs/configuring_mcp_clients.md)
|
296
350
|
|
297
351
|
## 📊 Supported Specifications
|
298
352
|
|
299
|
-
| Feature
|
300
|
-
|
301
|
-
| ✅ **JSON-RPC 2.0**
|
302
|
-
| ✅ **Tool Definition & Calling**
|
303
|
-
| ✅ **Resource Management** | Create, read, update, and subscribe to resources
|
304
|
-
| ✅ **Transport Options**
|
305
|
-
| ✅ **Framework Integration**
|
306
|
-
| ✅ **Authentication**
|
307
|
-
| ✅ **Schema Support**
|
353
|
+
| Feature | Status |
|
354
|
+
| ----------------------------------------------- | --------------------------------------------------------- |
|
355
|
+
| ✅ **JSON-RPC 2.0** | Full implementation for communication |
|
356
|
+
| ✅ **Tool Definition & Calling** | Define and call tools with rich argument types |
|
357
|
+
| ✅ **Resource & Resource Templates Management** | Create, read, update, and subscribe to resources |
|
358
|
+
| ✅ **Transport Options** | STDIO, HTTP, and SSE for flexible integration |
|
359
|
+
| ✅ **Framework Integration** | Rails, Sinatra, Hanami, and any Rack-compatible framework |
|
360
|
+
| ✅ **Authentication** | Secure your AI endpoints with token authentication |
|
361
|
+
| ✅ **Schema Support** | Full JSON Schema for tool arguments with validation |
|
308
362
|
|
309
363
|
## 🗺️ Use Cases
|
310
364
|
|
@@ -353,12 +407,14 @@ FastMcp.authenticated_rack_middleware(app,
|
|
353
407
|
- [📚 Resources](docs/resources.md)
|
354
408
|
- [🛠️ Tools](docs/tools.md)
|
355
409
|
- [🔒 Security](docs/security.md)
|
410
|
+
- [🎯 Dynamic Filtering](docs/filtering.md)
|
356
411
|
|
357
412
|
## 💻 Examples
|
358
413
|
|
359
414
|
Check out the [examples directory](examples) for more detailed examples:
|
360
415
|
|
361
416
|
- **🔨 Basic Examples**:
|
417
|
+
|
362
418
|
- [Simple Server](examples/server_with_stdio_transport.rb)
|
363
419
|
- [Tool Examples](examples/tool_examples.rb)
|
364
420
|
|
data/lib/fast_mcp.rb
CHANGED
@@ -16,9 +16,6 @@ require_relative 'mcp/server'
|
|
16
16
|
require_relative 'mcp/resource'
|
17
17
|
require_relative 'mcp/railtie' if defined?(Rails::Railtie)
|
18
18
|
|
19
|
-
# Load generators if Rails is available
|
20
|
-
require_relative 'generators/fast_mcp/install/install_generator' if defined?(Rails::Generators)
|
21
|
-
|
22
19
|
# Require all transport files
|
23
20
|
require_relative 'mcp/transports/base_transport'
|
24
21
|
Dir[File.join(File.dirname(__FILE__), 'mcp/transports', '*.rb')].each do |file|
|
@@ -39,6 +36,7 @@ module FastMcp
|
|
39
36
|
# @option options [String] :messages_route The route for the messages endpoint
|
40
37
|
# @option options [String] :sse_route The route for the SSE endpoint
|
41
38
|
# @option options [Logger] :logger The logger to use
|
39
|
+
# @option options [Class] :transport The transport class to use
|
42
40
|
# @option options [Array<String,Regexp>] :allowed_origins List of allowed origins for DNS rebinding protection
|
43
41
|
# @yield [server] A block to configure the server
|
44
42
|
# @yieldparam server [FastMcp::Server] The server to configure
|
@@ -71,17 +69,8 @@ module FastMcp
|
|
71
69
|
# @yieldparam server [FastMcp::Server] The server to configure
|
72
70
|
# @return [#call] The Rack middleware
|
73
71
|
def self.authenticated_rack_middleware(app, options = {})
|
74
|
-
|
75
|
-
|
76
|
-
logger = options.delete(:logger) || Logger.new
|
77
|
-
|
78
|
-
server = FastMcp::Server.new(name: name, version: version, logger: logger)
|
79
|
-
yield server if block_given?
|
80
|
-
|
81
|
-
# Store the server in the FastMcp module
|
82
|
-
self.server = server
|
83
|
-
|
84
|
-
server.start_authenticated_rack(app, options)
|
72
|
+
options[:transport] ||= FastMcp::Transports::AuthenticatedRackTransport
|
73
|
+
rack_middleware(app, options)
|
85
74
|
end
|
86
75
|
|
87
76
|
# Register a tool with the MCP server
|
@@ -20,12 +20,12 @@ FastMcp.mount_in_rails(
|
|
20
20
|
version: '1.0.0',
|
21
21
|
path_prefix: '/mcp', # This is the default path prefix
|
22
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
|
23
|
+
sse_route: 'sse', # This is the default route for the SSE endpoint
|
24
24
|
# Add allowed origins below, it defaults to Rails.application.config.hosts
|
25
25
|
# allowed_origins: ['localhost', '127.0.0.1', '[::1]', 'example.com', /.*\.example\.com/],
|
26
26
|
# localhost_only: true, # Set to false to allow connections from other hosts
|
27
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']
|
28
|
+
# allowed_ips: ['127.0.0.1', '::1'],
|
29
29
|
# authenticate: true, # Uncomment to enable authentication
|
30
30
|
# auth_token: 'your-token', # Required if authenticate: true
|
31
31
|
) do |server|
|
@@ -3,6 +3,13 @@
|
|
3
3
|
class SampleTool < ApplicationTool
|
4
4
|
description 'Greet a user'
|
5
5
|
|
6
|
+
# Optional: Add annotations to provide hints about the tool's behavior
|
7
|
+
# annotations(
|
8
|
+
# title: 'User Greeting',
|
9
|
+
# read_only_hint: true, # This tool only reads data
|
10
|
+
# open_world_hint: false # This tool only accesses the local database
|
11
|
+
# )
|
12
|
+
|
6
13
|
arguments do
|
7
14
|
required(:id).filled(:integer).description('ID of the user to greet')
|
8
15
|
optional(:prefix).filled(:string).description('Prefix to add to the greeting')
|
data/lib/mcp/railtie.rb
CHANGED
data/lib/mcp/resource.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'json'
|
4
4
|
require 'base64'
|
5
5
|
require 'mime/types'
|
6
|
-
require '
|
6
|
+
require 'addressable/template'
|
7
7
|
|
8
8
|
module FastMcp
|
9
9
|
# Resource class for MCP Resources feature
|
@@ -17,9 +17,62 @@ module FastMcp
|
|
17
17
|
# @return [String] The URI for this resource
|
18
18
|
def uri(value = nil)
|
19
19
|
@uri = value if value
|
20
|
+
|
20
21
|
@uri || (superclass.respond_to?(:uri) ? superclass.uri : nil)
|
21
22
|
end
|
22
23
|
|
24
|
+
# Variabilize the URI with the given params
|
25
|
+
# @param params [Hash] The parameters to variabilize the URI with
|
26
|
+
# @return [String] The variabilized URI
|
27
|
+
def variabilized_uri(params = {})
|
28
|
+
addressable_template.partial_expand(params).pattern
|
29
|
+
end
|
30
|
+
|
31
|
+
# Get the Addressable::Template for this resource
|
32
|
+
# @return [Addressable::Template] The Addressable::Template for this resource
|
33
|
+
def addressable_template
|
34
|
+
@addressable_template ||= Addressable::Template.new(uri)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Get the template variables for this resource
|
38
|
+
# @return [Array] The template variables for this resource
|
39
|
+
def template_variables
|
40
|
+
addressable_template.variables
|
41
|
+
end
|
42
|
+
|
43
|
+
# Check if this resource has a templated URI
|
44
|
+
# @return [Boolean] true if the URI contains template parameters
|
45
|
+
def templated?
|
46
|
+
template_variables.any?
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check if this resource has a non-templated URI
|
50
|
+
# @return [Boolean] true if the URI does not contain template parameters
|
51
|
+
def non_templated?
|
52
|
+
!templated?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Match the given URI against the resource's addressable template
|
56
|
+
# @param uri [String] The URI to match
|
57
|
+
# @return [Addressable::Template::MatchData, nil] The match data if the URI matches, nil otherwise
|
58
|
+
def match(uri)
|
59
|
+
addressable_template.match(uri)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Initialize a new instance from the given URI
|
63
|
+
# @param uri [String] The URI to initialize from
|
64
|
+
# @return [Resource] A new resource instance
|
65
|
+
def initialize_from_uri(uri)
|
66
|
+
new(params_from_uri(uri))
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get the parameters from the given URI
|
70
|
+
# @param uri [String] The URI to get the parameters from
|
71
|
+
# @return [Hash] The parameters from the URI
|
72
|
+
def params_from_uri(uri)
|
73
|
+
match(uri).mapping.transform_keys(&:to_sym)
|
74
|
+
end
|
75
|
+
|
23
76
|
# Define name for this resource
|
24
77
|
# @param value [String, nil] The name for this resource
|
25
78
|
# @return [String] The name for this resource
|
@@ -28,6 +81,13 @@ module FastMcp
|
|
28
81
|
@name || (superclass.respond_to?(:resource_name) ? superclass.resource_name : nil)
|
29
82
|
end
|
30
83
|
|
84
|
+
alias original_name name
|
85
|
+
def name
|
86
|
+
return resource_name if resource_name
|
87
|
+
|
88
|
+
original_name
|
89
|
+
end
|
90
|
+
|
31
91
|
# Define description for this resource
|
32
92
|
# @param value [String, nil] The description for this resource
|
33
93
|
# @return [String] The description for this resource
|
@@ -47,12 +107,21 @@ module FastMcp
|
|
47
107
|
# Get the resource metadata (without content)
|
48
108
|
# @return [Hash] Resource metadata
|
49
109
|
def metadata
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
110
|
+
if templated?
|
111
|
+
{
|
112
|
+
uriTemplate: uri,
|
113
|
+
name: resource_name,
|
114
|
+
description: description,
|
115
|
+
mimeType: mime_type
|
116
|
+
}.compact
|
117
|
+
else
|
118
|
+
{
|
119
|
+
uri: uri,
|
120
|
+
name: resource_name,
|
121
|
+
description: description,
|
122
|
+
mimeType: mime_type
|
123
|
+
}.compact
|
124
|
+
end
|
56
125
|
end
|
57
126
|
|
58
127
|
# Load content from a file (class method)
|
@@ -87,7 +156,11 @@ module FastMcp
|
|
87
156
|
end
|
88
157
|
end
|
89
158
|
|
90
|
-
|
159
|
+
# Initialize with instance variables
|
160
|
+
# @param params [Hash] The parameters for this resource instance
|
161
|
+
def initialize(params = {})
|
162
|
+
@params = params
|
163
|
+
end
|
91
164
|
|
92
165
|
# URI of the resource - delegates to class method
|
93
166
|
# @return [String, nil] The URI for this resource
|
@@ -98,7 +171,7 @@ module FastMcp
|
|
98
171
|
# Name of the resource - delegates to class method
|
99
172
|
# @return [String, nil] The name for this resource
|
100
173
|
def name
|
101
|
-
self.class.
|
174
|
+
self.class.resource_name
|
102
175
|
end
|
103
176
|
|
104
177
|
# Description of the resource - delegates to class method
|
@@ -113,6 +186,10 @@ module FastMcp
|
|
113
186
|
self.class.mime_type
|
114
187
|
end
|
115
188
|
|
189
|
+
# Get parameters from the URI template
|
190
|
+
# @return [Hash] The parameters extracted from the URI
|
191
|
+
attr_reader :params
|
192
|
+
|
116
193
|
# Method to be overridden by subclasses to dynamically generate content
|
117
194
|
# @return [String, nil] Generated content for this resource
|
118
195
|
def content
|
@@ -129,25 +206,5 @@ module FastMcp
|
|
129
206
|
mime_type == 'application/xml' ||
|
130
207
|
mime_type == 'application/javascript')
|
131
208
|
end
|
132
|
-
|
133
|
-
# Get the resource contents
|
134
|
-
# @return [Hash] Resource contents
|
135
|
-
def contents
|
136
|
-
result = {
|
137
|
-
uri: uri,
|
138
|
-
mimeType: mime_type
|
139
|
-
}
|
140
|
-
|
141
|
-
content_value = content
|
142
|
-
if content_value
|
143
|
-
if binary?
|
144
|
-
result[:blob] = Base64.strict_encode64(content_value)
|
145
|
-
else
|
146
|
-
result[:text] = content_value
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
result
|
151
|
-
end
|
152
209
|
end
|
153
210
|
end
|