Class: TrakFlow::Mcp::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/trak_flow/mcp/server.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name: "trak_flow", version: TrakFlow::VERSION) ⇒ Server

Returns a new instance of Server.



10
11
12
13
14
15
16
# File 'lib/trak_flow/mcp/server.rb', line 10

def initialize(name: "trak_flow", version: TrakFlow::VERSION)
  @name = name
  @version = version
  @mcp_server = FastMcp::Server.new(name: name, version: version)
  register_tools
  register_resources
end

Instance Attribute Details

#mcp_serverObject (readonly)

Returns the value of attribute mcp_server.



8
9
10
# File 'lib/trak_flow/mcp/server.rb', line 8

def mcp_server
  @mcp_server
end

#nameObject (readonly)

Returns the value of attribute name.



8
9
10
# File 'lib/trak_flow/mcp/server.rb', line 8

def name
  @name
end

#versionObject (readonly)

Returns the value of attribute version.



8
9
10
# File 'lib/trak_flow/mcp/server.rb', line 8

def version
  @version
end

Instance Method Details

#http_handler(handler_name = nil) ⇒ Object

The Rack server that will run the HTTP transport, resolved through the generic Rackup handler interface so any registered server works. Priority: the explicit argument, then TrakFlow.config.mcp.handler (or the TF_MCP__HANDLER env var), then Rackup's default lookup — which picks a server already in the bundle (puma, falcon, webrick).



76
77
78
79
80
81
82
83
84
# File 'lib/trak_flow/mcp/server.rb', line 76

def http_handler(handler_name = nil)
  handler_name ||= TrakFlow.config.mcp.handler
  handler_name ? Rackup::Handler.get(handler_name) : Rackup::Handler.default
rescue LoadError, NameError => e
  raise LoadError,
        "No usable Rack server#{" for handler '#{handler_name}'" if handler_name} found in the bundle. " \
        'Add one that supports rack.hijack — e.g. `gem "puma"` — to your Gemfile. ' \
        "(#{e.message})"
end

#rack_appObject

The MCP transport as a plain Rack application. Public so a host app that already runs its own Rack server can mount it there instead of letting trak_flow boot a second server:

# config.ru of the host app
map "/mcp" do
run TrakFlow::Mcp::Server.new.rack_app
end

The host's server must support rack.hijack for SSE (Puma, Falcon, WEBrick, iodine all do).



61
62
63
64
65
66
67
68
69
# File 'lib/trak_flow/mcp/server.rb', line 61

def rack_app
  require "rack"

  server = mcp_server
  Rack::Builder.new do
    use FastMcp::Transports::RackTransport, server
    run ->(_env) { [404, { "Content-Type" => "text/plain" }, ["TrakFlow MCP Server - Use /mcp/sse for SSE transport"]] }
  end.to_app
end

#require_http_transport_gemsObject

Loads the gems the HTTP transport needs. They are optional dependencies — deliberately NOT in the gemspec, so consumers that only use the models/storage API (or the stdio transport) don't carry HTTP machinery. The Rack server is the host application's choice: any bundled server registered with Rackup will do.



91
92
93
94
95
96
97
98
99
# File 'lib/trak_flow/mcp/server.rb', line 91

def require_http_transport_gems
  require "rack"
  require "rackup"
rescue LoadError => e
  raise LoadError,
        "TrakFlow's MCP HTTP transport needs the optional rackup gem plus a Rack " \
        'server that supports rack.hijack. Add `gem "rackup"` — and `gem "puma"` ' \
        "if your app doesn't already bundle a server — to your Gemfile. (#{e.message})"
end

#start_both(http_port: nil, handler: nil) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/trak_flow/mcp/server.rb', line 32

def start_both(http_port: nil, handler: nil)
  require_http_transport_gems
  http_port ||= TrakFlow.config.mcp.port
  puts "Starting TrakFlow MCP Server (dual transport)..."
  puts "  - HTTP: port #{http_port}"
  puts "  - STDIO: reading from stdin"

  # Start HTTP in a thread
  http_thread = Thread.new do
    start_http_server(http_port, handler)
  end

  # Run STDIO in main thread (blocking)
  mcp_server.start

  http_thread.join
end

#start_http(port: nil, handler: nil) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/trak_flow/mcp/server.rb', line 24

def start_http(port: nil, handler: nil)
  require_http_transport_gems
  port ||= TrakFlow.config.mcp.port
  puts "Starting TrakFlow MCP Server (HTTP transport on port #{port})..."

  start_http_server(port, handler)
end

#start_stdioObject



18
19
20
21
22
# File 'lib/trak_flow/mcp/server.rb', line 18

def start_stdio
  # Use warn (stderr) not puts (stdout) - stdout is for MCP protocol
  warn "Starting TrakFlow MCP Server (stdio transport)..."
  mcp_server.start
end