axios+telemetry cleanup

This commit is contained in:
2026-04-02 15:19:11 +03:00
parent a3cbca1e11
commit 7e1eac8002
100 changed files with 3048 additions and 4491 deletions

View File

@@ -24,7 +24,7 @@ import {
OAuthTokensSchema,
} from '@modelcontextprotocol/sdk/shared/auth.js'
import type { FetchLike } from '@modelcontextprotocol/sdk/shared/transport.js'
import axios from 'axios'
import { isHttpError, nativeRequest } from '../../utils/http.js'
import { createHash, randomBytes, randomUUID } from 'crypto'
import { mkdir } from 'fs/promises'
import { createServer, type Server } from 'http'
@@ -428,25 +428,30 @@ async function revokeToken({
}
try {
await axios.post(endpoint, params, { headers })
await nativeRequest(endpoint, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/x-www-form-urlencoded' },
body: params.toString(),
responseType: 'text',
})
logMCPDebug(serverName, `Successfully revoked ${tokenTypeHint}`)
} catch (error: unknown) {
// Fallback for non-RFC-7009-compliant servers that require Bearer auth
if (
axios.isAxiosError(error) &&
error.response?.status === 401 &&
isHttpError(error) &&
error.status === 401 &&
accessToken
) {
logMCPDebug(
serverName,
`Got 401, retrying ${tokenTypeHint} revocation with Bearer auth`,
)
// RFC 6749 §2.3.1: must not send more than one auth method. The retry
// switches to Bearer — clear any client creds from the body.
params.delete('client_id')
params.delete('client_secret')
await axios.post(endpoint, params, {
headers: { ...headers, Authorization: `Bearer ${accessToken}` },
await nativeRequest(endpoint, {
method: 'POST',
headers: { ...headers, Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/x-www-form-urlencoded' },
body: params.toString(),
responseType: 'text',
})
logMCPDebug(
serverName,

View File

@@ -1,4 +1,3 @@
import axios from 'axios'
import memoize from 'lodash-es/memoize.js'
import { getOauthConfig } from 'src/constants/oauth.js'
import {
@@ -9,6 +8,7 @@ import { getClaudeAIOAuthTokens } from 'src/utils/auth.js'
import { getGlobalConfig, saveGlobalConfig } from 'src/utils/config.js'
import { logForDebugging } from 'src/utils/debug.js'
import { isEnvDefinedFalsy } from 'src/utils/envUtils.js'
import { nativeRequest } from 'src/utils/http.js'
import { clearMcpAuthCache } from './client.js'
import { normalizeNameForMCP } from './normalization.js'
import type { ScopedMcpServerConfig } from './types.js'
@@ -79,7 +79,7 @@ export const fetchClaudeAIMcpConfigsIfEligible = memoize(
logForDebugging(`[claudeai-mcp] Fetching from ${url}`)
const response = await axios.get<ClaudeAIMcpServersResponse>(url, {
const { data: respData } = await nativeRequest<ClaudeAIMcpServersResponse>(url, {
headers: {
Authorization: `Bearer ${tokens.accessToken}`,
'Content-Type': 'application/json',
@@ -96,7 +96,7 @@ export const fetchClaudeAIMcpConfigsIfEligible = memoize(
// colliding with "Example Server! (2)" which both normalize to claude_ai_Example_Server_2).
const usedNormalizedNames = new Set<string>()
for (const server of response.data.data) {
for (const server of respData.data) {
const baseName = `claude.ai ${server.display_name}`
// Try without suffix first, then increment until we find an unused normalized name

View File

@@ -43,7 +43,7 @@ import pMap from 'p-map'
import { getOriginalCwd, getSessionId } from '../../bootstrap/state.js'
import type { Command } from '../../commands.js'
import { getOauthConfig } from '../../constants/oauth.js'
import { PRODUCT_URL } from '../../constants/product.js'
import { VERSION, PRODUCT_URL } from '../../constants/product.js'
import type { AppState } from '../../state/AppState.js'
import {
type Tool,
@@ -986,7 +986,7 @@ export const connectToServer = memoize(
{
name: 'claude-code',
title: 'Claude Code',
version: MACRO.VERSION ?? 'unknown',
version: VERSION ?? 'unknown',
description: "Anthropic's agentic coding tool",
websiteUrl: PRODUCT_URL,
},
@@ -3281,7 +3281,7 @@ export async function setupSdkMcpClients(
{
name: 'claude-code',
title: 'Claude Code',
version: MACRO.VERSION ?? 'unknown',
version: VERSION ?? 'unknown',
description: "Anthropic's agentic coding tool",
websiteUrl: PRODUCT_URL,
},

View File

@@ -1,4 +1,5 @@
import { getIsNonInteractiveSession } from '../../bootstrap/state.js'
import { FEEDBACK_CHANNEL } from '../../constants/product.js'
import { checkHasTrustDialogAccepted } from '../../utils/config.js'
import { logAntError } from '../../utils/debug.js'
import { errorMessage } from '../../utils/errors.js'
@@ -48,7 +49,7 @@ export async function getMcpHeadersFromHelper(
const hasTrust = checkHasTrustDialogAccepted()
if (!hasTrust) {
const error = new Error(
`Security: headersHelper for MCP server '${serverName}' executed before workspace trust is confirmed. If you see this message, post in ${MACRO.FEEDBACK_CHANNEL}.`,
`Security: headersHelper for MCP server '${serverName}' executed before workspace trust is confirmed. If you see this message, post in ${FEEDBACK_CHANNEL}.`,
)
logAntError('MCP headersHelper invoked before trust check', error)
logEvent('tengu_mcp_headersHelper_missing_trust', {})

View File

@@ -1,6 +1,6 @@
import axios from 'axios'
import { logForDebugging } from '../../utils/debug.js'
import { errorMessage } from '../../utils/errors.js'
import { nativeRequest } from '../../utils/http.js'
type RegistryServer = {
server: {
@@ -36,13 +36,13 @@ export async function prefetchOfficialMcpUrls(): Promise<void> {
}
try {
const response = await axios.get<RegistryResponse>(
const { data } = await nativeRequest<RegistryResponse>(
'https://api.anthropic.com/mcp-registry/v0/servers?version=latest&visibility=commercial',
{ timeout: 5000 },
)
const urls = new Set<string>()
for (const entry of response.data.servers) {
for (const entry of data.servers) {
for (const remote of entry.server.remotes ?? []) {
const normalized = normalizeUrl(remote.url)
if (normalized) {