mcp-inspector 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/.rspec +3 -0
- data/README.md +261 -0
- data/Rakefile +8 -0
- data/examples/mcp-inspector.json +28 -0
- data/exe/mcp-inspector +14 -0
- data/lib/mcp_inspector/cli.rb +257 -0
- data/lib/mcp_inspector/data/config_manager.rb +238 -0
- data/lib/mcp_inspector/data/input_adapter.rb +69 -0
- data/lib/mcp_inspector/data/output_adapter.rb +110 -0
- data/lib/mcp_inspector/presentation/base_formatter.rb +93 -0
- data/lib/mcp_inspector/presentation/json_formatter.rb +153 -0
- data/lib/mcp_inspector/transport/base_adapter.rb +81 -0
- data/lib/mcp_inspector/transport/client_adapter.rb +207 -0
- data/lib/mcp_inspector/transport/server_config.rb +141 -0
- data/lib/mcp_inspector/version.rb +5 -0
- data/lib/mcp_inspector.rb +14 -0
- data/sig/mcp/inspector.rbs +6 -0
- metadata +174 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MCPInspector
|
4
|
+
module Transport
|
5
|
+
class BaseAdapter
|
6
|
+
class ConnectionError < Error; end
|
7
|
+
class OperationError < Error; end
|
8
|
+
class TimeoutError < Error; end
|
9
|
+
|
10
|
+
def initialize(timeout: 30)
|
11
|
+
@timeout = timeout
|
12
|
+
@connected = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def connect(server_config)
|
16
|
+
raise NotImplementedError, "Subclasses must implement #connect"
|
17
|
+
end
|
18
|
+
|
19
|
+
def disconnect
|
20
|
+
raise NotImplementedError, "Subclasses must implement #disconnect"
|
21
|
+
end
|
22
|
+
|
23
|
+
def connected?
|
24
|
+
@connected
|
25
|
+
end
|
26
|
+
|
27
|
+
def list_tools
|
28
|
+
ensure_connected!
|
29
|
+
raise NotImplementedError, "Subclasses must implement #list_tools"
|
30
|
+
end
|
31
|
+
|
32
|
+
def list_resources
|
33
|
+
ensure_connected!
|
34
|
+
raise NotImplementedError, "Subclasses must implement #list_resources"
|
35
|
+
end
|
36
|
+
|
37
|
+
def list_prompts
|
38
|
+
ensure_connected!
|
39
|
+
raise NotImplementedError, "Subclasses must implement #list_prompts"
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute_tool(name, arguments = {})
|
43
|
+
ensure_connected!
|
44
|
+
raise NotImplementedError, "Subclasses must implement #execute_tool"
|
45
|
+
end
|
46
|
+
|
47
|
+
def read_resource(uri)
|
48
|
+
ensure_connected!
|
49
|
+
raise NotImplementedError, "Subclasses must implement #read_resource"
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_prompt(name, arguments = {})
|
53
|
+
ensure_connected!
|
54
|
+
raise NotImplementedError, "Subclasses must implement #get_prompt"
|
55
|
+
end
|
56
|
+
|
57
|
+
def server_info
|
58
|
+
ensure_connected!
|
59
|
+
raise NotImplementedError, "Subclasses must implement #server_info"
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
attr_reader :timeout
|
65
|
+
|
66
|
+
def ensure_connected!
|
67
|
+
raise ConnectionError, "Not connected to server" unless connected?
|
68
|
+
end
|
69
|
+
|
70
|
+
def with_timeout
|
71
|
+
if timeout
|
72
|
+
Timeout.timeout(timeout) { yield }
|
73
|
+
else
|
74
|
+
yield
|
75
|
+
end
|
76
|
+
rescue Timeout::Error
|
77
|
+
raise TimeoutError, "Operation timed out after #{timeout} seconds"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "mcp_client"
|
3
|
+
|
4
|
+
module MCPInspector
|
5
|
+
module Transport
|
6
|
+
class ClientAdapter < BaseAdapter
|
7
|
+
def initialize(timeout: 30)
|
8
|
+
super
|
9
|
+
@client = nil
|
10
|
+
@server_config = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def connect(server_config)
|
14
|
+
@server_config = server_config
|
15
|
+
|
16
|
+
begin
|
17
|
+
with_timeout do
|
18
|
+
case server_config.transport
|
19
|
+
when "stdio"
|
20
|
+
connect_stdio
|
21
|
+
when "sse"
|
22
|
+
connect_sse
|
23
|
+
when "websocket"
|
24
|
+
connect_websocket
|
25
|
+
else
|
26
|
+
raise ConnectionError, "Unsupported transport: #{server_config.transport}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@connected = true
|
30
|
+
rescue => e
|
31
|
+
@connected = false
|
32
|
+
raise ConnectionError, "Failed to connect to #{server_config.name}: #{e.message}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def disconnect
|
37
|
+
if @client && @client.respond_to?(:disconnect)
|
38
|
+
@client.disconnect
|
39
|
+
end
|
40
|
+
@client = nil
|
41
|
+
@connected = false
|
42
|
+
end
|
43
|
+
|
44
|
+
def list_tools
|
45
|
+
with_timeout do
|
46
|
+
response = @client.list_tools
|
47
|
+
normalize_response(response)
|
48
|
+
end
|
49
|
+
rescue => e
|
50
|
+
raise OperationError, "Failed to list tools: #{e.message}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def list_resources
|
54
|
+
if @client.respond_to?(:list_resources)
|
55
|
+
with_timeout do
|
56
|
+
response = @client.list_resources
|
57
|
+
normalize_response(response)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
rescue => e
|
63
|
+
raise OperationError, "Failed to list resources: #{e.message}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def list_prompts
|
67
|
+
if @client.respond_to?(:list_prompts)
|
68
|
+
with_timeout do
|
69
|
+
response = @client.list_prompts
|
70
|
+
normalize_response(response)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
# Return empty prompts list if not supported
|
74
|
+
[]
|
75
|
+
end
|
76
|
+
rescue => e
|
77
|
+
raise OperationError, "Failed to list prompts: #{e.message}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def execute_tool(name, arguments = {})
|
81
|
+
with_timeout do
|
82
|
+
response = @client.call_tool(name, arguments)
|
83
|
+
normalize_response(response)
|
84
|
+
end
|
85
|
+
rescue => e
|
86
|
+
raise OperationError, "Failed to execute tool '#{name}': #{e.message}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def read_resource(uri)
|
90
|
+
if @client.respond_to?(:read_resource)
|
91
|
+
with_timeout do
|
92
|
+
response = @client.read_resource(uri)
|
93
|
+
normalize_response(response)
|
94
|
+
end
|
95
|
+
else
|
96
|
+
raise OperationError, "Resource reading is not supported by this server"
|
97
|
+
end
|
98
|
+
rescue => e
|
99
|
+
raise OperationError, "Failed to read resource '#{uri}': #{e.message}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_prompt(name, arguments = {})
|
103
|
+
if @client.respond_to?(:get_prompt)
|
104
|
+
with_timeout do
|
105
|
+
response = @client.get_prompt(name, arguments)
|
106
|
+
normalize_response(response)
|
107
|
+
end
|
108
|
+
else
|
109
|
+
raise OperationError, "Prompts are not supported by this server"
|
110
|
+
end
|
111
|
+
rescue => e
|
112
|
+
raise OperationError, "Failed to get prompt '#{name}': #{e.message}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def server_info
|
116
|
+
{
|
117
|
+
name: @server_config.name,
|
118
|
+
transport: @server_config.transport,
|
119
|
+
connected: connected?,
|
120
|
+
capabilities: detect_capabilities
|
121
|
+
}
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def connect_stdio
|
127
|
+
@client = MCPClient::ServerStdio.new(
|
128
|
+
command: @server_config.command.join(' '),
|
129
|
+
env: @server_config.env
|
130
|
+
)
|
131
|
+
@client.connect
|
132
|
+
end
|
133
|
+
|
134
|
+
def connect_sse
|
135
|
+
@client = MCPClient::ServerSSE.new(url: @server_config.url)
|
136
|
+
@client.connect
|
137
|
+
end
|
138
|
+
|
139
|
+
def connect_websocket
|
140
|
+
@client = MCPClient::ServerHTTP.new(url: @server_config.url)
|
141
|
+
@client.connect
|
142
|
+
end
|
143
|
+
|
144
|
+
def normalize_response(response)
|
145
|
+
case response
|
146
|
+
when Hash
|
147
|
+
response
|
148
|
+
when Array
|
149
|
+
# Handle arrays of MCPClient objects
|
150
|
+
if response.first.respond_to?(:name) && response.first.respond_to?(:description)
|
151
|
+
# Array of Tool, Resource, or Prompt objects
|
152
|
+
response.map { |item| normalize_mcp_object(item) }
|
153
|
+
else
|
154
|
+
response
|
155
|
+
end
|
156
|
+
else
|
157
|
+
response
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def normalize_mcp_object(obj)
|
162
|
+
base_data = {
|
163
|
+
name: obj.name,
|
164
|
+
description: obj.description
|
165
|
+
}
|
166
|
+
|
167
|
+
# Add schema for tools
|
168
|
+
if obj.respond_to?(:schema) && obj.schema
|
169
|
+
base_data[:inputSchema] = obj.schema
|
170
|
+
end
|
171
|
+
|
172
|
+
# Add other properties that might exist
|
173
|
+
base_data[:uri] = obj.uri if obj.respond_to?(:uri)
|
174
|
+
base_data[:mimeType] = obj.mimeType if obj.respond_to?(:mimeType)
|
175
|
+
|
176
|
+
base_data
|
177
|
+
end
|
178
|
+
|
179
|
+
def detect_capabilities
|
180
|
+
capabilities = []
|
181
|
+
|
182
|
+
begin
|
183
|
+
list_tools
|
184
|
+
capabilities << "tools"
|
185
|
+
rescue OperationError
|
186
|
+
# Tools not supported
|
187
|
+
end
|
188
|
+
|
189
|
+
begin
|
190
|
+
list_resources
|
191
|
+
capabilities << "resources"
|
192
|
+
rescue OperationError
|
193
|
+
# Resources not supported
|
194
|
+
end
|
195
|
+
|
196
|
+
begin
|
197
|
+
list_prompts
|
198
|
+
capabilities << "prompts"
|
199
|
+
rescue OperationError
|
200
|
+
# Prompts not supported
|
201
|
+
end
|
202
|
+
|
203
|
+
capabilities
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module MCPInspector
|
6
|
+
module Transport
|
7
|
+
class ServerConfig
|
8
|
+
class ValidationError < Error; end
|
9
|
+
|
10
|
+
REQUIRED_FIELDS = %w[name transport].freeze
|
11
|
+
STDIO_REQUIRED_FIELDS = %w[command].freeze
|
12
|
+
URL_REQUIRED_FIELDS = %w[url].freeze
|
13
|
+
VALID_TRANSPORTS = %w[stdio sse websocket].freeze
|
14
|
+
|
15
|
+
attr_reader :name, :transport, :command, :args, :env, :working_directory, :url
|
16
|
+
|
17
|
+
def initialize(config_hash)
|
18
|
+
@raw_config = config_hash
|
19
|
+
validate_and_parse_config!
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_json(json_string)
|
23
|
+
config_hash = JSON.parse(json_string)
|
24
|
+
new(config_hash)
|
25
|
+
rescue JSON::ParserError => e
|
26
|
+
raise ValidationError, "Invalid JSON: #{e.message}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def stdio?
|
30
|
+
transport == "stdio"
|
31
|
+
end
|
32
|
+
|
33
|
+
def sse?
|
34
|
+
transport == "sse"
|
35
|
+
end
|
36
|
+
|
37
|
+
def websocket?
|
38
|
+
transport == "websocket"
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_h
|
42
|
+
{
|
43
|
+
name: name,
|
44
|
+
transport: transport,
|
45
|
+
command: command,
|
46
|
+
args: args,
|
47
|
+
env: env,
|
48
|
+
working_directory: working_directory,
|
49
|
+
url: url
|
50
|
+
}.compact
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_json(*args)
|
54
|
+
to_h.to_json(*args)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
attr_reader :raw_config
|
60
|
+
|
61
|
+
def validate_and_parse_config!
|
62
|
+
validate_required_fields!
|
63
|
+
validate_transport!
|
64
|
+
validate_transport_specific_fields!
|
65
|
+
parse_fields!
|
66
|
+
end
|
67
|
+
|
68
|
+
def validate_required_fields!
|
69
|
+
missing_fields = REQUIRED_FIELDS - raw_config.keys
|
70
|
+
return if missing_fields.empty?
|
71
|
+
|
72
|
+
raise ValidationError, "Missing required fields: #{missing_fields.join(', ')}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_transport!
|
76
|
+
unless VALID_TRANSPORTS.include?(raw_config["transport"])
|
77
|
+
raise ValidationError, "Invalid transport '#{raw_config['transport']}'. Valid options: #{VALID_TRANSPORTS.join(', ')}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def validate_transport_specific_fields!
|
82
|
+
case raw_config["transport"]
|
83
|
+
when "stdio"
|
84
|
+
validate_stdio_fields!
|
85
|
+
when "sse", "websocket"
|
86
|
+
validate_url_fields!
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate_stdio_fields!
|
91
|
+
missing_fields = STDIO_REQUIRED_FIELDS - raw_config.keys
|
92
|
+
return if missing_fields.empty?
|
93
|
+
|
94
|
+
raise ValidationError, "Missing required fields for stdio transport: #{missing_fields.join(', ')}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def validate_url_fields!
|
98
|
+
missing_fields = URL_REQUIRED_FIELDS - raw_config.keys
|
99
|
+
return if missing_fields.empty?
|
100
|
+
|
101
|
+
raise ValidationError, "Missing required fields for URL-based transport: #{missing_fields.join(', ')}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse_fields!
|
105
|
+
@name = raw_config["name"]
|
106
|
+
@transport = raw_config["transport"]
|
107
|
+
@command = parse_command(raw_config["command"]) if raw_config["command"]
|
108
|
+
@args = raw_config["args"] || []
|
109
|
+
@env = parse_env(raw_config["env"] || {})
|
110
|
+
@working_directory = raw_config["working_directory"] || "."
|
111
|
+
@url = raw_config["url"] if raw_config["url"]
|
112
|
+
end
|
113
|
+
|
114
|
+
def parse_command(command)
|
115
|
+
case command
|
116
|
+
when Array
|
117
|
+
command
|
118
|
+
when String
|
119
|
+
command.split
|
120
|
+
else
|
121
|
+
raise ValidationError, "Command must be a string or array of strings"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def parse_env(env_hash)
|
126
|
+
return {} unless env_hash.is_a?(Hash)
|
127
|
+
|
128
|
+
env_hash.transform_values { |value| expand_env_variable(value) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def expand_env_variable(value)
|
132
|
+
return value unless value.is_a?(String)
|
133
|
+
|
134
|
+
value.gsub(/\$\{([^}]+)\}/) do |match|
|
135
|
+
env_var = ::Regexp.last_match(1)
|
136
|
+
ENV[env_var] || match
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zeitwerk"
|
4
|
+
require "timeout"
|
5
|
+
|
6
|
+
loader = Zeitwerk::Loader.for_gem
|
7
|
+
loader.setup
|
8
|
+
|
9
|
+
module MCPInspector
|
10
|
+
class Error < StandardError; end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Eagerly load CLI so it's available for the executable
|
14
|
+
require_relative "mcp_inspector/cli"
|
metadata
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mcp-inspector
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Enrique Mogollan
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-08-26 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: thor
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.3'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '1.3'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: json
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.6'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.6'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: zeitwerk
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.6'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.6'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: ruby-mcp-client
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.7.0
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.7.0
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: base64
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: bundler
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '2.0'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '2.0'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: rake
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '13.0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '13.0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: rspec
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '3.12'
|
117
|
+
type: :development
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '3.12'
|
124
|
+
description: A Ruby gem that provides tooling for connecting to and inspecting MCP
|
125
|
+
servers, allowing you to list and execute tools, resources, and prompts with JSON
|
126
|
+
output.
|
127
|
+
email:
|
128
|
+
- emogollan@gmail.com
|
129
|
+
executables:
|
130
|
+
- mcp-inspector
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files: []
|
133
|
+
files:
|
134
|
+
- ".rspec"
|
135
|
+
- README.md
|
136
|
+
- Rakefile
|
137
|
+
- examples/mcp-inspector.json
|
138
|
+
- exe/mcp-inspector
|
139
|
+
- lib/mcp_inspector.rb
|
140
|
+
- lib/mcp_inspector/cli.rb
|
141
|
+
- lib/mcp_inspector/data/config_manager.rb
|
142
|
+
- lib/mcp_inspector/data/input_adapter.rb
|
143
|
+
- lib/mcp_inspector/data/output_adapter.rb
|
144
|
+
- lib/mcp_inspector/presentation/base_formatter.rb
|
145
|
+
- lib/mcp_inspector/presentation/json_formatter.rb
|
146
|
+
- lib/mcp_inspector/transport/base_adapter.rb
|
147
|
+
- lib/mcp_inspector/transport/client_adapter.rb
|
148
|
+
- lib/mcp_inspector/transport/server_config.rb
|
149
|
+
- lib/mcp_inspector/version.rb
|
150
|
+
- sig/mcp/inspector.rbs
|
151
|
+
homepage: https://github.com/mogox/mcp-inspector
|
152
|
+
licenses: []
|
153
|
+
metadata:
|
154
|
+
homepage_uri: https://github.com/mogox/mcp-inspector
|
155
|
+
source_code_uri: https://github.com/mogox/mcp-inspector
|
156
|
+
bug_tracker_uri: https://github.com/mogox/mcp-inspector/issues
|
157
|
+
rdoc_options: []
|
158
|
+
require_paths:
|
159
|
+
- lib
|
160
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: 2.7.0
|
165
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
requirements: []
|
171
|
+
rubygems_version: 3.6.6
|
172
|
+
specification_version: 4
|
173
|
+
summary: A tool for inspecting MCP (Model Context Protocol) servers
|
174
|
+
test_files: []
|