ManagedCode.MCPGateway exposes IMcpGatewayToolEmbeddingStore so hosts can reuse tool embeddings between index builds.
The package still needs a built-in process-local option for hosts that only want cheap embedding reuse inside one app instance, but horizontal scale, durability, and cross-replica cache coherence remain separate concerns.
The built-in McpGatewayInMemoryToolEmbeddingStore will use IMemoryCache for process-local embedding reuse, and the package will expose a dedicated AddMcpGatewayInMemoryToolEmbeddingStore() registration path that wires the store to the host's shared cache services.
Durable or distributed embedding reuse will remain the responsibility of host-provided IMcpGatewayToolEmbeddingStore implementations.
flowchart LR
Host["Host application"] --> DI["AddMcpGateway(...)"]
Host --> CacheRegistration["AddMcpGatewayInMemoryToolEmbeddingStore()"]
CacheRegistration --> MemoryCache["IMemoryCache"]
CacheRegistration --> Store["IMcpGatewayToolEmbeddingStore"]
Store --> Runtime["McpGatewayRuntime"]
Runtime --> Search["Index build / vector reuse"]
Host --> CustomStore["Custom durable store (optional)"]
CustomStore --> Runtime
Pros:
- smallest core package surface
- no opinionated local cache behavior
Cons:
- worse onboarding for hosts that only need local embedding reuse
- forces boilerplate for a very common optional scenario
Pros:
- stronger scaling story out of the box
- state can survive process restarts
Cons:
- introduces infrastructure and configuration assumptions into the core package
- forces dependency choices that belong to the host
- conflicts with the package goal of keeping embedding persistence optional
Pros:
- shared cache behavior is explicit in the package internals
- less host code for cache-backed multi-instance deployments
Cons:
- couples gateway runtime code to a specific cache family
- weakens the current abstraction boundary around
IMcpGatewayToolEmbeddingStore - makes single-instance local reuse heavier than necessary
Positive:
- the built-in store relies on a standard .NET caching primitive
- hosts can register the process-local store with one DI call and reuse the shared
IMemoryCache - process-local cache behavior stays explicitly separate from durable/distributed storage concerns
- fingerprint-agnostic lookups become deterministic by reusing the latest cached embedding for the same tool document
Trade-offs:
- the package takes a new runtime dependency on
Microsoft.Extensions.Caching.Memory - the built-in store is still process-local only and does not solve multi-instance cache sharing
- direct construction without DI now owns a private
MemoryCacheinstance and must be disposed like any other cache owner
Mitigations:
- keep
IMcpGatewayToolEmbeddingStoreas the only abstraction consumed by runtime code - document clearly that
AddMcpGatewayInMemoryToolEmbeddingStore()is for process-local reuse only - keep durable/distributed examples based on host-provided store implementations
McpGatewayRuntimeMUST continue to depend only onIMcpGatewayToolEmbeddingStore, not onIMemoryCachedirectly.McpGatewayInMemoryToolEmbeddingStoreMUST remain optional and MUST NOT become a mandatory dependency for gateway usage.AddMcpGatewayInMemoryToolEmbeddingStore()MUST register the built-in store through the hostIServiceCollectionand MUST provisionIMemoryCache.- Hosts that need cross-instance persistence or replication MUST continue to provide their own
IMcpGatewayToolEmbeddingStore. - The built-in store MUST clone vectors on read/write boundaries so callers cannot mutate cached embedding buffers in place.
Rollout:
- Add the
Microsoft.Extensions.Caching.Memorydependency to the package. - Implement
McpGatewayInMemoryToolEmbeddingStorewithIMemoryCache. - Expose
AddMcpGatewayInMemoryToolEmbeddingStore()for host DI registration. - Update README and architecture docs to distinguish process-local cache reuse from durable storage.
Rollback:
- Remove
AddMcpGatewayInMemoryToolEmbeddingStore()only if the package intentionally stops shipping a built-in process-local embedding store. - Keep
IMcpGatewayToolEmbeddingStoreas the only runtime dependency boundary unless the package intentionally adopts a different cache abstraction.
dotnet restore ManagedCode.MCPGateway.slnxdotnet build ManagedCode.MCPGateway.slnx -c Release --no-restoredotnet build ManagedCode.MCPGateway.slnx -c Release --no-restore -p:RunAnalyzers=truedotnet test --solution ManagedCode.MCPGateway.slnx -c Release --no-buildroslynator analyze src/ManagedCode.MCPGateway/ManagedCode.MCPGateway.csproj -p Configuration=Release --severity-level warningroslynator analyze tests/ManagedCode.MCPGateway.Tests/ManagedCode.MCPGateway.Tests.csproj -p Configuration=Release --severity-level warningcloc --include-lang=C# src tests
- Register
Microsoft.Extensions.Caching.Memoryas a package dependency. - Implement the built-in store with
IMemoryCachelookups keyed by tool id, document hash, and embedding fingerprint. - Keep the runtime abstraction unchanged by continuing to consume
IMcpGatewayToolEmbeddingStore. - Add tests for the cache-backed store, including deterministic fingerprint-agnostic fallback behavior.
- Update README and architecture docs so process-local cache reuse is not described as durable persistence.
- Product: the package still offers a zero-infrastructure local cache option, but durable storage remains opt-in.
- Dev: use
AddMcpGatewayInMemoryToolEmbeddingStore()when the host only needs process-local embedding reuse. - QA: verify vector reuse, clone safety, and fallback-to-latest behavior through the embedding-store tests.
- DevOps: multi-instance deployments still need a host-provided durable/distributed
IMcpGatewayToolEmbeddingStore.