vector_mcp 0.3.3 → 0.4.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 +80 -0
- data/README.md +132 -342
- data/lib/vector_mcp/handlers/core.rb +82 -27
- data/lib/vector_mcp/image_util.rb +53 -5
- data/lib/vector_mcp/log_filter.rb +48 -0
- data/lib/vector_mcp/middleware/base.rb +1 -5
- data/lib/vector_mcp/middleware/context.rb +11 -1
- data/lib/vector_mcp/rails/tool.rb +85 -0
- data/lib/vector_mcp/request_context.rb +1 -1
- data/lib/vector_mcp/security/middleware.rb +2 -2
- data/lib/vector_mcp/security/strategies/api_key.rb +27 -4
- data/lib/vector_mcp/security/strategies/jwt_token.rb +10 -5
- data/lib/vector_mcp/server/capabilities.rb +4 -10
- data/lib/vector_mcp/server/message_handling.rb +2 -2
- data/lib/vector_mcp/server/registry.rb +36 -4
- data/lib/vector_mcp/server.rb +49 -41
- data/lib/vector_mcp/session.rb +5 -3
- data/lib/vector_mcp/tool.rb +221 -0
- data/lib/vector_mcp/transport/base_session_manager.rb +1 -17
- data/lib/vector_mcp/transport/http_stream/event_store.rb +33 -13
- data/lib/vector_mcp/transport/http_stream/session_manager.rb +39 -14
- data/lib/vector_mcp/transport/http_stream/stream_handler.rb +133 -47
- data/lib/vector_mcp/transport/http_stream.rb +294 -33
- data/lib/vector_mcp/version.rb +1 -1
- data/lib/vector_mcp.rb +7 -8
- metadata +5 -10
- data/lib/vector_mcp/transport/sse/client_connection.rb +0 -113
- data/lib/vector_mcp/transport/sse/message_handler.rb +0 -166
- data/lib/vector_mcp/transport/sse/puma_config.rb +0 -77
- data/lib/vector_mcp/transport/sse/stream_manager.rb +0 -92
- data/lib/vector_mcp/transport/sse.rb +0 -377
- data/lib/vector_mcp/transport/sse_session_manager.rb +0 -188
- data/lib/vector_mcp/transport/stdio.rb +0 -473
- data/lib/vector_mcp/transport/stdio_session_manager.rb +0 -181
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de0f694bd85fb9d217c352fc907f7d77c27ee3837eea3512c8ca1791c53313c2
|
|
4
|
+
data.tar.gz: 86f0a7ab8c95e744ef8d80cb77faddaa195cef6636ea9fe175631b01bc0b0982
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c0f1f384fd9d654cc3385a87937c656dee9beaf38e0aeed6f0e92542366c17051615b774b58d1ecc2eb89dd23e6a6737e85e1dcdfb6d4c239a182d0d3c98f31f
|
|
7
|
+
data.tar.gz: 8d0047290e1033266498f197b94b3d51eb88b700c46e44f15229de985a74eb57889f8381887beb92b0007883244de8f0c53b652a9a8939963f30d3c81fecb406
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,83 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
|
|
3
|
+
## [0.4.0] – 2026-04-10
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
* **Declarative Tool DSL**: Added `VectorMCP::Tool` for class-based tool definitions.
|
|
8
|
+
- Define tools with `tool_name`, `description`, and `param`
|
|
9
|
+
- Register one or more tool classes with `server.register(MyTool, OtherTool)`
|
|
10
|
+
- Added `:date` and `:datetime` param types with automatic coercion to `Date` and `Time`
|
|
11
|
+
|
|
12
|
+
* **Rack and Rails Integration**: Added first-class mounting support for Rack-based applications.
|
|
13
|
+
- `Server#rack_app` returns a Rack-compatible MCP endpoint without starting Puma
|
|
14
|
+
- Added `VectorMCP::Rails::Tool` for ActiveRecord-backed tools
|
|
15
|
+
- Added `docs/rails-setup-guide.md` with a full Rails integration guide
|
|
16
|
+
|
|
17
|
+
* **Expanded Middleware Lifecycle Hooks**: Middleware can now observe and shape more of the request lifecycle.
|
|
18
|
+
- Added `before_auth`, `after_auth`, and `on_auth_error` hooks
|
|
19
|
+
- Added transport-level `before_request`, `after_response`, and `on_transport_error` hooks
|
|
20
|
+
- Middleware can now mutate params before handlers execute
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
* **MCP Protocol Version**: VectorMCP now advertises MCP protocol `2025-11-25` by default.
|
|
25
|
+
- `MCP-Protocol-Version` headers for `2025-11-25`, `2025-03-26`, and `2024-11-05` are accepted for compatibility
|
|
26
|
+
|
|
27
|
+
* **Streamable HTTP Compliance**: HttpStream was updated to align with the MCP 2025-11-25 transport requirements.
|
|
28
|
+
- POST bodies must contain a single JSON-RPC request, notification, or response
|
|
29
|
+
- POST `Accept` validation now enforces `application/json` plus `text/event-stream` when the header is present
|
|
30
|
+
- Notifications now return `202 Accepted`
|
|
31
|
+
- SSE streams now send priming events, retry hints, and comment-based heartbeats
|
|
32
|
+
- Event replay and outbound routing are now scoped to the originating stream
|
|
33
|
+
|
|
34
|
+
* **Ruby Requirement**: Minimum supported Ruby version is now `3.2`.
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
|
|
38
|
+
* **Stdio Transport**: Removed stdio transport support entirely.
|
|
39
|
+
- Deleted `lib/vector_mcp/transport/stdio.rb` and `lib/vector_mcp/transport/stdio_session_manager.rb`
|
|
40
|
+
- `Server#run` now defaults to `transport: :http_stream`
|
|
41
|
+
|
|
42
|
+
* **Standalone SSE Transport**: Removed the legacy SSE transport implementation.
|
|
43
|
+
- Deleted `lib/vector_mcp/transport/sse.rb`, `lib/vector_mcp/transport/sse_session_manager.rb`, and `lib/vector_mcp/transport/sse/`
|
|
44
|
+
- HttpStream is now the only built-in transport
|
|
45
|
+
|
|
46
|
+
* **Broadcast APIs**: Removed `broadcast_message` and `broadcast_notification` to comply with the no-broadcast delivery rules in the MCP streamable HTTP specification.
|
|
47
|
+
|
|
48
|
+
### Security
|
|
49
|
+
|
|
50
|
+
* **Safer Origin Defaults**: Default allowed origins are now restricted to localhost and loopback addresses.
|
|
51
|
+
- Explicit wildcard origin configuration still works, but now emits a security warning
|
|
52
|
+
|
|
53
|
+
* **Stronger Path Validation**: `ImageUtil` now canonicalizes file paths and blocks traversal attempts even when no `base_directory` is provided.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
* **Stream Routing and Replay**: Multiple active SSE streams in the same session now replay and deliver messages to the correct logical stream.
|
|
58
|
+
* **Authorization Context Propagation**: Resolved security context is now stored on the session so middleware and handlers can inspect authenticated state consistently.
|
|
59
|
+
|
|
60
|
+
## [0.3.4] – 2026-03-17
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
* **Batch JSON-RPC Support**: Added batch request dispatch on POST endpoint for processing multiple JSON-RPC requests in a single HTTP call
|
|
65
|
+
* **SSE Response Mode for POST**: POST requests can now receive responses via Server-Sent Events streaming
|
|
66
|
+
* **Accept Header Validation**: Added proper Accept header validation on POST and GET endpoints per MCP specification
|
|
67
|
+
|
|
68
|
+
### Security
|
|
69
|
+
|
|
70
|
+
* **Constant-Time API Key Comparison** (SECURITY-001): Replaced direct string comparison with `Rack::Utils.secure_compare` to prevent timing attacks
|
|
71
|
+
* **Disable Query Parameter Token Extraction** (SECURITY-002): Token extraction from query parameters now disabled by default to prevent token leakage via URL logging and browser history
|
|
72
|
+
* **Path Traversal Protection for ImageUtil** (SECURITY-004): Added path traversal validation to `ImageUtil` file operations to prevent unauthorized file access
|
|
73
|
+
* **Sensitive Data Filtering in Debug Logs** (SECURITY-005): Debug log output now filters sensitive fields (tokens, keys, credentials) to prevent accidental credential exposure
|
|
74
|
+
* **Cross-Session Event Leakage Prevention**: Fixed EventStore to prevent events from one session being accessible to another session
|
|
75
|
+
* **Session ID Validation on POST**: Fixed session fixation vulnerability where unknown session IDs were silently accepted; server now returns 404 for invalid sessions
|
|
76
|
+
|
|
77
|
+
### Fixed
|
|
78
|
+
|
|
79
|
+
* **Code Quality**: RuboCop style fixes and cleanup of unnecessary files
|
|
80
|
+
|
|
1
81
|
## [0.3.3] – 2025-07-29
|
|
2
82
|
|
|
3
83
|
### Fixed
|
data/README.md
CHANGED
|
@@ -6,441 +6,231 @@
|
|
|
6
6
|
[](https://qlty.sh/gh/sergiobayona/projects/vector_mcp)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
8
|
|
|
9
|
-
VectorMCP is a Ruby
|
|
9
|
+
VectorMCP is a Ruby implementation of the Model Context Protocol (MCP) server-side specification. It gives you a framework for exposing tools, resources, prompts, roots, sampling, middleware, and security over the MCP streamable HTTP transport.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Highlights
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
13
|
+
- Streamable HTTP is the built-in transport, with session management, resumability, and MCP 2025-11-25 compliance
|
|
14
|
+
- Class-based tools via `VectorMCP::Tool`, plus the original block-based `register_tool` API
|
|
15
|
+
- Rack and Rails mounting through `server.rack_app`
|
|
16
|
+
- Opt-in authentication and authorization, structured logging, and middleware hooks
|
|
17
|
+
- Image-aware tools/resources/prompts, roots, and server-initiated sampling
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Ruby 3.2+
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
20
24
|
|
|
21
25
|
```bash
|
|
22
26
|
gem install vector_mcp
|
|
23
27
|
```
|
|
24
28
|
|
|
25
29
|
```ruby
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Create a server
|
|
29
|
-
server = VectorMCP.new(name: 'MyApp', version: '1.0.0')
|
|
30
|
-
|
|
31
|
-
# Add a tool
|
|
32
|
-
server.register_tool(
|
|
33
|
-
name: 'greet',
|
|
34
|
-
description: 'Says hello to someone',
|
|
35
|
-
input_schema: {
|
|
36
|
-
type: 'object',
|
|
37
|
-
properties: { name: { type: 'string' } },
|
|
38
|
-
required: ['name']
|
|
39
|
-
}
|
|
40
|
-
) { |args| "Hello, #{args['name']}!" }
|
|
41
|
-
|
|
42
|
-
# Start the server
|
|
43
|
-
server.run # Uses stdio transport by default
|
|
30
|
+
gem "vector_mcp"
|
|
44
31
|
```
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## Transport Options
|
|
49
|
-
|
|
50
|
-
### Command Line Tools (stdio)
|
|
51
|
-
|
|
52
|
-
Perfect for desktop applications and process-based integrations:
|
|
33
|
+
## Quick Start
|
|
53
34
|
|
|
54
35
|
```ruby
|
|
55
|
-
|
|
56
|
-
```
|
|
36
|
+
require "vector_mcp"
|
|
57
37
|
|
|
58
|
-
|
|
38
|
+
class Greet < VectorMCP::Tool
|
|
39
|
+
description "Say hello to someone"
|
|
40
|
+
param :name, type: :string, desc: "Name to greet", required: true
|
|
59
41
|
|
|
60
|
-
|
|
42
|
+
def call(args, _session)
|
|
43
|
+
"Hello, #{args["name"]}!"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
server.
|
|
47
|
+
server = VectorMCP::Server.new(name: "MyApp", version: "1.0.0")
|
|
48
|
+
server.register(Greet)
|
|
49
|
+
server.run(port: 8080)
|
|
64
50
|
```
|
|
65
51
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
## Core Features
|
|
69
|
-
|
|
70
|
-
### Tools (Functions)
|
|
71
|
-
|
|
72
|
-
Expose functions that LLMs can call:
|
|
52
|
+
The class-based DSL is optional. The existing block-based API still works:
|
|
73
53
|
|
|
74
54
|
```ruby
|
|
75
55
|
server.register_tool(
|
|
76
|
-
name:
|
|
77
|
-
description:
|
|
56
|
+
name: "echo",
|
|
57
|
+
description: "Echo back the supplied text",
|
|
78
58
|
input_schema: {
|
|
79
|
-
type:
|
|
80
|
-
properties: {
|
|
81
|
-
|
|
82
|
-
a: { type: 'number' },
|
|
83
|
-
b: { type: 'number' }
|
|
84
|
-
},
|
|
85
|
-
required: ['operation', 'a', 'b']
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: { text: { type: "string" } },
|
|
61
|
+
required: ["text"]
|
|
86
62
|
}
|
|
87
|
-
)
|
|
88
|
-
case args['operation']
|
|
89
|
-
when 'add' then args['a'] + args['b']
|
|
90
|
-
when 'subtract' then args['a'] - args['b']
|
|
91
|
-
when 'multiply' then args['a'] * args['b']
|
|
92
|
-
end
|
|
93
|
-
end
|
|
63
|
+
) { |args| args["text"] }
|
|
94
64
|
```
|
|
95
65
|
|
|
96
|
-
|
|
66
|
+
## Rack and Rails
|
|
97
67
|
|
|
98
|
-
|
|
68
|
+
VectorMCP can run as a standalone HTTP server or be mounted inside an existing Rack app:
|
|
99
69
|
|
|
100
70
|
```ruby
|
|
101
|
-
|
|
102
|
-
uri: 'file://config.json',
|
|
103
|
-
name: 'App Configuration',
|
|
104
|
-
description: 'Current application settings'
|
|
105
|
-
) { File.read('config.json') }
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Prompts (Templates)
|
|
71
|
+
require "vector_mcp"
|
|
109
72
|
|
|
110
|
-
|
|
73
|
+
server = VectorMCP::Server.new(name: "MyApp", version: "1.0.0")
|
|
74
|
+
server.register(Greet)
|
|
111
75
|
|
|
112
|
-
|
|
113
|
-
server.register_prompt(
|
|
114
|
-
name: 'code_review',
|
|
115
|
-
description: 'Reviews code for best practices',
|
|
116
|
-
arguments: [
|
|
117
|
-
{ name: 'language', description: 'Programming language', required: true },
|
|
118
|
-
{ name: 'code', description: 'Code to review', required: true }
|
|
119
|
-
]
|
|
120
|
-
) do |args|
|
|
121
|
-
{
|
|
122
|
-
messages: [{
|
|
123
|
-
role: 'user',
|
|
124
|
-
content: {
|
|
125
|
-
type: 'text',
|
|
126
|
-
text: "Review this #{args['language']} code:\n\n#{args['code']}"
|
|
127
|
-
}
|
|
128
|
-
}]
|
|
129
|
-
}
|
|
130
|
-
end
|
|
76
|
+
MCP_APP = server.rack_app
|
|
131
77
|
```
|
|
132
78
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
VectorMCP provides comprehensive, **opt-in security** for production applications:
|
|
136
|
-
|
|
137
|
-
### Built-in Input Validation
|
|
138
|
-
|
|
139
|
-
All inputs are automatically validated against your schemas:
|
|
79
|
+
In Rails, mount it in `config/routes.rb`:
|
|
140
80
|
|
|
141
81
|
```ruby
|
|
142
|
-
|
|
143
|
-
server.register_tool(
|
|
144
|
-
name: 'process_user',
|
|
145
|
-
input_schema: {
|
|
146
|
-
type: 'object',
|
|
147
|
-
properties: {
|
|
148
|
-
email: { type: 'string', format: 'email' },
|
|
149
|
-
age: { type: 'integer', minimum: 0, maximum: 150 }
|
|
150
|
-
},
|
|
151
|
-
required: ['email']
|
|
152
|
-
}
|
|
153
|
-
) { |args| "Processing #{args['email']}" }
|
|
154
|
-
|
|
155
|
-
# Invalid inputs are automatically rejected:
|
|
156
|
-
# ❌ { email: "not-an-email" } -> Validation error
|
|
157
|
-
# ❌ { age: -5 } -> Missing required field
|
|
158
|
-
# ✅ { email: "user@example.com" } -> Passes validation
|
|
82
|
+
mount MCP_APP => "/mcp"
|
|
159
83
|
```
|
|
160
84
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Secure your MCP server with flexible authentication strategies:
|
|
85
|
+
For ActiveRecord-backed tools, opt into `VectorMCP::Rails::Tool`:
|
|
164
86
|
|
|
165
87
|
```ruby
|
|
166
|
-
|
|
167
|
-
server.enable_authentication!(
|
|
168
|
-
strategy: :api_key,
|
|
169
|
-
keys: ["your-secret-key", "another-key"]
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
# JWT Token Authentication
|
|
173
|
-
server.enable_authentication!(
|
|
174
|
-
strategy: :jwt,
|
|
175
|
-
secret: ENV["JWT_SECRET"]
|
|
176
|
-
)
|
|
88
|
+
require "vector_mcp/rails/tool"
|
|
177
89
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
User.find_by(api_key: api_key) ? { user_id: user.id } : false
|
|
182
|
-
end
|
|
183
|
-
```
|
|
90
|
+
class FindUser < VectorMCP::Rails::Tool
|
|
91
|
+
description "Find a user by id"
|
|
92
|
+
param :id, type: :integer, required: true
|
|
184
93
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
```ruby
|
|
190
|
-
server.enable_authorization! do
|
|
191
|
-
# Tool-level access control
|
|
192
|
-
authorize_tools do |user, action, tool|
|
|
193
|
-
case user[:role]
|
|
194
|
-
when "admin" then true
|
|
195
|
-
when "user" then !tool.name.start_with?("admin_")
|
|
196
|
-
else false
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# Resource-level permissions
|
|
201
|
-
authorize_resources do |user, action, resource|
|
|
202
|
-
user[:tenant_id] == resource.tenant_id
|
|
94
|
+
def call(args, _session)
|
|
95
|
+
user = find!(User, args[:id])
|
|
96
|
+
{ id: user.id, email: user.email }
|
|
203
97
|
end
|
|
204
98
|
end
|
|
205
99
|
```
|
|
206
100
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
Security works seamlessly across all transport layers:
|
|
210
|
-
|
|
211
|
-
- **Stdio**: Header simulation for desktop applications
|
|
212
|
-
- **SSE**: Full HTTP header and query parameter support
|
|
213
|
-
- **Request Pipeline**: Automatic authentication and authorization checking
|
|
214
|
-
|
|
215
|
-
**👉 [Complete Security Guide →](./security/README.md)**
|
|
101
|
+
See [docs/rails-setup-guide.md](./docs/rails-setup-guide.md) for a full setup guide.
|
|
216
102
|
|
|
217
|
-
|
|
103
|
+
## Tools, Resources, and Prompts
|
|
218
104
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
### File System Server
|
|
105
|
+
Expose callable tools:
|
|
222
106
|
|
|
223
107
|
```ruby
|
|
224
108
|
server.register_tool(
|
|
225
|
-
name:
|
|
226
|
-
description:
|
|
109
|
+
name: "calculate",
|
|
110
|
+
description: "Performs basic math",
|
|
227
111
|
input_schema: {
|
|
228
|
-
type:
|
|
229
|
-
properties: {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Database Query Tool
|
|
236
|
-
|
|
237
|
-
```ruby
|
|
238
|
-
server.register_tool(
|
|
239
|
-
name: 'search_users',
|
|
240
|
-
description: 'Searches users by name',
|
|
241
|
-
input_schema: {
|
|
242
|
-
type: 'object',
|
|
243
|
-
properties: {
|
|
244
|
-
query: { type: 'string', minLength: 1 },
|
|
245
|
-
limit: { type: 'integer', minimum: 1, maximum: 100 }
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {
|
|
114
|
+
operation: { type: "string", enum: ["add", "subtract", "multiply"] },
|
|
115
|
+
a: { type: "number" },
|
|
116
|
+
b: { type: "number" }
|
|
246
117
|
},
|
|
247
|
-
required: [
|
|
118
|
+
required: ["operation", "a", "b"]
|
|
248
119
|
}
|
|
249
120
|
) do |args|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
121
|
+
case args["operation"]
|
|
122
|
+
when "add" then args["a"] + args["b"]
|
|
123
|
+
when "subtract" then args["a"] - args["b"]
|
|
124
|
+
when "multiply" then args["a"] * args["b"]
|
|
125
|
+
end
|
|
253
126
|
end
|
|
254
127
|
```
|
|
255
128
|
|
|
256
|
-
|
|
129
|
+
Expose readable resources:
|
|
257
130
|
|
|
258
131
|
```ruby
|
|
259
|
-
server.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
properties: { city: { type: 'string' } },
|
|
265
|
-
required: ['city']
|
|
266
|
-
}
|
|
267
|
-
) do |args|
|
|
268
|
-
response = HTTP.get("https://api.weather.com/current", params: { city: args['city'] })
|
|
269
|
-
response.parse
|
|
270
|
-
end
|
|
132
|
+
server.register_resource(
|
|
133
|
+
uri: "file://config.json",
|
|
134
|
+
name: "App Configuration",
|
|
135
|
+
description: "Current application settings"
|
|
136
|
+
) { File.read("config.json") }
|
|
271
137
|
```
|
|
272
138
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
## Advanced Usage
|
|
276
|
-
|
|
277
|
-
<details>
|
|
278
|
-
<summary><strong>Filesystem Roots & Security</strong></summary>
|
|
279
|
-
|
|
280
|
-
Define secure filesystem boundaries:
|
|
139
|
+
Define prompt templates:
|
|
281
140
|
|
|
282
141
|
```ruby
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
input_schema: {
|
|
291
|
-
type: 'object',
|
|
292
|
-
properties: { root_uri: { type: 'string' } },
|
|
293
|
-
required: ['root_uri']
|
|
294
|
-
}
|
|
142
|
+
server.register_prompt(
|
|
143
|
+
name: "code_review",
|
|
144
|
+
description: "Reviews code for best practices",
|
|
145
|
+
arguments: [
|
|
146
|
+
{ name: "language", description: "Programming language", required: true },
|
|
147
|
+
{ name: "code", description: "Code to review", required: true }
|
|
148
|
+
]
|
|
295
149
|
) do |args|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
<details>
|
|
305
|
-
<summary><strong>LLM Sampling (Server → Client)</strong></summary>
|
|
306
|
-
|
|
307
|
-
Make requests to the connected LLM:
|
|
308
|
-
|
|
309
|
-
```ruby
|
|
310
|
-
server.register_tool(
|
|
311
|
-
name: 'generate_summary',
|
|
312
|
-
input_schema: {
|
|
313
|
-
type: 'object',
|
|
314
|
-
properties: { text: { type: 'string' } },
|
|
315
|
-
required: ['text']
|
|
150
|
+
{
|
|
151
|
+
messages: [{
|
|
152
|
+
role: "user",
|
|
153
|
+
content: {
|
|
154
|
+
type: "text",
|
|
155
|
+
text: "Review this #{args["language"]} code:\n\n#{args["code"]}"
|
|
156
|
+
}
|
|
157
|
+
}]
|
|
316
158
|
}
|
|
317
|
-
) do |args, session|
|
|
318
|
-
result = session.sample(
|
|
319
|
-
messages: [{
|
|
320
|
-
role: 'user',
|
|
321
|
-
content: { type: 'text', text: "Summarize: #{args['text']}" }
|
|
322
|
-
}],
|
|
323
|
-
max_tokens: 100
|
|
324
|
-
)
|
|
325
|
-
result.text_content
|
|
326
159
|
end
|
|
327
160
|
```
|
|
328
161
|
|
|
329
|
-
|
|
162
|
+
`VectorMCP::Tool` also supports `type: :date` and `type: :datetime`, which are validated as strings in JSON Schema and coerced to `Date` and `Time` before `#call` runs.
|
|
330
163
|
|
|
331
|
-
|
|
332
|
-
<summary><strong>Custom Error Handling</strong></summary>
|
|
164
|
+
## Security and Middleware
|
|
333
165
|
|
|
334
|
-
|
|
166
|
+
VectorMCP keeps security opt-in, but the primitives are built in:
|
|
335
167
|
|
|
336
168
|
```ruby
|
|
337
|
-
server.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
raise VectorMCP::InternalError.new('Operation failed')
|
|
169
|
+
server.enable_authentication!(
|
|
170
|
+
strategy: :api_key,
|
|
171
|
+
keys: ["your-secret-key"]
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
server.enable_authorization! do
|
|
175
|
+
authorize_tools do |user, _action, tool|
|
|
176
|
+
user[:role] == "admin" || !tool.name.start_with?("admin_")
|
|
346
177
|
end
|
|
347
178
|
end
|
|
348
179
|
```
|
|
349
180
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
<details>
|
|
353
|
-
<summary><strong>Session Information</strong></summary>
|
|
354
|
-
|
|
355
|
-
Access client context:
|
|
181
|
+
Custom authentication works too:
|
|
356
182
|
|
|
357
183
|
```ruby
|
|
358
|
-
server.
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
initialized: session.initialized?
|
|
363
|
-
}
|
|
184
|
+
server.enable_authentication!(strategy: :custom) do |request|
|
|
185
|
+
api_key = request[:headers]["X-API-Key"]
|
|
186
|
+
user = User.find_by(api_key: api_key)
|
|
187
|
+
user ? { user_id: user.id, role: user.role } : false
|
|
364
188
|
end
|
|
365
189
|
```
|
|
366
190
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
---
|
|
191
|
+
Middleware can hook into tool, resource, prompt, sampling, auth, and transport events, including `before_auth`, `after_auth`, `on_auth_error`, `before_request`, `after_response`, and `on_transport_error`.
|
|
370
192
|
|
|
371
|
-
|
|
193
|
+
See [security/README.md](./security/README.md) for the full security guide.
|
|
372
194
|
|
|
373
|
-
|
|
195
|
+
## Transport Notes
|
|
374
196
|
|
|
375
|
-
|
|
197
|
+
- VectorMCP ships with streamable HTTP as its built-in transport
|
|
198
|
+
- `POST /mcp` accepts a single JSON-RPC request, notification, or response; batch arrays are rejected
|
|
199
|
+
- `GET /mcp` opens an SSE stream for server-initiated messages
|
|
200
|
+
- `DELETE /mcp` terminates the session
|
|
201
|
+
- The server advertises MCP protocol `2025-11-25` and accepts `2025-03-26` and `2024-11-05` headers for compatibility
|
|
202
|
+
- Default allowed origins are restricted to localhost and loopback addresses
|
|
376
203
|
|
|
377
|
-
|
|
378
|
-
{
|
|
379
|
-
"mcpServers": {
|
|
380
|
-
"my-ruby-server": {
|
|
381
|
-
"command": "ruby",
|
|
382
|
-
"args": ["path/to/my_server.rb"]
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
```
|
|
204
|
+
Initialize a session with curl:
|
|
387
205
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
eventSource.addEventListener('endpoint', (event) => {
|
|
395
|
-
const { uri } = JSON.parse(event.data);
|
|
396
|
-
|
|
397
|
-
// Send MCP requests
|
|
398
|
-
fetch(uri, {
|
|
399
|
-
method: 'POST',
|
|
400
|
-
headers: { 'Content-Type': 'application/json' },
|
|
401
|
-
body: JSON.stringify({
|
|
402
|
-
jsonrpc: '2.0',
|
|
403
|
-
id: 1,
|
|
404
|
-
method: 'tools/call',
|
|
405
|
-
params: { name: 'greet', arguments: { name: 'World' } }
|
|
406
|
-
})
|
|
407
|
-
});
|
|
408
|
-
});
|
|
206
|
+
```bash
|
|
207
|
+
curl -X POST http://localhost:8080/mcp \
|
|
208
|
+
-H "Content-Type: application/json" \
|
|
209
|
+
-H "Accept: application/json, text/event-stream" \
|
|
210
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
|
|
409
211
|
```
|
|
410
212
|
|
|
411
|
-
##
|
|
412
|
-
|
|
413
|
-
**🏆 Battle-Tested**: Used in production applications serving thousands of requests
|
|
414
|
-
|
|
415
|
-
**⚡ Performance**: Optimized for low latency and high throughput
|
|
416
|
-
|
|
417
|
-
**🛡️ Secure by Default**: Comprehensive input validation prevents common attacks
|
|
213
|
+
## More Features
|
|
418
214
|
|
|
419
|
-
|
|
215
|
+
- Roots via `register_root` and `register_root_from_path`
|
|
216
|
+
- Image resources and image-aware tools/prompts
|
|
217
|
+
- Structured logging with component loggers
|
|
218
|
+
- Server-initiated sampling with streaming/tool-call support
|
|
219
|
+
- Middleware-driven request shaping and observability
|
|
420
220
|
|
|
421
|
-
|
|
221
|
+
## Documentation
|
|
422
222
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
-
|
|
428
|
-
-
|
|
429
|
-
- **[MCP Specification](https://modelcontext.dev/)** - Official protocol documentation
|
|
430
|
-
|
|
431
|
-
## Installation & Setup
|
|
432
|
-
|
|
433
|
-
```bash
|
|
434
|
-
gem install vector_mcp
|
|
435
|
-
|
|
436
|
-
# Or in your Gemfile
|
|
437
|
-
gem 'vector_mcp'
|
|
438
|
-
```
|
|
223
|
+
- [CHANGELOG.md](./CHANGELOG.md)
|
|
224
|
+
- [examples/](./examples/)
|
|
225
|
+
- [docs/rails-setup-guide.md](./docs/rails-setup-guide.md)
|
|
226
|
+
- [docs/streamable-http-spec-compliance.md](./docs/streamable-http-spec-compliance.md)
|
|
227
|
+
- [security/README.md](./security/README.md)
|
|
228
|
+
- [MCP Specification](https://modelcontextprotocol.io/)
|
|
439
229
|
|
|
440
230
|
## Contributing
|
|
441
231
|
|
|
442
|
-
Bug reports and pull requests welcome on [GitHub](https://github.com/sergiobayona/vector_mcp).
|
|
232
|
+
Bug reports and pull requests are welcome on [GitHub](https://github.com/sergiobayona/vector_mcp).
|
|
443
233
|
|
|
444
234
|
## License
|
|
445
235
|
|
|
446
|
-
Available as open source under the [MIT License](https://opensource.org/licenses/MIT).
|
|
236
|
+
Available as open source under the [MIT License](https://opensource.org/licenses/MIT).
|