
import { __decorate, __param } from '../../../../../../../external/tslib/tslib.es6.js';
import { raceCancellationError, Sequencer, AsyncIterableProducer } from '../../../../base/common/async.js';
import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js';
import { Iterable } from '../../../../base/common/iterator.js';
import { parseTree, findNodeAtOffset, getNodePath } from '../../../../base/common/json.js';
import { normalizeDriveLetter } from '../../../../base/common/labels.js';
import { Disposable, MutableDisposable, toDisposable, DisposableStore } from '../../../../base/common/lifecycle.js';
import { LRUCache } from '../../../../base/common/map.js';
import { Schemas } from '../../../../base/common/network.js';
import { mapValues } from '../../../../base/common/objects.js';
import '../../../../base/common/observableInternal/index.js';
import { basename } from '../../../../base/common/resources.js';
import { URI } from '../../../../base/common/uri.js';
import { createURITransformer } from '../../../../base/common/uriTransformer.js';
import { generateUuid } from '../../../../base/common/uuid.js';
import { localize } from '../../../../nls.js';
import { ICommandService } from '../../../../platform/commands/common/commands.service.js';
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.service.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ILoggerService } from '../../../../platform/log/common/log.service.js';
import '../../../../platform/notification/common/notification.js';
import { INotificationService } from '../../../../platform/notification/common/notification.service.js';
import { IOpenerService } from '../../../../platform/opener/common/opener.service.js';
import { StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IStorageService } from '../../../../platform/storage/common/storage.service.js';
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.service.js';
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.service.js';
import { IEditorService } from '../../../services/editor/common/editorService.service.js';
import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.service.js';
import { IExtensionService } from '../../../services/extensions/common/extensions.service.js';
import { IOutputService } from '../../../services/output/common/output.service.js';
import { chatSessionResourceToId } from '../../chat/common/model/chatUri.js';
import { mcpActivationEvent } from './mcpConfiguration.js';
import { McpDevModeServerAttache } from './mcpDevMode.js';
import { McpIcons, parseAndValidateMcpIcon } from './mcpIcons.js';
import { IMcpRegistry } from './mcpRegistryTypes.service.js';
import { IMcpSandboxService } from './mcpSandboxService.service.js';
import { McpTaskManager } from './mcpTaskManager.js';
import { McpToolName, McpConnectionState, McpConnectionFailedError, McpServerCacheState, McpServerStaticToolAvailability, extensionMcpCollectionPrefix, UserInteractionRequiredError, McpServerTransportType, McpToolVisibility, mcpPromptReplaceSpecialChars, McpCapability, MpcResponseError, ElicitationKind, McpResourceURI } from './mcpTypes.js';
import { IMcpSamplingService, IMcpElicitationService } from './mcpTypes.service.js';
import { MCP } from '../../../../platform/mcp/common/modelContextProtocol.js';
import { UriTemplate } from '../../../../base/common/uriTemplate.js';
import { observableValue, disposableObservableValue } from '../../../../base/common/observableInternal/observables/observableValue.js';
import { derived, derivedDisposable } from '../../../../base/common/observableInternal/observables/derived.js';
import { observableFromEvent } from '../../../../base/common/observableInternal/observables/observableFromEvent.js';
import { autorun, autorunSelfDisposable } from '../../../../base/common/observableInternal/reactions/autorun.js';
import { ObservablePromise } from '../../../../base/common/observableInternal/utils/promise.js';
import Severity$1 from '../../../../base/common/severity.js';
import { transaction } from '../../../../base/common/observableInternal/transaction.js';

