Depends on: #3732
Context
Issue #3732 introduces the EmbeddingClient interface and hybrid search backed by a fake/stub implementation. This issue replaces the stub with a real embedding client that calls the EmbeddingServer custom resource, enabling true semantic tool discovery in production.
Prototype reference: #3517 (see server integration and CLI wiring)
Requirements
- Implement the
EmbeddingClient interface with a real HTTP client that calls the EmbeddingServer custom resource endpoint.
- Push the use of the
EmbeddingClient into the database layer (the ToolStore SQLite implementation). The database is responsible for calling the embedding client at ingestion time and storing the resulting vectors. If an item already exists in the database with embeddings, no re-embedding is needed — the database acts as the cache.
- Wire the real client into the optimizer factory in
cmd/vmcp/app/commands.go, configured via OptimizerConfig fields (pkg/vmcp/config/config.go).
- Add configuration fields for the EmbeddingServer URL and embedding dimensions to
OptimizerConfig.
- If the EmbeddingServer is unavailable, the optimizer should fail — no graceful degradation or fallback.
- Update the existing e2e test that enables the optimizer (
test/e2e/thv-operator/virtualmcp/virtualmcp_optimizer_test.go) so it passes with the real embedding client wired in.
High-Level Implementation
- Create a real
EmbeddingClient implementation under pkg/vmcp/optimizer/internal/embeddings/ that calls the EmbeddingServer endpoint
- Update the SQLite
ToolStore implementation to accept an EmbeddingClient dependency. At tool ingestion time, the store calls the client to generate embeddings and persists them alongside the tool record. On lookup, embeddings are already present in the database.
- Extend
OptimizerConfig with fields for the EmbeddingServer URL and embedding dimensions
- Update the factory setup in
cmd/vmcp/app/commands.go to instantiate the real client from config and pass it to the ToolStore
- Update the existing e2e optimizer test to exercise the full path with a real EmbeddingServer
Acceptance Tests
Depends on: #3732
Context
Issue #3732 introduces the
EmbeddingClientinterface and hybrid search backed by a fake/stub implementation. This issue replaces the stub with a real embedding client that calls theEmbeddingServercustom resource, enabling true semantic tool discovery in production.Prototype reference: #3517 (see server integration and CLI wiring)
Requirements
EmbeddingClientinterface with a real HTTP client that calls theEmbeddingServercustom resource endpoint.EmbeddingClientinto the database layer (theToolStoreSQLite implementation). The database is responsible for calling the embedding client at ingestion time and storing the resulting vectors. If an item already exists in the database with embeddings, no re-embedding is needed — the database acts as the cache.cmd/vmcp/app/commands.go, configured viaOptimizerConfigfields (pkg/vmcp/config/config.go).OptimizerConfig.test/e2e/thv-operator/virtualmcp/virtualmcp_optimizer_test.go) so it passes with the real embedding client wired in.High-Level Implementation
EmbeddingClientimplementation underpkg/vmcp/optimizer/internal/embeddings/that calls the EmbeddingServer endpointToolStoreimplementation to accept anEmbeddingClientdependency. At tool ingestion time, the store calls the client to generate embeddings and persists them alongside the tool record. On lookup, embeddings are already present in the database.OptimizerConfigwith fields for the EmbeddingServer URL and embedding dimensionscmd/vmcp/app/commands.goto instantiate the real client from config and pass it to theToolStoreAcceptance Tests
ToolStoreand stored in SQLite; subsequent lookups use the persisted embeddings without re-calling the EmbeddingServerFindTool("manage GitHub pull requests")returns semantically relevant tools even when those exact words don't appear in tool descriptionstest/e2e/thv-operator/virtualmcp/virtualmcp_optimizer_test.gois updated and passes