@@ -19,6 +19,7 @@ import (
19
19
"github.com/stacklok/toolhive/pkg/transport/streamable"
20
20
"github.com/stacklok/toolhive/pkg/transport/types"
21
21
"github.com/stacklok/toolhive/pkg/versions"
22
+ "github.com/stacklok/toolhive/pkg/workloads"
22
23
)
23
24
24
25
var (
@@ -86,7 +87,7 @@ func newMCPCommand() *cobra.Command {
86
87
}
87
88
88
89
func addMCPFlags (cmd * cobra.Command ) {
89
- cmd .Flags ().StringVar (& mcpServerURL , "server" , "" , "MCP server URL (required)" )
90
+ cmd .Flags ().StringVar (& mcpServerURL , "server" , "" , "MCP server URL or name from ToolHive registry (required)" )
90
91
cmd .Flags ().StringVar (& mcpFormat , "format" , FormatText , "Output format (json or text)" )
91
92
cmd .Flags ().DurationVar (& mcpTimeout , "timeout" , 30 * time .Second , "Connection timeout" )
92
93
cmd .Flags ().StringVar (& mcpTransport , "transport" , "auto" , "Transport type (auto, sse, streamable-http)" )
@@ -98,7 +99,13 @@ func mcpListCmdFunc(cmd *cobra.Command, _ []string) error {
98
99
ctx , cancel := context .WithTimeout (cmd .Context (), mcpTimeout )
99
100
defer cancel ()
100
101
101
- mcpClient , err := createMCPClient ()
102
+ // Resolve server URL if it's a name
103
+ serverURL , err := resolveServerURL (ctx , mcpServerURL )
104
+ if err != nil {
105
+ return err
106
+ }
107
+
108
+ mcpClient , err := createMCPClient (serverURL )
102
109
if err != nil {
103
110
return err
104
111
}
@@ -143,7 +150,13 @@ func mcpListToolsCmdFunc(cmd *cobra.Command, _ []string) error {
143
150
ctx , cancel := context .WithTimeout (cmd .Context (), mcpTimeout )
144
151
defer cancel ()
145
152
146
- mcpClient , err := createMCPClient ()
153
+ // Resolve server URL if it's a name
154
+ serverURL , err := resolveServerURL (ctx , mcpServerURL )
155
+ if err != nil {
156
+ return err
157
+ }
158
+
159
+ mcpClient , err := createMCPClient (serverURL )
147
160
if err != nil {
148
161
return err
149
162
}
@@ -166,7 +179,13 @@ func mcpListResourcesCmdFunc(cmd *cobra.Command, _ []string) error {
166
179
ctx , cancel := context .WithTimeout (cmd .Context (), mcpTimeout )
167
180
defer cancel ()
168
181
169
- mcpClient , err := createMCPClient ()
182
+ // Resolve server URL if it's a name
183
+ serverURL , err := resolveServerURL (ctx , mcpServerURL )
184
+ if err != nil {
185
+ return err
186
+ }
187
+
188
+ mcpClient , err := createMCPClient (serverURL )
170
189
if err != nil {
171
190
return err
172
191
}
@@ -189,7 +208,13 @@ func mcpListPromptsCmdFunc(cmd *cobra.Command, _ []string) error {
189
208
ctx , cancel := context .WithTimeout (cmd .Context (), mcpTimeout )
190
209
defer cancel ()
191
210
192
- mcpClient , err := createMCPClient ()
211
+ // Resolve server URL if it's a name
212
+ serverURL , err := resolveServerURL (ctx , mcpServerURL )
213
+ if err != nil {
214
+ return err
215
+ }
216
+
217
+ mcpClient , err := createMCPClient (serverURL )
193
218
if err != nil {
194
219
return err
195
220
}
@@ -207,19 +232,48 @@ func mcpListPromptsCmdFunc(cmd *cobra.Command, _ []string) error {
207
232
return outputMCPData (map [string ]interface {}{"prompts" : result .Prompts }, mcpFormat )
208
233
}
209
234
235
+ // resolveServerURL resolves a server name to a URL or returns the URL if it's already a URL
236
+ func resolveServerURL (ctx context.Context , serverInput string ) (string , error ) {
237
+ // Check if it's already a URL
238
+ if strings .HasPrefix (serverInput , "http://" ) || strings .HasPrefix (serverInput , "https://" ) {
239
+ return serverInput , nil
240
+ }
241
+
242
+ // Try to get the workload by name
243
+ manager , err := workloads .NewManager (ctx )
244
+ if err != nil {
245
+ return "" , fmt .Errorf ("failed to create workload manager: %w" , err )
246
+ }
247
+
248
+ workload , err := manager .GetWorkload (ctx , serverInput )
249
+ if err != nil {
250
+ return "" , fmt .Errorf (
251
+ "server '%s' not found in running workloads. " +
252
+ "Please ensure the server is running or provide a valid URL" , serverInput )
253
+ }
254
+
255
+ // Check if the workload is running
256
+ if workload .Status != "running" {
257
+ return "" , fmt .Errorf ("server '%s' is not running (status: %s). " +
258
+ "Please start it first using 'thv run %s'" , serverInput , workload .Status , serverInput )
259
+ }
260
+
261
+ return workload .URL , nil
262
+ }
263
+
210
264
// createMCPClient creates an MCP client based on the server URL and transport type
211
- func createMCPClient () (* client.Client , error ) {
212
- transportType := determineTransportType (mcpServerURL , mcpTransport )
265
+ func createMCPClient (serverURL string ) (* client.Client , error ) {
266
+ transportType := determineTransportType (serverURL , mcpTransport )
213
267
214
268
switch transportType {
215
269
case types .TransportTypeSSE :
216
- mcpClient , err := client .NewSSEMCPClient (mcpServerURL )
270
+ mcpClient , err := client .NewSSEMCPClient (serverURL )
217
271
if err != nil {
218
272
return nil , fmt .Errorf ("failed to create SSE MCP client: %w" , err )
219
273
}
220
274
return mcpClient , nil
221
275
case types .TransportTypeStreamableHTTP :
222
- mcpClient , err := client .NewStreamableHttpClient (mcpServerURL )
276
+ mcpClient , err := client .NewStreamableHttpClient (serverURL )
223
277
if err != nil {
224
278
return nil , fmt .Errorf ("failed to create Streamable HTTP MCP client: %w" , err )
225
279
}
0 commit comments