2026-10-05 20:16:44 +08:00
import { McpServer } from "@modelcontextprotocol/server" ;
2026-10-06 20:46:48 +08:00
import { isAbsolute } from "node:path" ;
2026-07-12 03:25:23 +08:00
2026-07-12 19:32:13 +08:00
import type { AnalysisOperationPort } from "../application/AnalysisProvider.js" ;
2026-10-07 15:05:29 +08:00
import type { BinarySessionPort } from "../application/binary/BinarySession.js" ;
2026-07-14 12:27:13 +08:00
import type { BrowserObservationPort } from "../application/BrowserObservationPort.js" ;
2026-07-24 13:18:58 +00:00
import type { BrowserScenarioCapturePort } from "../application/BrowserScenarioCapturePort.js" ;
2026-10-07 16:03:37 +08:00
import type { ElectronActiveObservationPort } from "../application/javascript/ElectronActiveObservationPort.js" ;
import type { ElectronObservationPort } from "../application/javascript/ElectronObservationPort.js" ;
import type { JavaScriptRuntimeObservationPort } from "../application/javascript/JavaScriptRuntimeObservationPort.js" ;
2026-10-07 11:45:17 +08:00
import type { OptionalProviderLoadFailures } from "../application/OptionalObservationProviders.js" ;
2026-08-10 02:28:11 +08:00
import { PRODUCT_IDENTITY } from "../identity.js" ;
import { silentLogger , type Logger } from "../logger.js" ;
import { registerApplicationTools } from "./registerApplicationTools.js" ;
import { registerArtifactTools } from "./registerArtifactTools.js" ;
import { registerBrowserScenarioTool } from "./registerBrowserScenarioTool.js" ;
import { registerBrowserTools } from "./registerBrowserTools.js" ;
2026-10-07 05:24:32 +08:00
import { registerWebScriptTool } from "./registerWebScriptTool.js" ;
2026-10-07 14:59:52 +08:00
import { registerWebModuleTool } from "./registerWebModuleTool.js" ;
import type { WebModuleTraceService } from "../application/WebModuleTraceService.js" ;
import { createWebModuleTraceService } from "../composition/webModules.js" ;
2026-10-07 16:21:18 +08:00
import { createWebSourceLocationService } from "../composition/webSourceLocations.js" ;
import { registerWebSourceLocationTool } from "./registerWebSourceLocationTool.js" ;
import type { WebSourceLocationService } from "../application/WebSourceLocationService.js" ;
2026-10-07 21:45:07 +08:00
import type { WebRuntimeService } from "../application/WebRuntimeService.js" ;
import { createWebRuntimeService } from "../composition/webRuntime.js" ;
import { registerWebRuntimeTools } from "./registerWebRuntimeTools.js" ;
2026-10-07 12:46:13 +08:00
import { registerJavaScriptRecoveryTool } from "./registerJavaScriptRecoveryTool.js" ;
2026-10-07 16:03:37 +08:00
import { JavaScriptRecoveryService } from "../application/javascript/JavaScriptRecoveryService.js" ;
import type { JavaScriptRecoveryPort } from "../application/javascript/JavaScriptRecoveryPort.js" ;
2026-10-07 12:46:13 +08:00
import { createJavaScriptRecoveryProvider } from "../composition/javascriptRecovery.js" ;
2026-08-10 02:28:11 +08:00
import { registerElectronTools } from "./registerElectronTools.js" ;
import { registerEnhancedTools } from "./registerEnhancedTools.js" ;
import { registerJavaScriptRuntimeObservationTools } from "./registerJavaScriptRuntimeObservationTools.js" ;
import { registerManagedTools } from "./registerManagedTools.js" ;
2026-10-06 22:16:04 +08:00
import { registerFirmwareTools } from "./registerFirmwareTools.js" ;
2026-10-07 14:44:52 +08:00
import { FirmwareAnalysisService } from "../application/firmware/FirmwareAnalysisService.js" ;
import type { FirmwareAnalysisPort } from "../application/firmware/FirmwareAnalysisPort.js" ;
2026-10-07 11:20:26 +08:00
import { createFirmwareAnalysisProvider } from "../composition/firmware.js" ;
2026-10-06 20:46:48 +08:00
import { registerAndroidTools } from "./registerAndroidTools.js" ;
2026-10-07 14:09:57 +08:00
import { AndroidAnalysisService } from "../application/android/AndroidAnalysisService.js" ;
import type { AndroidAnalysisPort } from "../application/android/AndroidAnalysisPort.js" ;
2026-10-07 11:20:26 +08:00
import { createAndroidAnalysisProvider } from "../composition/android.js" ;
2026-08-10 02:28:11 +08:00
import { registerManagedWorkflowTools } from "./registerManagedWorkflowTools.js" ;
import { registerNativeTools } from "./registerNativeTools.js" ;
import { registerOfficialTools } from "./registerOfficialTools.js" ;
import { registerGuidedPrompts } from "./registerPrompts.js" ;
import { registerSessionTools } from "./registerSessionTools.js" ;
2026-07-21 19:51:11 +08:00
import type { SessionAvailability } from "./sessionAvailabilityPolicy.js" ;
2026-07-24 13:18:58 +00:00
import { sessionAvailabilityPolicy } from "./sessionAvailabilityPolicy.js" ;
2026-07-20 17:11:06 +08:00
const TARGET_FREE_INSTRUCTIONS =
2026-09-29 16:28:46 +08:00
"REA provides reverse-engineering tools for local artifacts, native binaries, managed code, browser pages, and runtimes. Use the tool that directly answers the question; discover targets or inspect inventory only when needed. Tool results include inline Evidence and report their coverage and limitations." ;
2026-07-20 17:11:06 +08:00
const ACTIVE_TARGET_INSTRUCTIONS =
2026-09-29 16:28:46 +08:00
"REA analyzes the active reverse-engineering target. Use the analysis tool that answers the question directly. Search or list symbols when discovery is needed; analyze_function provides a function dossier, and focused procedure tools return individual facets." ;
2026-07-12 21:12:18 +00:00
export interface CreateServerOptions {
readonly logger? : Logger ;
2026-10-06 22:16:04 +08:00
readonly firmwareAnalysis? : FirmwareAnalysisPort ;
2026-10-07 12:46:13 +08:00
readonly javascriptRecovery? : JavaScriptRecoveryPort ;
2026-10-07 14:59:52 +08:00
readonly webModuleTrace? : WebModuleTraceService ;
2026-10-07 16:21:18 +08:00
readonly webSourceLocation? : WebSourceLocationService ;
2026-10-07 21:45:07 +08:00
readonly webRuntime? : WebRuntimeService ;
2026-10-06 20:46:48 +08:00
readonly androidAnalysis? : AndroidAnalysisPort ;
2026-07-14 12:27:13 +08:00
readonly browserObservation? : BrowserObservationPort ;
2026-07-24 13:18:58 +00:00
readonly browserScenarioCapture? : BrowserScenarioCapturePort ;
2026-07-14 17:47:50 +08:00
readonly electronObservation? : ElectronObservationPort ;
2026-08-05 19:07:46 +08:00
readonly electronActiveObservation? : ElectronActiveObservationPort ;
2026-07-24 13:18:58 +00:00
readonly javascriptRuntimeObservation? : JavaScriptRuntimeObservationPort ;
2026-07-21 19:51:11 +08:00
readonly availabilityPolicy ?: () => SessionAvailability ;
2026-10-07 11:45:17 +08:00
readonly optionalProviderLoadFailures? : OptionalProviderLoadFailures ;
2026-07-12 21:12:18 +00:00
}
2026-07-12 03:25:23 +08:00
2026-07-24 13:18:58 +00:00
const installSessionToolAvailability = (
server : McpServer ,
session : BinarySessionPort | undefined ,
options : CreateServerOptions ,
) => {
if ( session === undefined ) return undefined ;
const policy = sessionAvailabilityPolicy ( options . availabilityPolicy , {
2026-10-07 11:45:17 +08:00
optionalProviderLoadFailures : options.optionalProviderLoadFailures ,
2026-07-24 13:18:58 +00:00
optionalFeatures : {
2026-10-07 14:59:52 +08:00
webModuleResolutionEnabled :
options.webModuleTrace !== undefined ||
isAbsolute ( process . env . REA_BROWSER_EXECUTABLE ?? "" ),
2026-10-06 22:16:04 +08:00
firmwareInspectionEnabled :
options.firmwareAnalysis !== undefined ||
( process . platform === "linux" &&
isAbsolute ( process . env . REA_BINWALK_COMMAND ?? "" )),
firmwareExtractionEnabled :
options.firmwareAnalysis !== undefined ||
( process . platform === "linux" &&
isAbsolute ( process . env . REA_UNBLOB_COMMAND ?? "" )),
2026-10-06 20:46:48 +08:00
androidAnalysisEnabled :
options.androidAnalysis !== undefined ||
(( process . platform === "linux" || process . platform === "darwin" ) &&
isAbsolute ( process . env . REA_JADX_MCP_JAR ?? "" )),
2026-07-24 13:18:58 +00:00
browserObservationEnabled : options.browserObservation !== undefined ,
2026-10-07 12:46:13 +08:00
javascriptRecoveryEnabled :
options.javascriptRecovery !== undefined ||
( process . platform === "linux" &&
process . arch === "x64" &&
isAbsolute ( process . env . REA_WAKARU_COMMAND ?? "" )),
2026-07-24 13:18:58 +00:00
browserScenarioEnabled : options.browserScenarioCapture !== undefined ,
electronObservationEnabled : options.electronObservation !== undefined ,
2026-08-05 19:07:46 +08:00
electronAutomationEnabled :
2026-10-05 20:16:44 +08:00
options.electronActiveObservation !== undefined ,
2026-07-24 13:18:58 +00:00
v8InspectorObservationEnabled :
options.javascriptRuntimeObservation !== undefined ,
},
});
return {
policy ,
};
};
2026-10-05 20:16:44 +08:00
const createMcpServer = ( session : BinarySessionPort | undefined ) : McpServer =>
2026-08-04 03:00:25 +08:00
new McpServer (
{
name : PRODUCT_IDENTITY.mcpServerKey ,
version : PRODUCT_IDENTITY.packageVersion ,
},
{
2026-09-29 07:08:46 +08:00
capabilities : {},
2026-08-04 03:00:25 +08:00
instructions :
session === undefined
? ACTIVE_TARGET_INSTRUCTIONS
: TARGET_FREE_INSTRUCTIONS ,
},
);
/**
* Construct one MCP server without acquiring subprocess resources.
* Supplying a session adds target lifecycle tools; omitting it retains the
* fixed-target seam used by focused tests and embedders.
*/
export const createServer = (
analysis : AnalysisOperationPort ,
session? : BinarySessionPort ,
options : CreateServerOptions = {},
) : McpServer => {
const startedAt = new Date (). toISOString ();
const logger = options . logger ?? silentLogger ;
2026-10-05 20:16:44 +08:00
const server = createMcpServer ( session );
2026-08-10 02:28:11 +08:00
const availability = installSessionToolAvailability ( server , session , options );
2026-08-04 03:00:25 +08:00
const toolLogger = logger . child ({ layer : "server" });
2026-10-06 20:17:59 +08:00
const {
evidenceById ,
activeTarget ,
recordEvidence ,
recordEvidenceWithUnknown ,
} = createSessionRecorders ( server , session );
2026-08-10 02:28:11 +08:00
const toolContext : ServerToolContext = {
2026-08-04 03:00:25 +08:00
server ,
analysis ,
session ,
options ,
2026-08-10 02:28:11 +08:00
logger : toolLogger ,
2026-10-06 20:17:59 +08:00
evidenceById ,
2026-08-04 03:00:25 +08:00
activeTarget ,
recordEvidence ,
recordEvidenceWithUnknown ,
2026-08-10 02:28:11 +08:00
};
registerBinaryAnalysisTools ( toolContext );
2026-10-07 16:50:41 +08:00
const android = options . androidAnalysis ?? createAndroidAnalysisProvider ();
const previousOnclose = server . server . onclose ;
server . server . onclose = () => {
previousOnclose ? .();
void android . close (). catch (( cause : unknown ) => {
logger . error (
{ error : cause instanceof Error ? cause.message : String ( cause ) },
"Android provider cleanup failed" ,
);
});
};
const closeServer = server . close . bind ( server );
server . close = async () => {
const results = await Promise . allSettled ([ closeServer (), android . close ()]);
for ( const result of results )
if ( result . status === "rejected" ) throw result . reason ;
};
2026-10-06 20:46:48 +08:00
registerAndroidTools (
server ,
2026-10-07 16:50:41 +08:00
new AndroidAnalysisService ( android ),
2026-10-06 20:46:48 +08:00
toolLogger ,
recordEvidence ,
);
2026-10-06 22:16:04 +08:00
registerFirmwareTools (
server ,
new FirmwareAnalysisService (
2026-10-07 11:20:26 +08:00
options . firmwareAnalysis ?? createFirmwareAnalysisProvider (),
2026-10-06 22:16:04 +08:00
),
toolLogger ,
recordEvidence ,
);
2026-08-10 02:28:11 +08:00
registerObservationTools ( toolContext );
2026-10-07 14:59:52 +08:00
registerWebModuleTool (
server ,
options . webModuleTrace ?? createWebModuleTraceService (),
toolLogger ,
recordEvidence ,
);
2026-10-07 16:21:18 +08:00
registerWebSourceLocationTool (
server ,
options . webSourceLocation ?? createWebSourceLocationService (),
toolLogger ,
recordEvidence ,
);
2026-10-07 21:45:07 +08:00
registerWebRuntimeTools (
server ,
options . webRuntime ?? createWebRuntimeService (),
toolLogger ,
recordEvidence ,
);
2026-10-07 12:46:13 +08:00
registerJavaScriptRecoveryTool (
server ,
new JavaScriptRecoveryService (
options . javascriptRecovery ?? createJavaScriptRecoveryProvider (),
),
toolLogger ,
recordEvidence ,
);
2026-07-18 04:11:29 +00:00
registerGuidedPrompts ( server , analysis , session );
if ( session !== undefined ) {
2026-08-10 02:28:11 +08:00
registerSessionTools ( server , session , toolLogger , {
... options ,
...( availability === undefined
? {}
: { availabilityPolicy : availability.policy }),
startedAt ,
});
2026-07-18 04:11:29 +00:00
}
return server ;
};
const createSessionRecorders = (
server : McpServer ,
session : BinarySessionPort | undefined ,
) => ({
2026-10-06 20:17:59 +08:00
evidenceById :
session === undefined
? undefined
: ( evidenceId : string ) => session . evidenceById ( evidenceId ),
2026-07-18 04:11:29 +00:00
activeTarget :
session === undefined ? undefined : () => session . activeTarget (),
recordEvidence :
session === undefined
? undefined
: ( evidence : Parameters < typeof session.recordEvidence >[ 0 ]) => {
const recorded = session . recordEvidence ( evidence );
return recorded ;
},
recordEvidenceWithUnknown :
session === undefined
? undefined
: (
evidence : Parameters < typeof session.recordEvidenceWithUnknown >[ 0 ],
input : Parameters < typeof session.recordEvidenceWithUnknown >[ 1 ],
) => {
const recorded = session . recordEvidenceWithUnknown ( evidence , input );
return recorded ;
},
});
2026-08-10 02:28:11 +08:00
interface ServerToolContext extends ReturnType < typeof createSessionRecorders > {
readonly server : McpServer ;
readonly analysis : AnalysisOperationPort ;
readonly session : BinarySessionPort | undefined ;
readonly options : CreateServerOptions ;
readonly logger : Logger ;
}
const registerBinaryAnalysisTools = ({
server ,
analysis ,
session ,
logger ,
activeTarget ,
recordEvidence ,
recordEvidenceWithUnknown ,
} : ServerToolContext ) : void => {
const recordUnknown =
session === undefined
? undefined
: ( input : Parameters < typeof session.recordUnknown >[ 0 ]) =>
session . recordUnknown ( input );
const analysisOptions = {
logger ,
activeTarget ,
recordEvidence ,
recordUnknown ,
};
registerOfficialTools ( server , analysis , analysisOptions );
registerEnhancedTools ( server , analysis , {
... analysisOptions ,
analysisProfile :
session === undefined ? undefined : () => session . analysisProfile (),
});
const evidenceOptions = { logger , activeTarget , recordEvidence };
registerNativeTools ( server , analysis , evidenceOptions );
registerArtifactTools ( server , analysis , {
... evidenceOptions ,
});
registerManagedTools ( server , analysis , {
... evidenceOptions ,
session ,
});
if ( session !== undefined )
registerManagedWorkflowTools ( server , {
logger ,
recordEvidence ,
recordEvidenceWithUnknown ,
session ,
});
};
const registerObservationTools = ({
2026-10-06 20:17:59 +08:00
evidenceById ,
2026-08-10 02:28:11 +08:00
server ,
options ,
logger ,
recordEvidence ,
recordEvidenceWithUnknown ,
} : ServerToolContext ) : void => {
2026-10-05 20:16:44 +08:00
const common = { logger , recordEvidence };
2026-10-07 05:24:32 +08:00
registerWebScriptTool ( server , common );
2026-08-10 02:28:11 +08:00
registerBrowserTools ( server , {
... common ,
browser : options.browserObservation ,
2026-10-07 11:45:17 +08:00
loadFailure : options.optionalProviderLoadFailures?.browserObservation ,
2026-08-10 02:28:11 +08:00
});
registerBrowserScenarioTool ( server , {
... common ,
provider : options.browserScenarioCapture ,
2026-10-07 11:45:17 +08:00
loadFailure : options.optionalProviderLoadFailures?.browserScenarioCapture ,
2026-08-10 02:28:11 +08:00
});
registerElectronTools ( server , {
... common ,
electron : options.electronObservation ,
electronActive : options.electronActiveObservation ,
2026-10-07 11:45:17 +08:00
observationLoadFailure :
options.optionalProviderLoadFailures?.electronObservation ,
activeLoadFailure :
options.optionalProviderLoadFailures?.electronActiveObservation ,
2026-08-10 02:28:11 +08:00
});
registerJavaScriptRuntimeObservationTools ( server , {
... common ,
runtime : options.javascriptRuntimeObservation ,
2026-10-07 11:45:17 +08:00
loadFailure :
options.optionalProviderLoadFailures?.javascriptRuntimeObservation ,
2026-08-10 02:28:11 +08:00
});
registerApplicationTools ( server , {
2026-10-06 20:17:59 +08:00
evidenceById ,
2026-08-10 02:28:11 +08:00
logger ,
recordEvidence ,
recordEvidenceWithUnknown ,
});
};