cf-mcp 0.19.0 → 0.20.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 +28 -0
- data/README.md +6 -0
- data/lib/cf/mcp/server.rb +25 -11
- data/lib/cf/mcp/templates/index.erb +1 -1
- data/lib/cf/mcp/templates/script.js +15 -2
- data/lib/cf/mcp/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa1835b909429755f2b06a50b6db8d973c68445f879413974b7b28863b6bce06
|
|
4
|
+
data.tar.gz: 6a110d101e27e125763506715bed2a92b973e9cecd709bd17a69c7088fb5e55f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e450154e426288754d99ee28a63e4b3fa99d2394600ab8519df3f0d584844b2428f64a1c62d106053f3f3826ace1d4e4beeadd6d9f45e0100b2d7bcc3717db69
|
|
7
|
+
data.tar.gz: 7fd889d1f4ae36abed48cb84048efa8debf22a4c97d198c2d12745ad095589a3ab02feeb5c2c1d4d3221f33a38069c363214f3142b7c56bcbf0c30e04d790f54
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.20.0] - 2026-09-19
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `CF_MCP_ALLOWED_HOSTS` environment variable (comma-separated) to allow extra `Host` header values on the HTTP endpoint; set to `cf-mcp.fly.dev` in `fly.toml`
|
|
15
|
+
- Support MCP protocol version 2026-07-28: stateless requests carrying their version in `_meta`, and the `server/discover` method
|
|
16
|
+
- Allow the `MCP-Protocol-Version`, `Mcp-Method` and `Mcp-Name` headers in CORS preflight responses
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **BREAKING:** Raised the minimum supported Ruby from 3.2 to 3.3 (`required_ruby_version` and the Standard Ruby target); 3.2 reached end of life on 2026-03-31; CI now also runs against Ruby 3.3
|
|
21
|
+
- Updated `mcp` from 0.25.0 to 1.5.1
|
|
22
|
+
- Updated `puma` from 7.2.1 to 8.0.2 (the gemspec constraint is now `~> 8.0`) and `rubyzip` from 3.6.0 to 3.7.0
|
|
23
|
+
- Removed the `2025-03-26` protocol pin; clients using the `initialize` handshake now negotiate up to 2025-11-25
|
|
24
|
+
- The web UI now calls tools through the stateless 2026-07-28 protocol
|
|
25
|
+
- The web UI shows both the modern and the legacy handshake protocol versions
|
|
26
|
+
- Bump Ruby to 4.0.7 in `.ruby-version`, the Dockerfile, and the CI matrix
|
|
27
|
+
- Bumped GitHub Actions: `actions/checkout` to v7 and `actions/cache` to v6
|
|
28
|
+
- Added least-privilege permissions, PR concurrency cancellation and a job timeout to the CI workflow, and Dependabot for GitHub Actions and Bundler
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- HTTP endpoint rejected all non-loopback requests with `403 Invalid Host header` since `mcp` 0.25 enabled DNS-rebinding protection, breaking the hosted server
|
|
33
|
+
|
|
8
34
|
## [0.19.0] - 2026-09-15
|
|
9
35
|
|
|
10
36
|
### Added
|
|
@@ -306,6 +332,8 @@ This version was prepared but never released. Changes rolled into 0.17.2.
|
|
|
306
332
|
- `cf_list_category` - List items by category
|
|
307
333
|
- `cf_get_details` - Get full documentation by name
|
|
308
334
|
|
|
335
|
+
[Unreleased]: https://github.com/pusewicz/cf-mcp/compare/v0.20.0...HEAD
|
|
336
|
+
[0.20.0]: https://github.com/pusewicz/cf-mcp/compare/v0.19.0...v0.20.0
|
|
309
337
|
[0.19.0]: https://github.com/pusewicz/cf-mcp/compare/v0.18.0...v0.19.0
|
|
310
338
|
[0.17.2]: https://github.com/pusewicz/cf-mcp/compare/v0.17.0...v0.17.2
|
|
311
339
|
[0.17.1]: https://github.com/pusewicz/cf-mcp/compare/v0.17.0...v0.17.1
|
data/README.md
CHANGED
|
@@ -63,6 +63,12 @@ Then launch the inspector and connect using Streamable HTTP transport to:
|
|
|
63
63
|
http://localhost:9292/http
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
When serving under a non-loopback hostname, allow it via `CF_MCP_ALLOWED_HOSTS` (comma-separated), otherwise requests are rejected with `403 Invalid Host header`:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
CF_MCP_ALLOWED_HOSTS=mcp.example.com cf-mcp http --root /path/to/cute_framework
|
|
70
|
+
```
|
|
71
|
+
|
|
66
72
|
## Development
|
|
67
73
|
|
|
68
74
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/cf/mcp/server.rb
CHANGED
|
@@ -12,7 +12,7 @@ module CF
|
|
|
12
12
|
CORS_HEADERS = {
|
|
13
13
|
"access-control-allow-origin" => "*",
|
|
14
14
|
"access-control-allow-methods" => "GET, POST, DELETE, OPTIONS",
|
|
15
|
-
"access-control-allow-headers" => "Content-Type, Accept, Mcp-Session-Id",
|
|
15
|
+
"access-control-allow-headers" => "Content-Type, Accept, MCP-Protocol-Version, Mcp-Method, Mcp-Name, Mcp-Session-Id",
|
|
16
16
|
"access-control-expose-headers" => "Mcp-Session-Id"
|
|
17
17
|
}.freeze
|
|
18
18
|
|
|
@@ -37,18 +37,27 @@ module CF
|
|
|
37
37
|
new(index, revision: builder.revision).rack_app
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
# Modern clients carry their version on every request (no handshake); legacy
|
|
41
|
+
# clients negotiate through `initialize`. Both track the SDK rather than pinning.
|
|
42
|
+
MODERN_PROTOCOL_VERSION = ::MCP::Configuration::LATEST_MODERN_PROTOCOL_VERSION
|
|
43
|
+
LEGACY_PROTOCOL_VERSION = ::MCP::Configuration::LATEST_HANDSHAKE_PROTOCOL_VERSION
|
|
41
44
|
WEBSITE_URL = ENV.fetch("FLY_APP_NAME", nil) ? "https://#{ENV["FLY_APP_NAME"]}.fly.dev" : "https://cf-mcp.fly.dev"
|
|
42
45
|
PUBLIC_DIR = File.join(__dir__, "public")
|
|
46
|
+
ALLOWED_HOSTS_ENV = "CF_MCP_ALLOWED_HOSTS"
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
# Comma-separated list of extra Host header values the HTTP transport accepts
|
|
49
|
+
# (the MCP SDK only allows loopback hosts by default).
|
|
50
|
+
def self.allowed_hosts_from_env(env = ENV)
|
|
51
|
+
env.fetch(ALLOWED_HOSTS_ENV, "").split(",").map(&:strip).reject(&:empty?)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def initialize(index, revision: nil, allowed_hosts: self.class.allowed_hosts_from_env)
|
|
45
55
|
@index = index
|
|
46
56
|
@revision = revision
|
|
57
|
+
@allowed_hosts = allowed_hosts
|
|
47
58
|
|
|
48
|
-
configuration = ::MCP::Configuration.new(protocol_version: PROTOCOL_VERSION)
|
|
49
59
|
@server = ::MCP::Server.new(
|
|
50
60
|
name: "cf-mcp",
|
|
51
|
-
configuration:,
|
|
52
61
|
version: CF::MCP::VERSION,
|
|
53
62
|
icons: [
|
|
54
63
|
::MCP::Icon.new(src: "#{WEBSITE_URL}/favicon.svg", mime_type: "image/svg+xml", sizes: ["any"]),
|
|
@@ -82,7 +91,7 @@ module CF
|
|
|
82
91
|
def rack_app
|
|
83
92
|
require "rack"
|
|
84
93
|
|
|
85
|
-
http_transport = ::MCP::Server::Transports::StreamableHTTPTransport.new(@server, stateless: true)
|
|
94
|
+
http_transport = ::MCP::Server::Transports::StreamableHTTPTransport.new(@server, stateless: true, allowed_hosts: @allowed_hosts)
|
|
86
95
|
@server.transport = http_transport
|
|
87
96
|
|
|
88
97
|
landing_page = build_landing_page
|
|
@@ -193,7 +202,8 @@ module CF
|
|
|
193
202
|
->(index, tool_classes) {
|
|
194
203
|
context = TemplateContext.new(
|
|
195
204
|
version: CF::MCP::VERSION,
|
|
196
|
-
|
|
205
|
+
modern_protocol_version: MODERN_PROTOCOL_VERSION,
|
|
206
|
+
legacy_protocol_version: LEGACY_PROTOCOL_VERSION,
|
|
197
207
|
revision: @revision,
|
|
198
208
|
revision_url: @revision && format(CUTE_FRAMEWORK_COMMIT_URL_TEMPLATE, revision: @revision),
|
|
199
209
|
stats: index.stats,
|
|
@@ -219,11 +229,12 @@ module CF
|
|
|
219
229
|
class TemplateContext
|
|
220
230
|
TEMPLATES_DIR = File.join(__dir__, "templates")
|
|
221
231
|
|
|
222
|
-
attr_reader :version, :
|
|
232
|
+
attr_reader :version, :modern_protocol_version, :legacy_protocol_version, :revision, :revision_url, :stats, :categories, :topics, :tools, :tool_schemas_json
|
|
223
233
|
|
|
224
|
-
def initialize(version:,
|
|
234
|
+
def initialize(version:, modern_protocol_version:, legacy_protocol_version:, revision:, revision_url:, stats:, categories:, topics:, tools:, tool_schemas_json:)
|
|
225
235
|
@version = version
|
|
226
|
-
@
|
|
236
|
+
@modern_protocol_version = modern_protocol_version
|
|
237
|
+
@legacy_protocol_version = legacy_protocol_version
|
|
227
238
|
@revision = revision
|
|
228
239
|
@revision_url = revision_url
|
|
229
240
|
@stats = stats
|
|
@@ -256,7 +267,10 @@ module CF
|
|
|
256
267
|
|
|
257
268
|
def js_content
|
|
258
269
|
js = File.read(File.join(TEMPLATES_DIR, "script.js"))
|
|
259
|
-
|
|
270
|
+
# Substitute the scalar placeholders first so injected content can't collide with them
|
|
271
|
+
js.sub("PROTOCOL_VERSION_PLACEHOLDER", @modern_protocol_version.to_json)
|
|
272
|
+
.sub("CLIENT_VERSION_PLACEHOLDER", @version.to_json)
|
|
273
|
+
.sub("TOOL_SCHEMAS_PLACEHOLDER", @tool_schemas_json)
|
|
260
274
|
.sub("CATEGORIES_PLACEHOLDER", categories_json)
|
|
261
275
|
.sub("TOPICS_PLACEHOLDER", topics_json)
|
|
262
276
|
.sub("CHANGELOG_PLACEHOLDER", changelog_json)
|
|
@@ -8,6 +8,8 @@ const TOOLS = TOOL_SCHEMAS_PLACEHOLDER;
|
|
|
8
8
|
const CATEGORIES = CATEGORIES_PLACEHOLDER;
|
|
9
9
|
const TOPICS = TOPICS_PLACEHOLDER;
|
|
10
10
|
const CHANGELOG = CHANGELOG_PLACEHOLDER;
|
|
11
|
+
const PROTOCOL_VERSION = PROTOCOL_VERSION_PLACEHOLDER;
|
|
12
|
+
const CLIENT_VERSION = CLIENT_VERSION_PLACEHOLDER;
|
|
11
13
|
|
|
12
14
|
// Helper to render topic options (used in multiple places)
|
|
13
15
|
const renderTopicOptions = () =>
|
|
@@ -38,13 +40,24 @@ function useMcpToolCall() {
|
|
|
38
40
|
method: 'POST',
|
|
39
41
|
headers: {
|
|
40
42
|
'Content-Type': 'application/json',
|
|
41
|
-
'Accept': 'application/json, text/event-stream'
|
|
43
|
+
'Accept': 'application/json, text/event-stream',
|
|
44
|
+
'MCP-Protocol-Version': PROTOCOL_VERSION,
|
|
45
|
+
'Mcp-Method': 'tools/call',
|
|
46
|
+
'Mcp-Name': toolName
|
|
42
47
|
},
|
|
43
48
|
body: JSON.stringify({
|
|
44
49
|
jsonrpc: '2.0',
|
|
45
50
|
id: Date.now(),
|
|
46
51
|
method: 'tools/call',
|
|
47
|
-
params: {
|
|
52
|
+
params: {
|
|
53
|
+
name: toolName,
|
|
54
|
+
arguments: args,
|
|
55
|
+
_meta: {
|
|
56
|
+
'io.modelcontextprotocol/protocolVersion': PROTOCOL_VERSION,
|
|
57
|
+
'io.modelcontextprotocol/clientCapabilities': {},
|
|
58
|
+
'io.modelcontextprotocol/clientInfo': { name: 'cf-mcp-dashboard', version: CLIENT_VERSION }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
48
61
|
})
|
|
49
62
|
});
|
|
50
63
|
|
data/lib/cf/mcp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cf-mcp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Piotr Usewicz
|
|
@@ -29,28 +29,28 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: '
|
|
32
|
+
version: '1.5'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '
|
|
39
|
+
version: '1.5'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: puma
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '
|
|
46
|
+
version: '8.0'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
53
|
+
version: '8.0'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
55
|
name: rack
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -161,14 +161,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
161
161
|
requirements:
|
|
162
162
|
- - ">="
|
|
163
163
|
- !ruby/object:Gem::Version
|
|
164
|
-
version: 3.
|
|
164
|
+
version: 3.3.0
|
|
165
165
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
166
|
requirements:
|
|
167
167
|
- - ">="
|
|
168
168
|
- !ruby/object:Gem::Version
|
|
169
169
|
version: '0'
|
|
170
170
|
requirements: []
|
|
171
|
-
rubygems_version: 4.0.
|
|
171
|
+
rubygems_version: 4.0.20
|
|
172
172
|
specification_version: 4
|
|
173
173
|
summary: MCP server providing documentation tools for Cute Framework
|
|
174
174
|
test_files: []
|