vector_mcp 0.3.4 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96c22c8497dcfd618605017a41a11d747e596654d86e856551159303133e0ab9
4
- data.tar.gz: 301099d4a3b6b21c28ad82adf95c77f3469a0c4ba40dbd63f9f4f1060391b37f
3
+ metadata.gz: de0f694bd85fb9d217c352fc907f7d77c27ee3837eea3512c8ca1791c53313c2
4
+ data.tar.gz: 86f0a7ab8c95e744ef8d80cb77faddaa195cef6636ea9fe175631b01bc0b0982
5
5
  SHA512:
6
- metadata.gz: 4d464e8ae1e4472eead1580582b2e39dcaadcc5da54087e3022386c05c2dafd0a45f80509a23653273d615a7f739e0cbd8de052acb6d816c1442819bb775b374
7
- data.tar.gz: 26818191d6c915a31562356b3dec35ada9a1e0bd42f662d37e5884ce05ba139bd54f4fe768d6a2b5106de21e97da2b5a3c9970797eb05082256761e82f276238
6
+ metadata.gz: c0f1f384fd9d654cc3385a87937c656dee9beaf38e0aeed6f0e92542366c17051615b774b58d1ecc2eb89dd23e6a6737e85e1dcdfb6d4c239a182d0d3c98f31f
7
+ data.tar.gz: 8d0047290e1033266498f197b94b3d51eb88b700c46e44f15229de985a74eb57889f8381887beb92b0007883244de8f0c53b652a9a8939963f30d3c81fecb406
data/CHANGELOG.md CHANGED
@@ -1,3 +1,62 @@
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
+
1
60
  ## [0.3.4] – 2026-03-17
2
61
 
3
62
  ### Added
