@@ -2,10 +2,13 @@ import { cmd } from "./cmd"
22import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
33import { effectCmd } from "../effect-cmd"
44import { Cause } from "effect"
5- import { Client , StreamableHTTPClientTransport , UnauthorizedError } from "@modelcontextprotocol/client"
5+ import { Client } from "@modelcontextprotocol/sdk/client/index.js"
6+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
7+ import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js"
8+ import { LATEST_PROTOCOL_VERSION } from "@modelcontextprotocol/sdk/types.js"
69import * as prompts from "@clack/prompts"
710import { UI } from "../ui"
8- import { CLIENT_OPTIONS , MCP } from "../../mcp"
11+ import { MCP } from "../../mcp"
912import { McpAuth } from "../../mcp/auth"
1013import { McpOAuthProvider } from "../../mcp/oauth-provider"
1114import { Config } from "@/config/config"
@@ -728,53 +731,107 @@ export const McpDebugCommand = effectCmd({
728731 const spinner = prompts . spinner ( )
729732 spinner . start ( "Testing connection..." )
730733
731- const oauthConfig = typeof serverConfig . oauth === "object" ? serverConfig . oauth : undefined
732- let authorizationUrl : URL | undefined
733- const authProvider = new McpOAuthProvider (
734- serverName ,
735- serverConfig . url ,
736- {
737- clientId : oauthConfig ?. clientId ,
738- clientSecret : oauthConfig ?. clientSecret ,
739- scope : oauthConfig ?. scope ,
740- callbackPort : oauthConfig ?. callbackPort ,
741- redirectUri : oauthConfig ?. redirectUri ,
742- } ,
743- {
744- onRedirect : async ( url ) => {
745- authorizationUrl = url
734+ // Test basic HTTP connectivity first
735+ try {
736+ const response = await fetch ( serverConfig . url , {
737+ method : "POST" ,
738+ headers : {
739+ ...serverConfig . headers ,
740+ "Content-Type" : "application/json" ,
741+ Accept : "application/json, text/event-stream" ,
746742 } ,
747- } ,
748- auth ,
749- )
750- const transport = new StreamableHTTPClientTransport ( new URL ( serverConfig . url ) , {
751- authProvider,
752- requestInit : serverConfig . headers ? { headers : serverConfig . headers } : undefined ,
753- } )
754- const client = new Client ( { name : "opencode-debug" , version : InstallationVersion } , CLIENT_OPTIONS )
743+ body : JSON . stringify ( {
744+ jsonrpc : "2.0" ,
745+ method : "initialize" ,
746+ params : {
747+ protocolVersion : LATEST_PROTOCOL_VERSION ,
748+ capabilities : { } ,
749+ clientInfo : { name : "opencode-debug" , version : InstallationVersion } ,
750+ } ,
751+ id : 1 ,
752+ } ) ,
753+ } )
755754
756- try {
757- await client . connect ( transport )
758- spinner . stop ( "SDK connection successful" )
759- prompts . log . success (
760- `Connected using MCP ${ client . getNegotiatedProtocolVersion ( ) ?? "unknown" } (${ client . getProtocolEra ( ) ?? "unknown" } )` ,
761- )
762- const serverInfo = client . getServerVersion ( )
763- if ( serverInfo ) prompts . log . info ( `Server info: ${ JSON . stringify ( serverInfo ) } ` )
764- } catch ( error ) {
765- if ( error instanceof UnauthorizedError ) {
766- spinner . stop ( "OAuth required" )
767- prompts . log . info ( `OAuth flow triggered: ${ error . message } ` )
768- if ( authorizationUrl ) prompts . log . info ( `Authorization URL: ${ authorizationUrl } ` )
769- const clientInfo = await authProvider . clientInformation ( )
770- if ( clientInfo ) prompts . log . info ( `Client ID available: ${ clientInfo . client_id } ` )
771- if ( ! clientInfo ) prompts . log . info ( "No client ID - dynamic registration will be attempted" )
755+ spinner . stop ( `HTTP response: ${ response . status } ${ response . statusText } ` )
756+
757+ // Check for WWW-Authenticate header
758+ const wwwAuth = response . headers . get ( "www-authenticate" )
759+ if ( wwwAuth ) {
760+ prompts . log . info ( `WWW-Authenticate: ${ wwwAuth } ` )
761+ }
762+
763+ if ( response . status === 401 ) {
764+ prompts . log . info ( "Initial unauthenticated check returned 401, so this server requires OAuth" )
765+
766+ // Try to discover OAuth metadata
767+ const oauthConfig = typeof serverConfig . oauth === "object" ? serverConfig . oauth : undefined
768+ const authProvider = new McpOAuthProvider (
769+ serverName ,
770+ serverConfig . url ,
771+ {
772+ clientId : oauthConfig ?. clientId ,
773+ clientSecret : oauthConfig ?. clientSecret ,
774+ scope : oauthConfig ?. scope ,
775+ redirectUri : oauthConfig ?. redirectUri ,
776+ } ,
777+ {
778+ onRedirect : async ( ) => { } ,
779+ } ,
780+ auth ,
781+ )
782+
783+ prompts . log . info ( "Testing OAuth flow (without completing authorization)..." )
784+
785+ // Try creating transport with auth provider to trigger discovery
786+ const transport = new StreamableHTTPClientTransport ( new URL ( serverConfig . url ) , {
787+ authProvider,
788+ requestInit : serverConfig . headers ? { headers : serverConfig . headers } : undefined ,
789+ } )
790+
791+ try {
792+ const client = new Client ( {
793+ name : "opencode-debug" ,
794+ version : InstallationVersion ,
795+ } )
796+ await client . connect ( transport )
797+ prompts . log . success ( "Connection successful (already authenticated)" )
798+ await client . close ( )
799+ } catch ( error ) {
800+ if ( error instanceof UnauthorizedError ) {
801+ prompts . log . info ( `OAuth flow triggered: ${ error . message } ` )
802+
803+ // Check if dynamic registration would be attempted
804+ const clientInfo = await authProvider . clientInformation ( )
805+ if ( clientInfo ) {
806+ prompts . log . info ( `Client ID available: ${ clientInfo . client_id } ` )
807+ } else {
808+ prompts . log . info ( "No client ID - dynamic registration will be attempted" )
809+ }
810+ } else {
811+ prompts . log . error ( `Connection error: ${ error instanceof Error ? error . message : String ( error ) } ` )
812+ }
813+ }
814+ } else if ( response . status >= 200 && response . status < 300 ) {
815+ prompts . log . success ( "Server responded successfully (no auth required or already authenticated)" )
816+ const body = await response . text ( )
817+ try {
818+ const json = JSON . parse ( body )
819+ if ( json . result ?. serverInfo ) {
820+ prompts . log . info ( `Server info: ${ JSON . stringify ( json . result . serverInfo ) } ` )
821+ }
822+ } catch {
823+ // Not JSON, ignore
824+ }
772825 } else {
773- spinner . stop ( "Connection failed" , 1 )
774- prompts . log . error ( `Error: ${ error instanceof Error ? error . message : String ( error ) } ` )
826+ prompts . log . warn ( `Unexpected status: ${ response . status } ` )
827+ const body = await response . text ( ) . catch ( ( ) => "" )
828+ if ( body ) {
829+ prompts . log . info ( `Response body: ${ body . substring ( 0 , 500 ) } ` )
830+ }
775831 }
776- } finally {
777- await client . close ( ) . catch ( ( ) => { } )
832+ } catch ( error ) {
833+ spinner . stop ( "Connection failed" , 1 )
834+ prompts . log . error ( `Error: ${ error instanceof Error ? error . message : String ( error ) } ` )
778835 }
779836
780837 prompts . outro ( "Debug complete" )
0 commit comments