Skip to content

Commit 0bb8397

Browse files
committed
feat: refactor and unify input handling, remove unnecessary logic
1 parent fee4ff7 commit 0bb8397

File tree

7 files changed

+32
-144
lines changed

7 files changed

+32
-144
lines changed

src/actor/server.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ import { getActorRunData } from './utils.js';
1717

1818
export function createExpressApp(
1919
host: string,
20-
mcpServerOptions: {
21-
enableAddingActors?: boolean;
22-
enableDefaultActors?: boolean;
23-
actors?: string[];
24-
},
2520
): express.Express {
2621
const app = express();
2722
const mcpServers: { [sessionId: string]: ActorsMcpServer } = {};
@@ -74,7 +69,7 @@ export function createExpressApp(
7469
rt: Routes.SSE,
7570
tr: TransportType.SSE,
7671
});
77-
const mcpServer = new ActorsMcpServer(mcpServerOptions, false);
72+
const mcpServer = new ActorsMcpServer(false);
7873
const transport = new SSEServerTransport(Routes.MESSAGE, res);
7974

8075
// Load MCP server tools
@@ -157,7 +152,7 @@ export function createExpressApp(
157152
sessionIdGenerator: () => randomUUID(),
158153
enableJsonResponse: false, // Use SSE response mode
159154
});
160-
const mcpServer = new ActorsMcpServer(mcpServerOptions, false);
155+
const mcpServer = new ActorsMcpServer(false);
161156

162157
// Load MCP server tools
163158
const apifyToken = process.env.APIFY_TOKEN as string;

