mcpdiscovery

package
v1.12.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package mcpdiscovery holds the database-backed MCP discovery stores a deployment hands the manager (schemas.MCPConfig): SharedStore for clients without per_user_discovery and PerUserStore for clients with it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type PerUserStore

type PerUserStore struct {
	// contains filtered or unexported fields
}

PerUserStore keeps the discoveries of MCP clients with per_user_discovery on: one per caller (a user or a virtual key) and client, persisted in mcp_per_user_discoveries, which is the source of truth, and served from memory. Writes go to the database before they change what this process serves.

The caller is resolved off ctx exactly as the per-user credential lookup resolves it, so a discovery written with the ctx its credential was looked up with lands under that credential's identity.

Each process keeps two things per client: the set of callers that hold a discovery on it, with each one's discovery hash, loaded from the database the first time the client is read; and a bounded cache of the distinct discoveries those callers hold, keyed by (client, hash), so callers holding the same discovery share one copy. A caller outside the set has no discovery and costs no database read, and a member is served the copy cached under the hash the set records for it. The set changes on this process's own writes and deletes, on another process's (delivered through EvictDiscovery), and is reloaded from the database once it is older than membershipRefreshInterval, which corrects a process that missed one. A cached copy no member's hash names any more is never served again, and ages out of the cache.

All methods are safe on a nil receiver: reads miss and writes are refused.

func NewPerUserStore

func NewPerUserStore(configStore configstore.ConfigStore, logger schemas.Logger) *PerUserStore

NewPerUserStore returns a PerUserStore reading and writing through configStore. A nil configStore leaves every caller with no per-user discovery.

func (*PerUserStore) DeleteDiscovery

func (s *PerUserStore) DeleteDiscovery(ctx context.Context, client *schemas.MCPClientConfig) error

DeleteDiscovery removes the caller's discovery for client. A ctx with no user or virtual-key caller is refused before any I/O.

func (*PerUserStore) EvictDiscoveriesByMCPClient

func (s *PerUserStore) EvictDiscoveriesByMCPClient(mcpClientID string)

EvictDiscoveriesByMCPClient forgets one client: its set and every cached discovery of it. Its next read loads it again. Used when the client is removed, or every discovery of it is.

func (*PerUserStore) EvictDiscoveriesByUser

func (s *PerUserStore) EvictDiscoveriesByUser(userID string)

EvictDiscoveriesByUser makes every user-mode discovery of one user, across clients, read again, the same way as EvictDiscoveriesByVirtualKey.

func (*PerUserStore) EvictDiscoveriesByVirtualKey

func (s *PerUserStore) EvictDiscoveriesByVirtualKey(virtualKeyID string)

EvictDiscoveriesByVirtualKey makes every vk-mode discovery of one virtual key, across clients, read again: its next read of each checks the database. A deleted key's rows are gone, and a key that only changed keeps its discoveries. See forgetHashes.

func (*PerUserStore) EvictDiscovery

func (s *PerUserStore) EvictDiscovery(mode schemas.MCPAuthMode, identity, mcpClientID string)

EvictDiscovery applies another process's write or delete of one binding: the caller is kept in the client's set with no hash, so its next read checks the database. Deletes are not taken out of the set directly: messages from two processes can arrive in another order than their writes landed, and a delete applied after a later write would hide a discovery the database has until the next refresh. Cached copies stay for the other callers holding them.

func (*PerUserStore) FlushDiscoveryCache

func (s *PerUserStore) FlushDiscoveryCache()

FlushDiscoveryCache forgets every client and every cached discovery.

func (*PerUserStore) GetDiscovery

func (s *PerUserStore) GetDiscovery(ctx context.Context, client *schemas.MCPClientConfig) *schemas.MCPDiscovery

GetDiscovery returns the caller's discovery for client, with tool names prefixed by the client's current name. A caller outside the client's set gets nil without a database read. Callers holding the same discovery are served one cached copy of it (see discoveryOf). A read error is logged and answered with nil, so the caller sees no tools rather than someone else's.

func (*PerUserStore) SetDiscovery

func (s *PerUserStore) SetDiscovery(ctx context.Context, client *schemas.MCPClientConfig, discovery *schemas.MCPDiscovery) error

SetDiscovery replaces the caller's discovery for client. Tool names are stored without the client prefix. A ctx with no user or virtual-key caller is refused before any I/O.

func (*PerUserStore) SetOnDiscoveryWritten

func (s *PerUserStore) SetOnDiscoveryWritten(cb func(ctx context.Context, mode schemas.MCPAuthMode, identity, mcpClientID string))

SetOnDiscoveryWritten registers a callback run after this store writes or deletes a discovery, once this process's own copy reflects it. That reaches only this process; a deployment running several processes over one database uses the callback to have the others apply EvictDiscovery too. The callback runs inline on the write path, so it must return promptly. nil clears it.

type SharedStore

type SharedStore struct {
	// contains filtered or unexported fields
}

SharedStore keeps the discoveries of MCP clients without per_user_discovery: one per client, served to every caller from memory, which is the source of truth, and written to the client's row so a restart and the admin API find them.

The manager calls it while holding its own lock, so nothing here waits on the database. SetDiscovery records the discovery and hands the write to a background writer, one per client, which writes the latest discovery it has been handed, skips one whose content the row already holds, and retries a failed write. A discovery with no DiscoveredAt was not produced by an upstream tools/list (the manager restored it from the row), so it is taken as what the row holds: it is not written, and a write handed over before it is dropped.

All methods are safe on a nil receiver: reads miss and writes are refused.

func NewSharedStore

func NewSharedStore(configStore configstore.ConfigStore, logger schemas.Logger) *SharedStore

NewSharedStore returns a SharedStore writing through configStore. A nil configStore keeps discoveries in memory only.

func (*SharedStore) DeleteDiscovery

func (s *SharedStore) DeleteDiscovery(_ context.Context, client *schemas.MCPClientConfig) error

DeleteDiscovery forgets client's discovery; ctx is ignored. The row is left as it is: a disabled client is restored from it when re-enabled, and a removed client's row goes with the client. A write already handed to the writer still lands, but is not retried once it fails.

func (*SharedStore) GetDiscovery

func (s *SharedStore) GetDiscovery(_ context.Context, client *schemas.MCPClientConfig) *schemas.MCPDiscovery

GetDiscovery returns client's discovery; ctx is ignored.

func (*SharedStore) SetDiscovery

func (s *SharedStore) SetDiscovery(_ context.Context, client *schemas.MCPClientConfig, discovery *schemas.MCPDiscovery) error

SetDiscovery replaces client's discovery and, unless it was restored, queues it to be written to the client's row; ctx is ignored. It never waits on the database.

func (*SharedStore) SetWriteGate

func (s *SharedStore) SetWriteGate(allow func() bool)

SetWriteGate registers allow, asked before every write to a client's row; a write it refuses is skipped, and the client's next discovery tries again. Every process discovers the same tools for a shared client, so a deployment running several processes over one database can leave the writes to one of them. nil clears it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL