Skip to content

Commit f8ad397

Browse files
committed
simplify mcp server class, move to actors/call.ts
1 parent 2c7edaf commit f8ad397

File tree

3 files changed

+64
-59
lines changed

3 files changed

+64
-59
lines changed

src/actors/call.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Actor, type ApifyClientOptions } from 'apify';
2+
import type { ActorCallOptions } from 'apify-client';
3+
import { ApifyClient } from 'apify-client';
4+
import type { AxiosRequestConfig } from 'axios';
5+
6+
import { USER_AGENT_ORIGIN } from '../const.js';
7+
import { log } from '../logger.js';
8+
9+
/**
10+
* Calls an Apify actor and retrieves the dataset items.
11+
*
12+
* It requires the `APIFY_TOKEN` environment variable to be set.
13+
* If the `APIFY_IS_AT_HOME` the dataset items are pushed to the Apify dataset.
14+
*
15+
* @param {string} actorName - The name of the actor to call.
16+
* @param {ActorCallOptions} callOptions - The options to pass to the actor.
17+
* @param {unknown} input - The input to pass to the actor.
18+
* @returns {Promise<object[]>} - A promise that resolves to an array of dataset items.
19+
* @throws {Error} - Throws an error if the `APIFY_TOKEN` is not set
20+
*/
21+
export async function callActorGetDataset(
22+
actorName: string,
23+
input: unknown,
24+
apifyToken: string,
25+
callOptions: ActorCallOptions | undefined = undefined,
26+
): Promise<object[]> {
27+
const name = actorName;
28+
try {
29+
log.info(`Calling Actor ${name} with input: ${JSON.stringify(input)}`);
30+
31+
const options: ApifyClientOptions = { requestInterceptors: [addUserAgent] };
32+
const client = new ApifyClient({ ...options, token: apifyToken });
33+
const actorClient = client.actor(name);
34+
35+
const results = await actorClient.call(input, callOptions);
36+
const dataset = await client.dataset(results.defaultDatasetId).listItems();
37+
log.info(`Actor ${name} finished with ${dataset.items.length} items`);
38+
39+
if (process.env.APIFY_IS_AT_HOME) {
40+
await Actor.pushData(dataset.items);
41+
log.info(`Pushed ${dataset.items.length} items to the dataset`);
42+
}
43+
return dataset.items;
44+
} catch (error) {
45+
log.error(`Error calling actor: ${error}. Actor: ${name}, input: ${JSON.stringify(input)}`);
46+
throw new Error(`Error calling Actor: ${error}`);
47+
}
48+
}
49+
50+
/**
51+
* Adds a User-Agent header to the request config.
52+
* @param config
53+
* @private
54+
*/
55+
function addUserAgent(config: AxiosRequestConfig): AxiosRequestConfig {
56+
const updatedConfig = { ...config };
57+
updatedConfig.headers = updatedConfig.headers ?? {};
58+
updatedConfig.headers['User-Agent'] = `${updatedConfig.headers['User-Agent'] ?? ''}; ${USER_AGENT_ORIGIN}`;
59+
return updatedConfig;
60+
}

src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import { Actor } from 'apify';
66
import type { ActorCallOptions } from 'apify-client';
77

8+
import { callActorGetDataset } from './actors/call.js';
89
import { processInput } from './input.js';
910
import { log } from './logger.js';
1011
import { ApifyMcpServer } from './mcp-server.js';
@@ -46,6 +47,6 @@ if (isActorStandby()) {
4647
await Actor.fail('If you need to debug a specific Actor, please provide the debugActor and debugActorInput fields in the input');
4748
}
4849
const options = { memory: input.maxActorMemoryBytes } as ActorCallOptions;
49-
await mcpServer.callActorGetDataset(input.debugActor!, input.debugActorInput!, process.env.APIFY_TOKEN, options);
50+
await callActorGetDataset(input.debugActor!, input.debugActorInput!, process.env.APIFY_TOKEN, options);
5051
await Actor.exit();
5152
}

src/mcp-server.ts

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ import { parse } from 'node:querystring';
77
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
88
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
99
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
10-
import { Actor, type ApifyClientOptions } from 'apify';
1110
import type { ActorCallOptions } from 'apify-client';
12-
import { ApifyClient } from 'apify-client';
13-
import type { AxiosRequestConfig } from 'axios';
1411

12+
import { callActorGetDataset } from './actors/call.js';
1513
import {
1614
getActorsAsTools,
1715
} from './actors/tools.js';
@@ -21,7 +19,6 @@ import {
2119
defaults,
2220
SERVER_NAME,
2321
SERVER_VERSION,
24-
USER_AGENT_ORIGIN,
2522
} from './const.js';
2623
import { processInput } from './input.js';
2724
import { log } from './logger.js';
@@ -52,59 +49,6 @@ export class ApifyMcpServer {
5249
this.setupToolHandlers();
5350
}
5451

55-
/**
56-
* Adds a User-Agent header to the request config.
57-
* @param config
58-
* @private
59-
*/
60-
private addUserAgent(config: AxiosRequestConfig): AxiosRequestConfig {
61-
const updatedConfig = { ...config };
62-
updatedConfig.headers = updatedConfig.headers ?? {};
63-
updatedConfig.headers['User-Agent'] = `${updatedConfig.headers['User-Agent'] ?? ''}; ${USER_AGENT_ORIGIN}`;
64-
return updatedConfig;
65-
}
66-
67-
/**
68-
* Calls an Apify actor and retrieves the dataset items.
69-
*
70-
* It requires the `APIFY_TOKEN` environment variable to be set.
71-
* If the `APIFY_IS_AT_HOME` the dataset items are pushed to the Apify dataset.
72-
*
73-
* @param {string} actorName - The name of the actor to call.
74-
* @param {ActorCallOptions} callOptions - The options to pass to the actor.
75-
* @param {unknown} input - The input to pass to the actor.
76-
* @returns {Promise<object[]>} - A promise that resolves to an array of dataset items.
77-
* @throws {Error} - Throws an error if the `APIFY_TOKEN` is not set
78-
*/
79-
public async callActorGetDataset(
80-
actorName: string,
81-
input: unknown,
82-
apifyToken: string,
83-
callOptions: ActorCallOptions | undefined = undefined,
84-
): Promise<object[]> {
85-
const name = actorName;
86-
try {
87-
log.info(`Calling Actor ${name} with input: ${JSON.stringify(input)}`);
88-
89-
const options: ApifyClientOptions = { requestInterceptors: [this.addUserAgent] };
90-
const client = new ApifyClient({ ...options, token: apifyToken });
91-
const actorClient = client.actor(name);
92-
93-
const results = await actorClient.call(input, callOptions);
94-
const dataset = await client.dataset(results.defaultDatasetId).listItems();
95-
log.info(`Actor ${name} finished with ${dataset.items.length} items`);
96-
97-
if (process.env.APIFY_IS_AT_HOME) {
98-
await Actor.pushData(dataset.items);
99-
log.info(`Pushed ${dataset.items.length} items to the dataset`);
100-
}
101-
return dataset.items;
102-
} catch (error) {
103-
log.error(`Error calling actor: ${error}. Actor: ${name}, input: ${JSON.stringify(input)}`);
104-
throw new Error(`Error calling Actor: ${error}`);
105-
}
106-
}
107-
10852
public async addToolsFromActors(actors: string[]) {
10953
const tools = await getActorsAsTools(actors);
11054
this.updateTools(tools);
@@ -207,7 +151,7 @@ export class ApifyMcpServer {
207151
if (tool.type === 'actor') {
208152
const actorTool = tool.tool as ActorTool;
209153

210-
const items = await this.callActorGetDataset(actorTool.actorFullName, args, apifyToken as string, {
154+
const items = await callActorGetDataset(actorTool.actorFullName, args, apifyToken as string, {
211155
memory: actorTool.memoryMbytes,
212156
} as ActorCallOptions);
213157
const content = items.map((item) => {

0 commit comments

Comments
 (0)