Class: ActionAgent::Api::McpServersController

Inherits:
BaseController show all
Defined in:
app/controllers/action_agent/api/mcp_servers_controller.rb

Overview

Read API for MCP services, plus sandbox provisioning for the servers that can be started on demand. Backs the dashboard MCP Services view.

The list is the union of three things: servers detected from telemetry and solid_agent records (ToolDiscovery), servers an agent declares in its configuration, and the default catalog (McpCatalog). An install therefore sees both what it is already using and what it could turn on.

Constant Summary collapse

STATUS_LABELS =
{
  "active" => "Called in this window",
  "configured" => "Declared by an agent, no traffic yet",
  "available" => "Available to connect",
  "idle" => "Seen previously, no traffic in this window"
}.freeze

Instance Method Summary collapse

Methods inherited from ActionAgent::ApplicationController

allow_unauthenticated_access

Instance Method Details

#indexObject

GET /api/mcp_servers



29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'app/controllers/action_agent/api/mcp_servers_controller.rb', line 29

def index
  finder = discovery
  tools = finder.detected_tools
  servers = finder.servers(tools)

  render json: {
    servers: servers,
    catalog: McpCatalog.all,
    summary: summary_for(servers),
    sandboxes: active_sandboxes,
    window_hours: finder.window_hours,
    statuses: STATUS_LABELS
  }
end

#launchObject

POST /api/mcp_servers/:id/launch

Starts the server inside a sandbox session. Only catalog entries marked sandbox: true are launchable — the rest need credentials the dashboard has nowhere safe to source, so they are listed but not startable.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/controllers/action_agent/api/mcp_servers_controller.rb', line 65

def launch
  unless @catalog_entry[:sandbox]
    return render json: {
      error: "#{@catalog_entry[:name]} can't be started from the dashboard",
      reason: launch_blocked_reason(@catalog_entry)
    }, status: :unprocessable_entity
  end

  sandbox = SandboxSession.new(
    sandbox_type: @catalog_entry[:sandbox_type] || "terminal",
    mcp_servers: [ @catalog_entry[:key] ]
  )
  # A sandbox belongs to whoever opened it, which is how
  # SandboxesController assigns them too — not to whatever
  # `current_owner` resolves to, since that is the account in a
  # multi-tenant install and this model prefers :user. Both are set
  # when the host app has them; a single-user install declares neither
  # association, so both are skipped.
  # respond_to? alone isn't enough: the association is declared from
  # configuration, but a host app's pre-existing table may not carry
  # the column behind it.
  assign_owner(sandbox, :user, current_user)
  assign_owner(sandbox, :account, )

  if sandbox.save
    sandbox.provision!
    sandbox.reload
    record_execution_usage
    render json: { sandbox: sandbox.summary, server: @catalog_entry }, status: :created
  else
    render json: { error: sandbox.errors.full_messages }, status: :unprocessable_entity
  end
end

#showObject

GET /api/mcp_servers/:id

One server with the tools detected for it, so the view can expand a row without refetching the whole inventory.



48
49
50
51
52
53
54
55
56
57
# File 'app/controllers/action_agent/api/mcp_servers_controller.rb', line 48

def show
  finder = discovery
  tools = finder.detected_tools
  server = finder.servers(tools).find { |row| row[:key] == params[:id] }

  render json: {
    server: server || @catalog_entry,
    tools: tools.select { |tool| tool[:mcp_server] == params[:id] }
  }
end