Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/aws-lsp-core/src/util/retryUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,18 @@ export interface RetryOptions {
*/
function defaultIsRetryable(error: any): boolean {
const errorCode = error.code || error.name
const statusCode = error.statusCode
const statusCode = error.statusCode || error?.$metadata?.httpStatusCode

// Fast fail on non-retryable client errors (except throttling)
if (statusCode >= CLIENT_ERROR_MIN && statusCode < CLIENT_ERROR_MAX && errorCode !== THROTTLING_EXCEPTION) {
return false
}

// Retry on throttling, server errors, and specific status codes
// Retry on throttling, server errors (5xx), and specific status codes
return (
errorCode === THROTTLING_EXCEPTION ||
errorCode === INTERNAL_SERVER_EXCEPTION ||
statusCode === INTERNAL_SERVER_ERROR ||
statusCode >= 500 ||
statusCode === SERVICE_UNAVAILABLE
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,10 @@ export class McpManager {
}
}

public resetRegistryService(): void {
this.registryService = undefined
}

/**
* Update registry URL and refetch registry
* @throws Error if registry fetch or validation fails
Expand All @@ -1849,28 +1853,20 @@ export class McpManager {
this.registryService = new McpRegistryService(this.features.logging)
}

const wasActive = this.registryUrlProvided

try {
const registry = await this.registryService.fetchRegistry(registryUrl)
if (registry) {
this.currentRegistry = registry
// Clear any previous registry errors on success
this.configLoadErrors.delete('registry')

if (!wasActive) {
this.features.logging.info(`MCP Registry: Registry mode ACTIVATED - ${registry.servers.length} servers`)
// Only discover servers when registry is newly activated and not during periodic sync
if (!isPeriodicSync) {
await this.discoverAllServers()
this.features.logging.info(
`MCP Registry: Registry mode ACTIVATED - ${registry.servers.length} servers`
`MCP: discovered ${this.getAllTools().length} tools after registry activation`
)
// Only discover servers when registry is newly activated and not during periodic sync
if (!isPeriodicSync) {
await this.discoverAllServers()
this.features.logging.info(
`MCP: discovered ${this.getAllTools().length} tools after registry activation`
)
}
} else {
this.features.logging.info(`MCP Registry: Updated registry with ${registry.servers.length} servers`)
}

// Only sync during periodic updates, not at startup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,36 @@ export class ProfileStatusMonitor {
ProfileStatusMonitor.setMcpState(true)
}

static resetMcpManager(): void {
try {
// note: use dynamic require to satisfy webpack requirements for webworker
const McpManager = eval('require')('./mcpManager').McpManager
if (McpManager.isInitialized()) {
McpManager.instance.setRegistryActive(false)
McpManager.instance.resetRegistryService()
void McpManager.instance.close(true)
}
} catch (error) {
ProfileStatusMonitor.logging?.error(`Failed to reset MCP manager: ${error}`)
}
}

/**
* When switching between connections especially builder id
* re-discover mcp servers for non-profile connections
*/
static discoverServersWhenNoProfiles(): void {
try {
// note: use dynamic require to satisfy webpack requirements for webworker
const McpManager = eval('require')('./mcpManager').McpManager
if (McpManager.isInitialized()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens when no mcpManager initialized yet?

Copy link
Copy Markdown
Contributor Author

@shruti0085 shruti0085 Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should default to false mcp state right? As mentioned offline, there is not an accessible way to use mcp manager without initialization and since it is the source for resolving servers, it seems reasonable for it have no servers. I believe even with my change that default behavior should not change as this is surrounded by a try catch

void McpManager.instance.discoverAllServers()
}
} catch (error) {
ProfileStatusMonitor.logging?.error(`Failed to discover mcp servers when no profiles available: ${error}`)
}
}

static emitAuthSuccess(): void {
ProfileStatusMonitor.eventEmitter.emit(AUTH_SUCCESS_EVENT)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ export const McpToolsServer: Server = ({
// Wait for profile ARN to be available before checking MCP state
const checkAndInitialize = async () => {
try {
// Check if MCP is enabled via isMcpEnabled check (only call once)
const mcpEnabled = await profileStatusMonitor!.checkInitialState()
// Check if MCP is enabled via get Mcp state
const mcpEnabled = ProfileStatusMonitor.getMcpState()

if (mcpEnabled) {
logging.info('MCP is enabled, discovering servers')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import { parse } from '@aws-sdk/util-arn-parser'
import { ChatDatabase } from '../../language-server/agenticChat/tools/chatDb/chatDb'
import { ProfileStatusMonitor } from '../../language-server/agenticChat/tools/mcp/profileStatusMonitor'
import { UserContext } from '@amzn/codewhisperer-runtime'

/**
* AmazonQTokenServiceManager manages state and provides centralized access to
* instance of CodeWhispererServiceToken SDK client to any consuming code.
Expand Down Expand Up @@ -160,6 +159,7 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager<

// Reset MCP state cache when auth changes
ProfileStatusMonitor.resetMcpState()
ProfileStatusMonitor.resetMcpManager()
}

public handleOnCredentialsUpdated(type: CredentialsType): void {
Expand Down Expand Up @@ -265,8 +265,7 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager<
this.state = 'INITIALIZED'
this.logging.log(`Initialized Amazon Q service with ${newConnectionType} connection`)

// Emit auth success event
ProfileStatusMonitor.emitAuthSuccess()
ProfileStatusMonitor.discoverServersWhenNoProfiles()

return
}
Expand All @@ -290,9 +289,6 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager<
this.state = 'INITIALIZED'
this.logging.log('Initialized Amazon Q service with identityCenter connection')

// Emit auth success event
ProfileStatusMonitor.emitAuthSuccess()

return
}

Expand Down Expand Up @@ -414,9 +410,6 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager<
this.activeIdcProfile = newProfile
this.state = 'INITIALIZED'

// Emit auth success event
ProfileStatusMonitor.emitAuthSuccess()

return
}

Expand All @@ -440,9 +433,6 @@ export class AmazonQTokenServiceManager extends BaseAmazonQServiceManager<
this.cachedStreamingClient.profileArn = newProfile.arn
}

// Emit auth success event
ProfileStatusMonitor.emitAuthSuccess()

return
}

Expand Down
Loading