|
| 1 | +# Integrating Optimizer with vMCP |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The optimizer package ingests MCP server and tool metadata into a searchable database with semantic embeddings. This enables intelligent tool discovery and token optimization for LLM consumption. |
| 6 | + |
| 7 | +## Integration Approach |
| 8 | + |
| 9 | +**Event-Driven Ingestion**: The optimizer integrates directly with vMCP's startup process. When vMCP starts and loads its configured servers, it calls the optimizer to ingest each server's metadata and tools. |
| 10 | + |
| 11 | +❌ **NOT** a separate polling service discovering backends |
| 12 | +✅ **IS** called directly by vMCP during server initialization |
| 13 | + |
| 14 | +## How It Is Integrated |
| 15 | + |
| 16 | +The optimizer is already integrated into vMCP and works automatically when enabled via configuration. Here's how the integration works: |
| 17 | + |
| 18 | +### Initialization |
| 19 | + |
| 20 | +When vMCP starts with optimizer enabled in the configuration, it: |
| 21 | + |
| 22 | +1. Initializes the optimizer database (chromem-go + SQLite FTS5) |
| 23 | +2. Configures the embedding backend (placeholder, Ollama, or vLLM) |
| 24 | +3. Sets up the ingestion service |
| 25 | + |
| 26 | +### Automatic Ingestion |
| 27 | + |
| 28 | +The optimizer integrates with vMCP's `OnRegisterSession` hook, which is called whenever: |
| 29 | + |
| 30 | +- vMCP starts and loads configured MCP servers |
| 31 | +- A new MCP server is dynamically added |
| 32 | +- A session reconnects or refreshes |
| 33 | + |
| 34 | +When this hook is triggered, the optimizer: |
| 35 | + |
| 36 | +1. Retrieves the server's metadata and tools via MCP protocol |
| 37 | +2. Generates embeddings for searchable content |
| 38 | +3. Stores the data in both the vector database (chromem-go) and FTS5 database |
| 39 | +4. Makes the tools immediately available for semantic search |
| 40 | + |
| 41 | +### Exposed Tools |
| 42 | + |
| 43 | +When the optimizer is enabled, vMCP automatically exposes these tools to LLM clients: |
| 44 | + |
| 45 | +- `optim.find_tool`: Semantic search for tools across all registered servers |
| 46 | +- `optim.call_tool`: Dynamic tool invocation after discovery |
| 47 | + |
| 48 | +### Implementation Location |
| 49 | + |
| 50 | +The integration code is located in: |
| 51 | +- `cmd/vmcp/optimizer.go`: Optimizer initialization and configuration |
| 52 | +- `pkg/vmcp/optimizer/optimizer.go`: Session registration hook implementation |
| 53 | +- `cmd/thv-operator/pkg/optimizer/ingestion/service.go`: Core ingestion service |
| 54 | + |
| 55 | +## Configuration |
| 56 | + |
| 57 | +Add optimizer configuration to vMCP's config: |
| 58 | + |
| 59 | +```yaml |
| 60 | +# vMCP config |
| 61 | +optimizer: |
| 62 | + enabled: true |
| 63 | + db_path: /data/optimizer.db |
| 64 | + embedding: |
| 65 | + backend: vllm # or "ollama" for local dev, "placeholder" for testing |
| 66 | + url: http://vllm-service:8000 |
| 67 | + model: sentence-transformers/all-MiniLM-L6-v2 |
| 68 | + dimension: 384 |
| 69 | +``` |
| 70 | +
|
| 71 | +## Error Handling |
| 72 | +
|
| 73 | +**Important**: Optimizer failures should NOT break vMCP functionality: |
| 74 | +
|
| 75 | +- ✅ Log warnings if optimizer fails |
| 76 | +- ✅ Continue server startup even if ingestion fails |
| 77 | +- ✅ Run ingestion in goroutines to avoid blocking |
| 78 | +- ❌ Don't fail server startup if optimizer is unavailable |
| 79 | +
|
| 80 | +## Benefits |
| 81 | +
|
| 82 | +1. **Automatic**: Servers are indexed as they're added to vMCP |
| 83 | +2. **Up-to-date**: Database reflects current vMCP state |
| 84 | +3. **No polling**: Event-driven, efficient |
| 85 | +4. **Semantic search**: Enables intelligent tool discovery |
| 86 | +5. **Token optimization**: Tracks token usage for LLM efficiency |
| 87 | +
|
| 88 | +## Testing |
| 89 | +
|
| 90 | +```go |
| 91 | +func TestOptimizerIntegration(t *testing.T) { |
| 92 | + // Initialize optimizer |
| 93 | + optimizerSvc, err := ingestion.NewService(&ingestion.Config{ |
| 94 | + DBConfig: &db.Config{Path: "/tmp/test-optimizer.db"}, |
| 95 | + EmbeddingConfig: &embeddings.Config{ |
| 96 | + BackendType: "ollama", |
| 97 | + BaseURL: "http://localhost:11434", |
| 98 | + Model: "all-minilm", |
| 99 | + Dimension: 384, |
| 100 | + Dimension: 384, |
| 101 | + }, |
| 102 | + }) |
| 103 | + require.NoError(t, err) |
| 104 | + defer optimizerSvc.Close() |
| 105 | + |
| 106 | + // Simulate vMCP starting a server |
| 107 | + ctx := context.Background() |
| 108 | + tools := []mcp.Tool{ |
| 109 | + {Name: "get_weather", Description: "Get current weather"}, |
| 110 | + {Name: "get_forecast", Description: "Get weather forecast"}, |
| 111 | + } |
| 112 | + |
| 113 | + err = optimizerSvc.IngestServer( |
| 114 | + ctx, |
| 115 | + "weather-001", |
| 116 | + "weather-service", |
| 117 | + "http://weather.local", |
| 118 | + models.TransportSSE, |
| 119 | + ptr("Weather information service"), |
| 120 | + tools, |
| 121 | + ) |
| 122 | + require.NoError(t, err) |
| 123 | + |
| 124 | + // Verify ingestion |
| 125 | + server, err := optimizerSvc.GetServer(ctx, "weather-001") |
| 126 | + require.NoError(t, err) |
| 127 | + assert.Equal(t, "weather-service", server.Name) |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +## See Also |
| 132 | + |
| 133 | +- [Optimizer Package README](./README.md) - Package overview and API |
| 134 | + |
0 commit comments