mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-12 08:14:06 +00:00
602 lines
21 KiB
Go
602 lines
21 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
mcpbridge "github.com/nextlevelbuilder/goclaw/internal/mcp"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// ---- mock helpers for getUserMCPTools OAuth tests ----
|
|
|
|
// minimalMCPServerStore implements store.MCPServerStore with panics for all
|
|
// methods except GetUserCredentials, which is the only method called in
|
|
// getUserMCPTools.
|
|
type minimalMCPServerStore struct {
|
|
userCreds *store.MCPUserCredentials
|
|
userCredsErr error
|
|
getUserCredsCalls int
|
|
}
|
|
|
|
func (m *minimalMCPServerStore) GetUserCredentials(_ context.Context, _ uuid.UUID, _ string) (*store.MCPUserCredentials, error) {
|
|
m.getUserCredsCalls++
|
|
return m.userCreds, m.userCredsErr
|
|
}
|
|
|
|
func (m *minimalMCPServerStore) CreateServer(_ context.Context, _ *store.MCPServerData) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) GetServer(_ context.Context, _ uuid.UUID) (*store.MCPServerData, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) GetServerByName(_ context.Context, _ string) (*store.MCPServerData, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) ListServers(_ context.Context) ([]store.MCPServerData, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) UpdateServer(_ context.Context, _ uuid.UUID, _ map[string]any) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) DeleteServer(_ context.Context, _ uuid.UUID) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) GrantToAgent(_ context.Context, _ *store.MCPAgentGrant) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) RevokeFromAgent(_ context.Context, _, _ uuid.UUID) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) ListAgentGrants(_ context.Context, _ uuid.UUID) ([]store.MCPAgentGrant, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) ListServerGrants(_ context.Context, _ uuid.UUID) ([]store.MCPAgentGrant, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) GrantToUser(_ context.Context, _ *store.MCPUserGrant) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) RevokeFromUser(_ context.Context, _ uuid.UUID, _ string) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) CountAgentGrantsByServer(_ context.Context) (map[uuid.UUID]int, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) ListAccessible(_ context.Context, _ uuid.UUID, _ string) ([]store.MCPAccessInfo, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) CreateRequest(_ context.Context, _ *store.MCPAccessRequest) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) ListPendingRequests(_ context.Context) ([]store.MCPAccessRequest, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) ReviewRequest(_ context.Context, _ uuid.UUID, _ bool, _, _ string) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) SetUserCredentials(_ context.Context, _ uuid.UUID, _ string, _ store.MCPUserCredentials) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) DeleteUserCredentials(_ context.Context, _ uuid.UUID, _ string) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *minimalMCPServerStore) CacheToolDescriptions(_ context.Context, _ uuid.UUID, _ map[string]store.CachedToolInfo) error {
|
|
return nil
|
|
}
|
|
|
|
// recordingOAuthProvider records calls to GetValidToken for assertion.
|
|
type recordingOAuthProvider struct {
|
|
mu sync.Mutex
|
|
callCount int
|
|
returnToken string
|
|
returnErr error
|
|
}
|
|
|
|
func (r *recordingOAuthProvider) GetValidToken(_ context.Context, _ uuid.UUID, _ uuid.UUID, _ string) (string, error) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.callCount++
|
|
return r.returnToken, r.returnErr
|
|
}
|
|
|
|
// newTestPool creates a real *mcpbridge.Pool with short timeouts for unit tests.
|
|
// The pool's AcquireUser will fail (no real MCP server), but token injection
|
|
// happens before the pool call.
|
|
func newTestPool(t *testing.T) *mcpbridge.Pool {
|
|
t.Helper()
|
|
pool := mcpbridge.NewPool(mcpbridge.PoolConfig{
|
|
MaxSize: 10,
|
|
UserAcquireTimeout: 10 * time.Millisecond,
|
|
})
|
|
t.Cleanup(func() { pool.Stop() })
|
|
return pool
|
|
}
|
|
|
|
// oauthSettings returns JSON settings with auth_type: oauth.
|
|
func oauthSettings() json.RawMessage {
|
|
return json.RawMessage(`{"oauth":{"auth_type":"oauth"}}`)
|
|
}
|
|
|
|
// oauthServerData returns a minimal MCPServerData for an OAuth-configured HTTP
|
|
// server. Transport=http + unreachable URL causes AcquireUser to fail quickly
|
|
// (connection refused) without panicking — unlike stdio with empty command
|
|
// which would spawn a goroutine reading from a nil pipe.
|
|
func oauthServerData() store.MCPServerData {
|
|
return store.MCPServerData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "oauth-server-" + uuid.New().String()[:8],
|
|
Transport: "http",
|
|
URL: "http://127.0.0.1:1", // port 1 = connection refused immediately
|
|
Settings: oauthSettings(),
|
|
}
|
|
}
|
|
|
|
// TestResolveActorUserID locks the actor-vs-context user-id resolution semantics
|
|
// that gate per-user MCP credential lookup (and other per-actor resources).
|
|
//
|
|
// Two bugs this helper fixes:
|
|
//
|
|
// 1. Group chats: gateway consumer rewrites UserID to a group-scope composite
|
|
// ("group:<channel>:<chatID>") for shared memory. The Bitrix24 provisioner
|
|
// stores MCPUserCredentials keyed by the real external user id (= SenderID).
|
|
// Lookup with group composite always missed → MCP tools silently absent.
|
|
//
|
|
// 2. DM with merged contact (C1): gateway consumer rewrites DM UserID to the
|
|
// tenant_user UUID when ContactCollector.ResolveTenantUserID succeeds.
|
|
// Provisioner still stores by SenderID. Lookup with UUID misses → MCP
|
|
// tools fail in DMs after contact merge.
|
|
//
|
|
// resolveActorUserID accepts channelType so Bitrix24 always recovers SenderID
|
|
// (covers both rewrite cases). Other channels retain group-only recovery.
|
|
func TestResolveActorUserID(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
userID string
|
|
senderID string
|
|
peerKind string
|
|
channelType string
|
|
want string
|
|
}{
|
|
// DM unmerged: UserID == SenderID. No rewrite happened.
|
|
{
|
|
name: "dm_returns_user_id_unchanged",
|
|
userID: "99",
|
|
senderID: "99",
|
|
peerKind: "direct",
|
|
channelType: "",
|
|
want: "99",
|
|
},
|
|
// Group: gateway overrides UserID with group composite for shared
|
|
// memory. Helper must recover SenderID for actor-scoped lookups.
|
|
{
|
|
name: "group_overrides_to_sender",
|
|
userID: "group:bitrix-synity:chat4838",
|
|
senderID: "99",
|
|
peerKind: "group",
|
|
channelType: "",
|
|
want: "99",
|
|
},
|
|
// Discord guild composite ("guild:<id>:user:<sender>") is also a
|
|
// group peer — fall back to SenderID for credential lookup.
|
|
{
|
|
name: "discord_guild_overrides_to_sender",
|
|
userID: "guild:1234:user:5678",
|
|
senderID: "5678",
|
|
peerKind: "group",
|
|
channelType: "",
|
|
want: "5678",
|
|
},
|
|
// Synthetic / system senders (ticker, notification) carry empty
|
|
// SenderID. No per-user credentials exist for them — fall back to
|
|
// UserID so the lookup still uses a sensible key.
|
|
{
|
|
name: "group_with_empty_sender_falls_back_to_user_id",
|
|
userID: "group:bitrix-synity:chat4838",
|
|
senderID: "",
|
|
peerKind: "group",
|
|
channelType: "",
|
|
want: "group:bitrix-synity:chat4838",
|
|
},
|
|
// Empty peer_kind defaults to direct semantics.
|
|
{
|
|
name: "empty_peer_kind_treated_as_direct",
|
|
userID: "99",
|
|
senderID: "99",
|
|
peerKind: "",
|
|
channelType: "",
|
|
want: "99",
|
|
},
|
|
// Future channel using a peer_kind we don't recognize must NOT be
|
|
// treated as group automatically — DM semantics are the safer
|
|
// default (no override).
|
|
{
|
|
name: "unknown_peer_kind_does_not_override",
|
|
userID: "99",
|
|
senderID: "42",
|
|
peerKind: "channel",
|
|
channelType: "",
|
|
want: "99",
|
|
},
|
|
|
|
// ── Bitrix24-specific cases (C1 fix) ───────────────────────────
|
|
|
|
// Bitrix24 DM, sender NOT merged: UserID == SenderID. Helper returns
|
|
// SenderID (which is identical) — same outcome either way.
|
|
{
|
|
name: "bitrix24_dm_unmerged_uses_sender",
|
|
userID: "62",
|
|
senderID: "62",
|
|
peerKind: "direct",
|
|
channelType: "bitrix24",
|
|
want: "62",
|
|
},
|
|
// Bitrix24 DM, sender MERGED to tenant_user (C1 bug): consumer
|
|
// rewrites UserID to tenant_user UUID. Provisioner stored creds
|
|
// by SenderID. Helper must return SenderID so lookup hits.
|
|
{
|
|
name: "bitrix24_dm_merged_uses_sender_not_uuid",
|
|
userID: "uuid-abc-def-0123",
|
|
senderID: "62",
|
|
peerKind: "direct",
|
|
channelType: "bitrix24",
|
|
want: "62",
|
|
},
|
|
// Bitrix24 group: same recovery as generic group, channelType
|
|
// discriminator does no harm.
|
|
{
|
|
name: "bitrix24_group_uses_sender",
|
|
userID: "group:bitrix-tamgiac:chat4686",
|
|
senderID: "62",
|
|
peerKind: "group",
|
|
channelType: "bitrix24",
|
|
want: "62",
|
|
},
|
|
// Bitrix24 synthetic event (system/ticker) with no sender: fall
|
|
// back to UserID. No creds exist anyway.
|
|
{
|
|
name: "bitrix24_synthetic_no_sender_falls_back",
|
|
userID: "system",
|
|
senderID: "",
|
|
peerKind: "direct",
|
|
channelType: "bitrix24",
|
|
want: "system",
|
|
},
|
|
|
|
// ── Other channel backward compat ──────────────────────────────
|
|
|
|
// Telegram DM (no channelType match): keep original behavior.
|
|
// Telegram doesn't provision per-user creds today; if it did, the
|
|
// consumer's UserID rewrite for merged contacts would still apply
|
|
// and Telegram support would be added here when introduced.
|
|
{
|
|
name: "telegram_dm_unchanged",
|
|
userID: "user-456",
|
|
senderID: "789",
|
|
peerKind: "direct",
|
|
channelType: "telegram",
|
|
want: "user-456",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got := resolveActorUserID(tc.userID, tc.senderID, tc.peerKind, tc.channelType)
|
|
if got != tc.want {
|
|
t.Errorf("resolveActorUserID(%q, %q, %q, %q) = %q; want %q",
|
|
tc.userID, tc.senderID, tc.peerKind, tc.channelType, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// ---- getUserMCPTools OAuth token injection tests ----
|
|
//
|
|
// These tests verify that mcpOAuthTokenProvider.GetValidToken is called (or
|
|
// not) based on whether the MCP server settings declare auth_type=oauth.
|
|
// Pool.AcquireUser fails (no real MCP server), but GetValidToken is injected
|
|
// BEFORE the pool call, so we can assert on call count without needing a
|
|
// working MCP connection.
|
|
|
|
// TestGetUserMCPToolsOAuthTokenProviderCalled verifies that when a server's
|
|
// settings declare auth_type=oauth, GetValidToken is called for the user.
|
|
func TestGetUserMCPToolsOAuthTokenProviderCalled(t *testing.T) {
|
|
pool := newTestPool(t)
|
|
provider := &recordingOAuthProvider{returnToken: "test-bearer-token"}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
|
|
defer cancel()
|
|
|
|
l := &Loop{
|
|
tenantID: uuid.New(),
|
|
mcpPool: pool,
|
|
mcpStore: &minimalMCPServerStore{},
|
|
mcpUserCredSrvs: []store.MCPAccessInfo{{Server: oauthServerData()}},
|
|
mcpOAuthTokenProvider: provider,
|
|
}
|
|
|
|
_ = l.getUserMCPTools(ctx, "user-1")
|
|
|
|
provider.mu.Lock()
|
|
callCount := provider.callCount
|
|
provider.mu.Unlock()
|
|
|
|
if callCount == 0 {
|
|
t.Error("expected GetValidToken to be called for OAuth-configured server, but it was not")
|
|
}
|
|
}
|
|
|
|
// TestGetUserMCPToolsOAuthTokenNotCalledForNonOAuth verifies that when a
|
|
// server has no OAuth settings, the token provider is never invoked and the
|
|
// server is skipped (neither static nor OAuth creds).
|
|
func TestGetUserMCPToolsOAuthTokenNotCalledForNonOAuth(t *testing.T) {
|
|
pool := newTestPool(t)
|
|
provider := &recordingOAuthProvider{}
|
|
|
|
l := &Loop{
|
|
tenantID: uuid.New(),
|
|
mcpPool: pool,
|
|
mcpStore: &minimalMCPServerStore{},
|
|
mcpUserCredSrvs: []store.MCPAccessInfo{
|
|
{Server: store.MCPServerData{
|
|
BaseModel: store.BaseModel{ID: uuid.New()},
|
|
Name: "plain-server",
|
|
Transport: "http",
|
|
URL: "http://127.0.0.1:1",
|
|
// No settings → auth_type defaults to "" (not "oauth")
|
|
}},
|
|
},
|
|
mcpOAuthTokenProvider: provider,
|
|
}
|
|
|
|
_ = l.getUserMCPTools(context.Background(), "user-1")
|
|
|
|
provider.mu.Lock()
|
|
callCount := provider.callCount
|
|
provider.mu.Unlock()
|
|
|
|
if callCount != 0 {
|
|
t.Errorf("GetValidToken must not be called for non-OAuth server, called %d times", callCount)
|
|
}
|
|
}
|
|
|
|
// TestGetUserMCPToolsOAuthNoTokenSkipsServer verifies that when GetValidToken
|
|
// returns no valid token (expired / not authorized yet), the OAuth server is
|
|
// SKIPPED entirely — it must NOT fall back to the shared server-level
|
|
// headers/api_key as Authorization (which would let an unauthorized user call
|
|
// tools with the common credential). GetValidToken is still consulted (proving
|
|
// we entered the OAuth branch) but no tools are produced.
|
|
func TestGetUserMCPToolsOAuthNoTokenSkipsServer(t *testing.T) {
|
|
pool := newTestPool(t)
|
|
expiredErr := errTokenExpiredForTest("oauth token expired")
|
|
provider := &recordingOAuthProvider{
|
|
returnToken: "",
|
|
returnErr: expiredErr,
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
|
|
defer cancel()
|
|
|
|
// Server carries a server-level API key — must NOT be used as a fallback.
|
|
srv := oauthServerData()
|
|
srv.APIKey = "shared-server-key"
|
|
|
|
l := &Loop{
|
|
tenantID: uuid.New(),
|
|
mcpPool: pool,
|
|
mcpStore: &minimalMCPServerStore{},
|
|
mcpUserCredSrvs: []store.MCPAccessInfo{{Server: srv}},
|
|
mcpOAuthTokenProvider: provider,
|
|
}
|
|
|
|
result := l.getUserMCPTools(ctx, "user-1")
|
|
if result != nil {
|
|
t.Errorf("expected nil tools when OAuth has no token (skip, no fallback), got %d tools", len(result))
|
|
}
|
|
provider.mu.Lock()
|
|
calls := provider.callCount
|
|
provider.mu.Unlock()
|
|
if calls == 0 {
|
|
t.Error("expected GetValidToken to be consulted before skipping the OAuth server")
|
|
}
|
|
}
|
|
|
|
// TestGetUserMCPToolsOAuthIgnoresStaticCreds verifies that for an OAuth server
|
|
// the user's static per-user credentials are NOT consulted or used: even when the
|
|
// user has set static creds, an OAuth server without a valid token is skipped
|
|
// (the OAuth token is the sole credential). This closes the bypass where a user
|
|
// with static headers could call OAuth tools without authorizing.
|
|
func TestGetUserMCPToolsOAuthIgnoresStaticCreds(t *testing.T) {
|
|
pool := newTestPool(t)
|
|
provider := &recordingOAuthProvider{returnToken: ""} // not authorized yet
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 300*time.Millisecond)
|
|
defer cancel()
|
|
|
|
// Store has valid static creds for the user — must be ignored for OAuth servers.
|
|
st := &minimalMCPServerStore{
|
|
userCreds: &store.MCPUserCredentials{
|
|
APIKey: "user-static-key",
|
|
Headers: map[string]string{"Authorization": "Bearer user-static-key"},
|
|
},
|
|
}
|
|
|
|
l := &Loop{
|
|
tenantID: uuid.New(),
|
|
mcpPool: pool,
|
|
mcpStore: st,
|
|
mcpUserCredSrvs: []store.MCPAccessInfo{{Server: oauthServerData()}},
|
|
mcpOAuthTokenProvider: provider,
|
|
}
|
|
|
|
result := l.getUserMCPTools(ctx, "user-1")
|
|
if result != nil {
|
|
t.Errorf("expected nil tools: OAuth server without token must be skipped even with static creds, got %d tools", len(result))
|
|
}
|
|
if st.getUserCredsCalls != 0 {
|
|
t.Errorf("static GetUserCredentials must NOT be consulted for OAuth servers, called %d times", st.getUserCredsCalls)
|
|
}
|
|
provider.mu.Lock()
|
|
calls := provider.callCount
|
|
provider.mu.Unlock()
|
|
if calls == 0 {
|
|
t.Error("expected GetValidToken to be consulted for the OAuth server")
|
|
}
|
|
}
|
|
|
|
// TestGetUserMCPToolsNilPoolEarlyReturn verifies that a nil pool causes the
|
|
// function to return immediately without calling the token provider.
|
|
func TestGetUserMCPToolsNilPoolEarlyReturn(t *testing.T) {
|
|
provider := &recordingOAuthProvider{}
|
|
|
|
l := &Loop{
|
|
tenantID: uuid.New(),
|
|
mcpPool: nil, // triggers early return
|
|
mcpStore: &minimalMCPServerStore{},
|
|
mcpUserCredSrvs: []store.MCPAccessInfo{{Server: oauthServerData()}},
|
|
mcpOAuthTokenProvider: provider,
|
|
}
|
|
|
|
result := l.getUserMCPTools(context.Background(), "user-1")
|
|
if result != nil {
|
|
t.Errorf("expected nil when pool is nil, got %v", result)
|
|
}
|
|
if provider.callCount != 0 {
|
|
t.Error("GetValidToken must not be called when pool is nil (early return path)")
|
|
}
|
|
}
|
|
|
|
// errTokenExpiredForTest is a simple error type used to simulate ErrTokenExpired
|
|
// without importing the oauth package (avoids potential import cycles in tests).
|
|
type errTokenExpiredForTest string
|
|
|
|
func (e errTokenExpiredForTest) Error() string { return string(e) }
|
|
|
|
// TestGetUserMCPToolsGroupCredentialResolution verifies that when a Telegram user
|
|
// posts in a group, the group's credentials (CredentialUserID) are used for MCP
|
|
// tool lookup instead of the individual sender's credentials.
|
|
//
|
|
// This is the fix for the calendar event creation bug: the user's calendar email
|
|
// was known but the MCP tools were being looked up with the wrong user ID,
|
|
// causing the tools to appear blocked by system policy.
|
|
func TestGetUserMCPToolsGroupCredentialResolution(t *testing.T) {
|
|
// Simulate a group chat where the group has its own MCP credentials
|
|
// (e.g., a Google Calendar MCP server configured for the group).
|
|
groupID := "group:telegram:-100456"
|
|
serverID := uuid.New()
|
|
|
|
// Track which user ID is used for credential lookup
|
|
var lookupUserID string
|
|
st := &trackingMCPServerStore{
|
|
userCreds: &store.MCPUserCredentials{
|
|
APIKey: "group-calendar-api-key",
|
|
Headers: map[string]string{"Authorization": "Bearer group-calendar-api-key"},
|
|
},
|
|
onGetUserCredentials: func(_ context.Context, _ uuid.UUID, userID string) {
|
|
lookupUserID = userID
|
|
},
|
|
}
|
|
|
|
pool := newTestPool(t)
|
|
l := &Loop{
|
|
tenantID: uuid.New(),
|
|
mcpPool: pool,
|
|
mcpStore: st,
|
|
mcpUserCredSrvs: []store.MCPAccessInfo{
|
|
{Server: store.MCPServerData{
|
|
BaseModel: store.BaseModel{ID: serverID},
|
|
Name: "google-calendar",
|
|
Transport: "http",
|
|
URL: "http://127.0.0.1:1",
|
|
}},
|
|
},
|
|
}
|
|
|
|
// When CredentialUserID is set in context (resolved group identity),
|
|
// it should be used for MCP credential lookup.
|
|
ctx := store.WithCredentialUserID(context.Background(), groupID)
|
|
_ = l.getUserMCPTools(ctx, groupID)
|
|
|
|
if lookupUserID != groupID {
|
|
t.Errorf("expected MCP credentials looked up with group ID %q, got %q", groupID, lookupUserID)
|
|
}
|
|
}
|
|
|
|
// trackingMCPServerStore is a test store that tracks GetUserCredentials calls.
|
|
type trackingMCPServerStore struct {
|
|
userCreds *store.MCPUserCredentials
|
|
onGetUserCredentials func(_ context.Context, _ uuid.UUID, userID string)
|
|
}
|
|
|
|
func (m *trackingMCPServerStore) GetUserCredentials(_ context.Context, _ uuid.UUID, userID string) (*store.MCPUserCredentials, error) {
|
|
if m.onGetUserCredentials != nil {
|
|
m.onGetUserCredentials(context.Background(), uuid.Nil, userID)
|
|
}
|
|
return m.userCreds, nil
|
|
}
|
|
|
|
func (m *trackingMCPServerStore) CreateServer(_ context.Context, _ *store.MCPServerData) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) GetServer(_ context.Context, _ uuid.UUID) (*store.MCPServerData, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) GetServerByName(_ context.Context, _ string) (*store.MCPServerData, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) ListServers(_ context.Context) ([]store.MCPServerData, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) UpdateServer(_ context.Context, _ uuid.UUID, _ map[string]any) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) DeleteServer(_ context.Context, _ uuid.UUID) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) GrantToAgent(_ context.Context, _ *store.MCPAgentGrant) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) RevokeFromAgent(_ context.Context, _, _ uuid.UUID) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) ListAgentGrants(_ context.Context, _ uuid.UUID) ([]store.MCPAgentGrant, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) ListServerGrants(_ context.Context, _ uuid.UUID) ([]store.MCPAgentGrant, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) GrantToUser(_ context.Context, _ *store.MCPUserGrant) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) RevokeFromUser(_ context.Context, _ uuid.UUID, _ string) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) CountAgentGrantsByServer(_ context.Context) (map[uuid.UUID]int, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) ListAccessible(_ context.Context, _ uuid.UUID, _ string) ([]store.MCPAccessInfo, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) CreateRequest(_ context.Context, _ *store.MCPAccessRequest) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) ListPendingRequests(_ context.Context) ([]store.MCPAccessRequest, error) {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) ReviewRequest(_ context.Context, _ uuid.UUID, _ bool, _, _ string) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) SetUserCredentials(_ context.Context, _ uuid.UUID, _ string, _ store.MCPUserCredentials) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) DeleteUserCredentials(_ context.Context, _ uuid.UUID, _ string) error {
|
|
panic("not implemented")
|
|
}
|
|
func (m *trackingMCPServerStore) CacheToolDescriptions(_ context.Context, _ uuid.UUID, _ map[string]store.CachedToolInfo) error {
|
|
return nil
|
|
}
|