Module: Explicit::MCPServer

Extended by:
MCPServer
Included in:
MCPServer
Defined in:
lib/explicit/mcp_server.rb,
lib/explicit/mcp_server/tool.rb,
lib/explicit/mcp_server/request.rb

Defined Under Namespace

Modules: Response Classes: Builder, Router

Constant Summary collapse

Tool =
::Data.define(:request) do
  def serialize
    {
      name: request.get_mcp_tool_name,
      description: request.get_mcp_tool_description,
      inputSchema: request.params_type.mcp_schema,
      annotations: {
        title: request.get_mcp_tool_title,
        readOnlyHint: request.get_mcp_tool_read_only_hint,
        destructiveHint: request.get_mcp_tool_destructive_hint,
        idempotentHint: request.get_mcp_tool_idempotent_hint,
        openWorldHint: request.get_mcp_tool_open_world_hint
      }.compact
    }.compact
  end
end
Request =
::Data.define(:id, :method, :params, :host, :headers) do
  def self.from_rack_env(env)
    headers = env.each_with_object({}) do |(key, value), hash|
      if key.start_with?("HTTP_") && key != "HTTP_HOST"
        header_name = key[5..-1].split("_").map(&:capitalize).join("-")
        hash[header_name] = value
      end
    end

    body = ::JSON.parse(env["rack.input"].read)

    new(
      id: body["id"],
      method: body["method"],
      params: body["params"],
      host: env["HTTP_HOST"],
      headers:
    )
  rescue ::JSON::ParserError
    new(
      id: nil,
      method: nil,
      params: nil,
      host: env["HTTP_HOST"],
      headers: headers
    )
  end

  def result(value)
    ::Explicit::MCPServer::Response::Result.new(id:, value:)
  end

  def error(value)
    ::Explicit::MCPServer::Response::Error.new(id:, value:)
  end
end

Instance Method Summary collapse

Instance Method Details

#new(&block) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/explicit/mcp_server.rb', line 6

def new(&block)
  engine = ::Class.new(::Rails::Engine)

  builder = Builder.new.tap do |builder|
    builder.instance_eval(&block)
  end

  if builder.get_name.blank?
    raise <<~TEXT
      MCP servers must have a name. For example:

      Explicit::MCPServer.new do
        name "My app"
      end
    TEXT
  end

  if builder.get_version.blank?
    raise <<~TEXT
      MCP servers must have a version. For example:

      Explicit::MCPServer.new do
        version "1.0.0"
      end
    TEXT
  end

  engine.routes.draw do
    match "/", to: builder, as: :explicit_mcp, via: :all
  end

  engine
end