Skip to content

Commit 22ba7c2

Browse files
committed
refactor: overhaul mbro CLI and clean up codebase
Breaking Changes: - Remove all specific mbro CLI flags (--connect, --list-tools, --call-tool, etc.) - mbro now takes commands as positional arguments instead of flags - Use semicolons to separate multiple commands - Connect to servers with mbro shell syntax in the CLI Major improvements: - Add script execution support with -x/--execute-script flag - Support stdin input with '-' as command argument - Implement semicolon command separator for chaining commands - Add friendly path display for script listing (relative/~/absolute) - Add smart partial path matching for scripts with full basename requirement - Fix script errors to exit(1) instead of dropping to interactive mode - Add format_warning method to OutputFormatter - Logging improvements Code cleanup: - Remove ~200 useless comments throughout mbro codebase - Clean up circular import handling Documentation: - Update mbro.md to reflect new CLI interface - Update all examples to use correct syntax - Add proper command line options documentation - Update readme.md to show magg CLI commands before mbro examples - Add MBro to features list with documentation link Testing: - Add test suite for CLI overhaul - Fix test expectations for stderr vs stdout output Signed-off-by: Phillip Sitbon <phillip.sitbon@gmail.com>
1 parent b4fe375 commit 22ba7c2

37 files changed

+999
-887
lines changed

docs/mbro.md

Lines changed: 64 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,28 @@ uvx --from magg mbro
4141

4242
### Basic Usage
4343

44-
Connect to an MCP server using the `--connect` option (requires both a name and connection string):
44+
Start mbro in interactive mode:
4545
```bash
46-
# Connect to an NPX-based server
47-
mbro --connect memory "npx -y @modelcontextprotocol/server-memory"
48-
49-
# Connect to an HTTP MCP server
50-
mbro --connect magg http://localhost:8080
46+
mbro
47+
```
5148

52-
# Connect to a Python-based server
53-
mbro --connect myserver "python -m mypackage.mcp_server"
49+
Then connect to an MCP server using the `connect` command (requires both a name and connection string):
50+
```bash
51+
mbro> connect memory "npx -y @modelcontextprotocol/server-memory"
52+
mbro> connect magg http://localhost:8080
53+
mbro> connect myserver "python -m mypackage.mcp_server"
5454
```
5555

56-
Start mbro in interactive mode (without a server):
56+
Or execute commands directly from the command line:
5757
```bash
58-
mbro
58+
# Connect and list tools in one command
59+
mbro "connect calc npx @modelcontextprotocol/server-calculator; tools"
60+
61+
# Multiple commands separated by semicolons
62+
mbro "connect magg http://localhost:8080; call magg_status"
63+
64+
# Read commands from stdin
65+
echo "connect calc npx calculator; tools" | mbro -
5966
```
6067

6168
### Authentication
@@ -70,7 +77,8 @@ When connecting to HTTP servers that require bearer token authentication, mbro a
7077
export MAGG_JWT=$(magg auth token -q)
7178

