Skip to content

Commit d1fe5a5

Browse files
committed
fix: stdio integration tests
1 parent ea90ae2 commit d1fe5a5

File tree

5 files changed

+60
-11
lines changed

5 files changed

+60
-11
lines changed

src/input.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const mcpOptionsSchema = z.preprocess((originalInput) => {
5959
}
6060
return items.filter((s) => toolCategoriesArray.includes(s as ToolCategory));
6161
}, z.array(z.enum(toolCategoriesArray)).default([])),
62-
fullActorSchema: z.boolean().default(false),
62+
fullActorSchema: z.preprocess(parseBoolean, z.boolean().default(false)),
6363
}));
6464

6565
export type McpOptions = z.infer<typeof mcpOptionsSchema>;

src/stdio.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import { hideBin } from 'yargs/helpers';
2222

2323
import log from '@apify/log';
2424

25+
import type { McpOptions } from './input.js';
2526
import { ActorsMcpServer } from './mcp/server.js';
2627
import { toolCategories } from './tools/index.js';
2728
import type { ToolCategory } from './types.js';
28-
import type { McpOptions } from './input.js';
2929
import { loadToolsFromInput } from './utils/tools-loader.js';
3030

3131
// Keeping this interface here and not types.ts since
@@ -40,6 +40,7 @@ interface CliArgs {
4040
enableActorAutoLoading: boolean;
4141
/** Tool categories to include */
4242
tools?: string;
43+
fullActorSchema: boolean;
4344
}
4445

