Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,4 @@ All notable changes to this project will be documented in this file.
### 🐛 Bug Fixes

- Update express routes to correctly handle GET and HEAD requests, fix CI ([#5](https://github.com/apify/actors-mcp-server/pull/5)) ([ec6e9b0](https://github.com/apify/actors-mcp-server/commit/ec6e9b0a4657f673b3650a5906fe00e66411d7f1)) by [@jirispilka](https://github.com/jirispilka)
- Correct publishing of npm module ([#6](https://github.com/apify/actors-mcp-server/pull/6)) ([4c953e9](https://github.com/apify/actors-mcp-server/commit/4c953e9fe0c735f1690c8356884dd78d8608979f)) by [@jirispilka](https://github.com/jirispilka)
- Correct publishing of npm module ([#6](https://github.com/apify/actors-mcp-server/pull/6)) ([4c953e9](https://github.com/apify/actors-mcp-server/commit/4c953e9fe0c735f1690c8356884dd78d8608979f)) by [@jirispilka](https://github.com/jirispilka)
28 changes: 11 additions & 17 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,7 @@ import log from '@apify/log';
import { createExpressApp } from './actor/server.js';
import { processInput } from './input.js';
import { ActorsMcpServer } from './mcp/server.js';
import {
actorDefinitionTool,
addTool,
callActorGetDataset,
getActorsAsTools,
removeTool,
searchTool,
} from './tools/index.js';
import { callActorGetDataset, getActorsAsTools } from './tools/index.js';
import type { Input } from './types.js';

const STANDBY_MODE = Actor.getEnv().metaOrigin === 'STANDBY';
Expand All @@ -33,25 +26,26 @@ if (!process.env.APIFY_TOKEN) {
process.exit(1);
}

const mcpServer = new ActorsMcpServer();

const input = processInput((await Actor.getInput<Partial<Input>>()) ?? ({} as Input));
log.info(`Loaded input: ${JSON.stringify(input)} `);

if (STANDBY_MODE) {
const mcpServer = new ActorsMcpServer({
enableAddingActors: Boolean(input.enableAddingActors),
enableDefaultActors: false,
});

const app = createExpressApp(HOST, mcpServer);
log.info('Actor is running in the STANDBY mode.');
// Do not load default Actors here, for mastra.ai template we need to start without default Actors
const tools = [searchTool, actorDefinitionTool];
if (input.enableAddingActors) {
tools.push(addTool, removeTool);
}

// Load only Actors specified in the input
// If you wish to start without any Actor, create a task and leave the input empty
if (input.actors && input.actors.length > 0) {
const { actors } = input;
const actorsToLoad = Array.isArray(actors) ? actors : actors.split(',');
tools.push(...await getActorsAsTools(actorsToLoad, process.env.APIFY_TOKEN as string));
const tools = await getActorsAsTools(actorsToLoad, process.env.APIFY_TOKEN as string);
mcpServer.updateTools(tools);
}
mcpServer.updateTools(tools);
app.listen(PORT, () => {
log.info(`The Actor web server is listening for user requests at ${HOST}`);
});
Expand Down
49 changes: 46 additions & 3 deletions src/mcp/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,37 @@ import {
SERVER_NAME,
SERVER_VERSION,
} from '../const.js';
import { actorDefinitionTool, callActorGetDataset, getActorsAsTools, searchTool } from '../tools/index.js';
import {
actorDefinitionTool,
addTool,
callActorGetDataset,
getActorsAsTools,
removeTool,
searchTool,
} from '../tools/index.js';
import { actorNameToToolName } from '../tools/utils.js';
import type { ActorMCPTool, ActorTool, HelperTool, ToolWrap } from '../types.js';
import { createMCPClient } from './client.js';
import { processParamsGetTools } from './utils.js';

type ActorsMcpServerOptions = {
enableAddingActors?: boolean;
enableDefaultActors?: boolean;
};

/**
* Create Apify MCP server
*/
export class ActorsMcpServer {
public readonly server: Server;
public readonly tools: Map<string, ToolWrap>;
private readonly options: ActorsMcpServerOptions;

constructor() {
constructor(options: ActorsMcpServerOptions = {}) {
this.options = {
enableAddingActors: options.enableAddingActors ?? false,
enableDefaultActors: options.enableDefaultActors ?? true, // Default to true for backward compatibility
};
this.server = new Server(
{
name: SERVER_NAME,
Expand All @@ -49,10 +66,29 @@ export class ActorsMcpServer {

// Add default tools
this.updateTools([searchTool, actorDefinitionTool]);

// Add tools to dynamically load Actors
if (this.options.enableAddingActors) {
this.loadToolsToAddActors();
}

// Initialize automatically for backward compatibility
this.initialize().catch((error) => {
log.error('Failed to initialize server:', error);
});
}

/**
* Initialize the server with default tools if enabled
*/
public async initialize(): Promise<void> {
if (this.options.enableDefaultActors) {
await this.loadDefaultTools(process.env.APIFY_TOKEN as string);
}
}

/**
* Loads missing default tools.
* Loads default tools if not already loaded.
*/
public async loadDefaultTools(apifyToken: string) {
const missingDefaultTools = defaults.actors.filter((name) => !this.tools.has(actorNameToToolName(name)));
Expand All @@ -78,6 +114,13 @@ export class ActorsMcpServer {
}
}

/**
* Add Actors to server dynamically
*/
public loadToolsToAddActors() {
this.updateTools([addTool, removeTool]);
}

/**
* Upsert new tools.
* @param tools - Array of tool wrappers.
Expand Down
11 changes: 4 additions & 7 deletions src/stdio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import log from '@apify/log';

import { defaults } from './const.js';
import { ActorsMcpServer } from './mcp/server.js';
import { addTool, getActorsAsTools, removeTool } from './tools/index.js';
import { getActorsAsTools } from './tools/index.js';

// Configure logging, set to ERROR
log.setLevel(log.LEVELS.ERROR);
Expand All @@ -36,7 +36,8 @@ const argv = parser(process.argv.slice(2), {
'enable-adding-actors': false,
},
});
const { actors = '', enableActorAutoLoading = false } = argv;
const enableAddingActors = argv['enable-adding-actors'] || argv.enableActorAutoLoading || false;
const { actors = '' } = argv;
const actorList = actors ? actors.split(',').map((a: string) => a.trim()) : [];

// Validate environment
Expand All @@ -46,12 +47,8 @@ if (!process.env.APIFY_TOKEN) {
}

async function main() {
const mcpServer = new ActorsMcpServer();
// Initialize tools
const mcpServer = new ActorsMcpServer({ enableAddingActors, enableDefaultActors: false });
const tools = await getActorsAsTools(actorList.length ? actorList : defaults.actors, process.env.APIFY_TOKEN as string);
if (enableActorAutoLoading) {
tools.push(addTool, removeTool);
}
mcpServer.updateTools(tools);

// Start server
Expand Down
Loading