Skip to content

Commit 15cbb87

Browse files
committed
use zod validation instead
1 parent 5fbec2b commit 15cbb87

File tree

7 files changed

+23
-49
lines changed

7 files changed

+23
-49
lines changed

src/tools/actor.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ export async function getActorsAsTools(
225225
}
226226

227227
const getActorArgs = z.object({
228-
actorId: z.string().describe('Actor ID or a tilde-separated owner\'s username and Actor name.'),
228+
actorId: z.string()
229+
.min(1)
230+
.describe('Actor ID or a tilde-separated owner\'s username and Actor name.'),
229231
});
230232

231233
/**
@@ -246,9 +248,6 @@ export const getActor: ToolEntry = {
246248
call: async (toolArgs) => {
247249
const { args, apifyToken } = toolArgs;
248250
const { actorId } = getActorArgs.parse(args);
249-
if (!actorId || typeof actorId !== 'string' || actorId.trim() === '') {
250-
return { content: [{ type: 'text', text: 'Actor ID is required.' }] };
251-
}
252251
const client = new ApifyClient({ token: apifyToken });
253252
// Get Actor - contains a lot of irrelevant information
254253
const actor = await client.actor(actorId).get();

src/tools/build.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ function truncateActorReadme(readme: string, limit = ACTOR_README_MAX_LENGTH): s
9696

9797
const getActorDefinitionArgsSchema = z.object({
9898
actorName: z.string()
99+
.min(1)
99100
.describe('Retrieve input, readme, and other details for Actor ID or Actor full name. '
100101
+ 'Actor name is always composed from `username/name`'),
101102
limit: z.number()
@@ -123,9 +124,6 @@ export const actorDefinitionTool: ToolEntry = {
123124
const { args, apifyToken } = toolArgs;
124125

125126
const parsed = getActorDefinitionArgsSchema.parse(args);
126-
if (!parsed.actorName || typeof parsed.actorName !== 'string' || parsed.actorName.trim() === '') {
127-
return { content: [{ type: 'text', text: 'Actor name is required.' }] };
128-
}
129127
const v = await getActorDefinition(parsed.actorName, apifyToken, parsed.limit);
130128
if (!v) {
131129
return { content: [{ type: 'text', text: `Actor '${parsed.actorName}' not found.` }] };

src/tools/dataset.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ import type { InternalTool, ToolEntry } from '../types.js';
99
const ajv = new Ajv({ coerceTypes: 'array', strict: false });
1010

1111
const getDatasetArgs = z.object({
12-
datasetId: z.string().describe('Dataset ID or username~dataset-name.'),
12+
datasetId: z.string()
13+
.min(1)
14+
.describe('Dataset ID or username~dataset-name.'),
1315
});
1416

1517
const getDatasetItemsArgs = z.object({
16-
datasetId: z.string().describe('Dataset ID or username~dataset-name.'),
18+
datasetId: z.string()
19+
.min(1)
20+
.describe('Dataset ID or username~dataset-name.'),
1721
clean: z.boolean().optional()
1822
.describe('If true, returns only non-empty items and skips hidden fields (starting with #). Shortcut for skipHidden=true and skipEmpty=true.'),
1923
offset: z.number().optional()
@@ -52,9 +56,6 @@ export const getDataset: ToolEntry = {
5256
call: async (toolArgs) => {
5357
const { args, apifyToken } = toolArgs;
5458
const parsed = getDatasetArgs.parse(args);
55-
if (!parsed.datasetId || typeof parsed.datasetId !== 'string' || parsed.datasetId.trim() === '') {
56-
return { content: [{ type: 'text', text: 'Dataset ID is required.' }] };
57-
}
5859
const client = new ApifyClient({ token: apifyToken });
5960
const v = await client.dataset(parsed.datasetId).get();
6061
if (!v) {
@@ -88,10 +89,8 @@ export const getDatasetItems: ToolEntry = {
8889
call: async (toolArgs) => {
8990
const { args, apifyToken } = toolArgs;
9091
const parsed = getDatasetItemsArgs.parse(args);
91-
if (!parsed.datasetId || typeof parsed.datasetId !== 'string' || parsed.datasetId.trim() === '') {
92-
return { content: [{ type: 'text', text: 'Dataset ID is required.' }] };
93-
}
9492
const client = new ApifyClient({ token: apifyToken });
93+
9594
// Convert comma-separated strings to arrays
9695
const fields = parsed.fields?.split(',').map((f) => f.trim());
9796
const omit = parsed.omit?.split(',').map((f) => f.trim());

src/tools/helpers.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ In that case, the user should check the MCP client documentation to see if the c
6262

6363
export const addToolArgsSchema = z.object({
6464
actorName: z.string()
65+
.min(1)
6566
.describe('Add a tool, Actor or MCP-Server to available tools by Actor ID or tool full name.'
6667
+ 'Tool name is always composed from `username/name`'),
6768
});
@@ -79,9 +80,6 @@ export const addTool: ToolEntry = {
7980
call: async (toolArgs) => {
8081
const { apifyMcpServer, mcpServer, apifyToken, args } = toolArgs;
8182
const parsed = addToolArgsSchema.parse(args);
82-
if (!parsed.actorName || typeof parsed.actorName !== 'string' || parsed.actorName.trim() === '') {
83-
return { content: [{ type: 'text', text: 'Actor name is required.' }] };
84-
}
8583
if (apifyMcpServer.listAllToolNames().includes(parsed.actorName)) {
8684
return {
8785
content: [{
@@ -109,6 +107,7 @@ export const addTool: ToolEntry = {
109107
};
110108
export const removeToolArgsSchema = z.object({
111109
toolName: z.string()
110+
.min(1)
112111
.describe('Tool name to remove from available tools.')
113112
.transform((val) => actorNameToToolName(val)),
114113
});

src/tools/key_value_store.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const ajv = new Ajv({ coerceTypes: 'array', strict: false });
1010

1111
const getKeyValueStoreArgs = z.object({
1212
storeId: z.string()
13+
.min(1)
1314
.describe('Key-value store ID or username~store-name'),
1415
});
1516

@@ -29,9 +30,6 @@ export const getKeyValueStore: ToolEntry = {
2930
call: async (toolArgs) => {
3031
const { args, apifyToken } = toolArgs;
3132
const parsed = getKeyValueStoreArgs.parse(args);
32-
if (!parsed.storeId || typeof parsed.storeId !== 'string' || parsed.storeId.trim() === '') {
33-
return { content: [{ type: 'text', text: 'Store ID is required.' }] };
34-
}
3533
const client = new ApifyClient({ token: apifyToken });
3634
const store = await client.keyValueStore(parsed.storeId).get();
3735
return { content: [{ type: 'text', text: JSON.stringify(store) }] };
@@ -41,6 +39,7 @@ export const getKeyValueStore: ToolEntry = {
4139

4240
const getKeyValueStoreKeysArgs = z.object({
4341
storeId: z.string()
42+
.min(1)
4443
.describe('Key-value store ID or username~store-name'),
4544
exclusiveStartKey: z.string()
4645
.optional()
@@ -68,9 +67,6 @@ export const getKeyValueStoreKeys: ToolEntry = {
6867
call: async (toolArgs) => {
6968
const { args, apifyToken } = toolArgs;
7069
const parsed = getKeyValueStoreKeysArgs.parse(args);
71-
if (!parsed.storeId || typeof parsed.storeId !== 'string' || parsed.storeId.trim() === '') {
72-
return { content: [{ type: 'text', text: 'Store ID is required.' }] };
73-
}
7470
const client = new ApifyClient({ token: apifyToken });
7571
const keys = await client.keyValueStore(parsed.storeId).listKeys({
7672
exclusiveStartKey: parsed.exclusiveStartKey,
@@ -83,8 +79,10 @@ export const getKeyValueStoreKeys: ToolEntry = {
8379

8480
const getKeyValueStoreRecordArgs = z.object({
8581
storeId: z.string()
82+
.min(1)
8683
.describe('Key-value store ID or username~store-name'),
8784
recordKey: z.string()
85+
.min(1)
8886
.describe('Key of the record to retrieve.'),
8987
});
9088

@@ -106,12 +104,6 @@ export const getKeyValueStoreRecord: ToolEntry = {
106104
call: async (toolArgs) => {
107105
const { args, apifyToken } = toolArgs;
108106
const parsed = getKeyValueStoreRecordArgs.parse(args);
109-
if (!parsed.storeId || typeof parsed.storeId !== 'string' || parsed.storeId.trim() === '') {
110-
return { content: [{ type: 'text', text: 'Store ID is required.' }] };
111-
}
112-
if (!parsed.recordKey || typeof parsed.recordKey !== 'string' || parsed.recordKey.trim() === '') {
113-
return { content: [{ type: 'text', text: 'Record key is required.' }] };
114-
}
115107
const client = new ApifyClient({ token: apifyToken });
116108
const record = await client.keyValueStore(parsed.storeId).getRecord(parsed.recordKey);
117109
return { content: [{ type: 'text', text: JSON.stringify(record) }] };

src/tools/run.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,15 @@ import type { InternalTool, ToolEntry } from '../types.js';
99
const ajv = new Ajv({ coerceTypes: 'array', strict: false });
1010

1111
const getActorRunArgs = z.object({
12-
runId: z.string().describe('The ID of the Actor run.'),
12+
runId: z.string()
13+
.min(1)
14+
.describe('The ID of the Actor run.'),
1315
});
1416

1517
const abortRunArgs = z.object({
16-
runId: z.string().describe('The ID of the Actor run to abort.'),
18+
runId: z.string()
19+
.min(1)
20+
.describe('The ID of the Actor run to abort.'),
1721
gracefully: z.boolean().optional().describe('If true, the Actor run will abort gracefully with a 30-second timeout.'),
1822
});
1923

@@ -33,9 +37,6 @@ export const getActorRun: ToolEntry = {
3337
call: async (toolArgs) => {
3438
const { args, apifyToken } = toolArgs;
3539
const parsed = getActorRunArgs.parse(args);
36-
if (!parsed.runId || typeof parsed.runId !== 'string' || parsed.runId.trim() === '') {
37-
return { content: [{ type: 'text', text: 'Run ID is required.' }] };
38-
}
3940
const client = new ApifyClient({ token: apifyToken });
4041
const v = await client.run(parsed.runId).get();
4142
if (!v) {
@@ -70,9 +71,6 @@ export const getActorLog: ToolEntry = {
7071
call: async (toolArgs) => {
7172
const { args, apifyToken } = toolArgs;
7273
const parsed = GetRunLogArgs.parse(args);
73-
if (!parsed.runId || typeof parsed.runId !== 'string' || parsed.runId.trim() === '') {
74-
return { content: [{ type: 'text', text: 'Run ID is required.' }] };
75-
}
7674
const client = new ApifyClient({ token: apifyToken });
7775
const v = await client.run(parsed.runId).log().get() ?? '';
7876
const lines = v.split('\n');
@@ -98,9 +96,6 @@ export const abortActorRun: ToolEntry = {
9896
call: async (toolArgs) => {
9997
const { args, apifyToken } = toolArgs;
10098
const parsed = abortRunArgs.parse(args);
101-
if (!parsed.runId || typeof parsed.runId !== 'string' || parsed.runId.trim() === '') {
102-
return { content: [{ type: 'text', text: 'Run ID is required.' }] };
103-
}
10499
const client = new ApifyClient({ token: apifyToken });
105100
const v = await client.run(parsed.runId).abort({ gracefully: parsed.gracefully });
106101
return { content: [{ type: 'text', text: JSON.stringify(v) }] };

src/tools/store_collection.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ export const searchActors: ToolEntry = {
8888
call: async (toolArgs) => {
8989
const { args, apifyToken } = toolArgs;
9090
const parsed = searchActorsArgsSchema.parse(args);
91-
if (!parsed.search || parsed.search.trim() === '') {
92-
return {
93-
content: [{
94-
type: 'text',
95-
text: 'Search string must not be empty. Please provide keywords to search for Actors.',
96-
}],
97-
};
98-
}
9991
const actors = await searchActorsByKeywords(
10092
parsed.search,
10193
apifyToken,

0 commit comments

Comments
 (0)