var McpServer_1;
const emptyToolEntry = {
    serverName: undefined,
    serverIcons: [],
    serverInstructions: undefined,
    trustedAtNonce: undefined,
    nonce: undefined,
    tools: [],
    prompts: undefined,
    capabilities: undefined
};
const toolInvalidCharRe = /[^a-z0-9_-]/gi;
let McpServerMetadataCache = class McpServerMetadataCache extends Disposable {
    constructor(scope, storageService) {
        super();
        this.didChange = false;
        this.cache = ( new LRUCache(128));
        this.extensionServers = ( new Map());
        const storageKey = "mcpToolCache";
        this._register(storageService.onWillSaveState(() => {
            if (this.didChange) {
                storageService.store(storageKey, {
                    extensionServers: [...this.extensionServers],
                    serverTools: this.cache.toJSON()
                }, scope, StorageTarget.MACHINE);
                this.didChange = false;
            }
        }));
        try {
            const cached = storageService.getObject(storageKey, scope);
            this.extensionServers = ( new Map(cached?.extensionServers ?? []));
            cached?.serverTools?.forEach(([k, v]) => this.cache.set(k, v));
        } catch {}
    }
    reset() {
        this.cache.clear();
        this.extensionServers.clear();
        this.didChange = true;
    }
    get(definitionId) {
        return this.cache.get(definitionId);
    }
    store(definitionId, entry) {
        const prev = this.get(definitionId) || emptyToolEntry;
        this.cache.set(definitionId, {
            ...prev,
            ...entry
        });
        this.didChange = true;
    }
    getServers(collectionId) {
        return this.extensionServers.get(collectionId);
    }
    storeServers(collectionId, entry) {
        if (entry) {
            this.extensionServers.set(collectionId, entry);
        } else {
            this.extensionServers.delete(collectionId);
        }
        this.didChange = true;
    }
};
McpServerMetadataCache = ( __decorate([( __param(1, IStorageService))], McpServerMetadataCache));
class McpPrefixGenerator {
    constructor() {
        this._buckets = ( new Map());
    }
    take(name) {
        const safeName = name.toLowerCase().replace(/[^a-z0-9_.-]+/g, "_").slice(0, McpToolName.MaxPrefixLen - McpToolName.Prefix.length - 1);
        let bucket = this._buckets.get(safeName);
        if (!bucket) {
            bucket = {
                usedIndexes: ( new Set()),
                size: 0
            };
            this._buckets.set(safeName, bucket);
        }
        let index = 1;
        while (( bucket.usedIndexes.has(index))) {
            index++;
        }
        bucket.usedIndexes.add(index);
        bucket.size++;
        const suffix = (index === 1 ? "" : String(index)) + "_";
        const maxNameLen = McpToolName.MaxPrefixLen - McpToolName.Prefix.length - suffix.length;
        const prefix = McpToolName.Prefix + safeName.slice(0, maxNameLen) + suffix;
        return {
            object: prefix,
            dispose: () => {
                bucket.usedIndexes.delete(index);
                bucket.size--;
                if (bucket.size === 0) {
                    this._buckets.delete(safeName);
                }
            }
        };
    }
}
class CachedPrimitive {
    constructor(
        _definitionId,
        _cache,
        _fromStaticDefinition,
        _fromCache,
        _toT,
        defaultValue
    ) {
        this._definitionId = _definitionId;
        this._cache = _cache;
        this._fromStaticDefinition = _fromStaticDefinition;
        this._fromCache = _fromCache;
        this._toT = _toT;
        this.defaultValue = defaultValue;
        this.fromServerPromise = observableValue(this, undefined);
        this.fromServer = derived(
            reader => this.fromServerPromise.read(reader)?.promiseResult.read(reader)?.data
        );
        this.value = derived(reader => {
            const serverTools = this.fromServer.read(reader);
            const definitions = serverTools?.data ?? this._fromStaticDefinition?.read(reader) ?? this.fromCache?.data ?? this.defaultValue;
            return this._toT(definitions, reader);
        });
    }
    get fromCache() {
        const c = this._cache.get(this._definitionId);
        return c ? {
            data: this._fromCache(c),
            nonce: c.nonce
        } : undefined;
    }
    hasStaticDefinition(reader) {
        return !!this._fromStaticDefinition?.read(reader);
    }
}
let McpServer = McpServer_1 = class McpServer extends Disposable {
    static async callOn(server, fn, token = CancellationToken.None) {
        await server.start({
            promptType: "all-untrusted"
        });
        let ranOnce = false;
        let d;
        const callPromise = ( new Promise((resolve, reject) => {
            d = autorun(reader => {
                const connection = server.connection.read(reader);
                if (!connection || ranOnce) {
                    return;
                }
                const handler = connection.handler.read(reader);
                if (!handler) {
                    const state = connection.state.read(reader);
                    if (state.state === McpConnectionState.Kind.Error) {
                        reject(( new McpConnectionFailedError(`MCP server could not be started: ${state.message}`)));
                        return;
                    } else if (state.state === McpConnectionState.Kind.Stopped) {
                        reject(( new McpConnectionFailedError("MCP server has stopped")));
                        return;
                    } else {
                        return;
                    }
                }
                resolve(fn(handler, connection));
                ranOnce = true;
            });
        }));
        return raceCancellationError(callPromise, token).finally(() => d.dispose());
    }
    get capabilities() {
        return this._capabilities.value;
    }
    get tools() {
        return this._tools.value;
    }
    get prompts() {
        return this._prompts.value;
    }
    get serverMetadata() {
        return this._serverMetadata.value;
    }
    get trustedAtNonce() {
        return this._primitiveCache.get(this.definition.id)?.trustedAtNonce;
    }
    set trustedAtNonce(nonce) {
        this._primitiveCache.store(this.definition.id, {
            trustedAtNonce: nonce
        });
    }
    get logger() {
        return this._logger;
    }
    constructor(
        initialCollection,
        definition,
        explicitRoots,
        _requiresExtensionActivation,
        _primitiveCache,
        prefixGenerator,
        enablementModel,
        _mcpRegistry,
        workspacesService,
        _extensionService,
        _loggerService,
        _outputService,
        _telemetryService,
        _commandService,
        _instantiationService,
        _dialogService,
        _notificationService,
        _openerService,
        _samplingService,
        _elicitationService,
        _mcpSandboxService,
        environmentService
    ) {
        super();
        this.definition = definition;
        this._requiresExtensionActivation = _requiresExtensionActivation;
        this._primitiveCache = _primitiveCache;
        this._mcpRegistry = _mcpRegistry;
        this._extensionService = _extensionService;
        this._loggerService = _loggerService;
        this._outputService = _outputService;
        this._telemetryService = _telemetryService;
        this._commandService = _commandService;
        this._instantiationService = _instantiationService;
        this._dialogService = _dialogService;
        this._notificationService = _notificationService;
        this._openerService = _openerService;
        this._samplingService = _samplingService;
        this._elicitationService = _elicitationService;
        this._mcpSandboxService = _mcpSandboxService;
        this._taskManager = this._register(( new McpTaskManager()));
        this._connectionSequencer = ( new Sequencer());
        this._connection = this._register(disposableObservableValue(this, undefined));
        this.connection = this._connection;
        this.connectionState = derived(reader => this._connection.read(reader)?.state.read(reader) ?? {
            state: McpConnectionState.Kind.Stopped
        });
        this.cacheState = derived(reader => {
            const currentNonce = () => this._fullDefinitions.read(reader)?.server?.cacheNonce;
            const stateWhenServingFromCache = () => {
                if (this._tools.hasStaticDefinition(reader)) {
                    return McpServerCacheState.Cached;
                }
                if (!this._tools.fromCache) {
                    return McpServerCacheState.Unknown;
                }
                return currentNonce() === this._tools.fromCache.nonce ? McpServerCacheState.Cached : McpServerCacheState.Outdated;
            };
            const fromServer = this._tools.fromServerPromise.read(reader);
            const connectionState = this.connectionState.read(reader);
            const isIdle = McpConnectionState.canBeStarted(connectionState.state) || !fromServer;
            if (isIdle) {
                return stateWhenServingFromCache();
            }
            const fromServerResult = fromServer?.promiseResult.read(reader);
            if (!fromServerResult) {
                return this._tools.fromCache ? McpServerCacheState.RefreshingFromCached : McpServerCacheState.RefreshingFromUnknown;
            }
            if (fromServerResult.error) {
                return stateWhenServingFromCache();
            }
            return fromServerResult.data?.nonce === currentNonce() ? McpServerCacheState.Live : McpServerCacheState.Outdated;
        });
        this._lastModeDebugged = false;
        this._isQuietStart = false;
        this._isSandboxSuggestionDialogVisible = false;
        this._potentialSandboxBlocks = [];
        this._potentialSandboxBlockListener = this._register(( new MutableDisposable()));
        this.runningToolCalls = ( new Set());
        this.collection = initialCollection;
        this._fullDefinitions = this._mcpRegistry.getServerDefinition(this.collection, this.definition);
        this.enablement = derived(r => enablementModel.readEnabled(definition.id, r));
        this._loggerId = `mcpServer.${definition.id}`;
        this._logger = this._register(_loggerService.createLogger(this._loggerId, {
            hidden: true,
            name: `MCP: ${definition.label}`
        }));
        const that = this;
        this._register(this._instantiationService.createInstance(McpDevModeServerAttache, this, {
            get lastModeDebugged() {
                return that._lastModeDebugged;
            }
        }));
        this._register(toDisposable(() => _loggerService.deregisterLogger(this._loggerId)));
        const workspaces = explicitRoots ? observableValue(this, ( explicitRoots.map(uri => ({
            uri,
            name: basename(uri)
        })))) : observableFromEvent(
            this,
            workspacesService.onDidChangeWorkspaceFolders,
            () => workspacesService.getWorkspace().folders
        );
        const uriTransformer = environmentService.remoteAuthority ? createURITransformer(environmentService.remoteAuthority) : undefined;
        this._register(autorun(reader => {
            const cnx = this._connection.read(reader)?.handler.read(reader);
            if (!cnx) {
                return;
            }
            cnx.roots = ( workspaces.read(reader).filter(w => w.uri.authority === (initialCollection.remoteAuthority || "")).map(w => {
                let uri = ( URI.from(uriTransformer?.transformIncoming(w.uri) ?? w.uri));
                if (uri.scheme === Schemas.file) {
                    uri = URI.file(normalizeDriveLetter(uri.fsPath, true));
                }
                return {
                    name: w.name,
                    uri: ( uri.toString())
                };
            }));
        }));
        this._register(autorun(reader => {
            const cnx = this._connection.read(reader);
            const handler = cnx?.handler.read(reader);
            if (handler) {
                this._populateLiveData(handler, cnx?.definition.cacheNonce, reader.store);
            } else if (this._tools) {
                this.resetLiveData();
            }
        }));
        this._register(autorun(reader => {
            const cnx = this._connection.read(reader);
            this._potentialSandboxBlockListener.value = cnx?.onPotentialSandboxBlock(block => this.recordPotentialSandboxBlock(block));
        }));
        const staticMetadata = derived(reader => {
            const def = this._fullDefinitions.read(reader).server;
            return def && def.cacheNonce !== this._tools.fromCache?.nonce ? def.staticMetadata : undefined;
        });
        this._serverMetadata = ( new CachedPrimitive(this.definition.id, this._primitiveCache, ( staticMetadata.map(
            m => m ? this._toStoredMetadata(m?.serverInfo, m?.instructions) : undefined
        )), entry => ({
            serverName: entry.serverName,
            serverInstructions: entry.serverInstructions,
            serverIcons: entry.serverIcons
        }), entry => ({
            serverName: entry?.serverName,
            serverInstructions: entry?.serverInstructions,
            icons: McpIcons.fromStored(entry?.serverIcons)
        }), undefined));
        const preferredName = derived(
            reader => this._serverMetadata.value.read(reader)?.serverName || this.definition.label
        );
        const prefixRef = derivedDisposable(reader => prefixGenerator.take(preferredName.read(reader)));
        const toolPrefix = ( prefixRef.map(ref => ref.object));
        this._tools = ( new CachedPrimitive(this.definition.id, this._primitiveCache, ( ( staticMetadata.map(m => {
            const tools = m?.tools?.filter(t => t.availability === McpServerStaticToolAvailability.Initial).map(t => t.definition);
            return tools?.length ? ( new ObservablePromise(this._getValidatedTools(tools))) : undefined;
        })).map((o, reader) => o?.promiseResult.read(reader)?.data)), entry => entry.tools, (entry, reader) => ( entry.map(
            def => this._instantiationService.createInstance(McpTool, this, toolPrefix.read(reader), def)
        )).sort((a, b) => a.compare(b)), []));
        this._prompts = ( new CachedPrimitive(
            this.definition.id,
            this._primitiveCache,
            undefined,
            entry => entry.prompts || [],
            entry => ( entry.map(e => ( new McpPrompt(this, e)))),
            []
        ));
        this._capabilities = ( new CachedPrimitive(this.definition.id, this._primitiveCache, ( staticMetadata.map(
            m => m?.capabilities !== undefined ? encodeCapabilities(m.capabilities) : undefined
        )), entry => entry.capabilities, entry => entry, undefined));
        prefixRef.recomputeInitiallyAndOnChange(this._store);
    }
    readDefinitions() {
        return this._fullDefinitions;
    }
    showOutput(preserveFocus) {
        this._loggerService.setVisibility(this._loggerId, true);
        return this._outputService.showChannel(this._loggerId, preserveFocus);
    }
    resources(token) {
        const cts = ( new CancellationTokenSource(token));
        return new AsyncIterableProducer(async emitter => {
            await McpServer_1.callOn(this, async handler => {
                for await (const resource of handler.listResourcesIterable({}, cts.token)) {
                    emitter.emitOne(( resource.map(r => ( new McpResource(this, r, McpIcons.fromParsed(this._parseIcons(r)))))));
                    if (cts.token.isCancellationRequested) {
                        return;
                    }
                }
            });
        }, () => cts.dispose(true));
    }
    resourceTemplates(token) {
        return McpServer_1.callOn(this, async handler => {
            const templates = await handler.listResourceTemplates({}, token);
            return ( templates.map(t => ( new McpResourceTemplate(this, t, McpIcons.fromParsed(this._parseIcons(t))))));
        }, token);
    }
    start(
        {
            interaction,
            autoTrustChanges,
            promptType,
            debug,
            errorOnUserInteraction
        } = {}
    ) {
        interaction?.participants.set(this.definition.id, {
            s: "unknown"
        });
        return this._connectionSequencer.queue(async () => {
            const activationEvent = mcpActivationEvent(this.collection.id.slice(extensionMcpCollectionPrefix.length));
            if (this._requiresExtensionActivation && !this._extensionService.activationEventIsDone(activationEvent)) {
                await this._extensionService.activateByEvent(activationEvent);
                await Promise.all(( this._mcpRegistry.delegates.get().map(r => r.waitForInitialProviderPromises())));
                if (this._store.isDisposed) {
                    return {
                        state: McpConnectionState.Kind.Stopped
                    };
                }
            }
            let connection = this._connection.get();
            this._isQuietStart = !!errorOnUserInteraction;
            if (connection && McpConnectionState.canBeStarted(connection.state.get().state)) {
                connection.dispose();
                connection = undefined;
                this._connection.set(connection, undefined);
            }
            if (!connection) {
                this._lastModeDebugged = !!debug;
                const that = this;
                connection = await this._mcpRegistry.resolveConnection({
                    interaction,
                    autoTrustChanges,
                    promptType,
                    trustNonceBearer: {
                        get trustedAtNonce() {
                            return that.trustedAtNonce;
                        },
                        set trustedAtNonce(nonce) {
                            that.trustedAtNonce = nonce;
                        }
                    },
                    logger: this._logger,
                    collectionRef: this.collection,
                    definitionRef: this.definition,
                    debug,
                    errorOnUserInteraction,
                    taskManager: this._taskManager
                });
                if (!connection) {
                    return {
                        state: McpConnectionState.Kind.Stopped
                    };
                }
                if (this._store.isDisposed) {
                    connection.dispose();
                    return {
                        state: McpConnectionState.Kind.Stopped
                    };
                }
                this._connection.set(connection, undefined);
                if (connection.definition.devMode) {
                    this.showOutput();
                }
            }
            this._potentialSandboxBlocks.length = 0;
            const start = Date.now();
            let state = await connection.start({
                createMessageRequestHandler: (params, token) => this._samplingService.sample({
                    isDuringToolCall: this.runningToolCalls.size > 0,
                    server: this,
                    params
                }, token).then(r => r.sample),
                elicitationRequestHandler: async (req, token) => {
                    const serverInfo = connection.handler.get()?.serverInfo;
                    if (serverInfo) {
                        this._telemetryService.publicLog2("mcp.elicitationRequested", {
                            serverName: serverInfo.name,
                            serverVersion: serverInfo.version
                        });
                    }
                    const r = await this._elicitationService.elicit(
                        this,
                        Iterable.first(this.runningToolCalls),
                        req,
                        token || CancellationToken.None
                    );
                    r.dispose();
                    return r.value;
                }
            });
            this._telemetryService.publicLog2("mcp/serverBootState", {
                state: McpConnectionState.toKindString(state.state),
                time: Date.now() - start
            });
            if (errorOnUserInteraction && state.state === McpConnectionState.Kind.Running) {
                let disposable;
                state = await ( new Promise((resolve, reject) => {
                    disposable = autorun(reader => {
                        const handler = connection.handler.read(reader);
                        if (handler) {
                            resolve(state);
                        }
                        const s = connection.state.read(reader);
                        if (s.state === McpConnectionState.Kind.Stopped && s.reason === "needs-user-interaction") {
                            reject(( new UserInteractionRequiredError("auth")));
                        }
                        if (!McpConnectionState.isRunning(s)) {
                            resolve(s);
                        }
                    });
                })).finally(() => disposable.dispose());
            }
            if (state.state === McpConnectionState.Kind.Error) {
                let disposable;
                state = await ( new Promise((resolve, reject) => {
                    disposable = autorun(reader => {
                        const cnx = this._connection.read(reader);
                        const state = cnx?.state.read(reader);
                        if (cnx && state?.state === McpConnectionState.Kind.Error) {
                            if (!this._isQuietStart) {
                                this.showInteractiveError(cnx, state, this._lastModeDebugged);
                            } else {
                                reject(( new UserInteractionRequiredError("start")));
                            }
                        }
                    });
                })).finally(() => disposable.dispose());
            }
            return state;
        }).finally(() => {
            interaction?.participants.set(this.definition.id, {
                s: "resolved"
            });
        });
    }
    showInteractiveError(cnx, error, debug) {
        if (cnx.definition.sandboxEnabled) {
            if (!this.showSandboxConfigSuggestionFromPotentialBlocks(cnx, this._potentialSandboxBlocks)) {
                this._notificationService.warn(( localize(
                    11537,
                    "The MCP server {0} could not be started: {1}",
                    cnx.definition.label,
                    error.message
                )));
            }
            return;
        }
        if (error.code === "ENOENT" && cnx.launchDefinition.type === McpServerTransportType.Stdio) {
            let docsLink;
            switch (cnx.launchDefinition.command) {
            case "uvx":
                docsLink = `https://aka.ms/vscode-mcp-install/uvx`;
                break;
            case "npx":
                docsLink = `https://aka.ms/vscode-mcp-install/npx`;
                break;
            case "dnx":
                docsLink = `https://aka.ms/vscode-mcp-install/dnx`;
                break;
            case "dotnet":
                docsLink = `https://aka.ms/vscode-mcp-install/dotnet`;
                break;
            }
            const options = [{
                label: ( localize(11538, "Show Output")),
                run: () => this.showOutput()
            }];
            if (cnx.definition.devMode?.debug?.type === "debugpy" && debug) {
                this._notificationService.prompt(Severity$1.Error, ( localize(
                    11539,
                    "The command \"{0}\" was not found. You can specify the path to debugpy in the `dev.debug.debugpyPath` option.",
                    cnx.launchDefinition.command,
                    cnx.definition.label
                )), [...options, {
                    label: ( localize(11540, "View Docs")),
                    run: () => this._openerService.open(( URI.parse("https://aka.ms/vscode-mcp-install/debugpy")))
                }]);
                return;
            }
            if (docsLink) {
                options.push({
                    label: ( localize(11541, "Install {0}", cnx.launchDefinition.command)),
                    run: () => this._openerService.open(( URI.parse(docsLink)))
                });
            }
            this._notificationService.prompt(Severity$1.Error, ( localize(
                11542,
                "The command \"{0}\" needed to run {1} was not found.",
                cnx.launchDefinition.command,
                cnx.definition.label
            )), options);
        } else {
            this._notificationService.warn(( localize(
                11537,
                "The MCP server {0} could not be started: {1}",
                cnx.definition.label,
                error.message
            )));
        }
    }
    showSandboxConfigSuggestionFromPotentialBlocks(cnx, potentialBlocks) {
        if (!cnx.definition.sandboxEnabled || !potentialBlocks.length || this._isSandboxSuggestionDialogVisible) {
            return false;
        }
        if (this._isQuietStart) {
            throw ( new UserInteractionRequiredError("sandbox-suggestion"));
        }
        const existingSandboxConfig = this._fullDefinitions.get().collection?.sandbox;
        const suggestion = this._mcpSandboxService.getSandboxConfigSuggestionMessage(cnx.definition.label, potentialBlocks, existingSandboxConfig);
        if (!suggestion) {
            this._removePotentialSandboxBlocks(potentialBlocks);
            return false;
        }
        this._confirmAndApplySandboxConfigSuggestion(cnx, potentialBlocks, suggestion);
        return true;
    }
    _confirmAndApplySandboxConfigSuggestion(cnx, potentialBlocks, suggestion) {
        const mcpResource = cnx.definition.presentation?.origin?.uri ?? this.collection.presentation?.origin;
        const configTarget = this._fullDefinitions.get().collection?.configTarget;
        this._isSandboxSuggestionDialogVisible = true;
        void this._dialogService.confirm({
            type: "warning",
            message: ( localize(
                11543,
                "Update sandbox configuration in mcp.json for {0}?",
                cnx.definition.label
            )),
            detail: suggestion.message,
            primaryButton: ( localize(11544, "Yes")),
            cancelButton: ( localize(11545, "No"))
        }).then(async result => {
            if (!result.confirmed) {
                return;
            }
            if (!mcpResource || configTarget === undefined) {
                this._notificationService.warn(( localize(
                    11546,
                    "Couldn't determine where to update sandbox configuration for {0}.",
                    cnx.definition.label
                )));
                return;
            }
            try {
                const updated = await this._mcpSandboxService.applySandboxConfigSuggestion(
                    cnx.definition,
                    mcpResource,
                    configTarget,
                    potentialBlocks,
                    suggestion.sandboxConfig
                );
                if (updated) {
                    this._removePotentialSandboxBlocks(potentialBlocks);
                    this._notificationService.info(( localize(
                        11547,
                        "Updated sandbox configuration for {0} in mcp.json. Restart server.",
                        cnx.definition.label
                    )));
                }
            } catch (e) {
                this._notificationService.error(( localize(
                    11548,
                    "Failed to update sandbox configuration for {0}: {1}",
                    cnx.definition.label,
                    e instanceof Error ? e.message : String(e)
                )));
            }
        }).finally(() => {
            this._isSandboxSuggestionDialogVisible = false;
        });
    }
    recordPotentialSandboxBlock(block) {
        this._potentialSandboxBlocks.push(block);
        if (this._potentialSandboxBlocks.length > 200) {
            this._potentialSandboxBlocks.splice(0, this._potentialSandboxBlocks.length - 200);
        }
        const connection = this._connection.get();
        if (connection?.state.get().state === McpConnectionState.Kind.Running) {
            this.showSandboxConfigSuggestionFromPotentialBlocks(connection, this._potentialSandboxBlocks);
        }
    }
    _removePotentialSandboxBlocks(blocks) {
        if (!blocks.length || !this._potentialSandboxBlocks.length) {
            return;
        }
        const toRemove = ( new Set(blocks));
        this._potentialSandboxBlocks = this._potentialSandboxBlocks.filter(block => !( toRemove.has(block)));
    }
    stop() {
        return this._connection.get()?.stop() || Promise.resolve();
    }
    awaitToolRefresh() {
        return ( new Promise(resolve => {
            autorunSelfDisposable(reader => {
                const promise = this._tools.fromServerPromise.read(reader);
                const result = promise?.promiseResult.read(reader);
                if (result) {
                    resolve();
                }
            });
        }));
    }
    resetLiveData() {
        transaction(tx => {
            this._tools.fromServerPromise.set(undefined, tx);
            this._prompts.fromServerPromise.set(undefined, tx);
        });
    }
    async _normalizeTool(originalTool) {
        const uiMeta = originalTool._meta?.ui;
        let visibility = McpToolVisibility.Model | McpToolVisibility.App;
        if (uiMeta?.visibility && Array.isArray(uiMeta.visibility)) {
            visibility &= 0;
            if (uiMeta.visibility.includes("model")) {
                visibility |= McpToolVisibility.Model;
            }
            if (uiMeta.visibility.includes("app")) {
                visibility |= McpToolVisibility.App;
            }
        }
        const tool = {
            ...originalTool,
            serverToolName: originalTool.name,
            _icons: this._parseIcons(originalTool),
            visibility,
            uiResourceUri: uiMeta?.resourceUri
        };
        if (!tool.description) {
            this._logger.warn(
                `Tool ${tool.name} does not have a description. Tools must be accurately described to be called`
            );
            tool.description = "<empty>";
        }
        if (toolInvalidCharRe.test(tool.name)) {
            this._logger.warn(
                `Tool ${JSON.stringify(tool.name)} is invalid. Tools names may only contain [a-z0-9_-]`
            );
            tool.name = tool.name.replace(toolInvalidCharRe, "_");
        }
        if (tool.inputSchema && !tool.inputSchema.properties) {
            tool.inputSchema = {
                ...tool.inputSchema,
                properties: {}
            };
        }
        let diagnostics = [];
        const toolJson = JSON.stringify(tool.inputSchema);
        try {
            const schemaUri = ( URI.parse("https://json-schema.org/draft-07/schema"));
            diagnostics = (await this._commandService.executeCommand("json.validate", schemaUri, toolJson)) || [];
        } catch (e) {}
        if (!diagnostics.length) {
            return tool;
        }
        const tree = parseTree(toolJson);
        const messages = ( diagnostics.map(d => {
            const node = findNodeAtOffset(tree, d.range[0].character);
            const path = node && `/${getNodePath(node).join("/")}`;
            return d.message + (path ? ` (at ${path})` : "");
        }));
        return {
            error: messages
        };
    }
    async _getValidatedTools(tools) {
        let error = "";
        const validations = await Promise.all(( tools.map(t => this._normalizeTool(t))));
        const validated = [];
        for (const [i, result] of validations.entries()) {
            if ("error" in result) {
                error += ( localize(11549, "Tool `{0}` has invalid JSON parameters:", tools[i].name)) + "\n";
                for (const message of result.error) {
                    error += `\t- ${message}\n`;
                }
                error += `\t- Schema: ${JSON.stringify(tools[i].inputSchema)}\n\n`;
            } else {
                validated.push(result);
            }
        }
        if (error) {
            this._logger.warn(
                `${tools.length - validated.length} tools have invalid JSON schemas and will be omitted`
            );
            warnInvalidTools(this._instantiationService, this.definition.label, error);
        }
        return validated;
    }
    _parseIcons(icons) {
        const cnx = this._connection.get();
        if (!cnx) {
            return [];
        }
        return parseAndValidateMcpIcon(icons, cnx.launchDefinition, this._logger);
    }
    _setServerTools(nonce, toolsPromise, tx) {
        const toolPromiseSafe = toolsPromise.then(async tools => {
            this._logger.info(`Discovered ${tools.length} tools`);
            const data = await this._getValidatedTools(tools);
            this._primitiveCache.store(this.definition.id, {
                tools: data,
                nonce
            });
            return {
                data,
                nonce
            };
        });
        this._tools.fromServerPromise.set(( new ObservablePromise(toolPromiseSafe)), tx);
        return toolPromiseSafe;
    }
    _setServerPrompts(nonce, promptsPromise, tx) {
        const promptsPromiseSafe = promptsPromise.then(result => {
            const data = ( result.map(prompt => ({
                ...prompt,
                _icons: this._parseIcons(prompt)
            })));
            this._primitiveCache.store(this.definition.id, {
                prompts: data,
                nonce
            });
            return {
                data,
                nonce
            };
        });
        this._prompts.fromServerPromise.set(( new ObservablePromise(promptsPromiseSafe)), tx);
        return promptsPromiseSafe;
    }
    _toStoredMetadata(serverInfo, instructions) {
        return {
            serverName: serverInfo ? serverInfo.title || serverInfo.name : undefined,
            serverInstructions: instructions,
            serverIcons: serverInfo ? this._parseIcons(serverInfo) : undefined
        };
    }
    _setServerMetadata(
        nonce,
        {
            serverInfo,
            instructions,
            capabilities
        },
        tx
    ) {
        const serverMetadata = this._toStoredMetadata(serverInfo, instructions);
        this._serverMetadata.fromServerPromise.set(ObservablePromise.resolved({
            nonce,
            data: serverMetadata
        }), tx);
        const capabilitiesEncoded = encodeCapabilities(capabilities);
        this._capabilities.fromServerPromise.set(ObservablePromise.resolved({
            data: capabilitiesEncoded,
            nonce
        }), tx);
        this._primitiveCache.store(this.definition.id, {
            ...serverMetadata,
            nonce,
            capabilities: capabilitiesEncoded
        });
    }
    _populateLiveData(handler, cacheNonce, store) {
        const cts = ( new CancellationTokenSource());
        store.add(toDisposable(() => cts.dispose(true)));
        const updateTools = tx => {
            const toolPromise = handler.capabilities.tools ? handler.listTools({}, cts.token) : Promise.resolve([]);
            return this._setServerTools(cacheNonce, toolPromise, tx);
        };
        const updatePrompts = tx => {
            const promptsPromise = handler.capabilities.prompts ? handler.listPrompts({}, cts.token) : Promise.resolve([]);
            return this._setServerPrompts(cacheNonce, promptsPromise, tx);
        };
        store.add(handler.onDidChangeToolList(() => {
            this._logger.info("Tool list changed, refreshing tools...");
            updateTools(undefined);
        }));
        store.add(handler.onDidChangePromptList(() => {
            this._logger.info("Prompts list changed, refreshing prompts...");
            updatePrompts(undefined);
        }));
        transaction(tx => {
            this._setServerMetadata(cacheNonce, {
                serverInfo: handler.serverInfo,
                instructions: handler.serverInstructions,
                capabilities: handler.capabilities
            }, tx);
            updatePrompts(tx);
            const toolUpdate = updateTools(tx);
            toolUpdate.then(tools => {
                this._telemetryService.publicLog2("mcp/serverBoot", {
                    supportsLogging: !!handler.capabilities.logging,
                    supportsPrompts: !!handler.capabilities.prompts,
                    supportsResources: !!handler.capabilities.resources,
                    toolCount: tools.data.length,
                    serverName: handler.serverInfo.name,
                    serverVersion: handler.serverInfo.version
                });
            });
        });
    }
};
McpServer = McpServer_1 = ( __decorate([( __param(7, IMcpRegistry)), ( __param(8, IWorkspaceContextService)), ( __param(9, IExtensionService)), ( __param(10, ILoggerService)), ( __param(11, IOutputService)), ( __param(12, ITelemetryService)), ( __param(13, ICommandService)), ( __param(14, IInstantiationService)), ( __param(15, IDialogService)), ( __param(16, INotificationService)), ( __param(17, IOpenerService)), ( __param(18, IMcpSamplingService)), ( __param(19, IMcpElicitationService)), ( __param(20, IMcpSandboxService)), ( __param(21, IWorkbenchEnvironmentService))], McpServer));
class McpPrompt {
    constructor(_server, _definition) {
        this._server = _server;
        this._definition = _definition;
        this.id = mcpPromptReplaceSpecialChars(this._server.definition.label + "." + _definition.name);
        this.name = _definition.name;
        this.title = _definition.title;
        this.description = _definition.description;
        this.arguments = _definition.arguments || [];
        this.icons = McpIcons.fromStored(this._definition._icons);
    }
    async resolve(args, token) {
        const result = await McpServer.callOn(this._server, h => h.getPrompt({
            name: this._definition.name,
            arguments: args
        }, token), token);
        return result.messages;
    }
    async complete(argument, prefix, alreadyResolved, token) {
        const result = await McpServer.callOn(this._server, h => h.complete({
            ref: {
                type: "ref/prompt",
                name: this._definition.name
            },
            argument: {
                name: argument,
                value: prefix
            },
            context: {
                arguments: alreadyResolved
            }
        }, token), token);
        return result.completion.values;
    }
}
function encodeCapabilities(cap) {
    let out = 0;
    if (cap.logging) {
        out |= McpCapability.Logging;
    }
    if (cap.completions) {
        out |= McpCapability.Completions;
    }
    if (cap.prompts) {
        out |= McpCapability.Prompts;
        if (cap.prompts.listChanged) {
            out |= McpCapability.PromptsListChanged;
        }
    }
    if (cap.resources) {
        out |= McpCapability.Resources;
        if (cap.resources.subscribe) {
            out |= McpCapability.ResourcesSubscribe;
        }
        if (cap.resources.listChanged) {
            out |= McpCapability.ResourcesListChanged;
        }
    }
    if (cap.tools) {
        out |= McpCapability.Tools;
        if (cap.tools.listChanged) {
            out |= McpCapability.ToolsListChanged;
        }
    }
    return out;
}
let McpTool = class McpTool {
    get definition() {
        return this._definition;
    }
    get uiResourceUri() {
        return this._definition.uiResourceUri;
    }
    constructor(_server, idPrefix, _definition, _elicitationService) {
        this._server = _server;
        this._definition = _definition;
        this._elicitationService = _elicitationService;
        this.referenceName = _definition.name.replaceAll(".", "_");
        this.id = (idPrefix + _definition.name).replaceAll(".", "_").slice(0, McpToolName.MaxLength);
        this.icons = McpIcons.fromStored(this._definition._icons);
        this.visibility = _definition.visibility ?? (McpToolVisibility.Model | McpToolVisibility.App);
    }
    async call(params, context, token) {
        if (context) {
            this._server.runningToolCalls.add(context);
        }
        try {
            return await this._callWithProgress(params, undefined, context, token);
        } finally {
            if (context) {
                this._server.runningToolCalls.delete(context);
            }
        }
    }
    async callWithProgress(params, progress, context, token) {
        if (context) {
            this._server.runningToolCalls.add(context);
        }
        try {
            return await this._callWithProgress(params, progress, context, token);
        } finally {
            if (context) {
                this._server.runningToolCalls.delete(context);
            }
        }
    }
    _callWithProgress(
        params,
        progress,
        context,
        token = CancellationToken.None,
        allowRetry = true
    ) {
        const name = this._definition.serverToolName ?? this._definition.name;
        const progressToken = progress ? generateUuid() : undefined;
        const store = ( new DisposableStore());
        return McpServer.callOn(this._server, async h => {
            if (progress) {
                store.add(h.onDidReceiveProgressNotification(e => {
                    if (e.params.progressToken === progressToken) {
                        progress.report({
                            message: e.params.message,
                            progress: e.params.total !== undefined && e.params.progress !== undefined ? e.params.progress / e.params.total : undefined
                        });
                    }
                }));
            }
            const meta = {
                progressToken
            };
            if (context?.chatSessionResource) {
                meta["vscode.conversationId"] = chatSessionResourceToId(context.chatSessionResource);
            }
            if (context?.chatRequestId) {
                meta["vscode.requestId"] = context.chatRequestId;
            }
            if (context?.traceparent) {
                meta["traceparent"] = context.traceparent;
                if (context.tracestate) {
                    meta["tracestate"] = context.tracestate;
                }
            }
            const taskHint = this._definition.execution?.taskSupport;
            const serverSupportsTasksForTools = h.capabilities.tasks?.requests?.tools?.call !== undefined;
            const shouldUseTask = serverSupportsTasksForTools && (taskHint === "required" || taskHint === "optional");
            try {
                const result = await h.callTool({
                    name,
                    arguments: params,
                    task: shouldUseTask ? {} : undefined,
                    _meta: meta
                }, token, progress ? message => progress.report({
                    message
                }) : undefined);
                await this._server.awaitToolRefresh();
                return result;
            } catch (err) {
                if (err instanceof MpcResponseError && err.code === MCP.URL_ELICITATION_REQUIRED && allowRetry) {
                    await this._handleElicitationErr(err, context, token);
                    return this._callWithProgress(params, progress, context, token, false);
                }
                const state = this._server.connectionState.get();
                if (allowRetry && state.state === McpConnectionState.Kind.Error && state.shouldRetry) {
                    return this._callWithProgress(params, progress, context, token, false);
                } else {
                    throw err;
                }
            } finally {
                store.dispose();
            }
        }, token);
    }
    async _handleElicitationErr(err, context, token) {
        const elicitations = err.data?.elicitations;
        if (Array.isArray(elicitations) && elicitations.length > 0) {
            for (const elicitation of elicitations) {
                const elicitResult = await this._elicitationService.elicit(this._server, context, elicitation, token);
                try {
                    if (elicitResult.value.action !== "accept") {
                        throw err;
                    }
                    if (elicitResult.kind === ElicitationKind.URL) {
                        await elicitResult.wait;
                    }
                } finally {
                    elicitResult.dispose();
                }
            }
        }
    }
    compare(other) {
        return this._definition.name.localeCompare(other.definition.name);
    }
};
McpTool = ( __decorate([( __param(3, IMcpElicitationService))], McpTool));
function warnInvalidTools(instaService, serverName, errorText) {
    instaService.invokeFunction(accessor => {
        const notificationService = accessor.get(INotificationService);
        const editorService = accessor.get(IEditorService);
        notificationService.notify({
            severity: Severity$1.Warning,
            message: ( localize(
                11550,
                "MCP server `{0}` has tools with invalid parameters which will be omitted.",
                serverName
            )),
            actions: {
                primary: [{
                    class: undefined,
                    enabled: true,
                    id: "mcpBadSchema.show",
                    tooltip: "",
                    label: ( localize(11551, "Show")),
                    run: () => {
                        editorService.openEditor({
                            resource: undefined,
                            contents: errorText
                        });
                    }
                }]
            }
        });
    });
}
class McpResource {
    constructor(server, original, icons) {
        this.icons = icons;
        this.mcpUri = original.uri;
        this.title = original.title;
        this.uri = McpResourceURI.fromServer(server.definition, original.uri);
        this.name = original.name;
        this.description = original.description;
        this.mimeType = original.mimeType;
        this.sizeInBytes = original.size;
    }
}
class McpResourceTemplate {
    constructor(_server, _definition, icons) {
        this._server = _server;
        this._definition = _definition;
        this.icons = icons;
        this.name = _definition.name;
        this.description = _definition.description;
        this.mimeType = _definition.mimeType;
        this.title = _definition.title;
        this.template = UriTemplate.parse(_definition.uriTemplate);
    }
    resolveURI(vars) {
        const serverUri = this.template.resolve(vars);
        return McpResourceURI.fromServer(this._server.definition, serverUri);
    }
    async complete(templatePart, prefix, alreadyResolved, token) {
        const result = await McpServer.callOn(this._server, h => h.complete({
            ref: {
                type: "ref/resource",
                uri: this._definition.uriTemplate
            },
            argument: {
                name: templatePart,
                value: prefix
            },
            context: {
                arguments: mapValues(alreadyResolved, v => Array.isArray(v) ? v.join("/") : v)
            }
        }, token), token);
        return result.completion.values;
    }
}

export { McpPrefixGenerator, McpServer, McpServerMetadataCache, McpTool };
