mcp 0.1.0 → 0.3.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/.cursor/rules/release-changelogs.mdc +11 -24
- data/.github/workflows/release.yml +25 -0
- data/.rubocop.yml +5 -3
- data/CHANGELOG.md +57 -0
- data/Gemfile +16 -6
- data/README.md +439 -61
- data/examples/README.md +197 -0
- data/examples/http_client.rb +184 -0
- data/examples/http_server.rb +171 -0
- data/examples/stdio_server.rb +6 -6
- data/examples/streamable_http_client.rb +203 -0
- data/examples/streamable_http_server.rb +173 -0
- data/lib/mcp/client/http.rb +88 -0
- data/lib/mcp/client/tool.rb +16 -0
- data/lib/mcp/client.rb +88 -0
- data/lib/mcp/configuration.rb +22 -3
- data/lib/mcp/methods.rb +55 -33
- data/lib/mcp/prompt.rb +15 -4
- data/lib/mcp/resource.rb +8 -6
- data/lib/mcp/resource_template.rb +8 -6
- data/lib/mcp/server/capabilities.rb +96 -0
- data/lib/mcp/server/transports/stdio_transport.rb +57 -0
- data/lib/mcp/server/transports/streamable_http_transport.rb +301 -0
- data/lib/mcp/server.rb +116 -52
- data/lib/mcp/tool/annotations.rb +4 -4
- data/lib/mcp/tool/input_schema.rb +49 -1
- data/lib/mcp/tool/output_schema.rb +66 -0
- data/lib/mcp/tool/response.rb +15 -4
- data/lib/mcp/tool.rb +38 -7
- data/lib/mcp/transport.rb +16 -4
- data/lib/mcp/transports/stdio.rb +8 -28
- data/lib/mcp/version.rb +1 -1
- data/lib/mcp.rb +20 -12
- data/mcp.gemspec +1 -2
- metadata +21 -24
data/examples/README.md
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
# MCP Ruby Examples
|
2
|
+
|
3
|
+
This directory contains examples of how to use the Model Context Protocol (MCP) Ruby library.
|
4
|
+
|
5
|
+
## Available Examples
|
6
|
+
|
7
|
+
### 1. STDIO Server (`stdio_server.rb`)
|
8
|
+
|
9
|
+
A simple server that communicates over standard input/output. This is useful for desktop applications and command-line tools.
|
10
|
+
|
11
|
+
**Usage:**
|
12
|
+
|
13
|
+
```console
|
14
|
+
$ ruby examples/stdio_server.rb
|
15
|
+
{"jsonrpc":"2.0","id":0,"method":"tools/list"}
|
16
|
+
```
|
17
|
+
|
18
|
+
### 2. HTTP Server (`http_server.rb`)
|
19
|
+
|
20
|
+
A standalone HTTP server built with Rack that implements the MCP Streamable HTTP transport protocol. This demonstrates how to create a web-based MCP server with session management and Server-Sent Events (SSE) support.
|
21
|
+
|
22
|
+
**Features:**
|
23
|
+
|
24
|
+
- HTTP transport with Server-Sent Events (SSE) for streaming
|
25
|
+
- Session management with unique session IDs
|
26
|
+
- Example tools, prompts, and resources
|
27
|
+
- JSON-RPC 2.0 protocol implementation
|
28
|
+
- Full MCP protocol compliance
|
29
|
+
|
30
|
+
**Usage:**
|
31
|
+
|
32
|
+
```console
|
33
|
+
$ ruby examples/http_server.rb
|
34
|
+
```
|
35
|
+
|
36
|
+
The server will start on `http://localhost:9292` and provide:
|
37
|
+
|
38
|
+
- **Tools**:
|
39
|
+
- `ExampleTool` - adds two numbers
|
40
|
+
- `echo` - echoes back messages
|
41
|
+
- **Prompts**: `ExamplePrompt` - echoes back arguments as a prompt
|
42
|
+
- **Resources**: `test_resource` - returns example content
|
43
|
+
|
44
|
+
### 3. HTTP Client Example (`http_client.rb`)
|
45
|
+
|
46
|
+
A client that demonstrates how to interact with the HTTP server using all MCP protocol methods.
|
47
|
+
|
48
|
+
**Usage:**
|
49
|
+
|
50
|
+
1. Start the HTTP server in one terminal:
|
51
|
+
|
52
|
+
```console
|
53
|
+
$ ruby examples/http_server.rb
|
54
|
+
```
|
55
|
+
|
56
|
+
2. Run the client example in another terminal:
|
57
|
+
```console
|
58
|
+
$ ruby examples/http_client.rb
|
59
|
+
```
|
60
|
+
|
61
|
+
The client will demonstrate:
|
62
|
+
|
63
|
+
- Session initialization
|
64
|
+
- Ping requests
|
65
|
+
- Listing and calling tools
|
66
|
+
- Listing and getting prompts
|
67
|
+
- Listing and reading resources
|
68
|
+
- Session cleanup
|
69
|
+
|
70
|
+
### 4. Streamable HTTP Server (`streamable_http_server.rb`)
|
71
|
+
|
72
|
+
A specialized HTTP server designed to test and demonstrate Server-Sent Events (SSE) functionality in the MCP protocol.
|
73
|
+
|
74
|
+
**Features:**
|
75
|
+
|
76
|
+
- Tools specifically designed to trigger SSE notifications
|
77
|
+
- Real-time progress updates and notifications
|
78
|
+
- Detailed SSE-specific logging
|
79
|
+
|
80
|
+
**Available Tools:**
|
81
|
+
|
82
|
+
- `NotificationTool` - Send custom SSE notifications with optional delays
|
83
|
+
- `echo` - Simple echo tool for basic testing
|
84
|
+
|
85
|
+
**Usage:**
|
86
|
+
|
87
|
+
```console
|
88
|
+
$ ruby examples/streamable_http_server.rb
|
89
|
+
```
|
90
|
+
|
91
|
+
The server will start on `http://localhost:9393` and provide detailed instructions for testing SSE functionality.
|
92
|
+
|
93
|
+
### 5. Streamable HTTP Client (`streamable_http_client.rb`)
|
94
|
+
|
95
|
+
An interactive client that connects to the SSE stream and provides a menu-driven interface for testing SSE functionality.
|
96
|
+
|
97
|
+
**Features:**
|
98
|
+
|
99
|
+
- Automatic SSE stream connection
|
100
|
+
- Interactive menu for triggering various SSE events
|
101
|
+
- Real-time display of received SSE notifications
|
102
|
+
- Session management
|
103
|
+
|
104
|
+
**Usage:**
|
105
|
+
|
106
|
+
1. Start the SSE test server in one terminal:
|
107
|
+
|
108
|
+
```console
|
109
|
+
$ ruby examples/streamable_http_server.rb
|
110
|
+
```
|
111
|
+
|
112
|
+
2. Run the SSE test client in another terminal:
|
113
|
+
```console
|
114
|
+
$ ruby examples/streamable_http_client.rb
|
115
|
+
```
|
116
|
+
|
117
|
+
The client will:
|
118
|
+
|
119
|
+
- Initialize a session automatically
|
120
|
+
- Connect to the SSE stream
|
121
|
+
- Provide an interactive menu to trigger notifications
|
122
|
+
- Display all received SSE events in real-time
|
123
|
+
|
124
|
+
### Testing SSE with cURL
|
125
|
+
|
126
|
+
You can also test SSE functionality manually using cURL:
|
127
|
+
|
128
|
+
1. Initialize a session:
|
129
|
+
|
130
|
+
```console
|
131
|
+
SESSION_ID=$(curl -D - -s -o /dev/null http://localhost:9393 \
|
132
|
+
--json '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-test","version":"1.0"}}}' | grep -i "Mcp-Session-Id:" | cut -d' ' -f2- | tr -d '\r')
|
133
|
+
```
|
134
|
+
|
135
|
+
2. Connect to SSE stream (in one terminal):
|
136
|
+
|
137
|
+
```console
|
138
|
+
curl -i -N -H "Mcp-Session-Id: $SESSION_ID" http://localhost:9393
|
139
|
+
```
|
140
|
+
|
141
|
+
3. Trigger notifications (in another terminal):
|
142
|
+
|
143
|
+
```console
|
144
|
+
# Send immediate notification
|
145
|
+
curl -i http://localhost:9393 \
|
146
|
+
-H "Mcp-Session-Id: $SESSION_ID" \
|
147
|
+
--json '{"jsonrpc":"2.0","method":"tools/call","id":2,"params":{"name":"notification_tool","arguments":{"message":"Hello from cURL!"}}}'
|
148
|
+
```
|
149
|
+
|
150
|
+
## Streamable HTTP Transport Details
|
151
|
+
|
152
|
+
### Protocol Flow
|
153
|
+
|
154
|
+
The HTTP server implements the MCP Streamable HTTP transport protocol:
|
155
|
+
|
156
|
+
1. **Initialize Session**:
|
157
|
+
|
158
|
+
- Client sends POST request with `initialize` method
|
159
|
+
- Server responds with session ID in `Mcp-Session-Id` header
|
160
|
+
|
161
|
+
2. **Establish SSE Connection** (optional):
|
162
|
+
|
163
|
+
- Client sends GET request with `Mcp-Session-Id` header
|
164
|
+
- Server establishes Server-Sent Events stream for notifications
|
165
|
+
|
166
|
+
3. **Send Requests**:
|
167
|
+
|
168
|
+
- Client sends POST requests with JSON-RPC 2.0 format
|
169
|
+
- Server processes and responds with results
|
170
|
+
|
171
|
+
4. **Close Session**:
|
172
|
+
- Client sends DELETE request with `Mcp-Session-Id` header
|
173
|
+
|
174
|
+
### Example cURL Commands
|
175
|
+
|
176
|
+
Initialize a session:
|
177
|
+
|
178
|
+
```console
|
179
|
+
curl -i http://localhost:9292 \
|
180
|
+
--json '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
|
181
|
+
```
|
182
|
+
|
183
|
+
List tools (using the session ID from initialization):
|
184
|
+
|
185
|
+
```console
|
186
|
+
curl -i http://localhost:9292 \
|
187
|
+
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
|
188
|
+
--json '{"jsonrpc":"2.0","method":"tools/list","id":2}'
|
189
|
+
```
|
190
|
+
|
191
|
+
Call a tool:
|
192
|
+
|
193
|
+
```console
|
194
|
+
curl -i http://localhost:9292 \
|
195
|
+
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
|
196
|
+
--json '{"jsonrpc":"2.0","method":"tools/call","id":3,"params":{"name":"ExampleTool","arguments":{"a":5,"b":3}}}'
|
197
|
+
```
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/http"
|
4
|
+
require "json"
|
5
|
+
require "uri"
|
6
|
+
|
7
|
+
# Simple HTTP client example for interacting with the MCP HTTP server
|
8
|
+
class MCPHTTPClient
|
9
|
+
def initialize(base_url = "http://localhost:9292")
|
10
|
+
@base_url = base_url
|
11
|
+
@session_id = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_request(method, params = nil, id = nil)
|
15
|
+
uri = URI(@base_url)
|
16
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
17
|
+
|
18
|
+
request = Net::HTTP::Post.new(uri.path.empty? ? "/" : uri.path)
|
19
|
+
request["Content-Type"] = "application/json"
|
20
|
+
request["Mcp-Session-Id"] = @session_id if @session_id
|
21
|
+
|
22
|
+
body = {
|
23
|
+
jsonrpc: "2.0",
|
24
|
+
method: method,
|
25
|
+
params: params,
|
26
|
+
id: id || rand(10000),
|
27
|
+
}.compact
|
28
|
+
|
29
|
+
request.body = body.to_json
|
30
|
+
|
31
|
+
response = http.request(request)
|
32
|
+
|
33
|
+
# Store session ID if provided
|
34
|
+
if response["Mcp-Session-Id"]
|
35
|
+
@session_id = response["Mcp-Session-Id"]
|
36
|
+
puts "Session ID: #{@session_id}"
|
37
|
+
end
|
38
|
+
|
39
|
+
JSON.parse(response.body)
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize_session
|
43
|
+
puts "=== Initializing session ==="
|
44
|
+
result = send_request("initialize", {
|
45
|
+
protocolVersion: "2024-11-05",
|
46
|
+
capabilities: {},
|
47
|
+
clientInfo: {
|
48
|
+
name: "example_client",
|
49
|
+
version: "1.0",
|
50
|
+
},
|
51
|
+
})
|
52
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
53
|
+
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
def ping
|
58
|
+
puts "=== Sending ping ==="
|
59
|
+
result = send_request("ping")
|
60
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
61
|
+
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
def list_tools
|
66
|
+
puts "=== Listing tools ==="
|
67
|
+
result = send_request("tools/list")
|
68
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
69
|
+
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
def call_tool(name, arguments)
|
74
|
+
puts "=== Calling tool: #{name} ==="
|
75
|
+
result = send_request("tools/call", {
|
76
|
+
name: name,
|
77
|
+
arguments: arguments,
|
78
|
+
})
|
79
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
80
|
+
|
81
|
+
result
|
82
|
+
end
|
83
|
+
|
84
|
+
def list_prompts
|
85
|
+
puts "=== Listing prompts ==="
|
86
|
+
result = send_request("prompts/list")
|
87
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
88
|
+
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_prompt(name, arguments)
|
93
|
+
puts "=== Getting prompt: #{name} ==="
|
94
|
+
result = send_request("prompts/get", {
|
95
|
+
name: name,
|
96
|
+
arguments: arguments,
|
97
|
+
})
|
98
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
99
|
+
|
100
|
+
result
|
101
|
+
end
|
102
|
+
|
103
|
+
def list_resources
|
104
|
+
puts "=== Listing resources ==="
|
105
|
+
result = send_request("resources/list")
|
106
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
107
|
+
|
108
|
+
result
|
109
|
+
end
|
110
|
+
|
111
|
+
def read_resource(uri)
|
112
|
+
puts "=== Reading resource: #{uri} ==="
|
113
|
+
result = send_request("resources/read", {
|
114
|
+
uri: uri,
|
115
|
+
})
|
116
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
117
|
+
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
def close_session
|
122
|
+
return unless @session_id
|
123
|
+
|
124
|
+
puts "=== Closing session ==="
|
125
|
+
uri = URI(@base_url)
|
126
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
127
|
+
|
128
|
+
request = Net::HTTP::Delete.new(uri.path.empty? ? "/" : uri.path)
|
129
|
+
request["Mcp-Session-Id"] = @session_id
|
130
|
+
|
131
|
+
response = http.request(request)
|
132
|
+
result = JSON.parse(response.body)
|
133
|
+
puts "Response: #{JSON.pretty_generate(result)}"
|
134
|
+
|
135
|
+
@session_id = nil
|
136
|
+
result
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Main script
|
141
|
+
if __FILE__ == $PROGRAM_NAME
|
142
|
+
puts <<~MESSAGE
|
143
|
+
MCP HTTP Client Example
|
144
|
+
Make sure the HTTP server is running (ruby examples/http_server.rb)
|
145
|
+
#{"=" * 50}
|
146
|
+
MESSAGE
|
147
|
+
|
148
|
+
client = MCPHTTPClient.new
|
149
|
+
|
150
|
+
begin
|
151
|
+
# Initialize session
|
152
|
+
client.initialize_session
|
153
|
+
|
154
|
+
# Test ping
|
155
|
+
client.ping
|
156
|
+
|
157
|
+
# List available tools
|
158
|
+
client.list_tools
|
159
|
+
|
160
|
+
# Call the example_tool (note: snake_case name)
|
161
|
+
client.call_tool("example_tool", { a: 5, b: 3 })
|
162
|
+
|
163
|
+
# Call the echo tool
|
164
|
+
client.call_tool("echo", { message: "Hello from client!" })
|
165
|
+
|
166
|
+
# List prompts
|
167
|
+
client.list_prompts
|
168
|
+
|
169
|
+
# Get a prompt (note: snake_case name)
|
170
|
+
client.get_prompt("example_prompt", { message: "This is a test message" })
|
171
|
+
|
172
|
+
# List resources
|
173
|
+
client.list_resources
|
174
|
+
|
175
|
+
# Read a resource
|
176
|
+
client.read_resource("test_resource")
|
177
|
+
rescue => e
|
178
|
+
puts "Error: #{e.message}"
|
179
|
+
puts e.backtrace
|
180
|
+
ensure
|
181
|
+
# Clean up session
|
182
|
+
client.close_session
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
4
|
+
require "mcp"
|
5
|
+
require "mcp/server/transports/streamable_http_transport"
|
6
|
+
require "rack"
|
7
|
+
require "rackup"
|
8
|
+
require "json"
|
9
|
+
require "logger"
|
10
|
+
|
11
|
+
# Create a simple tool
|
12
|
+
class ExampleTool < MCP::Tool
|
13
|
+
description "A simple example tool that adds two numbers"
|
14
|
+
input_schema(
|
15
|
+
properties: {
|
16
|
+
a: { type: "number" },
|
17
|
+
b: { type: "number" },
|
18
|
+
},
|
19
|
+
required: ["a", "b"],
|
20
|
+
)
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def call(a:, b:)
|
24
|
+
MCP::Tool::Response.new([{
|
25
|
+
type: "text",
|
26
|
+
text: "The sum of #{a} and #{b} is #{a + b}",
|
27
|
+
}])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Create a simple prompt
|
33
|
+
class ExamplePrompt < MCP::Prompt
|
34
|
+
description "A simple example prompt that echoes back its arguments"
|
35
|
+
arguments [
|
36
|
+
MCP::Prompt::Argument.new(
|
37
|
+
name: "message",
|
38
|
+
description: "The message to echo back",
|
39
|
+
required: true,
|
40
|
+
),
|
41
|
+
]
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def template(args, server_context:)
|
45
|
+
MCP::Prompt::Result.new(
|
46
|
+
messages: [
|
47
|
+
MCP::Prompt::Message.new(
|
48
|
+
role: "user",
|
49
|
+
content: MCP::Content::Text.new(args[:message]),
|
50
|
+
),
|
51
|
+
],
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set up the server
|
58
|
+
server = MCP::Server.new(
|
59
|
+
name: "example_http_server",
|
60
|
+
tools: [ExampleTool],
|
61
|
+
prompts: [ExamplePrompt],
|
62
|
+
resources: [
|
63
|
+
MCP::Resource.new(
|
64
|
+
uri: "https://test_resource.invalid",
|
65
|
+
name: "test-resource",
|
66
|
+
title: "Test Resource",
|
67
|
+
description: "Test resource that echoes back the uri as its content",
|
68
|
+
mime_type: "text/plain",
|
69
|
+
),
|
70
|
+
],
|
71
|
+
)
|
72
|
+
|
73
|
+
server.define_tool(
|
74
|
+
name: "echo",
|
75
|
+
description: "A simple example tool that echoes back its arguments",
|
76
|
+
input_schema: { properties: { message: { type: "string" } }, required: ["message"] },
|
77
|
+
) do |message:|
|
78
|
+
MCP::Tool::Response.new(
|
79
|
+
[
|
80
|
+
{
|
81
|
+
type: "text",
|
82
|
+
text: "Hello from echo tool! Message: #{message}",
|
83
|
+
},
|
84
|
+
],
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
server.resources_read_handler do |params|
|
89
|
+
[{
|
90
|
+
uri: params[:uri],
|
91
|
+
mimeType: "text/plain",
|
92
|
+
text: "Hello from HTTP server resource!",
|
93
|
+
}]
|
94
|
+
end
|
95
|
+
|
96
|
+
# Create the Streamable HTTP transport
|
97
|
+
transport = MCP::Server::Transports::StreamableHTTPTransport.new(server)
|
98
|
+
server.transport = transport
|
99
|
+
|
100
|
+
# Create a logger for MCP-specific logging
|
101
|
+
mcp_logger = Logger.new($stdout)
|
102
|
+
mcp_logger.formatter = proc do |_severity, _datetime, _progname, msg|
|
103
|
+
"[MCP] #{msg}\n"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Create a Rack application with logging
|
107
|
+
app = proc do |env|
|
108
|
+
request = Rack::Request.new(env)
|
109
|
+
|
110
|
+
# Log MCP-specific details for POST requests
|
111
|
+
if request.post?
|
112
|
+
body = request.body.read
|
113
|
+
request.body.rewind
|
114
|
+
begin
|
115
|
+
parsed_body = JSON.parse(body)
|
116
|
+
mcp_logger.info("Request: #{parsed_body["method"]} (id: #{parsed_body["id"]})")
|
117
|
+
mcp_logger.debug("Request body: #{JSON.pretty_generate(parsed_body)}")
|
118
|
+
rescue JSON::ParserError
|
119
|
+
mcp_logger.warn("Request body (raw): #{body}")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Handle the request
|
124
|
+
response = transport.handle_request(request)
|
125
|
+
|
126
|
+
# Log the MCP response details
|
127
|
+
_, _, body = response
|
128
|
+
if body.is_a?(Array) && !body.empty? && body.first
|
129
|
+
begin
|
130
|
+
parsed_response = JSON.parse(body.first)
|
131
|
+
if parsed_response["error"]
|
132
|
+
mcp_logger.error("Response error: #{parsed_response["error"]["message"]}")
|
133
|
+
else
|
134
|
+
mcp_logger.info("Response: #{parsed_response["result"] ? "success" : "empty"} (id: #{parsed_response["id"]})")
|
135
|
+
end
|
136
|
+
mcp_logger.debug("Response body: #{JSON.pretty_generate(parsed_response)}")
|
137
|
+
rescue JSON::ParserError
|
138
|
+
mcp_logger.warn("Response body (raw): #{body}")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
response
|
143
|
+
end
|
144
|
+
|
145
|
+
# Wrap the app with Rack middleware
|
146
|
+
rack_app = Rack::Builder.new do
|
147
|
+
# Use CommonLogger for standard HTTP request logging
|
148
|
+
use(Rack::CommonLogger, Logger.new($stdout))
|
149
|
+
|
150
|
+
# Add other useful middleware
|
151
|
+
use(Rack::ShowExceptions)
|
152
|
+
|
153
|
+
run(app)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Start the server
|
157
|
+
puts <<~MESSAGE
|
158
|
+
Starting MCP HTTP server on http://localhost:9292
|
159
|
+
Use POST requests to initialize and send JSON-RPC commands
|
160
|
+
Example initialization:
|
161
|
+
curl -i http://localhost:9292 --json '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
|
162
|
+
|
163
|
+
The server will return a session ID in the Mcp-Session-Id header.
|
164
|
+
Use this session ID for subsequent requests.
|
165
|
+
|
166
|
+
Press Ctrl+C to stop the server
|
167
|
+
MESSAGE
|
168
|
+
|
169
|
+
# Run the server
|
170
|
+
# Use Rackup to run the server
|
171
|
+
Rackup::Handler.get("puma").run(rack_app, Port: 9292, Host: "localhost")
|
data/examples/stdio_server.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
5
4
|
require "mcp"
|
6
|
-
require "mcp/transports/
|
5
|
+
require "mcp/server/transports/stdio_transport"
|
7
6
|
|
8
7
|
# Create a simple tool
|
9
8
|
class ExampleTool < MCP::Tool
|
@@ -59,8 +58,9 @@ server = MCP::Server.new(
|
|
59
58
|
prompts: [ExamplePrompt],
|
60
59
|
resources: [
|
61
60
|
MCP::Resource.new(
|
62
|
-
uri: "test_resource",
|
63
|
-
name: "
|
61
|
+
uri: "https://test_resource.invalid",
|
62
|
+
name: "test-resource",
|
63
|
+
title: "Test Resource",
|
64
64
|
description: "Test resource that echoes back the uri as its content",
|
65
65
|
mime_type: "text/plain",
|
66
66
|
),
|
@@ -86,10 +86,10 @@ server.resources_read_handler do |params|
|
|
86
86
|
[{
|
87
87
|
uri: params[:uri],
|
88
88
|
mimeType: "text/plain",
|
89
|
-
text: "Hello, world!",
|
89
|
+
text: "Hello, world! URI: #{params[:uri]}",
|
90
90
|
}]
|
91
91
|
end
|
92
92
|
|
93
93
|
# Create and start the transport
|
94
|
-
transport = MCP::Transports::StdioTransport.new(server)
|
94
|
+
transport = MCP::Server::Transports::StdioTransport.new(server)
|
95
95
|
transport.open
|