import * as plugins from './plugins.js'; import { controllerMcpTypedResponseMaximumBytes, controllerPackageName, controllerProtocolVersion, controllerSessionHarnessIds, controllerStandardProjectDirectoryLimit, controllerUpgradeManagementVersion, type TControllerSessionHarnessId, type IReq_ControllerMcpProjectsList, type IReq_ControllerMcpSessionRead, type IReq_ControllerMcpSessionScratchpadRead, type IReq_ControllerMcpSessionScratchpadUpdate, type IReq_ControllerMcpSessionSend, type IReq_ControllerMcpSessionsList, type IReq_ControllerMcpStatus, type IReq_ControllerMcpSettingsGet, type IReq_ControllerMcpSettingsUpdate, type IReq_ControllerMcpAuthSwitch, type TControllerMcpMethod, type TControllerMcpTypedRequest, type TControllerMcpWorkspaceMethod, type TControllerMcpWorkspaceRequest, type TControllerMcpWorkspaceResponse, } from '../ts_interfaces/index.js'; import { commitinfo } from './00_commitinfo_data.js'; import type { IAGLHomePaths } from './classes.aglhome.js'; import { ControllerMcpDescriptorError, readLiveControllerMcpDescriptor, type IControllerMcpDescriptor, type IControllerMcpDescriptorRecord, } from './classes.mcpdescriptor.js'; import type { IControllerProcessIdentity } from './classes.processinspection.js'; import { assertControllerMcpExactKeys, assertControllerMcpModelChoice, assertControllerMcpRuntimeId, controllerMcpValueIsRecord, isControllerMcpWorkspaceMethod, assertControllerMcpWorkspaceRequest, assertControllerMcpWorkspaceResponse, } from './classes.mcpvalidation.js'; const defaultRequestTimeoutMs = 30_000; const maximumSafeServerErrorBytes = 1024; const maximumScratchpadCharacters = 32_768; const maximumScratchpadBytes = 128 * 1024; const maximumProviderConnectionIdBytes = 512; export type TControllerMcpClientErrorCode = | 'CONTROLLER_UNAVAILABLE' | 'FENCED' | 'AUTHENTICATION_FAILED' | 'PROTOCOL_MISMATCH' | 'RESPONSE_LIMIT' | 'CONCURRENT_CHANGE' | 'PROJECT_NOT_FOUND' | 'SESSION_NOT_FOUND' | 'AMBIGUOUS_SESSION' | 'MODEL_NOT_FOUND' | 'REQUEST_FAILED' | 'OUTCOME_UNKNOWN'; export class ControllerMcpClientError extends Error { public readonly code: TControllerMcpClientErrorCode; constructor(codeArg: TControllerMcpClientErrorCode, messageArg: string) { super(messageArg); this.name = 'ControllerMcpClientError'; this.code = codeArg; } } export interface IControllerMcpClientOptions { controllerPort: number; /** * Proves which chat this server serves. Injected into the harness process environment by the * controller at spawn; absent for an independently launched MCP host, which then reaches only * the discovery surface. */ callerCredential?: string; paths?: IAGLHomePaths; requestTimeoutMs?: number; readProcessIdentity?: ( pidArg: number, ) => Promise; } type TControllerMcpRequestMap = { [TRequest in TControllerMcpTypedRequest as TRequest['method']]: TRequest; }; type TRequestForMethod = TControllerMcpRequestMap[TMethod]['request']; type TResponseForMethod = TControllerMcpRequestMap[TMethod]['response']; const assertScratchpadResponse = (valueArg: unknown): void => { if (!controllerMcpValueIsRecord(valueArg)) throw new Error('invalid'); assertControllerMcpExactKeys( valueArg, ['id', 'text', 'revision'], ['updatedAt', 'updatedBy'], ); const hasUpdatedAt = Object.hasOwn(valueArg, 'updatedAt'); const hasUpdatedBy = Object.hasOwn(valueArg, 'updatedBy'); if ( typeof valueArg.id !== 'string' || typeof valueArg.text !== 'string' || valueArg.text.length > maximumScratchpadCharacters || Buffer.byteLength(valueArg.text, 'utf8') > maximumScratchpadBytes || !Number.isSafeInteger(valueArg.revision) || (valueArg.revision as number) < 0 || hasUpdatedAt !== hasUpdatedBy || ( hasUpdatedAt && ( !Number.isSafeInteger(valueArg.updatedAt) || (valueArg.updatedAt as number) < 0 ) ) || ( hasUpdatedBy && valueArg.updatedBy !== 'user' && valueArg.updatedBy !== 'intelligence' && valueArg.updatedBy !== 'agent' && valueArg.updatedBy !== 'application' ) || ((valueArg.revision as number) === 0 && hasUpdatedAt) || ((valueArg.revision as number) > 0 && !hasUpdatedAt) ) throw new Error('invalid'); }; const asClientError = (errorArg: unknown): ControllerMcpClientError => { if (errorArg instanceof ControllerMcpClientError) return errorArg; if (errorArg instanceof ControllerMcpDescriptorError) { return new ControllerMcpClientError(errorArg.code, errorArg.message); } return new ControllerMcpClientError( 'REQUEST_FAILED', 'The private AGL controller request failed.', ); }; const assertControllerPort = (portArg: number): number => { if (!Number.isSafeInteger(portArg) || portArg < 1 || portArg > 65_535) { throw new ControllerMcpClientError('FENCED', 'The AGL controller port is invalid.'); } return portArg; }; const assertResponsePayload = ( methodArg: TControllerMcpMethod, valueArg: unknown, ): void => { if (!controllerMcpValueIsRecord(valueArg)) { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } try { if (methodArg === 'agl.mcp.controller.settings.get' || methodArg === 'agl.mcp.controller.settings.update') { assertControllerMcpExactKeys(valueArg, methodArg.endsWith('.get') ? ['settings', 'projectsRoot'] : ['settings']); if (methodArg.endsWith('.get') && typeof valueArg.projectsRoot !== 'string') throw new Error('invalid'); const settings = valueArg.settings; if (!controllerMcpValueIsRecord(settings)) throw new Error('invalid'); assertControllerMcpExactKeys(settings, ['defaultModels', 'standardProjectDirectories'], ['autoAcceptPermissions', 'browserVideoBackend', 'activeBrowserVideoBackend', 'lastSessionHarnessId']); if (!Array.isArray(settings.defaultModels) || settings.defaultModels.length > 3 || !Array.isArray(settings.standardProjectDirectories) || settings.standardProjectDirectories.length > controllerStandardProjectDirectoryLimit || !settings.standardProjectDirectories.every( entry => typeof entry === 'string' && entry.startsWith('/'), ) || (settings.autoAcceptPermissions !== undefined && typeof settings.autoAcceptPermissions !== 'boolean') || (settings.browserVideoBackend !== undefined && settings.browserVideoBackend !== 'native') || (settings.activeBrowserVideoBackend !== undefined && settings.activeBrowserVideoBackend !== 'native') || (settings.lastSessionHarnessId !== undefined && !controllerSessionHarnessIds.includes( settings.lastSessionHarnessId as TControllerSessionHarnessId, ))) throw new Error('invalid'); const models = settings.defaultModels.map(assertControllerMcpModelChoice); if (new Set(models.map(model => model.harnessId)).size !== models.length) throw new Error('invalid'); return; } if (methodArg === 'agl.mcp.authswitch.request') { assertControllerMcpExactKeys(valueArg, ['operation']); const operation = valueArg.operation; if (!controllerMcpValueIsRecord(operation) || typeof operation.id !== 'string' || !/^[a-f0-9-]{36}$/.test(operation.id) || typeof operation.contextId !== 'string' || !/^[a-f0-9]{64}$/.test(operation.contextId) || !['pending', 'complete', 'failed'].includes(String(operation.state))) throw new Error('invalid'); return; } if (isControllerMcpWorkspaceMethod(methodArg)) { assertControllerMcpWorkspaceResponse(methodArg, valueArg); return; } if (methodArg === 'agl.mcp.controller.status') { assertControllerMcpExactKeys(valueArg, [ 'status', 'controllerPort', 'lifecycleGeneration', ]); if ( !controllerMcpValueIsRecord(valueArg.status) || !Number.isSafeInteger(valueArg.controllerPort) || typeof valueArg.lifecycleGeneration !== 'string' ) throw new Error('invalid'); return; } if (methodArg === 'agl.mcp.projects.list') { assertControllerMcpExactKeys(valueArg, ['projects']); if (!Array.isArray(valueArg.projects)) throw new Error('invalid'); return; } if (methodArg === 'agl.mcp.sessions.list') { assertControllerMcpExactKeys(valueArg, ['sessions']); if (!Array.isArray(valueArg.sessions)) throw new Error('invalid'); return; } if (methodArg === 'agl.mcp.session.send') { assertControllerMcpExactKeys(valueArg, ['accepted']); if (valueArg.accepted !== true) throw new Error('invalid'); return; } if ( methodArg === 'agl.mcp.session.scratchpad.read' || methodArg === 'agl.mcp.session.scratchpad.update' ) { assertControllerMcpExactKeys(valueArg, ['scratchpad']); assertScratchpadResponse(valueArg.scratchpad); return; } assertControllerMcpExactKeys( valueArg, [ 'session', 'messagePage', 'pendingPrompts', 'permissions', 'questions', 'todos', 'scratchpad', 'intelligenceExchanges', 'toolStreamCursor', 'messageStreamCursor', ], ['autoAcceptPermissions', 'modelChoice', 'providerConnectionId', 'model', 'effort'], ); if ( !controllerMcpValueIsRecord(valueArg.session) || !controllerMcpValueIsRecord(valueArg.messagePage) || !Array.isArray(valueArg.pendingPrompts) || !Array.isArray(valueArg.permissions) || !Array.isArray(valueArg.questions) || !Array.isArray(valueArg.todos) || !controllerMcpValueIsRecord(valueArg.scratchpad) || !Array.isArray(valueArg.intelligenceExchanges) || !controllerMcpValueIsRecord(valueArg.toolStreamCursor) || !controllerMcpValueIsRecord(valueArg.messageStreamCursor) ) throw new Error('invalid'); const sessionId = assertControllerMcpRuntimeId(valueArg.session.id); assertScratchpadResponse(valueArg.scratchpad); const modelChoice = valueArg.modelChoice === undefined ? undefined : assertControllerMcpModelChoice(valueArg.modelChoice); if (modelChoice !== undefined && modelChoice.harnessId !== sessionId.harnessId) { throw new Error('invalid'); } if ( valueArg.providerConnectionId !== undefined && ( typeof valueArg.providerConnectionId !== 'string' || valueArg.providerConnectionId.trim().length === 0 || Buffer.byteLength(valueArg.providerConnectionId, 'utf8') > maximumProviderConnectionIdBytes || sessionId.harnessId !== 'flex' || modelChoice?.harnessId !== 'flex' ) ) throw new Error('invalid'); } catch { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } }; export class ControllerMcpClient { private readonly controllerPort: number; private readonly callerCredential?: string; private readonly paths?: IAGLHomePaths; private readonly requestTimeoutMs: number; private readonly readProcessIdentity?: ( pidArg: number, ) => Promise; constructor(optionsArg: IControllerMcpClientOptions) { this.controllerPort = assertControllerPort(optionsArg.controllerPort); this.callerCredential = optionsArg.callerCredential; this.paths = optionsArg.paths; this.readProcessIdentity = optionsArg.readProcessIdentity; const timeout = optionsArg.requestTimeoutMs ?? defaultRequestTimeoutMs; if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 120_000) { throw new ControllerMcpClientError('FENCED', 'The private request timeout is invalid.'); } this.requestTimeoutMs = timeout; } public async status(signalArg?: AbortSignal): Promise { const descriptor = await this.readCompatibleDescriptor(); const status = await this.dispatch( descriptor.descriptor, 'agl.mcp.controller.status', {}, signalArg, false, ); this.assertStatusHandshake(descriptor.descriptor, status); return status; } public async authswitch(request: IReq_ControllerMcpAuthSwitch['request'], signal?: AbortSignal): Promise { plugins.authswitch.assertAuthSwitchServiceRequest(request); const descriptor = await this.handshake(signal); return this.dispatch(descriptor, 'agl.mcp.authswitch.request', request, signal, request.action !== 'get'); } public async getSettings(signal?: AbortSignal): Promise { const descriptor = await this.handshake(signal); return this.dispatch(descriptor, 'agl.mcp.controller.settings.get', {}, signal, false); } public async updateSettings(request: IReq_ControllerMcpSettingsUpdate['request'], signal?: AbortSignal): Promise { assertControllerMcpExactKeys(request, [], ['browserVideoBackend', 'standardProjectDirectories']); if ( request.browserVideoBackend !== undefined && request.browserVideoBackend !== 'chromium' && request.browserVideoBackend !== 'native' ) { throw new Error('Invalid browser video backend.'); } if (request.standardProjectDirectories !== undefined && ( !Array.isArray(request.standardProjectDirectories) || request.standardProjectDirectories.length > controllerStandardProjectDirectoryLimit || !request.standardProjectDirectories.every( (entry) => typeof entry === 'string' && entry.startsWith('/'), ) )) { throw new Error('Standard project directories must be absolute paths.'); } if (Object.keys(request).length === 0) { throw new Error('A settings update must change at least one setting.'); } const descriptor = await this.handshake(signal); return this.dispatch(descriptor, 'agl.mcp.controller.settings.update', request, signal, true); } public async listProjects( signalArg?: AbortSignal, ): Promise { const descriptor = await this.handshake(signalArg); return this.dispatch( descriptor, 'agl.mcp.projects.list', {}, signalArg, false, ); } public async listSessions( requestArg: IReq_ControllerMcpSessionsList['request'], signalArg?: AbortSignal, ): Promise { const descriptor = await this.handshake(signalArg); return this.dispatch( descriptor, 'agl.mcp.sessions.list', requestArg, signalArg, false, ); } public async readSession( requestArg: IReq_ControllerMcpSessionRead['request'], signalArg?: AbortSignal, ): Promise { const descriptor = await this.handshake(signalArg); return this.dispatch( descriptor, 'agl.mcp.session.read', requestArg, signalArg, false, ); } public async sendSession( requestArg: IReq_ControllerMcpSessionSend['request'], signalArg?: AbortSignal, ): Promise { const descriptor = await this.handshake(signalArg); try { return await this.dispatch( descriptor, 'agl.mcp.session.send', requestArg, signalArg, true, ); } catch (errorArg) { if ( errorArg instanceof ControllerMcpClientError && (errorArg.code === 'PROTOCOL_MISMATCH' || errorArg.code === 'RESPONSE_LIMIT') ) { throw new ControllerMcpClientError( 'OUTCOME_UNKNOWN', 'The controller response could not prove the session-send outcome; do not retry.', ); } throw errorArg; } } public async readSessionScratchpad( requestArg: IReq_ControllerMcpSessionScratchpadRead['request'], signalArg?: AbortSignal, ): Promise { const descriptor = await this.handshake(signalArg); return this.dispatch( descriptor, 'agl.mcp.session.scratchpad.read', requestArg, signalArg, false, ); } public async updateSessionScratchpad( requestArg: IReq_ControllerMcpSessionScratchpadUpdate['request'], signalArg?: AbortSignal, ): Promise { const descriptor = await this.handshake(signalArg); return this.dispatch( descriptor, 'agl.mcp.session.scratchpad.update', requestArg, signalArg, false, ); } public async workspace( methodArg: TMethod, requestArg: TControllerMcpWorkspaceRequest, signalArg?: AbortSignal, ): Promise> { const request = assertControllerMcpWorkspaceRequest(methodArg, requestArg); const descriptor = await this.handshake(signalArg); const mutating = methodArg !== 'agl.mcp.model.list' && methodArg !== 'agl.mcp.resource.list' && methodArg !== 'agl.mcp.context.resolve'; try { return await this.dispatch(descriptor, methodArg, request, signalArg, mutating); } catch (errorArg) { if (mutating && errorArg instanceof ControllerMcpClientError && (errorArg.code === 'PROTOCOL_MISMATCH' || errorArg.code === 'RESPONSE_LIMIT')) { throw new ControllerMcpClientError('OUTCOME_UNKNOWN', 'The response could not prove the operation outcome; inspect state before acting again.'); } throw errorArg; } } private async readCompatibleDescriptor(): Promise { let record: IControllerMcpDescriptorRecord; try { record = await readLiveControllerMcpDescriptor(this.controllerPort, { ...(this.paths === undefined ? {} : { paths: this.paths }), ...(this.readProcessIdentity === undefined ? {} : { readProcessIdentity: this.readProcessIdentity }), }); } catch (errorArg) { throw asClientError(errorArg); } const descriptor = record.descriptor; if ( descriptor.packageName !== controllerPackageName || descriptor.packageVersion !== commitinfo.version || descriptor.protocolVersion !== controllerProtocolVersion || descriptor.upgradeManagementVersion !== controllerUpgradeManagementVersion ) { throw new ControllerMcpClientError( 'PROTOCOL_MISMATCH', 'The running AGL controller is not compatible with this agl mcp command.', ); } return record; } private async handshake(signalArg?: AbortSignal): Promise { const record = await this.readCompatibleDescriptor(); const status = await this.dispatch( record.descriptor, 'agl.mcp.controller.status', {}, signalArg, false, ); this.assertStatusHandshake(record.descriptor, status); return record.descriptor; } private assertStatusHandshake( descriptorArg: IControllerMcpDescriptor, responseArg: IReq_ControllerMcpStatus['response'], ): void { const status = responseArg.status; if ( responseArg.controllerPort !== descriptorArg.controllerPort || responseArg.lifecycleGeneration !== descriptorArg.lifecycleGeneration || status.packageName !== descriptorArg.packageName || status.packageVersion !== descriptorArg.packageVersion || status.protocolVersion !== descriptorArg.protocolVersion || status.upgradeManagementVersion !== descriptorArg.upgradeManagementVersion || status.controllerPid !== descriptorArg.controllerPid || status.processGroupId !== descriptorArg.processGroupId || status.processFingerprint !== descriptorArg.processFingerprint || status.lifecycleState !== 'ready' ) { throw new ControllerMcpClientError( 'PROTOCOL_MISMATCH', 'The private AGL controller handshake did not match its runtime descriptor.', ); } } private async dispatch( descriptorArg: IControllerMcpDescriptor, methodArg: TMethod, requestArg: TRequestForMethod, signalArg: AbortSignal | undefined, outcomeMayBeUnknownArg: boolean, ): Promise> { const requestInstanceId = plugins.crypto.randomBytes(16).toString('base64url'); const correlationId = plugins.crypto.randomBytes(16).toString('base64url'); const envelope = { requestInstanceId, method: methodArg, request: requestArg, response: {}, correlation: { id: correlationId, phase: 'request' as const }, // The controller strips this before responding, so the response stays exactly the five // documented keys and a credential can never be reflected back over the wire. ...(this.callerCredential === undefined ? {} : { caller: { credential: this.callerCredential } }), }; const body = Buffer.from(JSON.stringify(envelope), 'utf8'); let dispatchFinished = false; let responseBytes: Buffer; try { responseBytes = await this.performHttpRequest( descriptorArg, body, signalArg, () => { dispatchFinished = true; }, ); } catch (errorArg) { if (errorArg instanceof ControllerMcpClientError) throw errorArg; if (outcomeMayBeUnknownArg && dispatchFinished) { throw new ControllerMcpClientError( 'OUTCOME_UNKNOWN', 'The controller connection ended after operation dispatch; the outcome is unknown.', ); } throw asClientError(errorArg); } let decoded: unknown; try { const text = responseBytes.toString('utf8'); if (!Buffer.from(text, 'utf8').equals(responseBytes)) throw new Error('invalid UTF-8'); decoded = JSON.parse(text); } catch { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } if (!controllerMcpValueIsRecord(decoded)) { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } try { assertControllerMcpExactKeys( decoded, ['requestInstanceId', 'method', 'request', 'response', 'correlation'], ['error'], ); if ( decoded.requestInstanceId !== requestInstanceId || decoded.method !== methodArg || !plugins.util.isDeepStrictEqual(decoded.request, requestArg) || !controllerMcpValueIsRecord(decoded.response) || !controllerMcpValueIsRecord(decoded.correlation) ) throw new Error('invalid'); assertControllerMcpExactKeys(decoded.correlation, ['id', 'phase']); if ( decoded.correlation.id !== correlationId || decoded.correlation.phase !== 'response' ) throw new Error('invalid'); } catch { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } if (decoded.error !== undefined) { if (!controllerMcpValueIsRecord(decoded.error)) { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } let message = 'The private AGL controller rejected the request.'; let code: TControllerMcpClientErrorCode = 'REQUEST_FAILED'; try { assertControllerMcpExactKeys(decoded.error, ['text', 'data']); if ( typeof decoded.error.text === 'string' && Buffer.byteLength(decoded.error.text, 'utf8') <= maximumSafeServerErrorBytes ) message = decoded.error.text; if (controllerMcpValueIsRecord(decoded.error.data)) { const serverCode = decoded.error.data.code; if (serverCode === 'controller_unavailable') code = 'CONTROLLER_UNAVAILABLE'; if (serverCode === 'authentication_failed') code = 'AUTHENTICATION_FAILED'; if (serverCode === 'response_limit') code = 'RESPONSE_LIMIT'; if (serverCode === 'concurrent_change') code = 'CONCURRENT_CHANGE'; if (serverCode === 'project_not_found') code = 'PROJECT_NOT_FOUND'; if (serverCode === 'session_not_found') code = 'SESSION_NOT_FOUND'; if (serverCode === 'ambiguous_session') code = 'AMBIGUOUS_SESSION'; if (serverCode === 'model_not_found') code = 'MODEL_NOT_FOUND'; if (serverCode === 'outcome_unknown') code = 'OUTCOME_UNKNOWN'; } } catch { throw new ControllerMcpClientError('PROTOCOL_MISMATCH', 'The controller response is invalid.'); } throw new ControllerMcpClientError(code, message); } assertResponsePayload(methodArg, decoded.response); return decoded.response as TResponseForMethod; } private performHttpRequest( descriptorArg: IControllerMcpDescriptor, bodyArg: Buffer, signalArg: AbortSignal | undefined, onDispatchFinishedArg: () => void, ): Promise { const timeoutSignal = AbortSignal.timeout(this.requestTimeoutMs); const signal = signalArg === undefined ? timeoutSignal : AbortSignal.any([signalArg, timeoutSignal]); return new Promise((resolve, reject) => { const request = plugins.http.request({ protocol: 'http:', hostname: '127.0.0.1', port: descriptorArg.privatePort, path: descriptorArg.path, method: 'POST', agent: false, signal, headers: { Host: `127.0.0.1:${descriptorArg.privatePort}`, Authorization: `Bearer ${descriptorArg.token}`, Accept: 'application/json', 'Content-Type': 'application/json', 'Content-Length': String(bodyArg.byteLength), Connection: 'close', }, }, (response) => { const statusCode = response.statusCode ?? 0; const contentType = response.headers['content-type']; const contentLength = Number(response.headers['content-length']); if (statusCode !== 200) { response.resume(); reject(new ControllerMcpClientError( statusCode === 401 || statusCode === 403 ? 'AUTHENTICATION_FAILED' : statusCode === 503 ? 'CONTROLLER_UNAVAILABLE' : 'PROTOCOL_MISMATCH', statusCode === 401 || statusCode === 403 ? 'The private AGL controller rejected authentication.' : 'The private AGL controller rejected the request.', )); return; } if ( typeof contentType !== 'string' || !/^application\/json(?:;|$)/iu.test(contentType) ) { response.resume(); reject(new ControllerMcpClientError( 'PROTOCOL_MISMATCH', 'The controller response content type is invalid.', )); return; } if ( Number.isFinite(contentLength) && contentLength > controllerMcpTypedResponseMaximumBytes ) { response.destroy(); reject(new ControllerMcpClientError( 'RESPONSE_LIMIT', 'The private AGL controller response exceeded its transfer limit.', )); return; } const chunks: Buffer[] = []; let byteLength = 0; response.on('data', (chunkArg: Buffer | string) => { const chunk = Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg); byteLength += chunk.byteLength; if (byteLength > controllerMcpTypedResponseMaximumBytes) { response.destroy(); reject(new ControllerMcpClientError( 'RESPONSE_LIMIT', 'The private AGL controller response exceeded its transfer limit.', )); return; } chunks.push(chunk); }); response.once('end', () => resolve(Buffer.concat(chunks, byteLength))); response.once('error', reject); }); request.once('error', reject); request.once('finish', onDispatchFinishedArg); request.end(bodyArg); }); } }