tsikol 0.1.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 +7 -0
- data/CHANGELOG.md +22 -0
- data/CONTRIBUTING.md +84 -0
- data/LICENSE +21 -0
- data/README.md +579 -0
- data/Rakefile +12 -0
- data/docs/README.md +69 -0
- data/docs/api/middleware.md +721 -0
- data/docs/api/prompt.md +858 -0
- data/docs/api/resource.md +651 -0
- data/docs/api/server.md +509 -0
- data/docs/api/test-helpers.md +591 -0
- data/docs/api/tool.md +527 -0
- data/docs/cookbook/authentication.md +651 -0
- data/docs/cookbook/caching.md +877 -0
- data/docs/cookbook/dynamic-tools.md +970 -0
- data/docs/cookbook/error-handling.md +887 -0
- data/docs/cookbook/logging.md +1044 -0
- data/docs/cookbook/rate-limiting.md +717 -0
- data/docs/examples/code-assistant.md +922 -0
- data/docs/examples/complete-server.md +726 -0
- data/docs/examples/database-manager.md +1198 -0
- data/docs/examples/devops-tools.md +1382 -0
- data/docs/examples/echo-server.md +501 -0
- data/docs/examples/weather-service.md +822 -0
- data/docs/guides/completion.md +472 -0
- data/docs/guides/getting-started.md +462 -0
- data/docs/guides/middleware.md +823 -0
- data/docs/guides/project-structure.md +434 -0
- data/docs/guides/prompts.md +920 -0
- data/docs/guides/resources.md +720 -0
- data/docs/guides/sampling.md +804 -0
- data/docs/guides/testing.md +863 -0
- data/docs/guides/tools.md +627 -0
- data/examples/README.md +92 -0
- data/examples/advanced_features.rb +129 -0
- data/examples/basic-migrated/app/prompts/weather_chat.rb +44 -0
- data/examples/basic-migrated/app/resources/weather_alerts.rb +18 -0
- data/examples/basic-migrated/app/tools/get_current_weather.rb +34 -0
- data/examples/basic-migrated/app/tools/get_forecast.rb +30 -0
- data/examples/basic-migrated/app/tools/get_weather_by_coords.rb +48 -0
- data/examples/basic-migrated/server.rb +25 -0
- data/examples/basic.rb +73 -0
- data/examples/full_featured.rb +175 -0
- data/examples/middleware_example.rb +112 -0
- data/examples/sampling_example.rb +104 -0
- data/examples/weather-service/app/prompts/weather/chat.rb +90 -0
- data/examples/weather-service/app/resources/weather/alerts.rb +59 -0
- data/examples/weather-service/app/tools/weather/get_current.rb +82 -0
- data/examples/weather-service/app/tools/weather/get_forecast.rb +90 -0
- data/examples/weather-service/server.rb +28 -0
- data/exe/tsikol +6 -0
- data/lib/tsikol/cli/templates/Gemfile.erb +10 -0
- data/lib/tsikol/cli/templates/README.md.erb +38 -0
- data/lib/tsikol/cli/templates/gitignore.erb +49 -0
- data/lib/tsikol/cli/templates/prompt.rb.erb +53 -0
- data/lib/tsikol/cli/templates/resource.rb.erb +29 -0
- data/lib/tsikol/cli/templates/server.rb.erb +24 -0
- data/lib/tsikol/cli/templates/tool.rb.erb +60 -0
- data/lib/tsikol/cli.rb +203 -0
- data/lib/tsikol/error_handler.rb +141 -0
- data/lib/tsikol/health.rb +198 -0
- data/lib/tsikol/http_transport.rb +72 -0
- data/lib/tsikol/lifecycle.rb +149 -0
- data/lib/tsikol/middleware.rb +168 -0
- data/lib/tsikol/prompt.rb +101 -0
- data/lib/tsikol/resource.rb +53 -0
- data/lib/tsikol/router.rb +190 -0
- data/lib/tsikol/server.rb +660 -0
- data/lib/tsikol/stdio_transport.rb +108 -0
- data/lib/tsikol/test_helpers.rb +261 -0
- data/lib/tsikol/tool.rb +111 -0
- data/lib/tsikol/version.rb +5 -0
- data/lib/tsikol.rb +72 -0
- metadata +219 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 486f6d3cabbbf5b62f65a7135c592c1f1e23bf8d8f0ca5f7cdd72a3519230ec2
|
4
|
+
data.tar.gz: 4ad29f7c0cd2235bb954472cddae5adbe2e9664fc1094581ec1bfa18506d609f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 226b841f33b0c3f7cbec1a42f0b706fa262a0b86fe512f60d0e063dcbd98eaa38801eac80dd204c86314d50bd4a08c4ab3eb2089e38e9a9f62d6e5119626c528
|
7
|
+
data.tar.gz: 77e614efd0dc4a7211da3b9602a52bed1f26b6e1b7fffa5c38b75eaa7a3091dc13aef95317a2a04ffea7104ae52d3dbaed897c692cebf0d857d915c220794568
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [0.1.0] - 2024-01-29
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Initial release of Tsikol MCP Framework
|
12
|
+
- Full MCP protocol support (Tools, Resources, Prompts)
|
13
|
+
- Logging, Completion, and Sampling capabilities
|
14
|
+
- Middleware system for cross-cutting concerns
|
15
|
+
- Error handling with circuit breakers
|
16
|
+
- Lifecycle hooks (server and tool-level)
|
17
|
+
- Built-in health monitoring and metrics
|
18
|
+
- Testing utilities and mock client
|
19
|
+
- CLI tool with generators
|
20
|
+
- Rails-like project structure
|
21
|
+
- Auto-discovery of components
|
22
|
+
- Comprehensive documentation and examples
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Contributing to Tsikol
|
2
|
+
|
3
|
+
We love your input! We want to make contributing to Tsikol as easy and transparent as possible, whether it's:
|
4
|
+
|
5
|
+
- Reporting a bug
|
6
|
+
- Discussing the current state of the code
|
7
|
+
- Submitting a fix
|
8
|
+
- Proposing new features
|
9
|
+
- Becoming a maintainer
|
10
|
+
|
11
|
+
## We Develop with Github
|
12
|
+
|
13
|
+
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
|
14
|
+
|
15
|
+
## We Use [Github Flow](https://guides.github.com/introduction/flow/index.html)
|
16
|
+
|
17
|
+
Pull requests are the best way to propose changes to the codebase:
|
18
|
+
|
19
|
+
1. Fork the repo and create your branch from `main`.
|
20
|
+
2. If you've added code that should be tested, add tests.
|
21
|
+
3. If you've changed APIs, update the documentation.
|
22
|
+
4. Ensure the test suite passes.
|
23
|
+
5. Make sure your code lints.
|
24
|
+
6. Issue that pull request!
|
25
|
+
|
26
|
+
## Any contributions you make will be under the MIT Software License
|
27
|
+
|
28
|
+
In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
|
29
|
+
|
30
|
+
## Report bugs using Github's [issues](https://github.com/arturodz/tsikol/issues)
|
31
|
+
|
32
|
+
We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/arturodz/tsikol/issues/new); it's that easy!
|
33
|
+
|
34
|
+
## Write bug reports with detail, background, and sample code
|
35
|
+
|
36
|
+
**Great Bug Reports** tend to have:
|
37
|
+
|
38
|
+
- A quick summary and/or background
|
39
|
+
- Steps to reproduce
|
40
|
+
- Be specific!
|
41
|
+
- Give sample code if you can
|
42
|
+
- What you expected would happen
|
43
|
+
- What actually happens
|
44
|
+
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
|
45
|
+
|
46
|
+
## Development Setup
|
47
|
+
|
48
|
+
1. Fork and clone the repository
|
49
|
+
2. Run `bundle install`
|
50
|
+
3. Run tests with `bundle exec rake test`
|
51
|
+
4. Make your changes
|
52
|
+
5. Add tests for your changes
|
53
|
+
6. Run tests again to ensure they pass
|
54
|
+
7. Submit a pull request
|
55
|
+
|
56
|
+
## Testing
|
57
|
+
|
58
|
+
```bash
|
59
|
+
# Run all tests
|
60
|
+
bundle exec rake test
|
61
|
+
|
62
|
+
# Run specific test file
|
63
|
+
ruby -Ilib:test test/example_test.rb
|
64
|
+
```
|
65
|
+
|
66
|
+
## Code Style
|
67
|
+
|
68
|
+
- Follow Ruby community style guidelines
|
69
|
+
- Use RuboCop for linting: `bundle exec rubocop`
|
70
|
+
- Keep methods small and focused
|
71
|
+
- Write descriptive commit messages
|
72
|
+
|
73
|
+
## Adding New Features
|
74
|
+
|
75
|
+
When adding new features:
|
76
|
+
|
77
|
+
1. Update the appropriate documentation
|
78
|
+
2. Add examples if applicable
|
79
|
+
3. Update the CHANGELOG.md
|
80
|
+
4. Add tests covering the new functionality
|
81
|
+
|
82
|
+
## License
|
83
|
+
|
84
|
+
By contributing, you agree that your contributions will be licensed under its MIT License.
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Tsikol Contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,579 @@
|
|
1
|
+
# Tsikol - Ruby MCP Framework
|
2
|
+
|
3
|
+
A elegant and easy to use framework for building Model Context Protocol (MCP) servers in Ruby.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- 🚀 **Rails-like Structure** - Familiar project organization with `app/tools`, `app/resources`, `app/prompts`
|
8
|
+
- 🔧 **Flexible DSL** - Define components inline or in separate files
|
9
|
+
- 🔄 **Full MCP Protocol Support** - Tools, Resources, Prompts, Logging, Completion, Sampling
|
10
|
+
- 🛡️ **Middleware System** - Add cross-cutting concerns like auth, rate limiting, logging
|
11
|
+
- 📊 **Built-in Monitoring** - Health checks, metrics, error tracking
|
12
|
+
- 🧪 **Testing Utilities** - Comprehensive test helpers and mock client
|
13
|
+
- ⚡ **Hot Reload** - Auto-discovery of components
|
14
|
+
- 🔍 **Advanced Error Handling** - Circuit breakers, error recovery, detailed logging
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add to your Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'tsikol'
|
22
|
+
```
|
23
|
+
|
24
|
+
Or install directly:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
gem install tsikol
|
28
|
+
```
|
29
|
+
|
30
|
+
## CLI Usage
|
31
|
+
|
32
|
+
Tsikol includes a powerful CLI tool for scaffolding projects and generating components.
|
33
|
+
|
34
|
+
### Create a New Project
|
35
|
+
|
36
|
+
```bash
|
37
|
+
tsikol new my-mcp-server
|
38
|
+
cd my-mcp-server
|
39
|
+
bundle install
|
40
|
+
```
|
41
|
+
|
42
|
+
This creates a complete project structure with:
|
43
|
+
- `server.rb` - Main server file
|
44
|
+
- `Gemfile` - Dependencies
|
45
|
+
- `app/` directory structure for components
|
46
|
+
- README and .gitignore
|
47
|
+
|
48
|
+
### Generate Components
|
49
|
+
|
50
|
+
The CLI can generate tools, resources, and prompts with automatic server.rb updates:
|
51
|
+
|
52
|
+
#### Generate a Tool
|
53
|
+
|
54
|
+
```bash
|
55
|
+
# Basic tool
|
56
|
+
tsikol generate tool calculate
|
57
|
+
|
58
|
+
# Tool with parameters (name:type format)
|
59
|
+
tsikol generate tool calculate a:number b:number operation:string
|
60
|
+
|
61
|
+
# Optional parameters use ? suffix
|
62
|
+
tsikol generate tool weather_forecast location:string days?:integer units?:string
|
63
|
+
|
64
|
+
# Short alias
|
65
|
+
tsikol g tool my_tool param1:string param2:boolean
|
66
|
+
```
|
67
|
+
|
68
|
+
#### Generate a Resource
|
69
|
+
|
70
|
+
```bash
|
71
|
+
# Basic resource
|
72
|
+
tsikol generate resource system_status
|
73
|
+
|
74
|
+
# Resource with custom URI (auto-converts underscores to slashes)
|
75
|
+
tsikol generate resource user_profile # Creates URI: user/profile
|
76
|
+
|
77
|
+
# Short alias
|
78
|
+
tsikol g resource my_data
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Generate a Prompt
|
82
|
+
|
83
|
+
```bash
|
84
|
+
# Basic prompt
|
85
|
+
tsikol generate prompt code_review
|
86
|
+
|
87
|
+
# Prompt with arguments
|
88
|
+
tsikol generate prompt code_review language:string code:string style?:string
|
89
|
+
|
90
|
+
# Short alias
|
91
|
+
tsikol g prompt chat_assistant topic:string context?:string
|
92
|
+
```
|
93
|
+
|
94
|
+
### How the CLI Works
|
95
|
+
|
96
|
+
1. **Generates the component file** in the appropriate directory:
|
97
|
+
- Tools → `app/tools/`
|
98
|
+
- Resources → `app/resources/`
|
99
|
+
- Prompts → `app/prompts/`
|
100
|
+
|
101
|
+
2. **Updates server.rb automatically**:
|
102
|
+
- Adds the require statement
|
103
|
+
- Registers the component in the routes
|
104
|
+
|
105
|
+
3. **Smart insertion** - Components are grouped by type in server.rb
|
106
|
+
|
107
|
+
### Example Workflow
|
108
|
+
|
109
|
+
```bash
|
110
|
+
# Create a new weather service
|
111
|
+
tsikol new weather-service
|
112
|
+
cd weather-service
|
113
|
+
|
114
|
+
# Generate tools
|
115
|
+
tsikol g tool get_current_weather location:string units?:string
|
116
|
+
tsikol g tool get_forecast location:string days:integer
|
117
|
+
|
118
|
+
# Generate resources
|
119
|
+
tsikol g resource weather_alerts
|
120
|
+
tsikol g resource service_status
|
121
|
+
|
122
|
+
# Generate prompts
|
123
|
+
tsikol g prompt weather_chat city:string topic:string
|
124
|
+
|
125
|
+
# Your server.rb is automatically updated with all components!
|
126
|
+
./server.rb
|
127
|
+
```
|
128
|
+
|
129
|
+
## Quick Start
|
130
|
+
|
131
|
+
### Simple Server
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
#!/usr/bin/env ruby
|
135
|
+
require 'tsikol'
|
136
|
+
|
137
|
+
Tsikol.server "my-server" do
|
138
|
+
tool "greet" do |name:|
|
139
|
+
"Hello, #{name}!"
|
140
|
+
end
|
141
|
+
|
142
|
+
resource "status" do
|
143
|
+
"Server is running"
|
144
|
+
end
|
145
|
+
|
146
|
+
prompt "chat" do |topic:|
|
147
|
+
"Let's discuss #{topic}"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
```
|
151
|
+
|
152
|
+
### Rails-like Structure
|
153
|
+
|
154
|
+
```ruby
|
155
|
+
# server.rb
|
156
|
+
require 'tsikol'
|
157
|
+
|
158
|
+
Tsikol.start(name: "weather-service") do
|
159
|
+
# Direct class references
|
160
|
+
tool GetCurrentWeather
|
161
|
+
tool GetForecast
|
162
|
+
resource WeatherAlerts
|
163
|
+
prompt WeatherChat
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
# app/tools/get_current_weather.rb
|
169
|
+
class GetCurrentWeather < Tsikol::Tool
|
170
|
+
description "Get current weather for a location"
|
171
|
+
|
172
|
+
parameter :location do
|
173
|
+
type :string
|
174
|
+
required
|
175
|
+
description "City name"
|
176
|
+
|
177
|
+
complete do |partial|
|
178
|
+
["New York", "London", "Tokyo"].select { |c| c.start_with?(partial) }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def execute(location:)
|
183
|
+
"Currently 72°F in #{location}"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
## Core Concepts
|
189
|
+
|
190
|
+
### Tools
|
191
|
+
|
192
|
+
Tools are functions that can be called by the MCP client:
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
# Inline definition
|
196
|
+
tool "calculate" do |a:, b:, operation: "add"|
|
197
|
+
case operation
|
198
|
+
when "add" then a + b
|
199
|
+
when "subtract" then a - b
|
200
|
+
when "multiply" then a * b
|
201
|
+
when "divide" then b.zero? ? "Error: Division by zero" : a.to_f / b
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Class-based definition
|
206
|
+
class Calculate < Tsikol::Tool
|
207
|
+
description "Perform calculations"
|
208
|
+
|
209
|
+
parameter :a do
|
210
|
+
type :number
|
211
|
+
required
|
212
|
+
description "First number"
|
213
|
+
end
|
214
|
+
|
215
|
+
parameter :b do
|
216
|
+
type :number
|
217
|
+
required
|
218
|
+
description "Second number"
|
219
|
+
end
|
220
|
+
|
221
|
+
parameter :operation do
|
222
|
+
type :string
|
223
|
+
optional
|
224
|
+
default "add"
|
225
|
+
enum ["add", "subtract", "multiply", "divide"]
|
226
|
+
end
|
227
|
+
|
228
|
+
def execute(a:, b:, operation: "add")
|
229
|
+
# Implementation
|
230
|
+
end
|
231
|
+
end
|
232
|
+
```
|
233
|
+
|
234
|
+
### Resources
|
235
|
+
|
236
|
+
Resources provide data that can be read by the client:
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
# Inline definition
|
240
|
+
resource "config/database" do
|
241
|
+
{
|
242
|
+
host: ENV['DB_HOST'],
|
243
|
+
port: ENV['DB_PORT'],
|
244
|
+
name: ENV['DB_NAME']
|
245
|
+
}.to_json
|
246
|
+
end
|
247
|
+
|
248
|
+
# Class-based definition
|
249
|
+
class DatabaseConfig < Tsikol::Resource
|
250
|
+
uri "config/database"
|
251
|
+
description "Database configuration"
|
252
|
+
|
253
|
+
def read
|
254
|
+
# Return content
|
255
|
+
end
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
### Prompts
|
260
|
+
|
261
|
+
Prompts generate messages for AI interactions:
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
# Inline definition
|
265
|
+
prompt "code_review" do |language:, code:|
|
266
|
+
"Review this #{language} code:\n```#{language}\n#{code}\n```"
|
267
|
+
end
|
268
|
+
|
269
|
+
# Class-based definition
|
270
|
+
class CodeReview < Tsikol::Prompt
|
271
|
+
name "code_review"
|
272
|
+
description "Generate code review prompt"
|
273
|
+
|
274
|
+
argument :language do
|
275
|
+
type :string
|
276
|
+
required
|
277
|
+
complete do |partial|
|
278
|
+
["ruby", "python", "javascript"].select { |l| l.start_with?(partial) }
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def get_messages(language:, code:)
|
283
|
+
[{
|
284
|
+
role: "user",
|
285
|
+
content: {
|
286
|
+
type: "text",
|
287
|
+
text: "Review this #{language} code:\n```#{language}\n#{code}\n```"
|
288
|
+
}
|
289
|
+
}]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
```
|
293
|
+
|
294
|
+
### Completion (Autocomplete)
|
295
|
+
|
296
|
+
Provide intelligent autocomplete suggestions for tool parameters and prompt arguments:
|
297
|
+
|
298
|
+
```ruby
|
299
|
+
# Tool with parameter completion
|
300
|
+
class SearchFiles < Tsikol::Tool
|
301
|
+
description "Search for files in the project"
|
302
|
+
|
303
|
+
parameter :file_type do
|
304
|
+
type :string
|
305
|
+
required
|
306
|
+
description "Type of file to search for"
|
307
|
+
|
308
|
+
complete do |partial|
|
309
|
+
# Return suggestions based on partial input
|
310
|
+
extensions = ["rb", "js", "py", "md", "yml", "json", "xml"]
|
311
|
+
extensions.select { |ext| ext.start_with?(partial) }
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
parameter :directory do
|
316
|
+
type :string
|
317
|
+
optional
|
318
|
+
description "Directory to search in"
|
319
|
+
|
320
|
+
complete do |partial|
|
321
|
+
# Dynamic completion based on filesystem
|
322
|
+
Dir.glob("#{partial}*").select { |f| File.directory?(f) }
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def execute(file_type:, directory: ".")
|
327
|
+
Dir.glob("#{directory}/**/*.#{file_type}")
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
# Inline completion for tools
|
332
|
+
tool "database_query" do |table:, operation:|
|
333
|
+
"Executing #{operation} on #{table}"
|
334
|
+
end
|
335
|
+
|
336
|
+
# Define completions separately
|
337
|
+
completion_for "tool", "database_query", "table" do |partial|
|
338
|
+
# List available tables
|
339
|
+
["users", "posts", "comments", "tags"].select { |t| t.start_with?(partial) }
|
340
|
+
end
|
341
|
+
|
342
|
+
completion_for "tool", "database_query", "operation" do |partial|
|
343
|
+
["select", "insert", "update", "delete"].select { |op| op.start_with?(partial) }
|
344
|
+
end
|
345
|
+
```
|
346
|
+
|
347
|
+
## Advanced Features
|
348
|
+
|
349
|
+
### Middleware
|
350
|
+
|
351
|
+
Add cross-cutting concerns with middleware:
|
352
|
+
|
353
|
+
```ruby
|
354
|
+
Tsikol.server "my-server" do
|
355
|
+
# Built-in middleware
|
356
|
+
use Tsikol::LoggingMiddleware
|
357
|
+
use Tsikol::RateLimitMiddleware, max_requests: 100, window: 60
|
358
|
+
use Tsikol::ValidationMiddleware
|
359
|
+
|
360
|
+
# Custom middleware
|
361
|
+
use AuthMiddleware, api_keys: ["secret-key"]
|
362
|
+
|
363
|
+
# Tools, resources, prompts...
|
364
|
+
end
|
365
|
+
```
|
366
|
+
|
367
|
+
### Lifecycle Hooks
|
368
|
+
|
369
|
+
```ruby
|
370
|
+
Tsikol.server "my-server" do
|
371
|
+
before_start do
|
372
|
+
log :info, "Initializing connections..."
|
373
|
+
# Setup code
|
374
|
+
end
|
375
|
+
|
376
|
+
after_start do
|
377
|
+
log :info, "Server ready!"
|
378
|
+
end
|
379
|
+
|
380
|
+
before_stop do
|
381
|
+
log :info, "Cleaning up..."
|
382
|
+
# Cleanup code
|
383
|
+
end
|
384
|
+
|
385
|
+
# Tool-specific hooks
|
386
|
+
before_tool "critical_operation" do |params|
|
387
|
+
log :warning, "About to run critical operation", data: params
|
388
|
+
end
|
389
|
+
|
390
|
+
after_tool "critical_operation" do |params, result|
|
391
|
+
log :info, "Critical operation completed", data: { result: result }
|
392
|
+
end
|
393
|
+
end
|
394
|
+
```
|
395
|
+
|
396
|
+
### Sampling (AI Assistance)
|
397
|
+
|
398
|
+
Enable AI-assisted content generation where the MCP server can request help from the AI client:
|
399
|
+
|
400
|
+
```ruby
|
401
|
+
Tsikol.server "my-server" do
|
402
|
+
# Enable sampling and define handler
|
403
|
+
on_sampling do |request|
|
404
|
+
# The request contains:
|
405
|
+
# - messages: Array of conversation messages
|
406
|
+
# - model_preferences: Hints about which model to use
|
407
|
+
# - system_prompt: Optional system instructions
|
408
|
+
# - max_tokens: Maximum response length
|
409
|
+
|
410
|
+
# In production, the MCP client (e.g., Claude) handles this
|
411
|
+
# For testing, you can simulate responses:
|
412
|
+
{
|
413
|
+
role: "assistant",
|
414
|
+
content: {
|
415
|
+
type: "text",
|
416
|
+
text: "AI-generated response based on: #{request[:messages].last}"
|
417
|
+
}
|
418
|
+
}
|
419
|
+
end
|
420
|
+
|
421
|
+
# Tool that uses AI assistance
|
422
|
+
tool "write_documentation" do |code:, style: "technical"|
|
423
|
+
# In a real MCP client, this would trigger a sampling request
|
424
|
+
prompt = case style
|
425
|
+
when "technical"
|
426
|
+
"Write technical documentation for this code"
|
427
|
+
when "tutorial"
|
428
|
+
"Write a beginner-friendly tutorial for this code"
|
429
|
+
when "api"
|
430
|
+
"Write API reference documentation"
|
431
|
+
end
|
432
|
+
|
433
|
+
# The actual AI response would come from the client
|
434
|
+
"#{prompt}:\n\n```ruby\n#{code}\n```"
|
435
|
+
end
|
436
|
+
|
437
|
+
# Advanced example with context
|
438
|
+
tool "refactor_code" do |code:, goal:|
|
439
|
+
# Build conversation for AI
|
440
|
+
messages = [
|
441
|
+
{
|
442
|
+
role: "system",
|
443
|
+
content: "You are an expert Ruby developer focused on clean code."
|
444
|
+
},
|
445
|
+
{
|
446
|
+
role: "user",
|
447
|
+
content: "Refactor this code to #{goal}:\n\n```ruby\n#{code}\n```"
|
448
|
+
}
|
449
|
+
]
|
450
|
+
|
451
|
+
# In production, this would send a sampling request
|
452
|
+
# with the messages to the MCP client
|
453
|
+
"Refactored code would appear here"
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
# Class-based tool with sampling
|
458
|
+
class CodeGenerator < Tsikol::Tool
|
459
|
+
description "Generate code using AI assistance"
|
460
|
+
|
461
|
+
parameter :description do
|
462
|
+
type :string
|
463
|
+
required
|
464
|
+
description "What code to generate"
|
465
|
+
end
|
466
|
+
|
467
|
+
parameter :language do
|
468
|
+
type :string
|
469
|
+
optional
|
470
|
+
default "ruby"
|
471
|
+
enum ["ruby", "python", "javascript", "go"]
|
472
|
+
end
|
473
|
+
|
474
|
+
def execute(description:, language: "ruby")
|
475
|
+
# Build sampling request
|
476
|
+
sampling_request = {
|
477
|
+
messages: [
|
478
|
+
{
|
479
|
+
role: "user",
|
480
|
+
content: {
|
481
|
+
type: "text",
|
482
|
+
text: "Generate #{language} code that: #{description}"
|
483
|
+
}
|
484
|
+
}
|
485
|
+
],
|
486
|
+
model_preferences: {
|
487
|
+
hints: [{ name: "claude-3-sonnet" }],
|
488
|
+
temperature: 0.7
|
489
|
+
},
|
490
|
+
max_tokens: 2000
|
491
|
+
}
|
492
|
+
|
493
|
+
# This would be sent to the MCP client
|
494
|
+
# Response would contain AI-generated code
|
495
|
+
"Generated #{language} code for: #{description}"
|
496
|
+
end
|
497
|
+
end
|
498
|
+
```
|
499
|
+
|
500
|
+
### Health Monitoring
|
501
|
+
|
502
|
+
Built-in health endpoints are automatically added:
|
503
|
+
|
504
|
+
- `resource "health"` - Basic health status
|
505
|
+
- `resource "health/detailed"` - Detailed health with metrics
|
506
|
+
- `resource "metrics"` - Raw metrics data
|
507
|
+
|
508
|
+
### Error Handling
|
509
|
+
|
510
|
+
Advanced error handling with circuit breakers:
|
511
|
+
|
512
|
+
```ruby
|
513
|
+
tool "external_api" do
|
514
|
+
# Automatically wrapped with circuit breaker
|
515
|
+
# After 5 failures, circuit opens for 60 seconds
|
516
|
+
call_external_service
|
517
|
+
end
|
518
|
+
```
|
519
|
+
|
520
|
+
## Testing
|
521
|
+
|
522
|
+
Tsikol includes comprehensive testing utilities:
|
523
|
+
|
524
|
+
```ruby
|
525
|
+
require 'tsikol/test_helpers'
|
526
|
+
|
527
|
+
class MyServerTest < Minitest::Test
|
528
|
+
include Tsikol::TestHelpers::Assertions
|
529
|
+
|
530
|
+
def setup
|
531
|
+
@server = create_my_server
|
532
|
+
@client = Tsikol::TestHelpers::TestClient.new(@server)
|
533
|
+
end
|
534
|
+
|
535
|
+
def test_echo_tool
|
536
|
+
@client.initialize_connection
|
537
|
+
assert_tool_result(@client, "echo", { "msg" => "Hi" }, "Echo: Hi")
|
538
|
+
end
|
539
|
+
|
540
|
+
def test_error_handling
|
541
|
+
response = @client.call_tool("failing_tool")
|
542
|
+
assert_error_response(response, -32603, /Internal error/)
|
543
|
+
end
|
544
|
+
end
|
545
|
+
```
|
546
|
+
|
547
|
+
## Project Structure
|
548
|
+
|
549
|
+
```
|
550
|
+
my-mcp-server/
|
551
|
+
├── server.rb # Main entry point
|
552
|
+
├── Gemfile
|
553
|
+
├── app/
|
554
|
+
│ ├── tools/ # Tool classes
|
555
|
+
│ ├── resources/ # Resource classes
|
556
|
+
│ └── prompts/ # Prompt classes
|
557
|
+
├── config/
|
558
|
+
│ └── tsikol.yml # Configuration (optional)
|
559
|
+
└── test/
|
560
|
+
└── server_test.rb # Tests
|
561
|
+
```
|
562
|
+
|
563
|
+
## Examples
|
564
|
+
|
565
|
+
See the `examples/` directory for complete examples:
|
566
|
+
|
567
|
+
- `basic.rb` - Simple inline server
|
568
|
+
- `weather-service/` - Full Rails-like project
|
569
|
+
- `middleware_example.rb` - Middleware demonstration
|
570
|
+
- `sampling_example.rb` - AI assistance
|
571
|
+
- `advanced_features.rb` - All features combined
|
572
|
+
|
573
|
+
## License
|
574
|
+
|
575
|
+
MIT License - see LICENSE file for details.
|
576
|
+
|
577
|
+
## Acknowledgments
|
578
|
+
|
579
|
+
Built for the Model Context Protocol (MCP) by Anthropic.
|