@@ -2,13 +2,10 @@ 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 } 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"
5+ import { Client , StreamableHTTPClientTransport , UnauthorizedError } from "@modelcontextprotocol/client"
96import * as prompts from "@clack/prompts"
107import { UI } from "../ui"
11- import { MCP } from "../../mcp"
8+ import { CLIENT_OPTIONS , MCP } from "../../mcp"
129import { McpAuth } from "../../mcp/auth"
1310import { McpOAuthProvider } from "../../mcp/oauth-provider"
1411import { Config } from "@/config/config"
@@ -731,107 +728,53 @@ export const McpDebugCommand = effectCmd({
731728 const spinner = prompts . spinner ( )
732729 spinner . start ( "Testing connection..." )
733730
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" ,
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
742746 } ,
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- } )
754-
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- } )
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 )
790755
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- }
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" )
825772 } else {
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- }
773+ spinner . stop ( "Connection failed" , 1 )
774+ prompts . log . error ( `Error: ${ error instanceof Error ? error . message : String ( error ) } ` )
831775 }
832- } catch ( error ) {
833- spinner . stop ( "Connection failed" , 1 )
834- prompts . log . error ( `Error: ${ error instanceof Error ? error . message : String ( error ) } ` )
776+ } finally {
777+ await client . close ( ) . catch ( ( ) => { } )
835778 }
836779
837780 prompts . outro ( "Debug complete" )
0 commit comments