diff --git a/AGENT.md b/AGENT.md index 759766b..a2cf9e8 100644 --- a/AGENT.md +++ b/AGENT.md @@ -27,6 +27,10 @@ - Log errors with appropriate levels (debug, info, warn, error) - Defensive error handling with specific error types when available +## Development Workflow +- **Commit changes frequently** after each logical change or debugging step +- Use descriptive commit messages that explain what was changed and why + ### React Patterns - Use React hooks with useRef for mutable values - Stable callbacks with useCallback and appropriate dependencies \ No newline at end of file diff --git a/examples/chat-ui/src/components/McpServerModal.tsx b/examples/chat-ui/src/components/McpServerModal.tsx index a91943c..ce98fd7 100644 --- a/examples/chat-ui/src/components/McpServerModal.tsx +++ b/examples/chat-ui/src/components/McpServerModal.tsx @@ -23,6 +23,7 @@ function McpConnection({ debug: true, autoRetry: false, popupFeatures: 'width=500,height=600,resizable=yes,scrollbars=yes', + httpOnly: true, // DEBUG: Only try HTTP transport, no SSE fallback }) // Update parent component with connection data diff --git a/src/react/types.ts b/src/react/types.ts index 165c0ab..f9e7d4a 100644 --- a/src/react/types.ts +++ b/src/react/types.ts @@ -26,6 +26,8 @@ export type UseMcpOptions = { autoReconnect?: boolean | number /** Popup window features string (dimensions and behavior) for OAuth */ popupFeatures?: string + /** Only try HTTP transport, don't fallback to SSE (useful for debugging) */ + httpOnly?: boolean } export type UseMcpResult = { diff --git a/src/react/useMcp.ts b/src/react/useMcp.ts index 6da6e1b..ce2cad6 100644 --- a/src/react/useMcp.ts +++ b/src/react/useMcp.ts @@ -30,6 +30,7 @@ export function useMcp(options: UseMcpOptions): UseMcpResult { debug = false, autoRetry = false, autoReconnect = DEFAULT_RECONNECT_DELAY, + httpOnly = false, } = options const [state, setState] = useState('discovering') @@ -314,6 +315,11 @@ export function useMcp(options: UseMcpOptions): UseMcpResult { errorMessage === 'Load failed' /* Safari */ if (transportType === 'http' && (is404 || is405 || isLikelyCors)) { + if (httpOnly) { + addLog('warn', `HTTP transport failed (${isLikelyCors ? 'CORS' : is404 ? '404' : '405'}). httpOnly=true, no fallback.`) + failConnection(`HTTP transport failed: ${isLikelyCors ? 'CORS' : is404 ? '404' : '405'}`, errorInstance) + return 'failed' + } addLog('warn', `HTTP transport failed (${isLikelyCors ? 'CORS' : is404 ? '404' : '405'}). Will attempt fallback to SSE.`) return 'fallback' // Signal that fallback should be attempted } @@ -355,7 +361,7 @@ export function useMcp(options: UseMcpOptions): UseMcpResult { if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current) addLog('error', 'Auth flow failed:', sdkAuthError) // Auth failed, but still allow fallback to SSE - if (transportType === 'http') { + if (transportType === 'http' && !httpOnly) { return 'fallback' // Try SSE even after auth failure } else { failConnection( @@ -371,6 +377,11 @@ export function useMcp(options: UseMcpOptions): UseMcpResult { // Don't call failConnection here for HTTP transport - let orchestration handle it // so that SSE fallback can still be attempted if (transportType === 'http') { + if (httpOnly) { + addLog('warn', `HTTP transport failed: ${errorMessage}. httpOnly=true, no fallback.`) + failConnection(`HTTP transport failed: ${errorMessage}`, errorInstance) + return 'failed' + } addLog('warn', `HTTP transport failed: ${errorMessage}. Will attempt fallback to SSE.`) return 'fallback' } else {