Skip to content

Commit 5f15888

Browse files
committed
Merge remote-tracking branch 'origin/master' into fix/code-improvements
2 parents 80441b8 + 4f5e057 commit 5f15888

File tree

9 files changed

+104
-34
lines changed

9 files changed

+104
-34
lines changed

.actor/ACTOR.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Apify Model Context Protocol (MCP) Server
22

33
[![Actors MCP Server](https://apify.com/actor-badge?actor=apify/actors-mcp-server)](https://apify.com/apify/actors-mcp-server)
4-
[![smithery badge](https://smithery.ai/badge/@apify/actors-mcp-server)](https://smithery.ai/server/@apify/actors-mcp-server)
54

65
Implementation of an MCP server for all [Apify Actors](https://apify.com/store).
76
This server enables interaction with one or more Apify Actors that can be defined in the MCP Server configuration.

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,36 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
<!-- git-cliff-unreleased-start -->
6+
## 0.1.29 - **not yet released**
7+
8+
### 🐛 Bug Fixes
9+
10+
- Add tool call timeout ([#93](https://github.com/apify/actors-mcp-server/pull/93)) ([409ad50](https://github.com/apify/actors-mcp-server/commit/409ad50569e5bd2e3dff950c11523a8440a98034)) by [@MQ37](https://github.com/MQ37)
11+
12+
13+
<!-- git-cliff-unreleased-end -->
14+
## [0.1.28](https://github.com/apify/actors-mcp-server/releases/tag/v0.1.28) (2025-04-22)
15+
16+
### 🐛 Bug Fixes
17+
18+
- Default actors not loaded ([#94](https://github.com/apify/actors-mcp-server/pull/94)) ([fde4c3b](https://github.com/apify/actors-mcp-server/commit/fde4c3b0d66195439d2677d0ac33a08bc77b84cd)) by [@jirispilka](https://github.com/jirispilka)
19+
20+
21+
## [0.1.27](https://github.com/apify/actors-mcp-server/releases/tag/v0.1.27) (2025-04-22)
22+
23+
### 🐛 Bug Fixes
24+
25+
- Move logic to enableAddingActors and enableDefaultActors to constructor ([#90](https://github.com/apify/actors-mcp-server/pull/90)) ([0f44740](https://github.com/apify/actors-mcp-server/commit/0f44740ed3c34a15d938133ac30254afe5d81c57)) by [@jirispilka](https://github.com/jirispilka)
26+
27+
28+
## [0.1.26](https://github.com/apify/actors-mcp-server/releases/tag/v0.1.26) (2025-04-22)
29+
30+
### 🐛 Bug Fixes
31+
32+
- Readme smithery ([#92](https://github.com/apify/actors-mcp-server/pull/92)) ([e585cf3](https://github.com/apify/actors-mcp-server/commit/e585cf394a16aa9891428106d91c443ce9791001)) by [@jirispilka](https://github.com/jirispilka)
33+
34+
535
## [0.1.25](https://github.com/apify/actors-mcp-server/releases/tag/v0.1.25) (2025-04-21)
636

737
### 🐛 Bug Fixes

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@apify/actors-mcp-server",
3-
"version": "0.1.25",
3+
"version": "0.1.29",
44
"type": "module",
55
"description": "Model Context Protocol Server for Apify",
66
"engines": {

src/actor/server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import log from '@apify/log';
1313

1414
import { type ActorsMcpServer } from '../mcp/server.js';
1515
import { processParamsGetTools } from '../mcp/utils.js';
16+
import { addTool, removeTool } from '../tools/helpers.js';
1617
import { getHelpMessage, HEADER_READINESS_PROBE, Routes } from './const.js';
1718
import { getActorRunData } from './utils.js';
1819

@@ -69,7 +70,9 @@ export function createExpressApp(
6970
const tools = await processParamsGetTools(req.url, process.env.APIFY_TOKEN as string);
7071
if (tools.length > 0) {
7172
mcpServer.updateTools(tools);
72-
} else {
73+
}
74+
// TODO fix this - we should not be loading default tools here or provide more generic way
75+
if (tools.length === 2 && tools.includes(addTool) && tools.includes(removeTool)) {
7376
// We are loading default Actors (if not specified otherwise), so that we don't have "empty" tools
7477
await mcpServer.loadDefaultTools(process.env.APIFY_TOKEN as string);
7578
}

src/main.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,7 @@ import log from '@apify/log';
1111
import { createExpressApp } from './actor/server.js';
1212
import { processInput } from './input.js';
1313
import { ActorsMcpServer } from './mcp/server.js';
14-
import {
15-
actorDefinitionTool,
16-
addTool,
17-
callActorGetDataset,
18-
getActorsAsTools,
19-
removeTool,
20-
searchTool,
21-
} from './tools/index.js';
14+
import { callActorGetDataset, getActorsAsTools } from './tools/index.js';
2215
import type { Input } from './types.js';
2316

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

36-
const mcpServer = new ActorsMcpServer();
37-
3829
const input = processInput((await Actor.getInput<Partial<Input>>()) ?? ({} as Input));
3930
log.info(`Loaded input: ${JSON.stringify(input)} `);
4031

4132
if (STANDBY_MODE) {
33+
const mcpServer = new ActorsMcpServer({
34+
enableAddingActors: Boolean(input.enableAddingActors),
35+
enableDefaultActors: false,
36+
});
37+
4238
const app = createExpressApp(HOST, mcpServer);
4339
log.info('Actor is running in the STANDBY mode.');
44-
// Do not load default Actors here, for mastra.ai template we need to start without default Actors
45-
const tools = [searchTool, actorDefinitionTool];
46-
if (input.enableAddingActors) {
47-
tools.push(addTool, removeTool);
48-
}
40+
41+
// Load only Actors specified in the input
42+
// If you wish to start without any Actor, create a task and leave the input empty
4943
if (input.actors && input.actors.length > 0) {
5044
const { actors } = input;
5145
const actorsToLoad = Array.isArray(actors) ? actors : actors.split(',');
52-
tools.push(...await getActorsAsTools(actorsToLoad, process.env.APIFY_TOKEN as string));
46+
const tools = await getActorsAsTools(actorsToLoad, process.env.APIFY_TOKEN as string);
47+
mcpServer.updateTools(tools);
5348
}
54-
mcpServer.updateTools(tools);
5549
app.listen(PORT, () => {
5650
log.info(`The Actor web server is listening for user requests at ${HOST}`);
5751
});

src/mcp/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export const MAX_TOOL_NAME_LENGTH = 64;
22
export const SERVER_ID_LENGTH = 8;
3+
export const EXTERNAL_TOOL_CALL_TIMEOUT_MSEC = 120_000; // 2 minutes

src/mcp/server.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import type { Client } from '@modelcontextprotocol/sdk/client/index.js';
66
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
77
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
8-
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } from '@modelcontextprotocol/sdk/types.js';
8+
import { CallToolRequestSchema, CallToolResultSchema, ErrorCode, ListToolsRequestSchema, McpError } from '@modelcontextprotocol/sdk/types.js';
99
import type { ActorCallOptions } from 'apify-client';
1010

1111
import log from '@apify/log';
@@ -17,20 +17,38 @@ import {
1717
SERVER_NAME,
1818
SERVER_VERSION,
1919
} from '../const.js';
20-
import { actorDefinitionTool, callActorGetDataset, getActorsAsTools, searchTool } from '../tools/index.js';
20+
import {
21+
actorDefinitionTool,
22+
addTool,
23+
callActorGetDataset,
24+
getActorsAsTools,
25+
removeTool,
26+
searchTool,
27+
} from '../tools/index.js';
2128
import { actorNameToToolName } from '../tools/utils.js';
2229
import type { ActorMCPTool, ActorTool, HelperTool, ToolWrap } from '../types.js';
2330
import { createMCPClient } from './client.js';
31+
import { EXTERNAL_TOOL_CALL_TIMEOUT_MSEC } from './const.js';
2432
import { processParamsGetTools } from './utils.js';
2533

34+
type ActorsMcpServerOptions = {
35+
enableAddingActors?: boolean;
36+
enableDefaultActors?: boolean;
37+
};
38+
2639
/**
2740
* Create Apify MCP server
2841
*/
2942
export class ActorsMcpServer {
3043
public readonly server: Server;
3144
public readonly tools: Map<string, ToolWrap>;
45+
private readonly options: ActorsMcpServerOptions;
3246

33-
constructor() {
47+
constructor(options: ActorsMcpServerOptions = {}) {
48+
this.options = {
49+
enableAddingActors: options.enableAddingActors ?? false,
50+
enableDefaultActors: options.enableDefaultActors ?? true, // Default to true for backward compatibility
51+
};
3452
this.server = new Server(
3553
{
3654
name: SERVER_NAME,
@@ -49,10 +67,29 @@ export class ActorsMcpServer {
4967

5068
// Add default tools
5169
this.updateTools([searchTool, actorDefinitionTool]);
70+
71+
// Add tools to dynamically load Actors
72+
if (this.options.enableAddingActors) {
73+
this.loadToolsToAddActors();
74+
}
75+
76+
// Initialize automatically for backward compatibility
77+
this.initialize().catch((error) => {
78+
log.error('Failed to initialize server:', error);
79+
});
80+
}
81+
82+
/**
83+
* Initialize the server with default tools if enabled
84+
*/
85+
public async initialize(): Promise<void> {
86+
if (this.options.enableDefaultActors) {
87+
await this.loadDefaultTools(process.env.APIFY_TOKEN as string);
88+
}
5289
}
5390

5491
/**
55-
* Loads missing default tools.
92+
* Loads default tools if not already loaded.
5693
*/
5794
public async loadDefaultTools(apifyToken: string) {
5895
const missingDefaultTools = defaults.actors.filter((name) => !this.tools.has(actorNameToToolName(name)));
@@ -66,7 +103,7 @@ export class ActorsMcpServer {
66103
/**
67104
* Loads tools from URL params.
68105
*
69-
* This method also handles enabling of Actor auto loading via the processParamsGetTools.
106+
* This method also handles enabling of Actor autoloading via the processParamsGetTools.
70107
*
71108
* Used primarily for SSE.
72109
*/
@@ -78,6 +115,13 @@ export class ActorsMcpServer {
78115
}
79116
}
80117

118+
/**
119+
* Add Actors to server dynamically
120+
*/
121+
public loadToolsToAddActors() {
122+
this.updateTools([addTool, removeTool]);
123+
}
124+
81125
/**
82126
* Upsert new tools.
83127
* @param tools - Array of tool wrappers.
@@ -199,6 +243,8 @@ export class ActorsMcpServer {
199243
const res = await client.callTool({
200244
name: serverTool.originToolName,
201245
arguments: args,
246+
}, CallToolResultSchema, {
247+
timeout: EXTERNAL_TOOL_CALL_TIMEOUT_MSEC,
202248
});
203249

204250
return { ...res };

src/stdio.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import log from '@apify/log';
1919

2020
import { defaults } from './const.js';
2121
import { ActorsMcpServer } from './mcp/server.js';
22-
import { addTool, getActorsAsTools, removeTool } from './tools/index.js';
22+
import { getActorsAsTools } from './tools/index.js';
2323

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

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

4849
async function main() {
49-
const mcpServer = new ActorsMcpServer();
50-
// Initialize tools
50+
const mcpServer = new ActorsMcpServer({ enableAddingActors, enableDefaultActors: false });
5151
const tools = await getActorsAsTools(actorList.length ? actorList : defaults.actors, process.env.APIFY_TOKEN as string);
52-
if (enableActorAutoLoading) {
53-
tools.push(addTool, removeTool);
54-
}
5552
mcpServer.updateTools(tools);
5653

5754
// Start server

0 commit comments

Comments
 (0)