vscodeSdkMcp.ts
services/mcp/vscodeSdkMcp.ts
113
Lines
3703
Bytes
3
Exports
6
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with integrations, mcp. It contains 113 lines, 6 detected imports, and 3 detected exports.
Important relationships
Detected exports
LogEventNotificationSchemanotifyVscodeFileUpdatedsetupVscodeSdkMcp
Keywords
clientvscodenotificationenabledgetfeaturevalue_cached_may_be_staledisabledparamsvscodemcpclientvoidgates
Detected imports
src/utils/debug.jszod/v4../../utils/lazySchema.js../analytics/growthbook.js../analytics/index.js./types.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
import { logForDebugging } from 'src/utils/debug.js'
import { z } from 'zod/v4'
import { lazySchema } from '../../utils/lazySchema.js'
import {
checkStatsigFeatureGate_CACHED_MAY_BE_STALE,
getFeatureValue_CACHED_MAY_BE_STALE,
} from '../analytics/growthbook.js'
import { logEvent } from '../analytics/index.js'
import type { ConnectedMCPServer, MCPServerConnection } from './types.js'
// Mirror of AutoModeEnabledState in permissionSetup.ts — inlined because that
// file pulls in too many deps for this thin IPC module.
type AutoModeEnabledState = 'enabled' | 'disabled' | 'opt-in'
function readAutoModeEnabledState(): AutoModeEnabledState | undefined {
const v = getFeatureValue_CACHED_MAY_BE_STALE<{ enabled?: string }>(
'tengu_auto_mode_config',
{},
)?.enabled
return v === 'enabled' || v === 'disabled' || v === 'opt-in' ? v : undefined
}
export const LogEventNotificationSchema = lazySchema(() =>
z.object({
method: z.literal('log_event'),
params: z.object({
eventName: z.string(),
eventData: z.object({}).passthrough(),
}),
}),
)
// Store the VSCode MCP client reference for sending notifications
let vscodeMcpClient: ConnectedMCPServer | null = null
/**
* Sends a file_updated notification to the VSCode MCP server. This is used to
* notify VSCode when files are edited or written by Claude.
*/
export function notifyVscodeFileUpdated(
filePath: string,
oldContent: string | null,
newContent: string | null,
): void {
if (process.env.USER_TYPE !== 'ant' || !vscodeMcpClient) {
return
}
void vscodeMcpClient.client
.notification({
method: 'file_updated',
params: { filePath, oldContent, newContent },
})
.catch((error: Error) => {
// Do not throw if the notification failed
logForDebugging(
`[VSCode] Failed to send file_updated notification: ${error.message}`,
)
})
}
/**
* Sets up the speicial internal VSCode MCP for bidirectional communication using notifications.
*/
export function setupVscodeSdkMcp(sdkClients: MCPServerConnection[]): void {
const client = sdkClients.find(client => client.name === 'claude-vscode')
if (client && client.type === 'connected') {
// Store the client reference for later use
vscodeMcpClient = client
client.client.setNotificationHandler(
LogEventNotificationSchema(),
async notification => {
const { eventName, eventData } = notification.params
logEvent(
`tengu_vscode_${eventName}`,
eventData as { [key: string]: boolean | number | undefined },
)
},
)
// Send necessary experiment gates to VSCode immediately.
const gates: Record<string, boolean | string> = {
tengu_vscode_review_upsell: checkStatsigFeatureGate_CACHED_MAY_BE_STALE(
'tengu_vscode_review_upsell',
),
tengu_vscode_onboarding: checkStatsigFeatureGate_CACHED_MAY_BE_STALE(
'tengu_vscode_onboarding',
),
// Browser support.
tengu_quiet_fern: getFeatureValue_CACHED_MAY_BE_STALE(
'tengu_quiet_fern',
false,
),
// In-band OAuth via claude_authenticate (vs. extension-native PKCE).
tengu_vscode_cc_auth: getFeatureValue_CACHED_MAY_BE_STALE(
'tengu_vscode_cc_auth',
false,
),
}
// Tri-state: 'enabled' | 'disabled' | 'opt-in'. Omit if unknown so VSCode
// fails closed (treats absent as 'disabled').
const autoModeState = readAutoModeEnabledState()
if (autoModeState !== undefined) {
gates.tengu_auto_mode_state = autoModeState
}
void client.client.notification({
method: 'experiment_gates',
params: { gates },
})
}
}