Trim teammate prompt UI and MCP debug logs
This commit is contained in:
@@ -5,7 +5,6 @@ import * as React from 'react';
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useInterval } from 'usehooks-ts';
|
import { useInterval } from 'usehooks-ts';
|
||||||
import { useRegisterOverlay } from '../../context/overlayContext.js';
|
import { useRegisterOverlay } from '../../context/overlayContext.js';
|
||||||
import { stringWidth } from '../../ink/stringWidth.js';
|
|
||||||
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- raw j/k/arrow dialog navigation
|
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- raw j/k/arrow dialog navigation
|
||||||
import { Box, Text, useInput } from '../../ink.js';
|
import { Box, Text, useInput } from '../../ink.js';
|
||||||
import { useKeybindings } from '../../keybindings/useKeybinding.js';
|
import { useKeybindings } from '../../keybindings/useKeybinding.js';
|
||||||
@@ -15,7 +14,6 @@ import { getEmptyToolPermissionContext } from '../../Tool.js';
|
|||||||
import { AGENT_COLOR_TO_THEME_COLOR } from '../../tools/AgentTool/agentColorManager.js';
|
import { AGENT_COLOR_TO_THEME_COLOR } from '../../tools/AgentTool/agentColorManager.js';
|
||||||
import { logForDebugging } from '../../utils/debug.js';
|
import { logForDebugging } from '../../utils/debug.js';
|
||||||
import { execFileNoThrow } from '../../utils/execFileNoThrow.js';
|
import { execFileNoThrow } from '../../utils/execFileNoThrow.js';
|
||||||
import { truncateToWidth } from '../../utils/format.js';
|
|
||||||
import { getNextPermissionMode } from '../../utils/permissions/getNextPermissionMode.js';
|
import { getNextPermissionMode } from '../../utils/permissions/getNextPermissionMode.js';
|
||||||
import { getModeColor, type PermissionMode, permissionModeFromString, permissionModeSymbol } from '../../utils/permissions/PermissionMode.js';
|
import { getModeColor, type PermissionMode, permissionModeFromString, permissionModeSymbol } from '../../utils/permissions/PermissionMode.js';
|
||||||
import { jsonStringify } from '../../utils/slowOperations.js';
|
import { jsonStringify } from '../../utils/slowOperations.js';
|
||||||
@@ -381,7 +379,6 @@ function TeammateDetailView(t0) {
|
|||||||
teamName,
|
teamName,
|
||||||
onCancel
|
onCancel
|
||||||
} = t0;
|
} = t0;
|
||||||
const [promptExpanded, setPromptExpanded] = useState(false);
|
|
||||||
const cycleModeShortcut = useShortcutDisplay("confirm:cycleMode", "Confirmation", "shift+tab");
|
const cycleModeShortcut = useShortcutDisplay("confirm:cycleMode", "Confirmation", "shift+tab");
|
||||||
const themeColor = teammate.color ? AGENT_COLOR_TO_THEME_COLOR[teammate.color as keyof typeof AGENT_COLOR_TO_THEME_COLOR] : undefined;
|
const themeColor = teammate.color ? AGENT_COLOR_TO_THEME_COLOR[teammate.color as keyof typeof AGENT_COLOR_TO_THEME_COLOR] : undefined;
|
||||||
let t1;
|
let t1;
|
||||||
@@ -418,18 +415,6 @@ function TeammateDetailView(t0) {
|
|||||||
t3 = $[5];
|
t3 = $[5];
|
||||||
}
|
}
|
||||||
useEffect(t2, t3);
|
useEffect(t2, t3);
|
||||||
let t4;
|
|
||||||
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
|
||||||
t4 = input => {
|
|
||||||
if (input === "p") {
|
|
||||||
setPromptExpanded(_temp);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
$[6] = t4;
|
|
||||||
} else {
|
|
||||||
t4 = $[6];
|
|
||||||
}
|
|
||||||
useInput(t4);
|
|
||||||
const workingPath = teammate.worktreePath || teammate.cwd;
|
const workingPath = teammate.worktreePath || teammate.cwd;
|
||||||
let subtitleParts;
|
let subtitleParts;
|
||||||
if ($[7] !== teammate.model || $[8] !== teammate.worktreePath || $[9] !== workingPath) {
|
if ($[7] !== teammate.model || $[8] !== teammate.worktreePath || $[9] !== workingPath) {
|
||||||
@@ -498,21 +483,11 @@ function TeammateDetailView(t0) {
|
|||||||
} else {
|
} else {
|
||||||
t9 = $[24];
|
t9 = $[24];
|
||||||
}
|
}
|
||||||
let t10;
|
|
||||||
if ($[25] !== promptExpanded || $[26] !== teammate.prompt) {
|
|
||||||
t10 = teammate.prompt && <Box flexDirection="column"><Text bold={true}>Prompt</Text><Text>{promptExpanded ? teammate.prompt : truncateToWidth(teammate.prompt, 80)}{stringWidth(teammate.prompt) > 80 && !promptExpanded && <Text dimColor={true}> (p to expand)</Text>}</Text></Box>;
|
|
||||||
$[25] = promptExpanded;
|
|
||||||
$[26] = teammate.prompt;
|
|
||||||
$[27] = t10;
|
|
||||||
} else {
|
|
||||||
t10 = $[27];
|
|
||||||
}
|
|
||||||
let t11;
|
let t11;
|
||||||
if ($[28] !== onCancel || $[29] !== subtitle || $[30] !== t10 || $[31] !== t9 || $[32] !== title) {
|
if ($[28] !== onCancel || $[29] !== subtitle || $[31] !== t9 || $[32] !== title) {
|
||||||
t11 = <Dialog title={title} subtitle={subtitle} onCancel={onCancel} color="background" hideInputGuide={true}>{t9}{t10}</Dialog>;
|
t11 = <Dialog title={title} subtitle={subtitle} onCancel={onCancel} color="background" hideInputGuide={true}>{t9}</Dialog>;
|
||||||
$[28] = onCancel;
|
$[28] = onCancel;
|
||||||
$[29] = subtitle;
|
$[29] = subtitle;
|
||||||
$[30] = t10;
|
|
||||||
$[31] = t9;
|
$[31] = t9;
|
||||||
$[32] = title;
|
$[32] = title;
|
||||||
$[33] = t11;
|
$[33] = t11;
|
||||||
|
|||||||
@@ -124,6 +124,31 @@ function redactSensitiveUrlParams(url: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function summarizeHeadersForDebug(
|
||||||
|
headers: Record<string, string> | undefined,
|
||||||
|
): {
|
||||||
|
headerCount: number
|
||||||
|
headerNames: string[]
|
||||||
|
hasAuthorization: boolean
|
||||||
|
} {
|
||||||
|
if (!headers) {
|
||||||
|
return {
|
||||||
|
headerCount: 0,
|
||||||
|
headerNames: [],
|
||||||
|
hasAuthorization: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerNames = Object.keys(headers).sort()
|
||||||
|
return {
|
||||||
|
headerCount: headerNames.length,
|
||||||
|
headerNames,
|
||||||
|
hasAuthorization: headerNames.some(
|
||||||
|
headerName => headerName.toLowerCase() === 'authorization',
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some OAuth servers (notably Slack) return HTTP 200 for all responses,
|
* Some OAuth servers (notably Slack) return HTTP 200 for all responses,
|
||||||
* signaling errors via the JSON body instead. The SDK's executeTokenRequest
|
* signaling errors via the JSON body instead. The SDK's executeTokenRequest
|
||||||
@@ -696,14 +721,11 @@ async function performMCPXaaAuth(
|
|||||||
const haveKeys = Object.keys(
|
const haveKeys = Object.keys(
|
||||||
getSecureStorage().read()?.mcpOAuthClientConfig ?? {},
|
getSecureStorage().read()?.mcpOAuthClientConfig ?? {},
|
||||||
)
|
)
|
||||||
const headersForLogging = Object.fromEntries(
|
|
||||||
Object.entries(serverConfig.headers ?? {}).map(([k, v]) =>
|
|
||||||
k.toLowerCase() === 'authorization' ? [k, '[REDACTED]'] : [k, v],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
serverName,
|
serverName,
|
||||||
`XAA: secret lookup miss. wanted=${wantedKey} have=[${haveKeys.join(', ')}] configHeaders=${jsonStringify(headersForLogging)}`,
|
`XAA: secret lookup miss. wanted=${wantedKey} availableKeys=${haveKeys.length} configHeaderSummary=${jsonStringify(
|
||||||
|
summarizeHeadersForDebug(serverConfig.headers),
|
||||||
|
)}`,
|
||||||
)
|
)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`XAA: AS client secret not found for '${serverName}'. Re-add with --client-secret.`,
|
`XAA: AS client secret not found for '${serverName}'. Re-add with --client-secret.`,
|
||||||
@@ -988,7 +1010,9 @@ export async function performMCPOAuthFlow(
|
|||||||
provider.setMetadata(metadata)
|
provider.setMetadata(metadata)
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
serverName,
|
serverName,
|
||||||
`Fetched OAuth metadata with scope: ${getScopeFromMetadata(metadata) || 'NONE'}`,
|
`Fetched OAuth metadata (hasScope=${Boolean(
|
||||||
|
getScopeFromMetadata(metadata),
|
||||||
|
)})`,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1170,8 +1194,10 @@ export async function performMCPOAuthFlow(
|
|||||||
|
|
||||||
server.listen(port, '127.0.0.1', async () => {
|
server.listen(port, '127.0.0.1', async () => {
|
||||||
try {
|
try {
|
||||||
logMCPDebug(serverName, `Starting SDK auth`)
|
logMCPDebug(
|
||||||
logMCPDebug(serverName, `Server URL: ${serverConfig.url}`)
|
serverName,
|
||||||
|
`Starting SDK auth (transport=${serverConfig.type})`,
|
||||||
|
)
|
||||||
|
|
||||||
// First call to start the auth flow - should redirect
|
// First call to start the auth flow - should redirect
|
||||||
// Pass the scope and resource_metadata from WWW-Authenticate header if available
|
// Pass the scope and resource_metadata from WWW-Authenticate header if available
|
||||||
@@ -1189,7 +1215,7 @@ export async function performMCPOAuthFlow(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logMCPDebug(serverName, `SDK auth error: ${error}`)
|
logMCPDebug(serverName, `SDK auth error: ${errorMessage(error)}`)
|
||||||
cleanup()
|
cleanup()
|
||||||
rejectOnce(new Error(`SDK auth failed: ${errorMessage(error)}`))
|
rejectOnce(new Error(`SDK auth failed: ${errorMessage(error)}`))
|
||||||
}
|
}
|
||||||
@@ -1235,9 +1261,13 @@ export async function performMCPOAuthFlow(
|
|||||||
if (savedTokens) {
|
if (savedTokens) {
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
serverName,
|
serverName,
|
||||||
`Token access_token length: ${savedTokens.access_token?.length}`,
|
`Token summary after auth: ${jsonStringify({
|
||||||
|
hasAccessToken: Boolean(savedTokens.access_token),
|
||||||
|
hasRefreshToken: Boolean(savedTokens.refresh_token),
|
||||||
|
expiresInSec: savedTokens.expires_in,
|
||||||
|
hasScope: Boolean(savedTokens.scope),
|
||||||
|
})}`,
|
||||||
)
|
)
|
||||||
logMCPDebug(serverName, `Token expires_in: ${savedTokens.expires_in}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logEvent('tengu_mcp_oauth_flow_success', {
|
logEvent('tengu_mcp_oauth_flow_success', {
|
||||||
@@ -1257,7 +1287,10 @@ export async function performMCPOAuthFlow(
|
|||||||
throw new Error('Unexpected auth result: ' + result)
|
throw new Error('Unexpected auth result: ' + result)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logMCPDebug(serverName, `Error during auth completion: ${error}`)
|
logMCPDebug(
|
||||||
|
serverName,
|
||||||
|
`Error during auth completion: ${errorMessage(error)}`,
|
||||||
|
)
|
||||||
|
|
||||||
// Determine failure reason for attribution telemetry. The try block covers
|
// Determine failure reason for attribution telemetry. The try block covers
|
||||||
// port acquisition, the callback server, the redirect flow, and token
|
// port acquisition, the callback server, the redirect flow, and token
|
||||||
@@ -1429,7 +1462,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
|
|||||||
metadata.scope = metadataScope
|
metadata.scope = metadataScope
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
this.serverName,
|
this.serverName,
|
||||||
`Using scope from metadata: ${metadata.scope}`,
|
'Using scope from metadata',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1445,7 +1478,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
|
|||||||
get clientMetadataUrl(): string | undefined {
|
get clientMetadataUrl(): string | undefined {
|
||||||
const override = process.env.MCP_OAUTH_CLIENT_METADATA_URL
|
const override = process.env.MCP_OAUTH_CLIENT_METADATA_URL
|
||||||
if (override) {
|
if (override) {
|
||||||
logMCPDebug(this.serverName, `Using CIMD URL from env: ${override}`)
|
logMCPDebug(this.serverName, 'Using CIMD URL from env override')
|
||||||
return override
|
return override
|
||||||
}
|
}
|
||||||
return MCP_CLIENT_METADATA_URL
|
return MCP_CLIENT_METADATA_URL
|
||||||
@@ -1467,7 +1500,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
|
|||||||
*/
|
*/
|
||||||
markStepUpPending(scope: string): void {
|
markStepUpPending(scope: string): void {
|
||||||
this._pendingStepUpScope = scope
|
this._pendingStepUpScope = scope
|
||||||
logMCPDebug(this.serverName, `Marked step-up pending: ${scope}`)
|
logMCPDebug(this.serverName, 'Marked step-up pending')
|
||||||
}
|
}
|
||||||
|
|
||||||
async state(): Promise<string> {
|
async state(): Promise<string> {
|
||||||
@@ -1632,7 +1665,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
|
|||||||
if (needsStepUp) {
|
if (needsStepUp) {
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
this.serverName,
|
this.serverName,
|
||||||
`Step-up pending (${this._pendingStepUpScope}), omitting refresh_token`,
|
'Step-up pending, omitting refresh_token',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1693,10 +1726,15 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
|
|||||||
token_type: 'Bearer',
|
token_type: 'Bearer',
|
||||||
}
|
}
|
||||||
|
|
||||||
logMCPDebug(this.serverName, `Returning tokens`)
|
logMCPDebug(
|
||||||
logMCPDebug(this.serverName, `Token length: ${tokens.access_token?.length}`)
|
this.serverName,
|
||||||
logMCPDebug(this.serverName, `Has refresh token: ${!!tokens.refresh_token}`)
|
`Returning tokens: ${jsonStringify({
|
||||||
logMCPDebug(this.serverName, `Expires in: ${Math.floor(expiresIn)}s`)
|
hasAccessToken: Boolean(tokens.access_token),
|
||||||
|
hasRefreshToken: Boolean(tokens.refresh_token),
|
||||||
|
hasScope: Boolean(tokens.scope),
|
||||||
|
expiresInSec: Math.floor(expiresIn),
|
||||||
|
})}`,
|
||||||
|
)
|
||||||
|
|
||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
@@ -1707,9 +1745,15 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
|
|||||||
const existingData = storage.read() || {}
|
const existingData = storage.read() || {}
|
||||||
const serverKey = getServerKey(this.serverName, this.serverConfig)
|
const serverKey = getServerKey(this.serverName, this.serverConfig)
|
||||||
|
|
||||||
logMCPDebug(this.serverName, `Saving tokens`)
|
logMCPDebug(
|
||||||
logMCPDebug(this.serverName, `Token expires in: ${tokens.expires_in}`)
|
this.serverName,
|
||||||
logMCPDebug(this.serverName, `Has refresh token: ${!!tokens.refresh_token}`)
|
`Saving tokens: ${jsonStringify({
|
||||||
|
hasAccessToken: Boolean(tokens.access_token),
|
||||||
|
hasRefreshToken: Boolean(tokens.refresh_token),
|
||||||
|
hasScope: Boolean(tokens.scope),
|
||||||
|
expiresInSec: tokens.expires_in,
|
||||||
|
})}`,
|
||||||
|
)
|
||||||
|
|
||||||
const updatedData: SecureStorageData = {
|
const updatedData: SecureStorageData = {
|
||||||
...existingData,
|
...existingData,
|
||||||
|
|||||||
@@ -332,6 +332,51 @@ function mcpBaseUrlAnalytics(serverRef: ScopedMcpServerConfig): {
|
|||||||
: {}
|
: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mcpBaseUrlForDebug(serverRef: ScopedMcpServerConfig): string {
|
||||||
|
return getLoggingSafeMcpBaseUrl(serverRef) || '[unavailable]'
|
||||||
|
}
|
||||||
|
|
||||||
|
function summarizeHeadersForDebug(
|
||||||
|
headers: Record<string, string> | undefined,
|
||||||
|
): {
|
||||||
|
headerCount: number
|
||||||
|
headerNames: string[]
|
||||||
|
hasAuthorization: boolean
|
||||||
|
} {
|
||||||
|
if (!headers) {
|
||||||
|
return {
|
||||||
|
headerCount: 0,
|
||||||
|
headerNames: [],
|
||||||
|
hasAuthorization: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerNames = Object.keys(headers)
|
||||||
|
return {
|
||||||
|
headerCount: headerNames.length,
|
||||||
|
headerNames: headerNames.sort(),
|
||||||
|
hasAuthorization: headerNames.some(
|
||||||
|
headerName => headerName.toLowerCase() === 'authorization',
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function summarizeProxyEnvForDebug(): Record<string, string | boolean> {
|
||||||
|
return {
|
||||||
|
hasNodeOptions: Boolean(process.env.NODE_OPTIONS),
|
||||||
|
uvThreadpoolSizeConfigured: Boolean(process.env.UV_THREADPOOL_SIZE),
|
||||||
|
hasHttpProxy: Boolean(process.env.HTTP_PROXY),
|
||||||
|
hasHttpsProxy: Boolean(process.env.HTTPS_PROXY),
|
||||||
|
hasNoProxy: Boolean(process.env.NO_PROXY),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function summarizeStderrForDebug(stderrOutput: string): string {
|
||||||
|
const trimmed = stderrOutput.trim()
|
||||||
|
const lineCount = trimmed === '' ? 0 : trimmed.split('\n').length
|
||||||
|
return `Server stderr captured (${trimmed.length} chars, ${lineCount} lines)`
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared handler for sse/http/claudeai-proxy auth failures during connect:
|
* Shared handler for sse/http/claudeai-proxy auth failures during connect:
|
||||||
* emits tengu_mcp_server_needs_auth, caches the needs-auth entry, and returns
|
* emits tengu_mcp_server_needs_auth, caches the needs-auth entry, and returns
|
||||||
@@ -676,7 +721,10 @@ export const connectToServer = memoize(
|
|||||||
)
|
)
|
||||||
logMCPDebug(name, `SSE transport initialized, awaiting connection`)
|
logMCPDebug(name, `SSE transport initialized, awaiting connection`)
|
||||||
} else if (serverRef.type === 'sse-ide') {
|
} else if (serverRef.type === 'sse-ide') {
|
||||||
logMCPDebug(name, `Setting up SSE-IDE transport to ${serverRef.url}`)
|
logMCPDebug(
|
||||||
|
name,
|
||||||
|
`Setting up SSE-IDE transport to ${mcpBaseUrlForDebug(serverRef)}`,
|
||||||
|
)
|
||||||
// IDE servers don't need authentication
|
// IDE servers don't need authentication
|
||||||
// TODO: Use the auth token provided in the lockfile
|
// TODO: Use the auth token provided in the lockfile
|
||||||
const proxyOptions = getProxyFetchOptions()
|
const proxyOptions = getProxyFetchOptions()
|
||||||
@@ -735,7 +783,7 @@ export const connectToServer = memoize(
|
|||||||
} else if (serverRef.type === 'ws') {
|
} else if (serverRef.type === 'ws') {
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
name,
|
name,
|
||||||
`Initializing WebSocket transport to ${serverRef.url}`,
|
`Initializing WebSocket transport to ${mcpBaseUrlForDebug(serverRef)}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const combinedHeaders = await getMcpServerHeaders(name, serverRef)
|
const combinedHeaders = await getMcpServerHeaders(name, serverRef)
|
||||||
@@ -749,16 +797,17 @@ export const connectToServer = memoize(
|
|||||||
...combinedHeaders,
|
...combinedHeaders,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redact sensitive headers before logging
|
const wsHeadersForLogging = summarizeHeadersForDebug(
|
||||||
const wsHeadersForLogging = mapValues(wsHeaders, (value, key) =>
|
mapValues(wsHeaders, (_value, key) =>
|
||||||
key.toLowerCase() === 'authorization' ? '[REDACTED]' : value,
|
key.toLowerCase() === 'authorization' ? '[REDACTED]' : '[set]',
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
name,
|
name,
|
||||||
`WebSocket transport options: ${jsonStringify({
|
`WebSocket transport options: ${jsonStringify({
|
||||||
url: serverRef.url,
|
url: mcpBaseUrlForDebug(serverRef),
|
||||||
headers: wsHeadersForLogging,
|
...wsHeadersForLogging,
|
||||||
hasSessionAuth: !!sessionIngressToken,
|
hasSessionAuth: !!sessionIngressToken,
|
||||||
})}`,
|
})}`,
|
||||||
)
|
)
|
||||||
@@ -782,20 +831,17 @@ export const connectToServer = memoize(
|
|||||||
}
|
}
|
||||||
transport = new WebSocketTransport(wsClient)
|
transport = new WebSocketTransport(wsClient)
|
||||||
} else if (serverRef.type === 'http') {
|
} else if (serverRef.type === 'http') {
|
||||||
logMCPDebug(name, `Initializing HTTP transport to ${serverRef.url}`)
|
logMCPDebug(
|
||||||
|
name,
|
||||||
|
`Initializing HTTP transport to ${mcpBaseUrlForDebug(serverRef)}`,
|
||||||
|
)
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
name,
|
name,
|
||||||
`Node version: ${process.version}, Platform: ${process.platform}`,
|
`Node version: ${process.version}, Platform: ${process.platform}`,
|
||||||
)
|
)
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
name,
|
name,
|
||||||
`Environment: ${jsonStringify({
|
`Environment: ${jsonStringify(summarizeProxyEnvForDebug())}`,
|
||||||
NODE_OPTIONS: process.env.NODE_OPTIONS || 'not set',
|
|
||||||
UV_THREADPOOL_SIZE: process.env.UV_THREADPOOL_SIZE || 'default',
|
|
||||||
HTTP_PROXY: process.env.HTTP_PROXY || 'not set',
|
|
||||||
HTTPS_PROXY: process.env.HTTPS_PROXY || 'not set',
|
|
||||||
NO_PROXY: process.env.NO_PROXY || 'not set',
|
|
||||||
})}`,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create an auth provider for this server
|
// Create an auth provider for this server
|
||||||
@@ -843,16 +889,16 @@ export const connectToServer = memoize(
|
|||||||
const headersForLogging = transportOptions.requestInit?.headers
|
const headersForLogging = transportOptions.requestInit?.headers
|
||||||
? mapValues(
|
? mapValues(
|
||||||
transportOptions.requestInit.headers as Record<string, string>,
|
transportOptions.requestInit.headers as Record<string, string>,
|
||||||
(value, key) =>
|
(_value, key) =>
|
||||||
key.toLowerCase() === 'authorization' ? '[REDACTED]' : value,
|
key.toLowerCase() === 'authorization' ? '[REDACTED]' : '[set]',
|
||||||
)
|
)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
name,
|
name,
|
||||||
`HTTP transport options: ${jsonStringify({
|
`HTTP transport options: ${jsonStringify({
|
||||||
url: serverRef.url,
|
url: mcpBaseUrlForDebug(serverRef),
|
||||||
headers: headersForLogging,
|
...summarizeHeadersForDebug(headersForLogging),
|
||||||
hasAuthProvider: !!authProvider,
|
hasAuthProvider: !!authProvider,
|
||||||
timeoutMs: MCP_REQUEST_TIMEOUT_MS,
|
timeoutMs: MCP_REQUEST_TIMEOUT_MS,
|
||||||
})}`,
|
})}`,
|
||||||
@@ -879,7 +925,7 @@ export const connectToServer = memoize(
|
|||||||
const oauthConfig = getOauthConfig()
|
const oauthConfig = getOauthConfig()
|
||||||
const proxyUrl = `${oauthConfig.MCP_PROXY_URL}${oauthConfig.MCP_PROXY_PATH.replace('{server_id}', serverRef.id)}`
|
const proxyUrl = `${oauthConfig.MCP_PROXY_URL}${oauthConfig.MCP_PROXY_PATH.replace('{server_id}', serverRef.id)}`
|
||||||
|
|
||||||
logMCPDebug(name, `Using claude.ai proxy at ${proxyUrl}`)
|
logMCPDebug(name, `Using claude.ai proxy transport`)
|
||||||
|
|
||||||
// eslint-disable-next-line eslint-plugin-n/no-unsupported-features/node-builtins
|
// eslint-disable-next-line eslint-plugin-n/no-unsupported-features/node-builtins
|
||||||
const fetchWithAuth = createClaudeAiProxyFetch(globalThis.fetch)
|
const fetchWithAuth = createClaudeAiProxyFetch(globalThis.fetch)
|
||||||
@@ -1025,7 +1071,10 @@ export const connectToServer = memoize(
|
|||||||
|
|
||||||
// For HTTP transport, try a basic connectivity test first
|
// For HTTP transport, try a basic connectivity test first
|
||||||
if (serverRef.type === 'http') {
|
if (serverRef.type === 'http') {
|
||||||
logMCPDebug(name, `Testing basic HTTP connectivity to ${serverRef.url}`)
|
logMCPDebug(
|
||||||
|
name,
|
||||||
|
`Testing basic HTTP connectivity to ${mcpBaseUrlForDebug(serverRef)}`,
|
||||||
|
)
|
||||||
try {
|
try {
|
||||||
const testUrl = new URL(serverRef.url)
|
const testUrl = new URL(serverRef.url)
|
||||||
logMCPDebug(
|
logMCPDebug(
|
||||||
@@ -1079,7 +1128,7 @@ export const connectToServer = memoize(
|
|||||||
try {
|
try {
|
||||||
await Promise.race([connectPromise, timeoutPromise])
|
await Promise.race([connectPromise, timeoutPromise])
|
||||||
if (stderrOutput) {
|
if (stderrOutput) {
|
||||||
logMCPError(name, `Server stderr: ${stderrOutput}`)
|
logMCPError(name, summarizeStderrForDebug(stderrOutput))
|
||||||
stderrOutput = '' // Release accumulated string to prevent memory growth
|
stderrOutput = '' // Release accumulated string to prevent memory growth
|
||||||
}
|
}
|
||||||
const elapsed = Date.now() - connectStartTime
|
const elapsed = Date.now() - connectStartTime
|
||||||
@@ -1149,7 +1198,7 @@ export const connectToServer = memoize(
|
|||||||
}
|
}
|
||||||
transport.close().catch(() => {})
|
transport.close().catch(() => {})
|
||||||
if (stderrOutput) {
|
if (stderrOutput) {
|
||||||
logMCPError(name, `Server stderr: ${stderrOutput}`)
|
logMCPError(name, summarizeStderrForDebug(stderrOutput))
|
||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export type TeammateStatus = {
|
|||||||
agentId: string
|
agentId: string
|
||||||
agentType?: string
|
agentType?: string
|
||||||
model?: string
|
model?: string
|
||||||
prompt?: string
|
|
||||||
status: 'running' | 'idle' | 'unknown'
|
status: 'running' | 'idle' | 'unknown'
|
||||||
color?: string
|
color?: string
|
||||||
idleSince?: string // ISO timestamp from idle notification
|
idleSince?: string // ISO timestamp from idle notification
|
||||||
@@ -60,7 +59,6 @@ export function getTeammateStatuses(teamName: string): TeammateStatus[] {
|
|||||||
agentId: member.agentId,
|
agentId: member.agentId,
|
||||||
agentType: member.agentType,
|
agentType: member.agentType,
|
||||||
model: member.model,
|
model: member.model,
|
||||||
prompt: member.prompt,
|
|
||||||
status,
|
status,
|
||||||
color: member.color,
|
color: member.color,
|
||||||
tmuxPaneId: member.tmuxPaneId,
|
tmuxPaneId: member.tmuxPaneId,
|
||||||
|
|||||||
Reference in New Issue
Block a user