55import { Server } from '@modelcontextprotocol/sdk/server/index.js' ;
66import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js' ;
77import { CallToolRequestSchema , ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js' ;
8- import type { ValidateFunction } from 'ajv' ;
98import { Actor } from 'apify' ;
109import { ApifyClient } from 'apify-client' ;
1110
1211import { getActorsAsTools } from './actorDefinition.js' ;
1312import { defaults , SERVER_NAME , SERVER_VERSION } from './const.js' ;
1413import { log } from './logger.js' ;
14+ import type { Tool } from './types' ;
1515
1616/**
1717 * Create Apify MCP server
1818 */
1919export class ApifyMcpServer {
2020 private server : Server ;
21- private tools : { name : string ; description : string ; inputSchema : object , ajvValidate : ValidateFunction } [ ] ;
21+ private tools : Map < string , Tool > ;
2222
2323 constructor ( ) {
2424 this . server = new Server (
@@ -32,11 +32,22 @@ export class ApifyMcpServer {
3232 } ,
3333 } ,
3434 ) ;
35- this . tools = [ ] ;
35+ this . tools = new Map ( ) ;
3636 this . setupErrorHandling ( ) ;
3737 this . setupToolHandlers ( ) ;
3838 }
3939
40+ /**
41+ * Calls an Apify actor and retrieves the dataset items.
42+ *
43+ * It requires the `APIFY_API_TOKEN` environment variable to be set.
44+ * If the `APIFY_IS_AT_HOME` the dataset items are pushed to the Apify dataset.
45+ *
46+ * @param {string } actorName - The name of the actor to call.
47+ * @param {unknown } input - The input to pass to the actor.
48+ * @returns {Promise<object[]> } - A promise that resolves to an array of dataset items.
49+ * @throws {Error } - Throws an error if the `APIFY_API_TOKEN` is not set
50+ */
4051 public async callActorGetDataset ( actorName : string , input : unknown ) : Promise < object [ ] > {
4152 if ( ! process . env . APIFY_API_TOKEN ) {
4253 throw new Error ( 'APIFY_API_TOKEN is required but not set. Please set it as an environment variable' ) ;
@@ -71,18 +82,10 @@ export class ApifyMcpServer {
7182 await this . addToolsFromActors ( defaults . actors ) ;
7283 }
7384
74- public addToolIfNotExist ( name : string , description : string , inputSchema : object , ajvValidate : ValidateFunction ) : void {
75- if ( ! this . tools . find ( ( x ) => x . name === name ) ) {
76- this . tools . push ( { name, description, inputSchema, ajvValidate } ) ;
77- log . info ( `Added tool: ${ name } ` ) ;
78- } else {
79- log . info ( `Tool already exists: ${ name } ` ) ;
80- }
81- }
82-
83- public updateTools ( tools : { name : string ; description: string ; inputSchema: object , ajvValidate : ValidateFunction } [ ] ) : void {
85+ public updateTools ( tools : Tool [ ] ) : void {
8486 for ( const tool of tools ) {
85- this . addToolIfNotExist ( tool . name , tool . description , tool . inputSchema , tool . ajvValidate ) ;
87+ this . tools . set ( tool . name , tool ) ;
88+ log . info ( `Added/Updated tool: ${ tool . name } ` ) ;
8689 }
8790 }
8891
@@ -98,13 +101,18 @@ export class ApifyMcpServer {
98101
99102 private setupToolHandlers ( ) : void {
100103 this . server . setRequestHandler ( ListToolsRequestSchema , async ( ) => {
101- return { tools : this . tools } ;
104+ return { tools : this . tools . values ( ) } ;
102105 } ) ;
103106
107+ /**
108+ * Handles the request to call a tool.
109+ * @param {object } request - The request object containing tool name and arguments.
110+ * @throws {Error } - Throws an error if the tool is unknown or arguments are invalid.
111+ */
104112 this . server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
105113 const { name, arguments : args } = request . params ;
106114
107- const tool = this . tools . find ( ( t ) => t . name === name ) ;
115+ const tool = this . tools . get ( name ) ;
108116 if ( ! tool ) {
109117 throw new Error ( `Unknown tool: ${ name } ` ) ;
110118 }
0 commit comments