7279
# Connect to authenticated server
73-
mbro --connect magg http://localhost:8080
80+
mbro
81+
mbro> connect magg http://localhost:8080
7482
```
7583

7684
### Command Examples
@@ -278,24 +286,21 @@ call tool arg1="value1" \
278286
279287
### Server Connection Strings
280288
281-
mbro supports various server connection formats with the `--connect` option (format: `--connect NAME CONNECTION`):
289+
mbro supports various server connection formats with the `connect` command:
282290
283291
```bash
284-
# NPX packages
285-
mbro --connect filesystem "npx -y @modelcontextprotocol/server-filesystem"
286-
287-
# Python modules
288-
mbro --connect myserver "python -m mypackage.mcp_server"
289-
290-
# HTTP servers
291-
mbro --connect api http://localhost:3000
292-
mbro --connect remote https://api.example.com/mcp
293-
294-
# Local executables
295-
mbro --connect local "./my-mcp-server --port 8080"
296-
297-
# UV/UVX packages
298-
mbro --connect server "uvx myserver"
292+
# In interactive mode
293+
mbro> connect filesystem npx -y @modelcontextprotocol/server-filesystem
294+
mbro> connect myserver python -m mypackage.mcp_server
295+
mbro> connect api http://localhost:3000
296+
mbro> connect remote https://api.example.com/mcp
297+
mbro> connect local ./my-mcp-server --port 8080
298+
mbro> connect server uvx myserver
299+
300+
# Or from command line
301+
mbro "connect filesystem npx -y @modelcontextprotocol/server-filesystem"
302+
mbro "connect myserver python -m mypackage.mcp_server"
303+
mbro "connect api http://localhost:3000"
299304
```
300305
301306
### Async Python REPL
@@ -304,7 +309,9 @@ For advanced users and debugging, mbro includes an async Python REPL mode that p
304309
305310
```bash
306311
# Start mbro with Python REPL mode
307-
mbro --connect myserver "npx some-server" --repl
312+
mbro --repl
313+
# Then connect to a server
314+
>>> await self.handle_command('connect myserver npx some-server')
308315
```
309316
310317
In the Python REPL, you have access to:
@@ -355,7 +362,9 @@ This allows you to use mbro to explore all tools from all servers managed by Mag
355362
### Example 1: Calculator Operations
356363
357364
```bash
358-
$ mbro --connect calc "npx -y @modelcontextprotocol/server-calculator"
365+
$ mbro
366+
mbro> connect calc npx -y @modelcontextprotocol/server-calculator
367+
Connected to 'calc' (Tools: 4, Resources: 0, Prompts: 0)
359368

360369
mbro:calc> tools
361370
Available tools:
@@ -374,15 +383,17 @@ mbro:calc> call divide {"a": 100, "b": 4}
374383
### Example 2: File System Operations
375384
376385
```bash
377-
$ mbro --connect fs "npx -y @modelcontextprotocol/server-filesystem -- --readonly /"
386+
$ mbro
387+
mbro> connect fs npx -y @modelcontextprotocol/server-filesystem -- --readonly /
388+
Connected to 'fs' (Tools: 3, Resources: 100+, Prompts: 0)
378389

379390
mbro:fs> resources
380391
Available resources:
381392
- file:///etc/hosts
382393
- file:///etc/passwd
383394
- ...
384395

385-
mbro:fs> read file:///etc/hosts
396+
mbro:fs> resource file:///etc/hosts
386397
127.0.0.1 localhost
387398
::1 localhost
388399
...
@@ -395,7 +406,9 @@ mbro:fs> read file:///etc/hosts
395406
$ magg serve --http
396407

397408
# Terminal 2: Connect mbro to Magg
398-
$ mbro --connect magg http://localhost:8000
409+
$ mbro
410+
mbro> connect magg http://localhost:8000
411+
Connected to 'magg' (Tools: 11, Resources: 5, Prompts: 2)
399412

400413
mbro:magg> tools
401414
Tool Groups:
@@ -484,37 +497,41 @@ In JSON mode:
484497
Example using JSON mode in a script:
485498
```bash
486499
# Get tools list as JSON
487-
mbro --connect calc "npx calculator" --json --list-tools | jq '.[]'
500+
mbro --json "connect calc npx calculator; tools" | jq '.'
488501

