Skip to content

Commit ad960d0

Browse files
MQ37Copilotjirispilka
authored
feat: add help tool (#111)
* add help tool * Update src/tools/helpers.ts Co-authored-by: Copilot <[email protected]> * fix: move tool text into a constant * fix: helpTool text * Update src/tools/helpers.ts Co-authored-by: Jiří Spilka <[email protected]> --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Jiri Spilka <[email protected]> Co-authored-by: Jiří Spilka <[email protected]>
1 parent 5fa5cfa commit ad960d0

File tree

4 files changed

+73
-32
lines changed

4 files changed

+73
-32
lines changed

src/const.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export enum HelperTools {
2626
ADD_ACTOR = 'add-actor',
2727
REMOVE_ACTOR = 'remove-actor',
2828
GET_ACTOR_DETAILS = 'get-actor-details',
29+
HELP_TOOL = 'help-tool',
2930
}
3031

3132
export const defaults = {
@@ -35,6 +36,7 @@ export const defaults = {
3536
helperTools: [
3637
HelperTools.SEARCH_ACTORS,
3738
HelperTools.GET_ACTOR_DETAILS,
39+
HelperTools.HELP_TOOL,
3840
],
3941
actorAddingTools: [
4042
HelperTools.ADD_ACTOR,

src/mcp/server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
SERVER_NAME,
1818
SERVER_VERSION,
1919
} from '../const.js';
20+
import { helpTool } from '../tools/helpers.js';
2021
import {
2122
actorDefinitionTool,
2223
addTool,
@@ -66,7 +67,7 @@ export class ActorsMcpServer {
6667
this.setupToolHandlers();
6768

6869
// Add default tools
69-
this.updateTools([searchTool, actorDefinitionTool]);
70+
this.updateTools([searchTool, actorDefinitionTool, helpTool]);
7071

7172
// Add tools to dynamically load Actors
7273
if (this.options.enableAddingActors) {

src/tools/helpers.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,58 @@ import { getActorsAsTools } from './actor.js';
88
import { actorNameToToolName } from './utils.js';
99

1010
const ajv = new Ajv({ coerceTypes: 'array', strict: false });
11+
12+
const HELP_TOOL_TEXT = `Apify MCP server help:
13+
14+
Note: "MCP" stands for "Model Context Protocol". The user can use the "RAG Web Browser" tool to get the content of the links mentioned in this help and present it to the user.
15+
16+
This MCP server can be used in the following ways:
17+
- Locally over "STDIO".
18+
- Remotely over "SSE" or streamable "HTTP" transport with the "Actors MCP Server Apify Actor".
19+
- Remotely over "SSE" or streamable "HTTP" transport with "https://mcp.apify.com".
20+
21+
# Usage
22+
## Locally over "STDIO"
23+
1. The user should install the "@apify/actors-mcp-server" NPM package.
24+
2. The user should configure the MCP client to use the MCP server. Refer to "https://github.com/apify/actors-mcp-server" or the MCP client documentation for more details (the user can specify which MCP client is being used).
25+
The user needs to set the following environment variables:
26+
- "APIFY_TOKEN": Apify token to authenticate with the MCP server.
27+
If the user wants to load an Actor outside the default ones, the user needs to pass it as a CLI argument:
28+
- "--actors <actor1,actor2,...>" // comma-separated list of Actor names, for example, "apify/rag-web-browser,apify/instagram-scraper".
29+
If the user wants to enable the dynamic addition of Actors to the MCP server, the user needs to pass the following CLI argument:
30+
- "--enable-adding-actors".
31+
32+
## Remotely over "SSE" or streamable "HTTP" transport with "Actors MCP Server Apify Actor"
33+
1. The user should configure the MCP client to use the "Actors MCP Server Apify Actor" with:
34+
- "SSE" transport URL: "https://actors-mcp-server.apify.actor/sse".
35+
- Streamable "HTTP" transport URL: "https://actors-mcp-server.apify.actor/mcp".
36+
2. The user needs to pass an "APIFY_TOKEN" as a URL query parameter "?token=<APIFY_TOKEN>" or set the following headers: "Authorization: Bearer <APIFY_TOKEN>".
37+
If the user wants to load an Actor outside the default ones, the user needs to pass it as a URL query parameter:
38+
- "?actors=<actor1,actor2,...>" // comma-separated list of Actor names, for example, "apify/rag-web-browser,apify/instagram-scraper".
39+
If the user wants to enable the addition of Actors to the MCP server dynamically, the user needs to pass the following URL query parameter:
40+
- "?enable-adding-actors=true".
41+
42+
## Remotely over "SSE" or streamable "HTTP" transport with "https://mcp.apify.com"
43+
1. The user should configure the MCP client to use "https://mcp.apify.com" with:
44+
- "SSE" transport URL: "https://mcp.apify.com/sse".
45+
- Streamable "HTTP" transport URL: "https://mcp.apify.com/".
46+
2. The user needs to pass an "APIFY_TOKEN" as a URL query parameter "?token=<APIFY_TOKEN>" or set the following headers: "Authorization: Bearer <APIFY_TOKEN>".
47+
If the user wants to load an Actor outside the default ones, the user needs to pass it as a URL query parameter:
48+
- "?actors=<actor1,actor2,...>" // comma-separated list of Actor names, for example, "apify/rag-web-browser,apify/instagram-scraper".
49+
If the user wants to enable the addition of Actors to the MCP server dynamically, the user needs to pass the following URL query parameter:
50+
- "?enable-adding-actors=true".
51+
52+
# Features
53+
## Dynamic adding of Actors
54+
THIS FEATURE MAY NOT BE SUPPORTED BY ALL MCP CLIENTS. THE USER MUST ENSURE THAT THE CLIENT SUPPORTS IT!
55+
To enable this feature, see the usage section. Once dynamic adding is enabled, tools will be added that allow the user to add or remove Actors from the MCP server.
56+
Tools related:
57+
- "add-actor".
58+
- "remove-actor".
59+
If the user is using these tools and it seems like the tools have been added but cannot be called, the issue may be that the client does not support dynamic adding of Actors.
60+
In that case, the user should check the MCP client documentation to see if the client supports this feature.
61+
`;
62+
1163
export const AddToolArgsSchema = z.object({
1264
actorName: z.string()
1365
.describe('Add a tool, Actor or MCP-Server to available tools by Actor ID or tool full name.'
@@ -64,3 +116,20 @@ export const removeTool: ToolWrap = {
64116
},
65117
} as InternalTool,
66118
};
119+
120+
// Tool takes no arguments
121+
export const HelpToolArgsSchema = z.object({});
122+
export const helpTool: ToolWrap = {
123+
type: 'internal',
124+
tool: {
125+
name: HelperTools.HELP_TOOL,
126+
description: 'Helper tool to get information on how to use and troubleshoot the Apify MCP server. '
127+
+ 'This tool always returns the same help message with information about the server and how to use it. '
128+
+ 'Call this tool in case of any problems or uncertainties with the server. ',
129+
inputSchema: zodToJsonSchema(HelpToolArgsSchema),
130+
ajvValidate: ajv.compile(zodToJsonSchema(HelpToolArgsSchema)),
131+
call: async () => {
132+
return { content: [{ type: 'text', text: HELP_TOOL_TEXT }] };
133+
},
134+
} as InternalTool,
135+
};

tests/integration/actor.server.test.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -52,37 +52,6 @@ describe('Actors MCP Server SSE', {
5252
});
5353
});
5454

55-
it('should load actors from query parameters', async () => {
56-
// Test with multiple actors including different username cases
57-
const testActors = ['apify/rag-web-browser', 'apify/instagram-scraper'];
58-
const numberOfHelperTools = 2;
59-
60-
// Make request to trigger server initialization
61-
const response = await fetch(`${testHost}/?actors=${testActors.join(',')}`);
62-
expect(response.status).toBe(200);
63-
64-
// Verify loaded tools
65-
const toolNames = server.getToolNames();
66-
expect(toolNames).toEqual(expect.arrayContaining([
67-
'apify-slash-rag-web-browser',
68-
'apify-slash-instagram-scraper',
69-
]));
70-
expect(toolNames.length).toBe(testActors.length + numberOfHelperTools);
71-
});
72-
73-
it('should enable auto-loading tools when flag is set', async () => {
74-
const response = await fetch(`${testHost}/?enableActorAutoLoading=true`);
75-
expect(response.status).toBe(200);
76-
77-
const toolNames = server.getToolNames();
78-
expect(toolNames).toEqual([
79-
HelperTools.SEARCH_ACTORS,
80-
HelperTools.GET_ACTOR_DETAILS,
81-
HelperTools.ADD_ACTOR,
82-
HelperTools.REMOVE_ACTOR,
83-
]);
84-
});
85-
8655
it('default tools list', async () => {
8756
const client = await createMCPSSEClient(`${testHost}/sse`);
8857

0 commit comments

Comments
 (0)