|
20 | 20 | import threading |
21 | 21 | from basic_memory.services.initialization import initialize_file_sync |
22 | 22 |
|
23 | | - |
24 | | -@app.command() |
25 | | -def mcp( |
26 | | - transport: str = typer.Option("stdio", help="Transport type: stdio, streamable-http, or sse"), |
27 | | - host: str = typer.Option( |
28 | | - "0.0.0.0", help="Host for HTTP transports (use 0.0.0.0 to allow external connections)" |
29 | | - ), |
30 | | - port: int = typer.Option(8000, help="Port for HTTP transports"), |
31 | | - path: str = typer.Option("/mcp", help="Path prefix for streamable-http transport"), |
32 | | - project: Optional[str] = typer.Option(None, help="Restrict MCP server to single project"), |
33 | | -): # pragma: no cover |
34 | | - """Run the MCP server with configurable transport options. |
35 | | -
|
36 | | - This command starts an MCP server using one of three transport options: |
37 | | -
|
38 | | - - stdio: Standard I/O (good for local usage) |
39 | | - - streamable-http: Recommended for web deployments (default) |
40 | | - - sse: Server-Sent Events (for compatibility with existing clients) |
41 | | - """ |
42 | | - |
43 | | - # Validate and set project constraint if specified |
44 | | - if project: |
45 | | - config_manager = ConfigManager() |
46 | | - project_name, _ = config_manager.get_project(project) |
47 | | - if not project_name: |
48 | | - typer.echo(f"No project found named: {project}", err=True) |
49 | | - raise typer.Exit(1) |
50 | | - |
51 | | - # Set env var with validated project name |
52 | | - os.environ["BASIC_MEMORY_MCP_PROJECT"] = project_name |
53 | | - logger.info(f"MCP server constrained to project: {project_name}") |
54 | | - |
55 | | - app_config = ConfigManager().config |
56 | | - |
57 | | - def run_file_sync(): |
58 | | - """Run file sync in a separate thread with its own event loop.""" |
59 | | - loop = asyncio.new_event_loop() |
60 | | - asyncio.set_event_loop(loop) |
61 | | - try: |
62 | | - loop.run_until_complete(initialize_file_sync(app_config)) |
63 | | - except Exception as e: |
64 | | - logger.error(f"File sync error: {e}", err=True) |
65 | | - finally: |
66 | | - loop.close() |
67 | | - |
68 | | - logger.info(f"Sync changes enabled: {app_config.sync_changes}") |
69 | | - if app_config.sync_changes: |
70 | | - # Start the sync thread |
71 | | - sync_thread = threading.Thread(target=run_file_sync, daemon=True) |
72 | | - sync_thread.start() |
73 | | - logger.info("Started file sync in background") |
74 | | - |
75 | | - # Now run the MCP server (blocks) |
76 | | - logger.info(f"Starting MCP server with {transport.upper()} transport") |
77 | | - |
78 | | - if transport == "stdio": |
79 | | - mcp_server.run( |
80 | | - transport=transport, |
81 | | - ) |
82 | | - elif transport == "streamable-http" or transport == "sse": |
83 | | - mcp_server.run( |
84 | | - transport=transport, |
85 | | - host=host, |
86 | | - port=port, |
87 | | - path=path, |
88 | | - log_level="INFO", |
89 | | - ) |
| 23 | +config = ConfigManager().config |
| 24 | + |
| 25 | +if not config.cloud_mode_enabled: |
| 26 | + |
| 27 | + @app.command() |
| 28 | + def mcp( |
| 29 | + transport: str = typer.Option( |
| 30 | + "stdio", help="Transport type: stdio, streamable-http, or sse" |
| 31 | + ), |
| 32 | + host: str = typer.Option( |
| 33 | + "0.0.0.0", help="Host for HTTP transports (use 0.0.0.0 to allow external connections)" |
| 34 | + ), |
| 35 | + port: int = typer.Option(8000, help="Port for HTTP transports"), |
| 36 | + path: str = typer.Option("/mcp", help="Path prefix for streamable-http transport"), |
| 37 | + project: Optional[str] = typer.Option(None, help="Restrict MCP server to single project"), |
| 38 | + ): # pragma: no cover |
| 39 | + """Run the MCP server with configurable transport options. |
| 40 | +
|
| 41 | + This command starts an MCP server using one of three transport options: |
| 42 | +
|
| 43 | + - stdio: Standard I/O (good for local usage) |
| 44 | + - streamable-http: Recommended for web deployments (default) |
| 45 | + - sse: Server-Sent Events (for compatibility with existing clients) |
| 46 | + """ |
| 47 | + |
| 48 | + # Validate and set project constraint if specified |
| 49 | + if project: |
| 50 | + config_manager = ConfigManager() |
| 51 | + project_name, _ = config_manager.get_project(project) |
| 52 | + if not project_name: |
| 53 | + typer.echo(f"No project found named: {project}", err=True) |
| 54 | + raise typer.Exit(1) |
| 55 | + |
| 56 | + # Set env var with validated project name |
| 57 | + os.environ["BASIC_MEMORY_MCP_PROJECT"] = project_name |
| 58 | + logger.info(f"MCP server constrained to project: {project_name}") |
| 59 | + |
| 60 | + app_config = ConfigManager().config |
| 61 | + |
| 62 | + def run_file_sync(): |
| 63 | + """Run file sync in a separate thread with its own event loop.""" |
| 64 | + loop = asyncio.new_event_loop() |
| 65 | + asyncio.set_event_loop(loop) |
| 66 | + try: |
| 67 | + loop.run_until_complete(initialize_file_sync(app_config)) |
| 68 | + except Exception as e: |
| 69 | + logger.error(f"File sync error: {e}", err=True) |
| 70 | + finally: |
| 71 | + loop.close() |
| 72 | + |
| 73 | + logger.info(f"Sync changes enabled: {app_config.sync_changes}") |
| 74 | + if app_config.sync_changes: |
| 75 | + # Start the sync thread |
| 76 | + sync_thread = threading.Thread(target=run_file_sync, daemon=True) |
| 77 | + sync_thread.start() |
| 78 | + logger.info("Started file sync in background") |
| 79 | + |
| 80 | + # Now run the MCP server (blocks) |
| 81 | + logger.info(f"Starting MCP server with {transport.upper()} transport") |
| 82 | + |
| 83 | + if transport == "stdio": |
| 84 | + mcp_server.run( |
| 85 | + transport=transport, |
| 86 | + ) |
| 87 | + elif transport == "streamable-http" or transport == "sse": |
| 88 | + mcp_server.run( |
| 89 | + transport=transport, |
| 90 | + host=host, |
| 91 | + port=port, |
| 92 | + path=path, |
| 93 | + log_level="INFO", |
| 94 | + ) |
0 commit comments