4546
// Configure logging, set to ERROR
@@ -80,6 +81,11 @@ Note: Tools that enable you to search Actors from the Apify Store and get their
8081
`,
8182
example: 'docs,runs,storage',
8283
})
84+
.option('full-actor-schema', {
85+
type: 'boolean',
86+
default: false,
87+
describe: 'Enable full Actor schema for all Actors.',
88+
})
8389
.help('help')
8490
.alias('h', 'help')
8591
.version(false)
@@ -116,7 +122,8 @@ async function main() {
116122
actors: actorList.length ? actorList : [],
117123
enableAddingActors,
118124
tools: toolCategoryKeys as ToolCategory[],
119-
fullActorSchema: false,
125+
enableDefaultActors: false,
126+
fullActorSchema: argv.fullActorSchema,
120127
};
121128

122129
const mcpServer = new ActorsMcpServer(input);

tests/helpers.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ export async function createMcpStreamableClient(
9292
}
9393

9494
export async function createMcpStdioClient(
95-
options?: McpClientOptions,
95+
options?: Partial<McpOptions>,
9696
): Promise<Client> {
9797
if (!process.env.APIFY_TOKEN) {
9898
throw new Error('APIFY_TOKEN environment variable is not set.');
9999
}
100-
const { actors, enableAddingActors, tools } = options || {};
100+
const { actors, enableAddingActors, tools, fullActorSchema } = options || {};
101101
const args = ['dist/stdio.js'];
102102
if (actors) {
103103
args.push('--actors', actors.join(','));
@@ -108,6 +108,9 @@ export async function createMcpStdioClient(
108108
if (tools && tools.length > 0) {
109109
args.push('--tools', tools.join(','));
110110
}
111+
if (fullActorSchema !== undefined) {
112+
args.push('--full-actor-schema', fullActorSchema.toString());
113+
}
111114

112115
const transport = new StdioClientTransport({
113116
command: 'node',

tests/integration/suite.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ import type { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/cl
33
import { ToolListChangedNotificationSchema } from '@modelcontextprotocol/sdk/types.js';
44
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
55

6-
import { defaults, HelperTools } from '../../src/const.js';
6+
import { ADVANCED_INPUT_KEY, defaults, HelperTools } from '../../src/const.js';
7+
import type { McpOptions } from '../../src/input.js';
78
import { latestNewsOnTopicPrompt } from '../../src/prompts/latest-news-on-topic.js';
89
import { addRemoveTools, defaultTools, toolCategories, toolCategoriesEnabledByDefault } from '../../src/tools/index.js';
910
import { actorNameToToolName } from '../../src/tools/utils.js';
1011
import type { ToolCategory } from '../../src/types.js';
1112
import { ACTOR_MCP_SERVER_ACTOR_NAME, ACTOR_PYTHON_EXAMPLE, DEFAULT_ACTOR_NAMES, DEFAULT_TOOL_NAMES } from '../const.js';
12-
import { addActor, type McpClientOptions } from '../helpers.js';
13+
import { addActor } from '../helpers.js';
1314

1415
interface IntegrationTestsSuiteOptions {
1516
suiteName: string;
1617
transport: 'sse' | 'streamable-http' | 'stdio';
17-
createClientFn: (options?: McpClientOptions) => Promise<Client>;
18+
createClientFn: (options?: Partial<McpOptions>) => Promise<Client>;
1819
beforeAllFn?: () => Promise<void>;
1920
afterAllFn?: () => Promise<void>;
2021
beforeEachFn?: () => Promise<void>;
@@ -273,7 +274,7 @@ export function createIntegrationTestsSuite(
273274
limit: 5,
274275
},
275276
});
276-
const content = result.content as {text: string}[];
277+
const content = result.content as { text: string }[];
277278
expect(content.some((item) => item.text.includes(ACTOR_PYTHON_EXAMPLE))).toBe(true);
278279

279280
await client.close();
@@ -292,7 +293,7 @@ export function createIntegrationTestsSuite(
292293
limit: 100,
293294
},
294295
});
295-
const content = result.content as {text: string}[];
296+
const content = result.content as { text: string }[];
296297
expect(content.length).toBe(1);
297298
const outputText = content[0].text;
298299

@@ -485,6 +486,37 @@ export function createIntegrationTestsSuite(
485486
await client.close();
486487
});
487488

489+
it(`should make ${ADVANCED_INPUT_KEY} in Actor properties available`, async () => {
490+
const client = await createClientFn({ enableAddingActors: true, fullActorSchema: true });
491+
await client.callTool({ name: HelperTools.ACTOR_ADD, arguments: { actor: 'compass/crawler-google-places' } });
492+
// Get input type for actor 'compass-slash-crawler-google-places'
493+
const tools = await client.listTools();
494+
const googlePlacesTool = tools.tools.find((tool) => tool.name === 'compass-slash-crawler-google-places');
495+
const properties = googlePlacesTool!.inputSchema.properties as Record<string, unknown>;
496+
expect(Object.keys(properties)).toMatchInlineSnapshot(`
497+
[
498+
"searchStringsArray",
499+
"locationQuery",
500+
"maxCrawledPlacesPerSearch",
501+
"language",
502+
"advancedInput",
503+
]
504+
`);
505+
expect(Object.keys((properties[ADVANCED_INPUT_KEY] as { properties: Record<string, unknown> }).properties).length).toBeGreaterThan(0);
506+
507+
await client.close();
508+
});
509+
510+
it(`should not create ${ADVANCED_INPUT_KEY} if is disabled`, async () => {
511+
const client = await createClientFn({ enableAddingActors: true, fullActorSchema: false });
512+
await client.callTool({ name: HelperTools.ACTOR_ADD, arguments: { actor: 'compass/crawler-google-places' } });
513+
const tools = await client.listTools();
514+
const googlePlacesTool = tools.tools.find((tool) => tool.name === 'compass-slash-crawler-google-places');
515+
const properties = googlePlacesTool!.inputSchema.properties as Record<string, unknown>;
516+
expect(Object.keys(properties)).not.toContain(ADVANCED_INPUT_KEY);
517+
await client.close();
518+
});
519+
488520
// Session termination is only possible for streamable HTTP transport.
489521
it.runIf(options.transport === 'streamable-http')('should successfully terminate streamable session', async () => {
490522
const client = await createClientFn();

tests/unit/mcp.utils.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, expect, it } from 'vitest';
22

3+
import { defaults } from '../../src/const.js';
34
import { parseInputParamsFromUrl } from '../../src/mcp/utils.js';
45

56
describe('parseInputParamsFromUrl', () => {
@@ -18,7 +19,7 @@ describe('parseInputParamsFromUrl', () => {
1819
it('should handle URL without query params', () => {
1920
const url = 'https://actors-mcp-server.apify.actor';
2021
const result = parseInputParamsFromUrl(url);
21-
expect(result.actors).toEqual([]);
22+
expect(result.actors).toEqual(defaults.actors);
2223
});
2324

2425
it('should parse enableActorAutoLoading flag', () => {
@@ -44,4 +45,10 @@ describe('parseInputParamsFromUrl', () => {
4445
const result = parseInputParamsFromUrl(url);
4546
expect(result.actors).toEqual(['apify/rag-web-browser']);
4647
});
48+
49+
it('should parse fullActorSchema flag', () => {
50+
const url = 'https://actors-mcp-server.apify.actor?fullActorSchema=true';
51+
const result = parseInputParamsFromUrl(url);
52+
expect(result.fullActorSchema).toBe(true);
53+
});
4754
});

0 commit comments

Comments
 (0)