17 Commits

Author SHA1 Message Date
Deluan
c7d7ec306e fix(mcp-agent): stream native mcp-server stderr to logs
The previous implementation buffered stderr from the native mcp-server process and only logged the full buffer content when the process exited. This prevented real-time viewing of logs from the server.

This change modifies the native process startup logic (`startProcess_locked`) to use `cmd.StderrPipe()` instead of assigning `cmd.Stderr` to a buffer. A separate goroutine is now launched within the process monitoring goroutine. This new goroutine uses a `bufio.Scanner` to continuously read lines from the stderr pipe and logs them using the Navidrome logger (`log.Info`) with an `[MCP-SERVER]` prefix.

This ensures logs from the native mcp-server appear in Navidrome's logs immediately as they are written.

(Note: Also includes update to McpServerPath constant to point to the native binary.)

Signed-off-by: Deluan <deluan@navidrome.org>
2025-04-19 20:53:10 -04:00
Deluan
bcc3643c81 chore: add debug logging to mcp-server
Added debug logging throughout the mcp-server components using the standard Go `log` package. All log messages are prefixed with `[MCP]` for easy identification.

This includes logging in: main function (startup, CLI execution, registration, serve loop), Tool handlers, Native and WASM fetcher implementations, Wikipedia, Wikidata, and DBpedia data fetching functions

Replaced previous `println` statements with `log.Println` or `log.Printf`.
2025-04-19 19:37:32 -04:00
Deluan
97b101685e perf: pre-compile WASM module for MCP agent
Modified the MCP agent constructor to pre-compile the WASM module when detected. This shifts the costly compilation step out of the first API request path.

The `MCPWasm` implementation now stores the `wazero.CompiledModule` provided by the constructor and uses it directly for instantiation via `runtime.InstantiateModule()` when the agent is first used or restarted. This significantly speeds up the initialization during the first request.

Updated tests and cleanup logic to accommodate the shared nature of the pre-compiled module.
2025-04-19 19:23:23 -04:00
Deluan
8660cb4fff refactor: centralize MCP agent method logic and cleanup comments
Centralized the argument preparation for GetArtistBiography and GetArtistURL within the main MCPAgent struct. Added callMCPTool to the mcpImplementation interface and removed the redundant GetArtist* methods from the native and WASM implementations.

Removed the embedded agents.Artist*Retriever interfaces from mcpImplementation as MCPAgent now directly fulfills these.

Also removed various redundant comments and leftover commented-out code from the agent, implementation, and test files.
2025-04-19 19:11:34 -04:00
Deluan
ae93e555c9 feat: refactor MCP agent to support native and WASM implementations
Refactored the MCPAgent to delegate core functionality to separate implementations for native process and WASM execution.

Introduced an `mcpImplementation` interface (`MCPNative`, `MCPWasm`) to abstract the underlying execution method. The main `MCPAgent` now holds an instance of this interface, selected by the `mcpConstructor` based on the `McpServerPath` (native executable or `.wasm` file).

Shared Wazero resources (runtime, cache, WASI, host functions) are now initialized once in the constructor and passed to the `MCPWasm` implementation, improving resource management and potentially startup performance for WASM modules.

Updated tests (`mcp_agent_test.go`) to use a new testing constructor (`NewAgentForTesting`) which injects a mock client into the appropriate implementation. Assertions were adjusted to reflect the refactored error handling and structure. Also updated the `McpServerPath` to use a relative path.
2025-04-19 19:05:15 -04:00
Deluan
2f71516dde fix: update MCP server path for agent initialization
Change the MCP server path in MCPAgent to point to the correct relative directory for the WASM file. This adjustment ensures proper initialization and access to the server resources, aligning with recent enhancements in the MCPAgent's handling of server types.
2025-04-19 18:43:50 -04:00
Deluan
73da7550d6 refactor: separate native and WASM process handling in MCPAgent
- Moved the native process handling logic from mcp_agent.go to a new file mcp_process_native.go for better organization.
- Introduced a new file mcp_host_functions.go to define and register host functions for WASM modules.
- Updated MCPAgent to ensure proper initialization and cleanup of both native and WASM processes, enhancing code clarity and maintainability.
- Added comments to clarify the purpose of changes and ensure future developers understand the structure.
2025-04-19 15:22:15 -04:00
Deluan
674129a34b fix: update MCP server path for agent initialization
Change the MCP server path in MCPAgent from a WASM file to a directory. This adjustment aligns with recent enhancements to the MCPAgent's handling of server types, ensuring proper initialization and access to the server resources.
2025-04-19 14:48:18 -04:00
Deluan
fb0714562d feat: grant filesystem access for WASM modules in MCPAgent
Enhance the MCPAgent's WASM module initialization by granting access to the host filesystem. This is necessary for DNS lookups and other operations that may depend on filesystem access. Added comments to highlight the security implications of this change and the need for potential restrictions in the future.
2025-04-19 14:46:54 -04:00
Deluan
6b89f7ab63 feat: integrate Wazero for WASM support in MCPAgent
Enhance MCPAgent to support both native executables and WASM modules using Wazero. This includes:
- Adding Wazero dependencies in go.mod and go.sum.
- Modifying MCPAgent to initialize a shared Wazero runtime and compile/load WASM modules.
- Implementing cleanup logic for WASM resources.
- Updating the process initialization to handle both native and WASM paths.

