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 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
@@ -0,0 +1,3 @@
1
+ ### 0.1.0 (2025/09/12)
2
+
3
+ * Initial public release - [@dblock](https://github.com/dblock).
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
+ [![Gem Version](https://badge.fury.io/rb/hyperclient-mcp.svg)](https://badge.fury.io/rb/hyperclient-mcp)
4
+ [![Test](https://github.com/dblock/hyperclient-mcp/actions/workflows/test.yml/badge.svg?branch=master)](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
+ ![](examples/sup.playplay.io/mcp.gif)
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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hyperclient
4
+ module Mcp
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'hyperclient'
4
+ require 'fast_mcp'
5
+
6
+ require_relative 'hyperclient-mcp/version'
7
+ require_relative 'hyperclient-mcp/resource'
8
+ require_relative 'hyperclient-mcp/api'
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: []