hyperclient-mcp 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 +3 -0
- data/LICENSE.md +22 -0
- data/README.md +80 -0
- data/lib/hyperclient-mcp/api.rb +68 -0
- data/lib/hyperclient-mcp/resource.rb +21 -0
- data/lib/hyperclient-mcp/version.rb +7 -0
- data/lib/hyperclient-mcp.rb +8 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 788205f7a40dcce22ef7e160e7077833c28666c7ad27f0564916a1d18e6a7679
|
4
|
+
data.tar.gz: fead56f84529c880a3524e9b0ed732bf1838c6eb14db400b1b659904cd28e11a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca6f4fe3fcfb2ffaaeb03aae44736f1746da4b41fe22f8f0eb76fb12c9f70eb79a24b5411962b38497f0265649c0fb7b463ff103b35d1fac22140efaaeed985c
|
7
|
+
data.tar.gz: e0fd1072626e0a35b370ab595edf0a81990aaed104e4afae01e9918ea7103d8e913303e55a696da933ebc6fafdae8738c91477512a73807de59f2e30ffe84265
|
data/CHANGELOG.md
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 Daniel Doubrovkine and Contributors
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Hyperclient Mcp
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/hyperclient-mcp)
|
4
|
+
[](https://github.com/dblock/hyperclient-mcp/actions/workflows/test.yml)
|
5
|
+
|
6
|
+
Turn any hypermedia api into an mcp server.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add to Gemfile.
|
11
|
+
|
12
|
+
```
|
13
|
+
gem 'hyperclient-mcp'
|
14
|
+
```
|
15
|
+
|
16
|
+
Run `bundle install`.
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
### Identify a Hypermedia API
|
21
|
+
|
22
|
+
The S'Up service at [sup2.playplay.io](https://sup2.playplay.io) generates fresh triads of team members in Slack to meet for coffee every week in an informal standup. It has a Hypermedia API under [sup2.playplay.io/api](https://sup2.playplay.io/api) that can be enabled with `set api on` and accessed with a token obtained using `set api token`. We'll export TOKEN in a shell for future use.
|
23
|
+
|
24
|
+
```bash
|
25
|
+
export TOKEN=...
|
26
|
+
```
|
27
|
+
|
28
|
+
The Hypermedia client to this api is as follows.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
api = Hyperclient.new('https://sup2.playplay.io/api') do |client|
|
32
|
+
client.headers['X-Access-Token'] = ENV.fetch('TOKEN', nil)
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
### Use Hyperclient MCP
|
37
|
+
|
38
|
+
To turn any hypermedia API into an MCP, create an mcp wrapper and register its `resources` with FastMcp and mount it as usual.
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
hyperclient_mcp = Hyperclient::Mcp::Api.new(api)
|
42
|
+
|
43
|
+
mcp_server = FastMcp::Server.new(name: "S'Up", version: '0.0.1')
|
44
|
+
mcp_server.register_resources(*hyperclient_mcp.resources)
|
45
|
+
|
46
|
+
use FastMcp::Transports::RackTransport, mcp_server
|
47
|
+
```
|
48
|
+
|
49
|
+
### See It
|
50
|
+
|
51
|
+
The MCP code in [examples/sup.playplay.io](examples/sup.playplay.io/) can be directly used with Claude.
|
52
|
+
|
53
|
+
```bash
|
54
|
+
bundle install
|
55
|
+
bundle exec ruby mcp.rb
|
56
|
+
```
|
57
|
+
|
58
|
+
```bash
|
59
|
+
claude mcp add --transport sse local http://127.0.0.1:4567/mcp/sse
|
60
|
+
```
|
61
|
+
|
62
|
+

|
63
|
+
|
64
|
+
## Examples
|
65
|
+
|
66
|
+
See [examples/grape-with-roar](examples/grape-with-roar/) for a complete example.
|
67
|
+
|
68
|
+
## Upgrading
|
69
|
+
|
70
|
+
See [UPGRADING](UPGRADING.md).
|
71
|
+
|
72
|
+
## Contributing
|
73
|
+
|
74
|
+
See [CONTRIBUTING](CONTRIBUTING.md).
|
75
|
+
|
76
|
+
## Copyright and License
|
77
|
+
|
78
|
+
Copyright (c) 2025, [Daniel Doubrovkine](https://twitter.com/dblockdotorg) and [Contributors](CHANGELOG.md).
|
79
|
+
|
80
|
+
This project is licensed under the [MIT License](LICENSE.md).
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Hyperclient
|
2
|
+
module Mcp
|
3
|
+
class Api
|
4
|
+
attr_reader :api
|
5
|
+
|
6
|
+
def initialize(api)
|
7
|
+
@api = api
|
8
|
+
end
|
9
|
+
|
10
|
+
def resources
|
11
|
+
@resources ||= _resources(@api)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def _resources(api, name = 'root')
|
17
|
+
api._links.map do |key, link|
|
18
|
+
name = key unless key == 'self'
|
19
|
+
|
20
|
+
href = link.instance_variable_get('@link')['href'].gsub(api.to_s, '')
|
21
|
+
|
22
|
+
klass = Class.new(Hyperclient::Mcp::Resource) do
|
23
|
+
uri "api://#{href}" # TODO: configure api prefix
|
24
|
+
resource_name name
|
25
|
+
mime_type 'application/json'
|
26
|
+
api api
|
27
|
+
key key
|
28
|
+
link link
|
29
|
+
|
30
|
+
def content
|
31
|
+
JSON.generate(
|
32
|
+
api.send(
|
33
|
+
key, params
|
34
|
+
)._resource._attributes.to_h
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Assign a stable constant name like Hyperclient::Mcp::Resources::<CamelizedName>
|
40
|
+
const_module = Hyperclient::Mcp.const_defined?(:Resources) ? Hyperclient::Mcp::Resources : Hyperclient::Mcp.const_set(:Resources, Module.new)
|
41
|
+
const_name = name.to_s
|
42
|
+
.gsub(/[^a-zA-Z0-9]+/, '_')
|
43
|
+
.split('_')
|
44
|
+
.reject(&:empty?)
|
45
|
+
.map { |part| part[0].upcase + part[1..].to_s.downcase }
|
46
|
+
.join
|
47
|
+
const_name = 'Root' if const_name.empty?
|
48
|
+
|
49
|
+
# Avoid collisions by appending a numeric suffix if needed
|
50
|
+
candidate = const_name
|
51
|
+
suffix = 2
|
52
|
+
while const_module.const_defined?(candidate)
|
53
|
+
candidate = "#{const_name}#{suffix}"
|
54
|
+
suffix += 1
|
55
|
+
end
|
56
|
+
const_module.const_set(candidate, klass)
|
57
|
+
|
58
|
+
klass.class_eval do
|
59
|
+
@api = api
|
60
|
+
@key = key
|
61
|
+
end
|
62
|
+
|
63
|
+
klass
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hyperclient
|
2
|
+
module Mcp
|
3
|
+
class Resource < FastMcp::Resource
|
4
|
+
%i[api key link].each do |f|
|
5
|
+
self.class.send :define_method, f do |val|
|
6
|
+
instance_variable_set "@#{f}", val
|
7
|
+
end
|
8
|
+
|
9
|
+
send :define_method, f do
|
10
|
+
self.class.instance_variable_get("@#{f}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# class << self
|
15
|
+
# def inspect
|
16
|
+
# "#<Class:#{object_id} uri=#{uri}, name=#{resource_name}>"
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hyperclient-mcp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Doubrovkine
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-09-12 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: fast-mcp
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: hyperclient
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
email: dblock@dblock.org
|
41
|
+
executables: []
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- CHANGELOG.md
|
46
|
+
- LICENSE.md
|
47
|
+
- README.md
|
48
|
+
- lib/hyperclient-mcp.rb
|
49
|
+
- lib/hyperclient-mcp/api.rb
|
50
|
+
- lib/hyperclient-mcp/resource.rb
|
51
|
+
- lib/hyperclient-mcp/version.rb
|
52
|
+
homepage: http://github.com/dblock/hyperclient-mcp
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata:
|
56
|
+
rubygems_mfa_required: 'true'
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '3.0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.5'
|
70
|
+
requirements: []
|
71
|
+
rubygems_version: 3.6.2
|
72
|
+
specification_version: 4
|
73
|
+
summary: Turn any Hypermedia api into an mcp server.
|
74
|
+
test_files: []
|