1- import type { ParsedUrlQuery } from 'querystring' ;
2- import { parse } from 'querystring' ;
1+ /*
2+ This file serves as an Actor MCP SSE server entry point.
3+ */
4+
5+ import type { ParsedUrlQuery } from 'node:querystring' ;
6+ import { parse } from 'node:querystring' ;
37
48import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js' ;
59import { Actor } from 'apify' ;
@@ -10,30 +14,25 @@ import express from 'express';
1014import { HEADER_READINESS_PROBE , Routes } from './const.js' ;
1115import { processInput } from './input.js' ;
1216import { log } from './logger.js' ;
13- import { ApifyMcpServer } from './server.js' ;
17+ import { ApifyMcpServer } from './mcp-server.js' ;
18+ import { createServerApp } from './server.js' ;
1419import { getActorDiscoveryTools , getActorAutoLoadingTools } from './tools.js' ;
1520import type { Input } from './types.js' ;
21+ import { isActorStandby } from './utils.js' ;
1622
1723await Actor . init ( ) ;
1824
19- const STANDBY_MODE = Actor . getEnv ( ) . metaOrigin === 'STANDBY' ;
20- const HOST = Actor . isAtHome ( ) ? process . env . ACTOR_STANDBY_URL : 'http://localhost' ;
21- const PORT = Actor . isAtHome ( ) ? process . env . ACTOR_STANDBY_PORT : 3001 ;
25+ const HOST = Actor . isAtHome ( ) ? process . env . ACTOR_STANDBY_URL as string : 'http://localhost' ;
26+ const PORT = Actor . isAtHome ( ) ? Number ( process . env . ACTOR_STANDBY_PORT ) : 3001 ;
2227
2328if ( ! process . env . APIFY_TOKEN ) {
2429 log . error ( 'APIFY_TOKEN is required but not set in the environment variables.' ) ;
2530 process . exit ( 1 ) ;
2631}
2732
28- const app = express ( ) ;
29-
3033const mcpServer = new ApifyMcpServer ( ) ;
31- let transport : SSEServerTransport ;
3234
33- const HELP_MESSAGE = `Connect to the server with GET request to ${ HOST } /sse?token=YOUR-APIFY-TOKEN`
34- + ` and then send POST requests to ${ HOST } /message?token=YOUR-APIFY-TOKEN` ;
35-
36- const actorRun = Actor . isAtHome ( ) ? {
35+ const actorRunData = Actor . isAtHome ( ) ? {
3736 id : process . env . ACTOR_RUN_ID ,
3837 actId : process . env . ACTOR_ID ,
3938 userId : process . env . APIFY_USER_ID ,
@@ -56,86 +55,11 @@ const actorRun = Actor.isAtHome() ? {
5655 standbyUrl : process . env . ACTOR_STANDBY_URL ,
5756} : { } ;
5857
59- /**
60- * Process input parameters and update tools
61- * If URL contains query parameter actors, add tools from actors, otherwise add tools from default actors
62- * @param url
63- */
64- async function processParamsAndUpdateTools ( url : string ) {
65- const params = parse ( url . split ( '?' ) [ 1 ] || '' ) as ParsedUrlQuery ;
66- delete params . token ;
67- log . debug ( `Received input parameters: ${ JSON . stringify ( params ) } ` ) ;
68- const input = await processInput ( params as unknown as Input ) ;
69- if ( input . actors ) {
70- await mcpServer . addToolsFromActors ( input . actors as string [ ] ) ;
71- }
72- if ( input . enableActorAutoLoading ) {
73- mcpServer . updateTools ( getActorAutoLoadingTools ( ) ) ;
74- }
75- log . debug ( `Server is running in STANDBY mode with the following Actors (tools): ${ mcpServer . getToolNames ( ) } .
76- To use different Actors, provide them in query parameter "actors" or include them in the Actor Task input.` ) ;
77- }
78-
79- app . route ( Routes . ROOT )
80- . get ( async ( req : Request , res : Response ) => {
81- if ( req . headers && req . get ( HEADER_READINESS_PROBE ) !== undefined ) {
82- log . debug ( 'Received readiness probe' ) ;
83- res . status ( 200 ) . json ( { message : 'Server is ready' } ) . end ( ) ;
84- return ;
85- }
86- try {
87- log . info ( `Received GET message at: ${ Routes . ROOT } ` ) ;
88- await processParamsAndUpdateTools ( req . url ) ;
89- res . status ( 200 ) . json ( { message : `Actor is using Model Context Protocol. ${ HELP_MESSAGE } ` , data : actorRun } ) . end ( ) ;
90- } catch ( error ) {
91- log . error ( `Error in GET ${ Routes . ROOT } ${ error } ` ) ;
92- res . status ( 500 ) . json ( { message : 'Internal Server Error' } ) . end ( ) ;
93- }
94- } )
95- . head ( ( _req : Request , res : Response ) => {
96- res . status ( 200 ) . end ( ) ;
97- } ) ;
98-
99- app . route ( Routes . SSE )
100- . get ( async ( req : Request , res : Response ) => {
101- try {
102- log . info ( `Received GET message at: ${ Routes . SSE } ` ) ;
103- await processParamsAndUpdateTools ( req . url ) ;
104- transport = new SSEServerTransport ( Routes . MESSAGE , res ) ;
105- await mcpServer . connect ( transport ) ;
106- } catch ( error ) {
107- log . error ( `Error in GET ${ Routes . SSE } : ${ error } ` ) ;
108- res . status ( 500 ) . json ( { message : 'Internal Server Error' } ) . end ( ) ;
109- }
110- } ) ;
111-
112- app . route ( Routes . MESSAGE )
113- . post ( async ( req : Request , res : Response ) => {
114- try {
115- log . info ( `Received POST message at: ${ Routes . MESSAGE } ` ) ;
116- if ( transport ) {
117- await transport . handlePostMessage ( req , res ) ;
118- } else {
119- res . status ( 400 ) . json ( {
120- message : 'Server is not connected to the client. '
121- + 'Connect to the server with GET request to /sse endpoint' ,
122- } ) ;
123- }
124- } catch ( error ) {
125- log . error ( `Error in POST ${ Routes . MESSAGE } : ${ error } ` ) ;
126- res . status ( 500 ) . json ( { message : 'Internal Server Error' } ) . end ( ) ;
127- }
128- } ) ;
129-
130- // Catch-all for undefined routes
131- app . use ( ( req : Request , res : Response ) => {
132- res . status ( 404 ) . json ( { message : `There is nothing at route ${ req . method } ${ req . originalUrl } . ${ HELP_MESSAGE } ` } ) . end ( ) ;
133- } ) ;
134-
13558const input = await processInput ( ( await Actor . getInput < Partial < Input > > ( ) ) ?? ( { } as Input ) ) ;
13659log . info ( `Loaded input: ${ JSON . stringify ( input ) } ` ) ;
13760
138- if ( STANDBY_MODE ) {
61+ if ( isActorStandby ( ) ) {
62+ const app = createServerApp ( HOST , mcpServer , actorRunData ) ;
13963 log . info ( 'Actor is running in the STANDBY mode.' ) ;
14064 await mcpServer . addToolsFromDefaultActors ( ) ;
14165 mcpServer . updateTools ( getActorDiscoveryTools ( ) ) ;
0 commit comments