@@ -237,6 +237,8 @@ func (r *REPL) handleMCPCommand(args []string) (string, error) {
237237 if len (args ) < 2 {
238238 var output strings.Builder
239239 output .WriteString ("MCP server management commands:\r \n " )
240+ output .WriteString (" /mcp add <name> <command> [args...] - Add a new MCP server (enabled by default)\r \n " )
241+ output .WriteString (" /mcp del <server> - Remove MCP server from configuration\r \n " )
240242 output .WriteString (" /mcp start [server] - Start MCP server(s) (all enabled if no server specified)\r \n " )
241243 output .WriteString (" /mcp stop [server] - Stop MCP server(s) (all if no server specified)\r \n " )
242244 output .WriteString (" /mcp restart [server] - Restart MCP server(s)\r \n " )
@@ -249,6 +251,10 @@ func (r *REPL) handleMCPCommand(args []string) (string, error) {
249251
250252 action := args [1 ]
251253 switch action {
254+ case "add" :
255+ return r .handleMCPAdd (args [2 :])
256+ case "del" , "rm" , "remove" :
257+ return r .handleMCPDel (args [2 :])
252258 case "start" :
253259 return r .handleMCPStart (args [2 :])
254260 case "stop" :
@@ -268,6 +274,97 @@ func (r *REPL) handleMCPCommand(args []string) (string, error) {
268274 }
269275}
270276
277+ // handleMCPAdd adds a new MCP server to the configuration.
278+ // Accepts either:
279+ // /mcp add <name> <http-or-sse-url>
280+ // /mcp add <name> <command> [args...]
281+ // A single remainder argument starting with http:// or https:// is stored as a
282+ // URL server (type=http, or type=sse if the URL path ends with /sse). Anything
283+ // else is treated as a shell one-liner and split into command + args.
284+ func (r * REPL ) handleMCPAdd (args []string ) (string , error ) {
285+ if len (args ) < 2 {
286+ return "Usage: /mcp add <name> <url-or-command> [args...]\r \n " , nil
287+ }
288+
289+ name := args [0 ]
290+ if r .mcpConfig .Servers == nil {
291+ r .mcpConfig .Servers = make (map [string ]MCPServer )
292+ }
293+ if _ , exists := r .mcpConfig .Servers [name ]; exists {
294+ return fmt .Sprintf ("Server %s already exists. Use /mcp del %s first or /mcp edit to modify it.\r \n " , name , name ), nil
295+ }
296+
297+ server := MCPServer {Enabled : true }
298+ first := args [1 ]
299+ rest := args [2 :]
300+
301+ if isMCPURL (first ) && len (rest ) == 0 {
302+ server .Type = "http"
303+ if strings .HasSuffix (strings .TrimRight (first , "/" ), "/sse" ) {
304+ server .Type = "sse"
305+ }
306+ server .URL = first
307+ } else {
308+ parts := []string {first }
309+ if len (rest ) == 0 {
310+ // Single remainder may itself be a shell-style one-liner.
311+ parts = strings .Fields (first )
312+ if len (parts ) == 0 {
313+ return "Usage: /mcp add <name> <url-or-command> [args...]\r \n " , nil
314+ }
315+ } else {
316+ parts = append (parts , rest ... )
317+ }
318+ server .Type = "stdio"
319+ server .Command = parts [0 ]
320+ if len (parts ) > 1 {
321+ server .Args = append (server .Args , parts [1 :]... )
322+ }
323+ }
324+
325+ r .mcpConfig .Servers [name ] = server
326+
327+ if err := r .saveMCPConfig (); err != nil {
328+ return fmt .Sprintf ("Failed to save config: %v\r \n " , err ), nil
329+ }
330+
331+ if server .Type == "stdio" {
332+ return fmt .Sprintf ("Added MCP server %s (stdio: %s)\r \n " , name , formatCommandString (append ([]string {server .Command }, server .Args ... ))), nil
333+ }
334+ return fmt .Sprintf ("Added MCP server %s (%s: %s)\r \n " , name , server .Type , server .URL ), nil
335+ }
336+
337+ // isMCPURL reports whether s looks like an http(s) URL suitable for an MCP
338+ // HTTP/SSE transport.
339+ func isMCPURL (s string ) bool {
340+ s = strings .ToLower (strings .TrimSpace (s ))
341+ return strings .HasPrefix (s , "http://" ) || strings .HasPrefix (s , "https://" )
342+ }
343+
344+ // handleMCPDel removes an MCP server from the configuration
345+ func (r * REPL ) handleMCPDel (args []string ) (string , error ) {
346+ if len (args ) == 0 {
347+ return "Usage: /mcp del <server>\r \n " , nil
348+ }
349+
350+ var output strings.Builder
351+ for _ , name := range args {
352+ if _ , exists := r .mcpConfig .Servers [name ]; ! exists {
353+ fmt .Fprintf (& output , "Server %s not found\r \n " , name )
354+ continue
355+ }
356+ _ = r .stopMCPServer (name )
357+ delete (r .mcpConfig .Servers , name )
358+ fmt .Fprintf (& output , "Removed %s\r \n " , name )
359+ }
360+
361+ if err := r .saveMCPConfig (); err != nil {
362+ fmt .Fprintf (& output , "Failed to save config: %v\r \n " , err )
363+ }
364+
365+ return output .String (), nil
366+ }
367+
271368// handleMCPStart starts MCP servers
272369func (r * REPL ) handleMCPStart (servers []string ) (string , error ) {
273370 var output strings.Builder
@@ -2245,7 +2342,10 @@ func (r *REPL) handleCompactCommand() error {
22452342 return nil
22462343}
22472344
2248- // handleToolCommand executes the mai-tool command with the given arguments
2345+ // handleToolCommand executes the mai-tool command with the given arguments.
2346+ // When mcp.transport=embed, list/call/prompts subcommands are served from the
2347+ // in-process wmcplib service so they see the same set of MCP servers managed
2348+ // by /mcp instead of the external mai-wmcp HTTP daemon.
22492349func (r * REPL ) handleToolCommand (args []string ) (string , error ) {
22502350 if len (args ) < 2 {
22512351 tools , err := GetAvailableToolsWithStatus (r .configOptions , r .agentConfig )
@@ -2254,8 +2354,48 @@ func (r *REPL) handleToolCommand(args []string) (string, error) {
22542354 }
22552355 return tools + "\n " , nil
22562356 }
2357+
2358+ subArgs := args [1 :]
2359+ if replEmbedActive (r ) {
2360+ if _ , err := embedGetService (r ); err != nil {
2361+ return "" , fmt .Errorf ("embed transport: %v" , err )
2362+ }
2363+ switch subArgs [0 ] {
2364+ case "list" :
2365+ format := Markdown
2366+ if v := strings .TrimSpace (r .configOptions .Get ("mcp.toolformat" )); v != "" && v != "?" {
2367+ format = parseToolFormat (v )
2368+ }
2369+ out , err := embedListToolsFormatted (r , format )
2370+ if err != nil {
2371+ return "" , err
2372+ }
2373+ if ! strings .HasSuffix (out , "\n " ) {
2374+ out += "\n "
2375+ }
2376+ return out , nil
2377+ case "call" :
2378+ if len (subArgs ) < 2 {
2379+ return "Usage: /tool call <name> [key=value ...]\r \n " , nil
2380+ }
2381+ out , err := embedCallToolStringArgs (r , subArgs [1 ], subArgs [2 :], 60 )
2382+ if err != nil {
2383+ return "" , err
2384+ }
2385+ if ! strings .HasSuffix (out , "\n " ) {
2386+ out += "\n "
2387+ }
2388+ return out , nil
2389+ case "prompts" :
2390+ if len (subArgs ) >= 2 && subArgs [1 ] == "list" {
2391+ return embedListPromptsSimple (r )
2392+ }
2393+ }
2394+ return fmt .Sprintf ("Subcommand '%s' not supported under mcp.transport=embed. Use /set mcp.transport=http to fall back to mai-tool.\r \n " , strings .Join (subArgs , " " )), nil
2395+ }
2396+
22572397 // Execute mai-tool directly with the provided arguments
2258- cmd := exec .Command ("mai-tool" , args [ 1 :] ... )
2398+ cmd := exec .Command ("mai-tool" , subArgs ... )
22592399 output , err := cmd .CombinedOutput ()
22602400 if err != nil {
22612401 return "" , fmt .Errorf ("mai-tool execution failed: %v\n %s" , err , string (output ))
0 commit comments