data/README.md CHANGED
@@ -6,441 +6,231 @@
6
6
  [![Maintainability](https://qlty.sh/badges/fdb143b3-148a-4a86-8e3b-4ccebe993528/maintainability.svg)](https://qlty.sh/gh/sergiobayona/projects/vector_mcp)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
- VectorMCP is a Ruby gem implementing the Model Context Protocol (MCP) server-side specification. It provides a framework for creating MCP servers that expose tools, resources, prompts, and roots to LLM clients.
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
- ## Why VectorMCP?
11
+ ## Highlights
12
12
 
13
- - **🛡️ Security-First**: Built-in input validation and schema checking prevent injection attacks
14
- - **⚡ Production-Ready**: Robust error handling, comprehensive test suite, and proven reliability
15
- - **🔌 Multiple Transports**: stdio for CLI tools, SSE for web applications
16
- - **📦 Zero Configuration**: Works out of the box with sensible defaults
17
- - **🔄 Fully Compatible**: Implements the complete MCP specification
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
- ## Quick Start
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
- require 'vector_mcp'
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
- **That's it!** Your MCP server is ready to connect with Claude Desktop, custom clients, or any MCP-compatible application.
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
- server.run # Default: stdio transport
56
- ```
36
+ require "vector_mcp"
57
37
 
58
- ### Web Applications (HTTP + SSE)
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
- Ideal for web apps and browser-based clients:
42
+ def call(args, _session)
43
+ "Hello, #{args["name"]}!"
44
+ end
45
+ end
61
46
 
62
- ```ruby
63
- server.run(transport: :sse, port: 8080)
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
- Connect via Server-Sent Events at `http://localhost:8080/sse`
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: 'calculate',
77
- description: 'Performs basic math',
56
+ name: "echo",
57
+ description: "Echo back the supplied text",
78
58
  input_schema: {
79
- type: 'object',
80
- properties: {
81
- operation: { type: 'string', enum: ['add', 'subtract', 'multiply'] },
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
- ) do |args|
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
- ### Resources (Data Sources)
66
+ ## Rack and Rails
97
67
 
98
- Provide data that LLMs can read:
68
+ VectorMCP can run as a standalone HTTP server or be mounted inside an existing Rack app:
99
69
 
100
70
  ```ruby
101
- server.register_resource(
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
- Create reusable prompt templates:
73
+ server = VectorMCP::Server.new(name: "MyApp", version: "1.0.0")
74
+ server.register(Greet)
111
75
 
112
- ```ruby
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
- ## Security Features
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
- # This tool is protected against invalid inputs
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
- ### Authentication & Authorization
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
- # API Key Authentication
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
- # Custom Authentication Logic
179
- server.enable_authentication!(strategy: :custom) do |request|
180
- api_key = request[:headers]["X-API-Key"]
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
- ### Fine-Grained Authorization
186
-
187
- Control access to tools, resources, and prompts:
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
- ### Transport Security
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
- Our comprehensive security documentation covers authentication strategies, authorization policies, session management, and real-world examples.
103
+ ## Tools, Resources, and Prompts
218
104
 
219
- ## Real-World Examples
220
-
221
- ### File System Server
105
+ Expose callable tools:
222
106
 
223
107
  ```ruby
224
108
  server.register_tool(
225
- name: 'read_file',
226
- description: 'Reads a text file',
109
+ name: "calculate",
110
+ description: "Performs basic math",
227
111
  input_schema: {
228
- type: 'object',
229
- properties: { path: { type: 'string' } },
230
- required: ['path']
231
- }
232
- ) { |args| File.read(args['path']) }
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: ['query']
118
+ required: ["operation", "a", "b"]
248
119
  }
249
120
  ) do |args|
250
- User.where('name ILIKE ?', "%#{args['query']}%")
251
- .limit(args['limit'] || 10)
252
- .to_json
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
- ### API Integration
129
+ Expose readable resources:
257
130
 
258
131
  ```ruby
259
- server.register_tool(
260
- name: 'get_weather',
261
- description: 'Gets current weather for a city',
262
- input_schema: {
263
- type: 'object',
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
- # Register allowed directories
284
- server.register_root_from_path('./src', name: 'Source Code')
285
- server.register_root_from_path('./docs', name: 'Documentation')
286
-
287
- # Tools can safely operate within these bounds
288
- server.register_tool(
289
- name: 'list_files',
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
- root = server.roots[args['root_uri']]
297
- raise 'Invalid root' unless root
298
- Dir.entries(root.path).reject { |f| f.start_with?('.') }
299
- end
300
- ```
301
-
302
- </details>
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
- </details>
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
- <details>
332
- <summary><strong>Custom Error Handling</strong></summary>
164
+ ## Security and Middleware
333
165
 
334
- Use proper MCP error types:
166
+ VectorMCP keeps security opt-in, but the primitives are built in:
335
167
 
336
168
  ```ruby
337
- server.register_tool(name: 'risky_operation') do |args|
338
- if args['dangerous']
339
- raise VectorMCP::InvalidParamsError.new('Dangerous operation not allowed')
340
- end
341
-
342
- begin
343
- perform_operation(args)
344
- rescue SomeError => e
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
- </details>
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.register_tool(name: 'client_info') do |args, session|
359
- {
360
- client: session.client_info&.dig('name'),
361
- capabilities: session.client_capabilities,
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
- </details>
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
- ## Integration Examples
193
+ See [security/README.md](./security/README.md) for the full security guide.
372
194
 
373
- ### Claude Desktop
195
+ ## Transport Notes
374
196
 
375
- Add to your Claude Desktop configuration:
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
- ```json
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
- ### Web Applications
389
-
390
- ```javascript
391
- // Connect to SSE endpoint
392
- const eventSource = new EventSource('http://localhost:8080/sse');
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
- ## Why Choose VectorMCP?
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
- **📖 Well-Documented**: Extensive examples and clear API documentation
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
- **🔧 Extensible**: Easy to customize and extend for your specific needs
221
+ ## Documentation
422
222
 
423
- **🤝 Community**: Active development and responsive maintainer
424
-
425
- ## Examples & Resources
426
-
427
- - **[Examples Directory](./examples/)** - Complete working examples
428
- - **[File System MCP](https://github.com/sergiobayona/file_system_mcp)** - Real-world implementation
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).