mcp-sdk.rb 0.1.1 → 0.1.4
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/README.md +288 -5
- data/lib/mcp/angelo_sse_server.rb +200 -0
- data/lib/mcp/enhanced_sse_server.rb +300 -0
- data/lib/mcp/server.rb +629 -0
- data/lib/mcp/sse_client.rb +3 -0
- data/lib/mcp/stdio_client.rb +3 -1
- data/lib/mcp.rb +2 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a9f49fa38172f0c33f2294a0854871f9dbd0ba3e8a7ee2b68d168fff64f2bbf
|
|
4
|
+
data.tar.gz: 25a48fe35af5cbdf85e36cddde8ece4d1628e1a72a728d4c78eb66eefb4a9284
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35a216611ff9232bac3b3791f45e36317c02067e3cdcf273fe40861a4faa0946f85c861631d29d08b4987724fd9a18ff229e5385b7c2a8501bf529ba3cc3880d
|
|
7
|
+
data.tar.gz: c0fda6f709b4ac25aefd98a45b17c7991b53a97f48790eeef1ce09f8c7efb2489e433deba8048862aa6c8176a88435aada59f56fed39b2a5d63653d9b21df656
|
data/README.md
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://badge.fury.io/rb/mcp-sdk.rb)
|
|
4
4
|
|
|
5
|
-
A Ruby implementation of the Model Context Protocol (MCP) for connecting to MCP servers.
|
|
5
|
+
A Ruby implementation of the Model Context Protocol (MCP) for both connecting to MCP servers and creating MCP servers.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
9
|
+
- **Client Support**: Connect to SSE (Server-Sent Events) and Stdio-based MCP servers
|
|
10
|
+
- **Server Support**: Create MCP servers with tool registration
|
|
11
|
+
- Type-safe client interfaces
|
|
11
12
|
- Easy integration with Ruby applications
|
|
12
13
|
- Comprehensive error handling
|
|
14
|
+
- JSON-RPC 2.0 compliant
|
|
13
15
|
|
|
14
16
|
## Installation
|
|
15
17
|
|
|
@@ -33,7 +35,9 @@ $ gem install mcp-sdk.rb
|
|
|
33
35
|
|
|
34
36
|
## Usage
|
|
35
37
|
|
|
36
|
-
###
|
|
38
|
+
### MCP Client
|
|
39
|
+
|
|
40
|
+
#### Connecting to an SSE-based MCP server
|
|
37
41
|
|
|
38
42
|
```ruby
|
|
39
43
|
require 'mcp-sdk.rb'
|
|
@@ -43,7 +47,7 @@ mcp_server_json = client.list_tools
|
|
|
43
47
|
puts JSON.pretty_generate(convertFormat(mcp_server_json))
|
|
44
48
|
```
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
#### Connecting to a Stdio-based MCP server
|
|
47
51
|
|
|
48
52
|
```ruby
|
|
49
53
|
require 'mcp-sdk.rb'
|
|
@@ -54,6 +58,285 @@ mcp_server_json = client.list_tools
|
|
|
54
58
|
puts JSON.pretty_generate(convertFormat(mcp_server_json))
|
|
55
59
|
```
|
|
56
60
|
|
|
61
|
+
### MCP Server
|
|
62
|
+
|
|
63
|
+
#### Creating an MCP Server
|
|
64
|
+
|
|
65
|
+
**Stdio Server (Default)**
|
|
66
|
+
```ruby
|
|
67
|
+
require 'mcp-sdk.rb'
|
|
68
|
+
|
|
69
|
+
# Create stdio server (processes JSON-RPC over stdin/stdout)
|
|
70
|
+
server = MCP::Server.new(
|
|
71
|
+
name: "Demo",
|
|
72
|
+
version: "1.0.0",
|
|
73
|
+
type: "stdio" # optional, this is the default
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Add an addition tool
|
|
77
|
+
server.add_tool("add") do |params|
|
|
78
|
+
result = params["a"] + params["b"]
|
|
79
|
+
{
|
|
80
|
+
content: [{ type: "text", text: result.to_s }]
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Start the server (listens on stdin, responds on stdout)
|
|
85
|
+
server.start
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**SSE Server (HTTP with Server-Sent Events)**
|
|
89
|
+
```ruby
|
|
90
|
+
require 'mcp-sdk.rb'
|
|
91
|
+
|
|
92
|
+
# Create SSE server (HTTP server with SSE support)
|
|
93
|
+
server = MCP::Server.new(
|
|
94
|
+
name: "Demo",
|
|
95
|
+
version: "1.0.0",
|
|
96
|
+
type: "sse",
|
|
97
|
+
port: 8080
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Add tools as needed
|
|
101
|
+
server.add_tool("add") do |params|
|
|
102
|
+
result = params["a"] + params["b"]
|
|
103
|
+
{
|
|
104
|
+
content: [{ type: "text", text: result.to_s }]
|
|
105
|
+
}
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
server.add_tool("multiply") do |params|
|
|
109
|
+
result = params["x"] * params["y"]
|
|
110
|
+
{
|
|
111
|
+
content: [{ type: "text", text: result.to_s }]
|
|
112
|
+
}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
server.add_tool("greet") do |params|
|
|
116
|
+
name = params["name"] || "World"
|
|
117
|
+
{
|
|
118
|
+
content: [{ type: "text", text: "Hello, #{name}!" }]
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Start the HTTP server
|
|
123
|
+
server.start
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Enhanced SSE Server (Advanced Features)**
|
|
127
|
+
```ruby
|
|
128
|
+
require 'mcp-sdk.rb'
|
|
129
|
+
|
|
130
|
+
# Create Enhanced SSE server with advanced features
|
|
131
|
+
server = MCP::Server.new(
|
|
132
|
+
name: "Enhanced Demo",
|
|
133
|
+
version: "1.0.0",
|
|
134
|
+
type: "enhanced_sse",
|
|
135
|
+
port: 8080
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Add tools as needed
|
|
139
|
+
server.add_tool("calculate") do |params|
|
|
140
|
+
operation = params["operation"] || "add"
|
|
141
|
+
a = params["a"] || 0
|
|
142
|
+
b = params["b"] || 0
|
|
143
|
+
|
|
144
|
+
result = case operation
|
|
145
|
+
when "add" then a + b
|
|
146
|
+
when "multiply" then a * b
|
|
147
|
+
when "subtract" then a - b
|
|
148
|
+
when "divide" then b != 0 ? a / b : "Error: Division by zero"
|
|
149
|
+
else "Unknown operation"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
{
|
|
153
|
+
content: [{ type: "text", text: "#{a} #{operation} #{b} = #{result}" }]
|
|
154
|
+
}
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Start the Enhanced SSE server
|
|
158
|
+
server.start
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Server Types
|
|
162
|
+
|
|
163
|
+
**Stdio Server (`type: "stdio"`)**
|
|
164
|
+
- Default server type
|
|
165
|
+
- Communicates via stdin/stdout using JSON-RPC 2.0
|
|
166
|
+
- Perfect for command-line tools and process-based communication
|
|
167
|
+
- No additional configuration required
|
|
168
|
+
|
|
169
|
+
**SSE Server (`type: "sse"`)**
|
|
170
|
+
- HTTP server with Server-Sent Events support
|
|
171
|
+
- Requires `port` parameter
|
|
172
|
+
- Provides REST endpoints and real-time SSE communication
|
|
173
|
+
- Includes CORS support for web applications
|
|
174
|
+
|
|
175
|
+
**Enhanced SSE Server (`type: "enhanced_sse"`)**
|
|
176
|
+
- Advanced HTTP server with enhanced SSE capabilities
|
|
177
|
+
- Requires `port` parameter
|
|
178
|
+
- Provides all standard SSE features plus:
|
|
179
|
+
- Connection management and tracking
|
|
180
|
+
- Broadcasting to multiple clients
|
|
181
|
+
- WebSocket-like bidirectional communication simulation
|
|
182
|
+
- Enhanced health monitoring
|
|
183
|
+
- Connection status endpoints
|
|
184
|
+
- Includes CORS support for web applications
|
|
185
|
+
- Built with Sinatra for better performance and extensibility
|
|
186
|
+
|
|
187
|
+
#### SSE Server Protocol
|
|
188
|
+
|
|
189
|
+
The MCP SSE server follows a specific two-step protocol flow:
|
|
190
|
+
|
|
191
|
+
**Step 1: Get Message Endpoint**
|
|
192
|
+
```bash
|
|
193
|
+
curl http://localhost:8080/sse
|
|
194
|
+
```
|
|
195
|
+
This returns the endpoint information in SSE format:
|
|
196
|
+
```
|
|
197
|
+
event: endpoint
|
|
198
|
+
data: /mcp/message
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Step 2: Send JSON-RPC to Message Endpoint**
|
|
202
|
+
```bash
|
|
203
|
+
curl -X POST http://localhost:8080/mcp/message \
|
|
204
|
+
-H 'Content-Type: application/json' \
|
|
205
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
|
206
|
+
```
|
|
207
|
+
This returns the JSON-RPC response in SSE format:
|
|
208
|
+
```
|
|
209
|
+
data: {"jsonrpc":"2.0","id":1,"result":{"tools":[...]}}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Additional Endpoints:**
|
|
213
|
+
- `GET /health` - Server health check (convenience)
|
|
214
|
+
|
|
215
|
+
#### Enhanced SSE Server Protocol
|
|
216
|
+
|
|
217
|
+
The Enhanced SSE server provides all standard SSE endpoints plus advanced features:
|
|
218
|
+
|
|
219
|
+
**Standard Endpoints:**
|
|
220
|
+
- `GET /sse` - Get message endpoint (MCP protocol compliance)
|
|
221
|
+
- `POST /mcp/message` - Send JSON-RPC requests and receive SSE responses
|
|
222
|
+
- `GET /health` - Enhanced health check with detailed server information
|
|
223
|
+
|
|
224
|
+
**Advanced Endpoints:**
|
|
225
|
+
- `GET /sse/events` - Advanced SSE endpoint with connection management
|
|
226
|
+
- `POST /mcp/broadcast` - Broadcast messages to all connected SSE clients
|
|
227
|
+
- `GET /ws/connect` - WebSocket-like connection simulation (long polling)
|
|
228
|
+
- `POST /ws/send/:connection_id` - Send messages to specific connections
|
|
229
|
+
- `GET /connections` - View active connection status
|
|
230
|
+
|
|
231
|
+
**Enhanced SSE Events Example:**
|
|
232
|
+
```bash
|
|
233
|
+
# Connect to advanced SSE endpoint
|
|
234
|
+
curl -N http://localhost:8080/sse/events
|
|
235
|
+
# Returns connection ID and keeps connection alive with heartbeats
|
|
236
|
+
|
|
237
|
+
# Broadcast to all connected clients
|
|
238
|
+
curl -X POST http://localhost:8080/mcp/broadcast \
|
|
239
|
+
-H 'Content-Type: application/json' \
|
|
240
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
|
241
|
+
|
|
242
|
+
# Check connection status
|
|
243
|
+
curl http://localhost:8080/connections
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
#### Server API
|
|
247
|
+
|
|
248
|
+
- `MCP::Server.new(name:, version:, type:, port:)` - Create a new server instance
|
|
249
|
+
- `name`: Server name (required)
|
|
250
|
+
- `version`: Server version (required)
|
|
251
|
+
- `type`: Server type - `"stdio"` (default), `"sse"`, or `"enhanced_sse"` (optional)
|
|
252
|
+
- `port`: Port number (required for SSE servers, ignored for stdio)
|
|
253
|
+
- `server.add_tool(name, &block)` - Register a tool with a block that receives parameters
|
|
254
|
+
- `server.start` - Start the server and listen for requests
|
|
255
|
+
- `server.stop` - Stop the server
|
|
256
|
+
- `server.list_tools` - Get list of registered tools
|
|
257
|
+
- `server.call_tool(name, arguments)` - Call a tool directly
|
|
258
|
+
|
|
259
|
+
The server implements the MCP protocol over JSON-RPC 2.0, supporting:
|
|
260
|
+
- `tools/list` - List available tools
|
|
261
|
+
- `tools/call` - Execute a specific tool
|
|
262
|
+
|
|
263
|
+
#### Examples
|
|
264
|
+
|
|
265
|
+
**Test MCP SSE Protocol with curl:**
|
|
266
|
+
```bash
|
|
267
|
+
# Step 1: Get the message endpoint
|
|
268
|
+
curl http://localhost:8080/sse
|
|
269
|
+
# Returns: event: endpoint\ndata: /mcp/message
|
|
270
|
+
|
|
271
|
+
# Step 2: Send JSON-RPC requests to the message endpoint
|
|
272
|
+
curl -X POST http://localhost:8080/mcp/message \
|
|
273
|
+
-H 'Content-Type: application/json' \
|
|
274
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
|
|
275
|
+
|
|
276
|
+
curl -X POST http://localhost:8080/mcp/message \
|
|
277
|
+
-H 'Content-Type: application/json' \
|
|
278
|
+
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"add","arguments":{"a":5,"b":3}}}'
|
|
279
|
+
|
|
280
|
+
# Health check (convenience)
|
|
281
|
+
curl http://localhost:8080/health
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Test Stdio Server:**
|
|
285
|
+
```bash
|
|
286
|
+
# Send JSON-RPC to stdin
|
|
287
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | ruby your_server.rb
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### Tool Response Format
|
|
291
|
+
|
|
292
|
+
Tools should return responses in MCP format:
|
|
293
|
+
|
|
294
|
+
```ruby
|
|
295
|
+
{
|
|
296
|
+
content: [
|
|
297
|
+
{ type: "text", text: "your response text" }
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
For simple text responses, you can return any value and it will be automatically wrapped in the proper format.
|
|
303
|
+
|
|
304
|
+
## Example Files
|
|
305
|
+
|
|
306
|
+
This repository includes several example files to help you get started:
|
|
307
|
+
|
|
308
|
+
- `example_enhanced_sse.rb` - Complete Enhanced SSE server example with multiple tools
|
|
309
|
+
- `enhanced_sse_client.html` - HTML client demo for testing SSE connections
|
|
310
|
+
- `test_enhanced_sse.rb` - Integration test suite for Enhanced SSE functionality
|
|
311
|
+
- `demo_both_servers.rb` - Demonstration of both stdio and SSE servers
|
|
312
|
+
- `example_usage.rb` - Basic usage examples
|
|
313
|
+
|
|
314
|
+
### Running Examples
|
|
315
|
+
|
|
316
|
+
**Start Enhanced SSE Server:**
|
|
317
|
+
```bash
|
|
318
|
+
ruby example_enhanced_sse.rb
|
|
319
|
+
```
|
|
320
|
+
Then open `enhanced_sse_client.html` in your browser to test the connection.
|
|
321
|
+
|
|
322
|
+
**Run Integration Tests:**
|
|
323
|
+
```bash
|
|
324
|
+
ruby test_enhanced_sse.rb
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Test Basic SSE Protocol:**
|
|
328
|
+
```bash
|
|
329
|
+
# Terminal 1: Start server
|
|
330
|
+
ruby example_enhanced_sse.rb
|
|
331
|
+
|
|
332
|
+
# Terminal 2: Test endpoints
|
|
333
|
+
curl http://localhost:8081/health
|
|
334
|
+
curl http://localhost:8081/sse
|
|
335
|
+
curl -X POST http://localhost:8081/mcp/message \
|
|
336
|
+
-H 'Content-Type: application/json' \
|
|
337
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
|
|
338
|
+
```
|
|
339
|
+
|
|
57
340
|
## Contributing
|
|
58
341
|
|
|
59
342
|
Bug reports and pull requests are welcome on GitHub at https://github.com/zhuangbiaowei/mcp-sdk.rb.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
require "angelo"
|
|
3
|
+
|
|
4
|
+
module MCP
|
|
5
|
+
# Angelo-based SSE server implementation for MCP
|
|
6
|
+
class AngeloSSEServer < Angelo::Base
|
|
7
|
+
attr_reader :mcp_server_instance
|
|
8
|
+
|
|
9
|
+
def initialize(mcp_server_instance)
|
|
10
|
+
@mcp_server_instance = mcp_server_instance
|
|
11
|
+
super()
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Configure server settings
|
|
15
|
+
def self.configure_for_mcp(port)
|
|
16
|
+
port port
|
|
17
|
+
addr "0.0.0.0"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Enable CORS for all routes
|
|
21
|
+
before do
|
|
22
|
+
headers 'Access-Control-Allow-Origin' => '*',
|
|
23
|
+
'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',
|
|
24
|
+
'Access-Control-Allow-Headers' => 'Content-Type'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Handle OPTIONS requests for CORS
|
|
28
|
+
options '*' do
|
|
29
|
+
halt 200
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# SSE endpoint - returns the message endpoint for subsequent requests
|
|
33
|
+
# This follows the MCP SSE protocol specification
|
|
34
|
+
get '/sse' do
|
|
35
|
+
content_type 'text/event-stream'
|
|
36
|
+
headers 'Cache-Control' => 'no-cache',
|
|
37
|
+
'Connection' => 'keep-alive'
|
|
38
|
+
|
|
39
|
+
# Send endpoint event as per MCP SSE protocol
|
|
40
|
+
response = "event: endpoint\n"
|
|
41
|
+
response += "data: /mcp/message\n\n"
|
|
42
|
+
response
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# MCP message endpoint - handles POST requests and returns SSE responses
|
|
46
|
+
post '/mcp/message' do
|
|
47
|
+
content_type 'text/event-stream'
|
|
48
|
+
headers 'Cache-Control' => 'no-cache',
|
|
49
|
+
'Connection' => 'keep-alive'
|
|
50
|
+
|
|
51
|
+
begin
|
|
52
|
+
request_data = JSON.parse(request.body.read)
|
|
53
|
+
response = @mcp_server_instance.send(:handle_request, request_data)
|
|
54
|
+
|
|
55
|
+
# Return JSON-RPC response in SSE format
|
|
56
|
+
sse_response = "data: #{response.to_json}\n\n"
|
|
57
|
+
sse_response
|
|
58
|
+
rescue JSON::ParserError => e
|
|
59
|
+
error_response = {
|
|
60
|
+
jsonrpc: "2.0",
|
|
61
|
+
id: nil,
|
|
62
|
+
error: {
|
|
63
|
+
code: -32700,
|
|
64
|
+
message: "Parse error: #{e.message}"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
"data: #{error_response.to_json}\n\n"
|
|
68
|
+
rescue => e
|
|
69
|
+
error_response = {
|
|
70
|
+
jsonrpc: "2.0",
|
|
71
|
+
id: nil,
|
|
72
|
+
error: {
|
|
73
|
+
code: -32603,
|
|
74
|
+
message: "Internal error: #{e.message}"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
"data: #{error_response.to_json}\n\n"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Alternative SSE endpoint using Angelo's eventsource functionality
|
|
82
|
+
# This provides more advanced SSE features
|
|
83
|
+
eventsource '/sse/events' do |sse|
|
|
84
|
+
# Add the connection to the SSE stash for broadcasting
|
|
85
|
+
sses << sse
|
|
86
|
+
|
|
87
|
+
# Send initial endpoint event
|
|
88
|
+
sse.event :endpoint, '/mcp/message'
|
|
89
|
+
|
|
90
|
+
# Keep connection alive
|
|
91
|
+
sse.on_close do
|
|
92
|
+
puts "SSE client disconnected"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# POST endpoint for broadcasting events to all SSE connections
|
|
97
|
+
post '/mcp/broadcast' do
|
|
98
|
+
content_type 'application/json'
|
|
99
|
+
|
|
100
|
+
begin
|
|
101
|
+
request_data = JSON.parse(request.body.read)
|
|
102
|
+
response = @mcp_server_instance.send(:handle_request, request_data)
|
|
103
|
+
|
|
104
|
+
# Broadcast to all connected SSE clients
|
|
105
|
+
sses.each do |sse|
|
|
106
|
+
sse.message response.to_json
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
{ status: 'broadcasted', clients: sses.count }.to_json
|
|
110
|
+
rescue JSON::ParserError => e
|
|
111
|
+
error_response = {
|
|
112
|
+
jsonrpc: "2.0",
|
|
113
|
+
id: nil,
|
|
114
|
+
error: {
|
|
115
|
+
code: -32700,
|
|
116
|
+
message: "Parse error: #{e.message}"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
sses.each do |sse|
|
|
121
|
+
sse.message error_response.to_json
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
{ status: 'error', message: e.message }.to_json
|
|
125
|
+
rescue => e
|
|
126
|
+
error_response = {
|
|
127
|
+
jsonrpc: "2.0",
|
|
128
|
+
id: nil,
|
|
129
|
+
error: {
|
|
130
|
+
code: -32603,
|
|
131
|
+
message: "Internal error: #{e.message}"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
sses.each do |sse|
|
|
136
|
+
sse.message error_response.to_json
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
{ status: 'error', message: e.message }.to_json
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Health check endpoint
|
|
144
|
+
get '/health' do
|
|
145
|
+
content_type 'application/json'
|
|
146
|
+
{
|
|
147
|
+
status: 'ok',
|
|
148
|
+
server: @mcp_server_instance.name,
|
|
149
|
+
version: @mcp_server_instance.version,
|
|
150
|
+
type: 'angelo_sse',
|
|
151
|
+
tools_count: @mcp_server_instance.tools.size,
|
|
152
|
+
protocol: 'MCP SSE (Angelo)',
|
|
153
|
+
endpoints: {
|
|
154
|
+
sse: '/sse',
|
|
155
|
+
sse_events: '/sse/events',
|
|
156
|
+
message: '/mcp/message',
|
|
157
|
+
broadcast: '/mcp/broadcast'
|
|
158
|
+
},
|
|
159
|
+
connected_clients: sses.count
|
|
160
|
+
}.to_json
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# WebSocket endpoint for real-time bidirectional communication
|
|
164
|
+
websocket '/ws' do |ws|
|
|
165
|
+
websockets << ws
|
|
166
|
+
|
|
167
|
+
ws.on_message do |msg|
|
|
168
|
+
begin
|
|
169
|
+
request_data = JSON.parse(msg)
|
|
170
|
+
response = @mcp_server_instance.send(:handle_request, request_data)
|
|
171
|
+
ws.write response.to_json
|
|
172
|
+
rescue JSON::ParserError => e
|
|
173
|
+
error_response = {
|
|
174
|
+
jsonrpc: "2.0",
|
|
175
|
+
id: nil,
|
|
176
|
+
error: {
|
|
177
|
+
code: -32700,
|
|
178
|
+
message: "Parse error: #{e.message}"
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
ws.write error_response.to_json
|
|
182
|
+
rescue => e
|
|
183
|
+
error_response = {
|
|
184
|
+
jsonrpc: "2.0",
|
|
185
|
+
id: nil,
|
|
186
|
+
error: {
|
|
187
|
+
code: -32603,
|
|
188
|
+
message: "Internal error: #{e.message}"
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
ws.write error_response.to_json
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
ws.on_close do
|
|
196
|
+
puts "WebSocket client disconnected"
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|