@@ -10,7 +10,6 @@ import { McpOAuthProvider } from "../../mcp/oauth-provider"
1010import { Config } from "../../config"
1111import { ConfigMCP } from "../../config/mcp"
1212import { Instance } from "../../project/instance"
13- import { Installation } from "../../installation"
1413import { InstallationVersion } from "../../installation/version"
1514import path from "path"
1615import { Global } from "../../global"
@@ -68,14 +67,49 @@ async function listState() {
6867 return AppRuntime . runPromise (
6968 Effect . gen ( function * ( ) {
7069 const cfg = yield * Config . Service
71- const mcp = yield * MCP . Service
70+ const auth = yield * McpAuth . Service
7271 const config = yield * cfg . get ( )
73- const statuses = yield * mcp . status ( )
72+ const global = yield * cfg . getGlobal ( )
73+
74+ const serverStatuses = yield * Effect . promise ( ( ) => {
75+ const hostname = global . server ?. hostname === "0.0.0.0" ? "127.0.0.1" : ( global . server ?. hostname ?? "127.0.0.1" )
76+ const password = process . env . OPENCODE_SERVER_PASSWORD
77+ const username = process . env . OPENCODE_SERVER_USERNAME ?? "opencode"
78+ const headers = password
79+ ? {
80+ Authorization : `Basic ${ Buffer . from ( `${ username } :${ password } ` ) . toString ( "base64" ) } ` ,
81+ }
82+ : undefined
83+
84+ const ports = [ ...new Set ( [ global . server ?. port , 18790 , 4096 ] . filter ( ( value ) : value is number => ! ! value ) ) ]
85+ if ( ports . length === 0 ) return Promise . resolve ( undefined )
86+
87+ return ( async ( ) => {
88+ for ( const port of ports ) {
89+ const response = await fetch ( `http://${ hostname } :${ port } /mcp` , {
90+ headers,
91+ signal : AbortSignal . timeout ( 1_000 ) ,
92+ } ) . catch ( ( ) => undefined )
93+
94+ if ( response ?. ok ) return ( await response . json ( ) ) as Record < string , MCP . Status >
95+ }
96+
97+ return undefined
98+ } ) ( )
99+ } )
100+
101+ const statuses =
102+ serverStatuses ??
103+ ( yield * Effect . gen ( function * ( ) {
104+ const mcp = yield * MCP . Service
105+ return yield * mcp . status ( )
106+ } ) )
107+
74108 const stored = yield * Effect . all (
75- Object . fromEntries ( configuredServers ( config ) . map ( ( [ name ] ) => [ name , mcp . hasStoredTokens ( name ) ] ) ) ,
109+ Object . fromEntries ( configuredServers ( config ) . map ( ( [ name ] ) => [ name , Effect . map ( auth . get ( name ) , ( entry ) => ! ! entry ?. tokens ) ] ) ) ,
76110 { concurrency : "unbounded" } ,
77111 )
78- return { config, statuses, stored }
112+ return { config, statuses, stored, source : serverStatuses ? ( "server" as const ) : ( "local" as const ) }
79113 } ) ,
80114 )
81115}
@@ -120,7 +154,7 @@ export const McpListCommand = cmd({
120154 UI . empty ( )
121155 prompts . intro ( "MCP Servers" )
122156
123- const { config, statuses, stored } = await listState ( )
157+ const { config, statuses, stored, source } = await listState ( )
124158 const servers = configuredServers ( config )
125159
126160 if ( servers . length === 0 ) {
@@ -169,7 +203,8 @@ export const McpListCommand = cmd({
169203 )
170204 }
171205
172- prompts . outro ( `${ servers . length } server(s)` )
206+ const sourceText = source === "server" ? "live server state" : "local process state"
207+ prompts . outro ( `${ servers . length } server(s) · source: ${ sourceText } ` )
173208 } ,
174209 } )
175210 } ,
0 commit comments