489502
# Call a tool and parse result
490-
result=$(mbro --connect calc "npx calculator" --json --call-tool add '{"a": 5, "b": 3}')
503+
result=$(mbro --json "connect calc npx calculator; call add {\"a\": 5, \"b\": 3}")
491504
echo $result | jq '.'
505+
506+
# One-liner with shell-style arguments
507+
mbro --json connect calc 'npx -y @wrtnlabs/calculator-mcp@latest' \; call add a=5 b=3 | jq
492508
```
493509
494510
## Tips and Tricks
495511
496512
1. **Tab Completion**: mbro supports tab completion for commands (not tool names)
497513
2. **JSON in Interactive Shell vs Command Line**: In the interactive shell, use JSON directly without surrounding quotes. On the command line, you may need single quotes to protect from shell parsing.
498514
3. **Multiple Connections**: You can connect to multiple servers and switch between them using the `switch` command.
499-
4. **Direct Commands**: Use command line options like `--call-tool` to execute operations without entering the interactive shell.
515+
4. **Direct Commands**: Pass commands as arguments to execute operations without entering the interactive shell.
500516
5. **Empty Arguments**: When calling tools with no arguments, you can omit the empty `{}` in the interactive shell
501517
502518
### Command Line Options
503-
- `--connect NAME CONNECTION` - Connect to a server on startup
504-
- `--json` - Output only JSON (machine-readable)
519+
- `commands` - Commands to execute (positional arguments)
520+
- `--json` / `-j` - Output only JSON (machine-readable)
521+
- `--no-rich` - Disable Rich formatting
522+
- `--indent N` - Set JSON indent level (0 for compact, default: 2)
523+
- `--verbose` / `-v` - Enable verbose output (can be used multiple times)
505524
- `--no-enhanced` - Disable enhanced features (shell-style args, multiline, etc.)
506-
- `--indent N` - Set JSON indent level (0 for compact)
507-
- `--verbose` / `-v` - Enable verbose output
508-
- `--list-tools` - List available tools
509-
- `--list-resources` - List available resources
510-
- `--list-prompts` - List available prompts
511-
- `--call-tool TOOL [ARGS]` - Call a tool directly (use quotes for JSON args on command line)
512-
- `--get-resource URI` - Get a resource directly
513-
- `--get-prompt NAME [ARGS]` - Get a prompt directly
514-
- `--search TERM` - Search tools, resources, and prompts
515-
- `--info TYPE NAME` - Show info about tool/resource/prompt
525+
- `--repl` - Drop into REPL mode on startup
526+
- `-n` / `--no-interactive` - Don't drop into interactive mode after commands
527+
- `-x SCRIPT` / `--execute-script SCRIPT` - Execute script file (can be used multiple times)
516528
- `--help` - Show help message
517529
530+
Special command line usage:
531+
- Use `-` as command to read from stdin
532+
- Use `;` to separate multiple commands
533+
- Quote commands containing spaces: `mbro "connect calc npx calculator"`
534+
518535
## Troubleshooting
519536
520537
### Common Issues

examples/config_reload.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async def demo_config_reload():
2525

2626
logger.setLevel(logging.INFO)
2727
logger.info("Starting Magg server with config reloading enabled")
28-
logger.info(f"Config path: {config_path}")
28+
logger.info("Config path: %s", config_path)
2929
logger.info("You can:")
3030
logger.info(" 1. Modify the config file to see automatic reload")
3131
logger.info(" 2. Send SIGHUP signal to trigger reload: kill -HUP %d", os.getpid())

magg/auth.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ def _load_private_key(self) -> Optional[rsa.RSAPrivateKey]:
7777
backend=default_backend()
7878
)
7979
except Exception as e:
80-
logger.error(f"Failed to load private key: {e}")
80+
logger.error("Failed to load private key: %s", e)
8181
return None
8282

8383
def _generate_keypair(self) -> Optional[rsa.RSAPrivateKey]:
8484
"""Generate new RSA keypair and save to files."""
85-
logger.debug(f"Generating new RSA keypair for audience '{self.bearer_config.audience}'")
85+
logger.debug("Generating new RSA keypair for audience %r", self.bearer_config.audience)
8686

8787
try:
8888
private_key = rsa.generate_private_key(
@@ -111,11 +111,11 @@ def _generate_keypair(self) -> Optional[rsa.RSAPrivateKey]:
111111
format=serialization.PublicFormat.OpenSSH
112112
))
113113

114-
logger.info(f"Generated new RSA keypair in {self.bearer_config.key_path}")
114+
logger.info("Generated new RSA keypair in %s", self.bearer_config.key_path)
115115
return private_key
116116

117117
except Exception as e:
118-
logger.error(f"Failed to generate keypair: {e}")
118+
logger.error("Failed to generate keypair: %s", e)
119119
return None
120120

121121
@classmethod
@@ -191,5 +191,5 @@ def create_token(self, subject: str = "dev-user", hours: int = 24,
191191
return jwt.encode(claims, self._private_key, algorithm="RS256")
192192

193193
except Exception as e:
194-
logger.error(f"Failed to create token: {e}")
194+
logger.error("Failed to create token: %s", e)
195195
return None

0 commit comments

Comments
 (0)