fix: make remote MCP service start reliably
Use the Python module entrypoint in the user service, prepare the MCP optional runtime before restart, and serve the configured vault path instead of the repo root. Verify binary asset resources use an octet-stream MIME type and cover service vault resolution in tests.
This commit is contained in:
@@ -35,13 +35,15 @@ class McpServiceConfigTests(unittest.TestCase):
|
||||
def test_render_service_unit_uses_http_transport_without_embedding_token(self):
|
||||
unit = manage_mcp_service.render_service_unit(
|
||||
project_root=Path("/opt/obsidian-wiki"),
|
||||
vault_path=Path("/data/bjd-vault"),
|
||||
env_file=Path("/opt/obsidian-wiki/.runtime/obsidian-wiki-mcp.env"),
|
||||
uv_path=Path("/home/nac/.local/bin/uv"),
|
||||
)
|
||||
|
||||
self.assertIn("WorkingDirectory=/opt/obsidian-wiki", unit)
|
||||
self.assertIn("EnvironmentFile=/opt/obsidian-wiki/.runtime/obsidian-wiki-mcp.env", unit)
|
||||
self.assertIn("/home/nac/.local/bin/uv run --no-sync obsidian-wiki-mcp", unit)
|
||||
self.assertIn("/home/nac/.local/bin/uv run --no-sync python -m obsidian_wiki.mcp_server", unit)
|
||||
self.assertIn("--vault /data/bjd-vault", unit)
|
||||
self.assertIn("--transport streamable-http", unit)
|
||||
self.assertIn("--host 0.0.0.0", unit)
|
||||
self.assertIn("--port 8765", unit)
|
||||
@@ -61,6 +63,25 @@ class McpServiceConfigTests(unittest.TestCase):
|
||||
self.assertEqual(stat.S_IMODE(os.stat(env_path).st_mode), 0o600)
|
||||
self.assertEqual(stat.S_IMODE(os.stat(env_path.parent).st_mode), 0o700)
|
||||
|
||||
def test_resolve_vault_for_service_uses_explicit_or_configured_vault(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
project_root = Path(tmp) / "project"
|
||||
explicit_vault = Path(tmp) / "explicit-vault"
|
||||
configured_vault = Path(tmp) / "configured-vault"
|
||||
project_root.mkdir()
|
||||
explicit_vault.mkdir()
|
||||
configured_vault.mkdir()
|
||||
|
||||
self.assertEqual(
|
||||
manage_mcp_service.resolve_vault_for_service(project_root, vault_path=explicit_vault),
|
||||
explicit_vault.resolve(),
|
||||
)
|
||||
with patch.object(manage_mcp_service, "resolve_vault_path", return_value=str(configured_vault)):
|
||||
self.assertEqual(
|
||||
manage_mcp_service.resolve_vault_for_service(project_root),
|
||||
configured_vault.resolve(),
|
||||
)
|
||||
|
||||
def test_render_remote_config_prints_client_configuration(self):
|
||||
output = manage_mcp_service.render_remote_config(
|
||||
hosts=["192.168.1.10"],
|
||||
@@ -133,17 +154,21 @@ class McpServiceConfigTests(unittest.TestCase):
|
||||
patch.object(manage_mcp_service, "generate_token") as generate_token,
|
||||
patch.object(manage_mcp_service, "detect_remote_hosts", return_value=["10.0.0.2"]),
|
||||
patch.object(manage_mcp_service, "find_uv_path", return_value=Path("/home/nac/.local/bin/uv")),
|
||||
patch.object(manage_mcp_service, "resolve_vault_for_service", return_value=Path("/data/bjd-vault")),
|
||||
patch.object(manage_mcp_service, "prepare_runtime") as prepare_runtime,
|
||||
patch.object(manage_mcp_service, "run_systemctl") as run_systemctl,
|
||||
):
|
||||
output = manage_mcp_service.start_service(project_root=project_root)
|
||||
|
||||
unit_path = config_home / "systemd" / "user" / manage_mcp_service.SERVICE_NAME
|
||||
unit_content = unit_path.read_text(encoding="utf-8")
|
||||
self.assertIn("/home/nac/.local/bin/uv run --no-sync obsidian-wiki-mcp", unit_content)
|
||||
self.assertIn("/home/nac/.local/bin/uv run --no-sync python -m obsidian_wiki.mcp_server", unit_content)
|
||||
self.assertIn("--vault /data/bjd-vault", unit_content)
|
||||
self.assertIn("EnvironmentFile=", unit_content)
|
||||
self.assertIn("http://10.0.0.2:8765/mcp", output)
|
||||
self.assertIn("Bearer saved-token", output)
|
||||
generate_token.assert_not_called()
|
||||
prepare_runtime.assert_called_once_with(project_root, uv_path=Path("/home/nac/.local/bin/uv"))
|
||||
run_systemctl.assert_has_calls(
|
||||
[
|
||||
call(["daemon-reload"]),
|
||||
@@ -162,6 +187,7 @@ class McpServiceConfigTests(unittest.TestCase):
|
||||
patch.object(manage_mcp_service, "generate_token", return_value="created-token"),
|
||||
patch.object(manage_mcp_service, "detect_remote_hosts", return_value=["10.0.0.4"]),
|
||||
patch.object(manage_mcp_service, "find_uv_path", return_value=Path("/home/nac/.local/bin/uv")),
|
||||
patch.object(manage_mcp_service, "prepare_runtime") as prepare_runtime,
|
||||
patch.object(manage_mcp_service, "run_systemctl") as run_systemctl,
|
||||
):
|
||||
output = manage_mcp_service.start_service(project_root=project_root, host="0.0.0.0", port=9876, path="/wiki-mcp")
|
||||
@@ -174,6 +200,7 @@ class McpServiceConfigTests(unittest.TestCase):
|
||||
self.assertIn("http://10.0.0.4:9876/wiki-mcp", output)
|
||||
self.assertIn("Authorization: Bearer created-token", output)
|
||||
self.assertIn('"type": "streamable-http"', output)
|
||||
prepare_runtime.assert_called_once_with(project_root, uv_path=Path("/home/nac/.local/bin/uv"))
|
||||
run_systemctl.assert_has_calls(
|
||||
[
|
||||
call(["daemon-reload"]),
|
||||
|
||||
Reference in New Issue
Block a user