src/main.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,9 @@ const input = processInput((await Actor.getInput<Partial<Input>>()) ?? ({} as In
2929
log.info('Loaded input', { input: JSON.stringify(input) });
3030

3131
if (STANDBY_MODE) {
32-
let actorsToLoad: string[] = [];
33-
// TODO: in standby mode the input loading does not actually work,
34-
// we should remove this since we are using the URL query parameters to load Actors
35-
// Load only Actors specified in the input
36-
// If you wish to start without any Actor, create a task and leave the input empty
37-
if (input.actors && input.actors.length > 0) {
38-
const { actors } = input;
39-
actorsToLoad = Array.isArray(actors) ? actors : actors.split(',');
40-
}
41-
// Include Actors to load in the MCP server options for backwards compatibility
42-
const app = createExpressApp(HOST, {
43-
enableAddingActors: Boolean(input.enableAddingActors),
44-
enableDefaultActors: false,
45-
actors: actorsToLoad,
46-
});
32+
// In standby mode, actors and tools are provided via URL query params per request
33+
// Start express app
34+
const app = createExpressApp(HOST);
4735
log.info('Actor is running in the STANDBY mode.');
4836

4937
app.listen(PORT, () => {

src/mcp/server.ts

Lines changed: 4 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,19 @@ import { type ActorCallOptions, ApifyApiError } from 'apify-client';
2121
import log from '@apify/log';
2222

2323
import {
24-
defaults,
2524
SERVER_NAME,
2625
SERVER_VERSION,
2726
} from '../const.js';
2827
import { prompts } from '../prompts/index.js';
2928
import { addRemoveTools, callActorGetDataset, defaultTools, getActorsAsTools, toolCategories } from '../tools/index.js';
30-
import { actorNameToToolName, decodeDotPropertyNames } from '../tools/utils.js';
29+
import { decodeDotPropertyNames } from '../tools/utils.js';
3130
import type { ActorMcpTool, ActorTool, HelperTool, ToolEntry } from '../types.js';
3231
import { createProgressTracker } from '../utils/progress.js';
3332
import { getToolPublicFieldOnly } from '../utils/tools.js';
3433
import { connectMCPClient } from './client.js';
3534
import { EXTERNAL_TOOL_CALL_TIMEOUT_MSEC } from './const.js';
3635
import { processParamsGetTools } from './utils.js';
3736

38-
type ActorsMcpServerOptions = {
39-
enableAddingActors?: boolean;
40-
enableDefaultActors?: boolean;
41-
};
42-
4337
type ToolsChangedHandler = (toolNames: string[]) => void;
4438

4539
/**
@@ -48,15 +42,10 @@ type ToolsChangedHandler = (toolNames: string[]) => void;
4842
export class ActorsMcpServer {
4943
public readonly server: Server;
5044
public readonly tools: Map<string, ToolEntry>;
51-
private options: ActorsMcpServerOptions;
5245
private toolsChangedHandler: ToolsChangedHandler | undefined;
5346
private sigintHandler: (() => Promise<void>) | undefined;
5447

55-
constructor(options: ActorsMcpServerOptions = {}, setupSigintHandler = true) {
56-
this.options = {
57-
enableAddingActors: options.enableAddingActors ?? true,
58-
enableDefaultActors: options.enableDefaultActors ?? true, // Default to true for backward compatibility
59-
};
48+
constructor(setupSigintHandler = true) {
6049
this.server = new Server(
6150
{
6251
name: SERVER_NAME,
@@ -74,16 +63,6 @@ export class ActorsMcpServer {
7463
this.setupErrorHandling(setupSigintHandler);
7564
this.setupToolHandlers();
7665
this.setupPromptHandlers();
77-
78-
// Add tools to dynamically load Actors
79-
if (this.options.enableAddingActors) {
80-
this.enableDynamicActorTools();
81-
}
82-
83-
// Initialize automatically for backward compatibility
84-
this.initialize().catch((error) => {
85-
log.error('Failed to initialize server', { error });
86-
});
8766
}
8867

8968
/**
@@ -199,47 +178,6 @@ export class ActorsMcpServer {
199178
}
200179
}
201180

202-
/**
203-
* Resets the server to the default state.
204-
* This method clears all tools and loads the default tools.
205-
* Used primarily for testing purposes.
206-
*/
207-
public async reset(): Promise<void> {
208-
this.tools.clear();
209-
// Unregister the tools changed handler
210-
if (this.toolsChangedHandler) {
211-
this.unregisterToolsChangedHandler();
212-
}
213-
if (this.options.enableAddingActors) {
214-
this.enableDynamicActorTools();
215-
}
216-
// Initialize automatically for backward compatibility
217-
await this.initialize();
218-
}
219-
220-
/**
221-
* Initialize the server with default tools if enabled
222-
*/
223-
public async initialize(): Promise<void> {
224-
if (this.options.enableDefaultActors) {
225-
await this.loadDefaultActors(process.env.APIFY_TOKEN as string);
226-
}
227-
}
228-
229-
/**
230-
* Loads default tools if not already loaded.
231-
* @param apifyToken - Apify API token for authentication
232-
* @returns {Promise<void>} - A promise that resolves when the tools are loaded
233-
*/
234-
public async loadDefaultActors(apifyToken: string): Promise<void> {
235-
const missingActors = defaults.actors.filter((name) => !this.tools.has(actorNameToToolName(name)));
236-
const tools = await getActorsAsTools(missingActors, apifyToken);
237-
if (tools.length > 0) {
238-
log.debug('Loading default tools');
239-
this.upsertTools(tools);
240-
}
241-
}
242-
243181
/**
244182
* Loads tools from URL params.
245183
*
@@ -255,18 +193,8 @@ export class ActorsMcpServer {
255193
}
256194
}
257195

258-
/**
259-
* Add Actors to server dynamically
260-
*/
261-
public enableDynamicActorTools() {
262-
this.options.enableAddingActors = true;
263-
this.upsertTools(addRemoveTools, false);
264-
}
265-
266-
public disableDynamicActorTools() {
267-
this.options.enableAddingActors = false;
268-
this.removeToolsByName(addRemoveTools.map((tool) => tool.tool.name));
269-
}
196+
// Methods for toggling dynamic tools have been removed; add/remove helper tools
197+
// should be managed via the unified input loader.
270198

271199
/** Delete tools from the server and notify the handler.
272200
*/

src/stdio.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ if (!process.env.APIFY_TOKEN) {
114114
}
115115

116116
async function main() {
117-
const mcpServer = new ActorsMcpServer({ enableAddingActors, enableDefaultActors: false });
117+
const mcpServer = new ActorsMcpServer();
118118

119119
// Create an Input object from CLI arguments
120120
const input: Input = {

tests/integration/actor.server-sse.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,8 @@ createIntegrationTestsSuite({
2121
beforeAllFn: async () => {
2222
log.setLevel(log.LEVELS.OFF);
2323

24-
// Create an express app using the proper server setup
25-
const mcpServerOptions = {
26-
enableAddingActors: false,
27-
enableDefaultActors: false,
28-
};
29-
app = createExpressApp(httpServerHost, mcpServerOptions);
24+
// Create an express app
25+
app = createExpressApp(httpServerHost);
3026

3127
// Start a test server
3228
await new Promise<void>((resolve) => {

tests/integration/actor.server-streamable.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,8 @@ createIntegrationTestsSuite({
2121
beforeAllFn: async () => {
2222
log.setLevel(log.LEVELS.OFF);
2323

24-
// Create an express app using the proper server setup
25-
const mcpServerOptions = {
26-
enableAddingActors: false,
27-
enableDefaultActors: false,
28-
};
29-
app = createExpressApp(httpServerHost, mcpServerOptions);
24+
// Create an express app
25+
app = createExpressApp(httpServerHost);
3026

3127
// Start a test server
3228
await new Promise<void>((resolve) => {

tests/integration/internals.test.ts

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import log from '@apify/log';
55
import { actorNameToToolName } from '../../dist/tools/utils.js';
66
import { defaults } from '../../src/const.js';
77
import { ActorsMcpServer } from '../../src/index.js';
8-
import { addRemoveTools, getActorsAsTools } from '../../src/tools/index.js';
8+
import { addRemoveTools, defaultTools, getActorsAsTools } from '../../src/tools/index.js';
9+
import type { Input } from '../../src/types.js';
10+
import { loadToolsFromInput } from '../../src/utils/tools-loader.js';
911
import { ACTOR_PYTHON_EXAMPLE } from '../const.js';
1012
import { expectArrayWeakEquals } from '../helpers.js';
1113

@@ -15,8 +17,11 @@ beforeAll(() => {
1517

1618
describe('MCP server internals integration tests', () => {
1719
it('should load and restore tools from a tool list', async () => {
18-
const actorsMcpServer = new ActorsMcpServer({ enableDefaultActors: true, enableAddingActors: true }, false);
19-
await actorsMcpServer.initialize();
20+
const actorsMcpServer = new ActorsMcpServer(false);
21+
const initialTools = await loadToolsFromInput({
22+
enableAddingActors: true,
23+
} as Input, process.env.APIFY_TOKEN as string);
24+
actorsMcpServer.upsertTools(initialTools);
2025

2126
// Load new tool
2227
const newTool = await getActorsAsTools([ACTOR_PYTHON_EXAMPLE], process.env.APIFY_TOKEN as string);
@@ -27,7 +32,8 @@ describe('MCP server internals integration tests', () => {
2732
const expectedToolNames = [
2833
...defaults.actors,
2934
...addRemoveTools.map((tool) => tool.tool.name),
30-
...[ACTOR_PYTHON_EXAMPLE],
35+
...defaultTools.map((tool) => tool.tool.name),
36+
ACTOR_PYTHON_EXAMPLE,
3137
];
3238
expectArrayWeakEquals(expectedToolNames, names);
3339

@@ -42,41 +48,19 @@ describe('MCP server internals integration tests', () => {
4248
expectArrayWeakEquals(actorsMcpServer.listAllToolNames(), expectedToolNames);
4349
});
4450

45-
it('should reset and restore tool state with default tools', async () => {
46-
const actorsMCPServer = new ActorsMcpServer({ enableDefaultActors: true, enableAddingActors: true }, false);
47-
await actorsMCPServer.initialize();
48-
49-
const numberOfTools = addRemoveTools.length + defaults.actors.length;
50-
const toolList = actorsMCPServer.listAllToolNames();
51-
expect(toolList.length).toEqual(numberOfTools);
52-
// Add a new Actor
53-
const newTool = await getActorsAsTools([ACTOR_PYTHON_EXAMPLE], process.env.APIFY_TOKEN as string);
54-
actorsMCPServer.upsertTools(newTool);
55-
56-
// Store the tool name list
57-
const toolListWithActor = actorsMCPServer.listAllToolNames();
58-
expect(toolListWithActor.length).toEqual(numberOfTools + 1); // + 1 for the added Actor
59-
60-
// Remove all tools
61-
await actorsMCPServer.reset();
62-
// We connect second client so that the default tools are loaded
63-
// if no specific list of Actors is provided
64-
const toolListAfterReset = actorsMCPServer.listAllToolNames();
65-
expect(toolListAfterReset.length).toEqual(numberOfTools);
66-
});
67-
6851
it('should notify tools changed handler on tool modifications', async () => {
6952
let latestTools: string[] = [];
70-
const numberOfTools = addRemoveTools.length + defaults.actors.length;
53+
const numberOfTools = addRemoveTools.length + defaults.actors.length + defaultTools.length;
7154

7255
let toolNotificationCount = 0;
7356
const onToolsChanged = (tools: string[]) => {
7457
latestTools = tools;
7558
toolNotificationCount++;
7659
};
7760

78-
const actorsMCPServer = new ActorsMcpServer({ enableDefaultActors: true, enableAddingActors: true }, false);
79-
await actorsMCPServer.initialize();
61+
const actorsMCPServer = new ActorsMcpServer(false);
62+
const seeded = await loadToolsFromInput({ enableAddingActors: true } as Input, process.env.APIFY_TOKEN as string);
63+
actorsMCPServer.upsertTools(seeded);
8064
actorsMCPServer.registerToolsChangedHandler(onToolsChanged);
8165

8266
// Add a new Actor
@@ -113,14 +97,15 @@ describe('MCP server internals integration tests', () => {
11397
it('should stop notifying after unregistering tools changed handler', async () => {
11498
let latestTools: string[] = [];
11599
let notificationCount = 0;
116-
const numberOfTools = addRemoveTools.length + defaults.actors.length;
100+
const numberOfTools = addRemoveTools.length + defaults.actors.length + defaultTools.length;
117101
const onToolsChanged = (tools: string[]) => {
118102
latestTools = tools;
119103
notificationCount++;
120104
};
121105

122-
const actorsMCPServer = new ActorsMcpServer({ enableDefaultActors: true, enableAddingActors: true }, false);
123-
await actorsMCPServer.initialize();
106+
const actorsMCPServer = new ActorsMcpServer(false);
107+
const seeded = await loadToolsFromInput({ enableAddingActors: true } as Input, process.env.APIFY_TOKEN as string);
108+
actorsMCPServer.upsertTools(seeded);
124109
actorsMCPServer.registerToolsChangedHandler(onToolsChanged);
125110

126111
// Add a new Actor

0 commit comments

Comments
 (0)