mcp-browser/mcp_browser/__main__.py

155 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""
MCP Browser command-line interface.
"""
import sys
import asyncio
import argparse
import json
from pathlib import Path
from .proxy import MCPBrowser
async def interactive_mode(browser: MCPBrowser):
"""Run MCP Browser in interactive mode."""
print("MCP Browser Interactive Mode")
print("Type 'help' for commands, 'exit' to quit\n")
while True:
try:
command = input("> ").strip()
if command == "exit":
break
elif command == "help":
print("\nCommands:")
print(" list - List available tools (sparse mode)")
print(" discover <path> - Discover tools using JSONPath")
print(" call <json> - Execute JSON-RPC call")
print(" onboard <id> - Get onboarding for identity")
print(" exit - Exit interactive mode")
print("\nExamples:")
print(' discover $.tools[*].name')
print(' call {"method": "tools/list"}')
print(' onboard MyProject')
continue
elif command.startswith("discover "):
jsonpath = command[9:]
result = browser.discover(jsonpath)
print(json.dumps(result, indent=2))
elif command.startswith("call "):
json_str = command[5:]
request = json.loads(json_str)
if "jsonrpc" not in request:
request["jsonrpc"] = "2.0"
response = await browser.call(request)
print(json.dumps(response, indent=2))
elif command.startswith("onboard "):
identity = command[8:]
response = await browser.call({
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "onboarding",
"arguments": {"identity": identity}
}
})
if "result" in response:
print(response["result"]["content"][0]["text"])
elif command == "list":
response = await browser.call({
"jsonrpc": "2.0",
"method": "tools/list"
})
if "result" in response:
tools = response["result"]["tools"]
for tool in tools:
print(f"- {tool['name']}: {tool['description']}")
else:
print("Unknown command. Type 'help' for available commands.")
except KeyboardInterrupt:
print("\nUse 'exit' to quit")
except Exception as e:
print(f"Error: {e}")
async def run_server_mode(browser: MCPBrowser):
"""Run MCP Browser as an MCP server (stdin/stdout)."""
import sys
await browser.initialize()
# Read JSON-RPC from stdin, write to stdout
buffer = ""
while True:
try:
chunk = sys.stdin.read(4096)
if not chunk:
break
buffer += chunk
while '\n' in buffer:
line, buffer = buffer.split('\n', 1)
if line.strip():
try:
request = json.loads(line)
response = await browser.call(request)
print(json.dumps(response))
sys.stdout.flush()
except json.JSONDecodeError:
pass
except KeyboardInterrupt:
break
except EOFError:
break
def main():
"""Main entry point."""
parser = argparse.ArgumentParser(description="MCP Browser - Generic MCP interface")
parser.add_argument("--server", "-s", help="Target MCP server name")
parser.add_argument("--config", "-c", help="Configuration file path")
parser.add_argument("--mode", choices=["interactive", "server"],
default="interactive", help="Operating mode")
parser.add_argument("--no-sparse", action="store_true",
help="Disable sparse mode")
parser.add_argument("--no-builtin", action="store_true",
help="Disable built-in servers")
args = parser.parse_args()
# Create browser
browser = MCPBrowser(
server_name=args.server,
config_path=args.config,
sparse_mode=not args.no_sparse,
enable_builtin=not args.no_builtin
)
# Run in appropriate mode
if args.mode == "server":
asyncio.run(run_server_mode(browser))
else:
asyncio.run(async_main(browser))
async def async_main(browser: MCPBrowser):
"""Async main for interactive mode."""
try:
await browser.initialize()
await interactive_mode(browser)
finally:
await browser.close()
if __name__ == "__main__":
main()