|
17 | 17 | import basic_memory.mcp.prompts # noqa: F401 # pragma: no cover |
18 | 18 | from loguru import logger |
19 | 19 |
|
20 | | -config = ConfigManager().config |
21 | | - |
22 | | -if not config.cloud_mode_enabled: |
23 | | - |
24 | | - @app.command() |
25 | | - def mcp( |
26 | | - transport: str = typer.Option( |
27 | | - "stdio", help="Transport type: stdio, streamable-http, or sse" |
28 | | - ), |
29 | | - host: str = typer.Option( |
30 | | - "0.0.0.0", help="Host for HTTP transports (use 0.0.0.0 to allow external connections)" |
31 | | - ), |
32 | | - port: int = typer.Option(8000, help="Port for HTTP transports"), |
33 | | - path: str = typer.Option("/mcp", help="Path prefix for streamable-http transport"), |
34 | | - project: Optional[str] = typer.Option(None, help="Restrict MCP server to single project"), |
35 | | - ): # pragma: no cover |
36 | | - """Run the MCP server with configurable transport options. |
37 | | -
|
38 | | - This command starts an MCP server using one of three transport options: |
39 | | -
|
40 | | - - stdio: Standard I/O (good for local usage) |
41 | | - - streamable-http: Recommended for web deployments (default) |
42 | | - - sse: Server-Sent Events (for compatibility with existing clients) |
43 | | -
|
44 | | - Initialization, file sync, and cleanup are handled by the MCP server's lifespan. |
45 | | - """ |
46 | | - # Initialize logging for MCP (file only, stdout breaks protocol) |
47 | | - init_mcp_logging() |
48 | | - |
49 | | - # Validate and set project constraint if specified |
50 | | - if project: |
51 | | - config_manager = ConfigManager() |
52 | | - project_name, _ = config_manager.get_project(project) |
53 | | - if not project_name: |
54 | | - typer.echo(f"No project found named: {project}", err=True) |
55 | | - raise typer.Exit(1) |
56 | | - |
57 | | - # Set env var with validated project name |
58 | | - os.environ["BASIC_MEMORY_MCP_PROJECT"] = project_name |
59 | | - logger.info(f"MCP server constrained to project: {project_name}") |
60 | | - |
61 | | - # Run the MCP server (blocks) |
62 | | - # Lifespan handles: initialization, migrations, file sync, cleanup |
63 | | - logger.info(f"Starting MCP server with {transport.upper()} transport") |
64 | | - |
65 | | - if transport == "stdio": |
66 | | - mcp_server.run( |
67 | | - transport=transport, |
68 | | - ) |
69 | | - elif transport == "streamable-http" or transport == "sse": |
70 | | - mcp_server.run( |
71 | | - transport=transport, |
72 | | - host=host, |
73 | | - port=port, |
74 | | - path=path, |
75 | | - log_level="INFO", |
76 | | - ) |
| 20 | + |
| 21 | +@app.command() |
| 22 | +def mcp( |
| 23 | + transport: str = typer.Option("stdio", help="Transport type: stdio, streamable-http, or sse"), |
| 24 | + host: str = typer.Option( |
| 25 | + "0.0.0.0", help="Host for HTTP transports (use 0.0.0.0 to allow external connections)" |
| 26 | + ), |
| 27 | + port: int = typer.Option(8000, help="Port for HTTP transports"), |
| 28 | + path: str = typer.Option("/mcp", help="Path prefix for streamable-http transport"), |
| 29 | + project: Optional[str] = typer.Option(None, help="Restrict MCP server to single project"), |
| 30 | +): # pragma: no cover |
| 31 | + """Run the MCP server with configurable transport options. |
| 32 | +
|
| 33 | + This command starts an MCP server using one of three transport options: |
| 34 | +
|
| 35 | + - stdio: Standard I/O (good for local usage) |
| 36 | + - streamable-http: Recommended for web deployments (default) |
| 37 | + - sse: Server-Sent Events (for compatibility with existing clients) |
| 38 | +
|
| 39 | + Initialization, file sync, and cleanup are handled by the MCP server's lifespan. |
| 40 | +
|
| 41 | + Note: This command is available regardless of cloud mode setting. |
| 42 | + Users who have cloud mode enabled can still use local MCP for Claude Code |
| 43 | + and Claude Desktop while using cloud MCP for web and mobile access. |
| 44 | + """ |
| 45 | + # Force local routing for local MCP server |
| 46 | + # Why: The local MCP server should always talk to the local API, not the cloud proxy. |
| 47 | + # Even when cloud_mode_enabled is True, stdio MCP runs locally and needs local API access. |
| 48 | + os.environ["BASIC_MEMORY_FORCE_LOCAL"] = "true" |
| 49 | + |
| 50 | + # Initialize logging for MCP (file only, stdout breaks protocol) |
| 51 | + init_mcp_logging() |
| 52 | + |
| 53 | + # Validate and set project constraint if specified |
| 54 | + if project: |
| 55 | + config_manager = ConfigManager() |
| 56 | + project_name, _ = config_manager.get_project(project) |
| 57 | + if not project_name: |
| 58 | + typer.echo(f"No project found named: {project}", err=True) |
| 59 | + raise typer.Exit(1) |
| 60 | + |
| 61 | + # Set env var with validated project name |
| 62 | + os.environ["BASIC_MEMORY_MCP_PROJECT"] = project_name |
| 63 | + logger.info(f"MCP server constrained to project: {project_name}") |
| 64 | + |
| 65 | + # Run the MCP server (blocks) |
| 66 | + # Lifespan handles: initialization, migrations, file sync, cleanup |
| 67 | + logger.info(f"Starting MCP server with {transport.upper()} transport") |
| 68 | + |
| 69 | + if transport == "stdio": |
| 70 | + mcp_server.run( |
| 71 | + transport=transport, |
| 72 | + ) |
| 73 | + elif transport == "streamable-http" or transport == "sse": |
| 74 | + mcp_server.run( |
| 75 | + transport=transport, |
| 76 | + host=host, |
| 77 | + port=port, |
| 78 | + path=path, |
| 79 | + log_level="INFO", |
| 80 | + ) |
0 commit comments