This change improves the flexibility of the MCPAgent in handling different server types.
2025-04-19 14:28:55 -04:00
Deluan
c548168503 fix: handle error messages returned in MCP tool response content
Modify callMCPTool helper to check if the text content returned by\nthe MCP server starts with 'handler returned an error:'.\n\nIf it does, log a warning and return agents.ErrNotFound, treating\nthe error signaled by the external tool as if the data was not found.\nAdded test cases to verify this behavior.
2025-04-19 14:01:51 -04:00
Deluan
8ebefe4065 refactor: DRY up MCPAgent implementation
Refactor the MCPAgent to reduce code duplication.\n\n- Consolidate GetArtistBiographyArgs and GetArtistURLArgs into a single\n  ArtistArgs struct.\n- Extract common logic (initialization check, locking, tool calling,\n  error handling, response validation) into a private callMCPTool helper method.\n- Simplify GetArtistBiography and GetArtistURL to delegate to callMCPTool.\n- Update tests to use the consolidated ArtistArgs struct.\n- Correct mutex locking in ensureClientInitialized to prevent race conditions.
2025-04-19 13:04:41 -04:00
Deluan
be9e10db37 test: add mock-based tests for MCPAgent
Implement unit tests for MCPAgent using a mocked MCP client.\n\n- Define an mcpClient interface and a mock implementation in the test file.\n- Modify MCPAgent to use the interface and add an exported ClientOverride field\n  to allow injecting the mock during tests.\n- Export necessary constants and argument structs from the agent package.\n- Add test cases covering success, tool errors, empty responses, and pipe errors\n  for both GetArtistBiography and GetArtistURL.\n- Fix agent logic to handle empty TextContent in responses correctly.\n- Remove previous placeholder tests and unreliable initialization test.
2025-04-19 12:56:22 -04:00
Deluan
9c20520d59 feat: implement GetArtistURL in MCP agent
Add support for retrieving artist URLs via the MCP agent.\n\n- Implement the agents.ArtistURLRetriever interface.\n- Add the GetArtistURL method, which calls the 'get_artist_url'\n  tool on the external MCP server.\n- Define the necessary constants and argument struct.\n\nThis mirrors the existing implementation for GetArtistBiography, reusing\nthe persistent process and client logic.
2025-04-19 12:48:27 -04:00
Deluan
8b754a7c73 feat: implement MCP agent process auto-restart
Modify the MCPAgent to automatically attempt restarting the external\nserver process if it detects the process has exited.\n\n- Replaced sync.Once with mutex-protected checks (a.client == nil) to allow\n  re-initialization.\n- The monitoring goroutine now cleans up agent state (nils client, cmd, stdin)\n  upon process exit, signaling the need for restart.\n- ensureClientInitialized now attempts to start/initialize if the client is nil.\n- GetArtistBiography checks client validity again after locking to handle race\n  conditions where the process might die just after initialization check.
2025-04-19 12:45:41 -04:00
Deluan
8326a20eda refactor: keep MCP agent server process running
Refactor MCPAgent to maintain a persistent external server process.\n\nInstead of starting and stopping the MCP server for each request, the agent\nnow uses sync.Once for lazy initialization on the first call.\nIt stores the running exec.Cmd, stdio pipes, and the mcp.Client\nin the agent struct.\n\nA sync.Mutex protects concurrent access to the client/pipes.\nA goroutine monitors the process using cmd.Wait() and logs if it exits\nunexpectedly.\n\nThis avoids the overhead of process creation/destruction on every\nmetadata retrieval request.
2025-04-19 12:04:39 -04:00
Deluan
51567a0bdf feat: add proof-of-concept MCP agent
Add a new agent implementation MCPAgent in core/agents/mcp.\n\nThis agent interacts with an external Model Context Protocol (MCP) server\nusing the github.com/metoro-io/mcp-golang library via stdio.\n\nIt currently implements the ArtistBiographyRetriever interface to fetch\nbiographies by calling the 'get_artist_biography' tool on the MCP server.\nThe path to the MCP server executable is hardcoded for this PoC.\n\nIncludes basic Ginkgo test setup for the new agent.
2025-04-19 11:59:34 -04:00