Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/index_internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { processParamsGetTools } from './mcp/utils.js';
import { resolvePaymentProvider } from './payments/index.js';
import type { PaymentProvider } from './payments/types.js';
import { getServerCard } from './server_card.js';
import { addTool } from './tools/actors/add_actor.js';
import { addActor } from './tools/actors/add_actor.js';
import {
getActorsAsTools,
getCategoryTools,
Expand Down Expand Up @@ -37,7 +37,11 @@ export {
SERVER_TITLE,
defaults,
getDefaultTools,
addTool,
addActor,
/**
* @deprecated Use `addActor` instead. Kept for the apify-mcp-server-internal migration; remove once it no longer imports `addTool`.
*/
addActor as addTool,
getCategoryTools,
toolCategoriesEnabledByDefault,
type ActorStore,
Expand Down
2 changes: 1 addition & 1 deletion src/tools/actors/add_actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const addToolArgsSchema = z.object({
.min(1)
.describe(`Actor ID or full name in the format "username/name", e.g., "apify/rag-web-browser".`),
});
export const addTool: ToolEntry = Object.freeze({
export const addActor: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.ACTOR_ADD,
title: 'Add tool',
Expand Down
4 changes: 2 additions & 2 deletions src/tools/actors/call_actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ function createCallActorTool(description: string): ToolEntry {
}

/** Default mode call-actor tool. */
export const defaultCallActor: ToolEntry = createCallActorTool(buildCallActorDescription());
export const callActorDefault: ToolEntry = createCallActorTool(buildCallActorDescription());

/**
* Apps mode call-actor tool.
* Renders no widget; for a live progress UI, use the call-actor-widget sibling.
*/
export const appsCallActor: ToolEntry = createCallActorTool(buildCallActorAppsDescription());
export const callActorApps: ToolEntry = createCallActorTool(buildCallActorAppsDescription());
2 changes: 1 addition & 1 deletion src/tools/actors/fetch_actor_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { buildFetchActorDetailsResult, fetchActorDetailsMetadata } from './fetch
* Default mode fetch-actor-details tool.
* Returns full text response with output schema fetch.
*/
export const defaultFetchActorDetails: ToolEntry = Object.freeze({
export const fetchActorDetails: ToolEntry = Object.freeze({
...fetchActorDetailsMetadata,
call: async (toolArgs) => buildFetchActorDetailsResult(toolArgs),
} as const);
2 changes: 1 addition & 1 deletion src/tools/actors/search_actors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
* Default mode search-actors tool.
* Returns text-based Actor cards without widget metadata.
*/
export const defaultSearchActors: ToolEntry = Object.freeze({
export const searchActors: ToolEntry = Object.freeze({
...searchActorsMetadata,
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken, apifyClient, apifyMcpServer } = toolArgs;
Expand Down
2 changes: 1 addition & 1 deletion src/tools/actors/search_actors_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ Returns list of Actor cards with the following info:

/**
* Tool metadata for the base search-actors tool — mode-independent, no widget `_meta`.
* Used by `defaultSearchActors` in both default and apps modes.
* Used by `searchActors` in both default and apps modes.
*/
export const searchActorsMetadata: Omit<HelperTool, 'call'> = {
type: TOOL_TYPE.INTERNAL,
Expand Down
2 changes: 1 addition & 1 deletion src/tools/docs/fetch_apify_docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Please verify the URL is correct and accessible. \
You can search for available documentation pages using the ${HelperTools.DOCS_SEARCH} tool.`;
}

export const fetchApifyDocsTool: ToolEntry = Object.freeze({
export const fetchApifyDocs: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.DOCS_FETCH,
title: 'Fetch Apify docs',
Expand Down
2 changes: 1 addition & 1 deletion src/tools/docs/search_apify_docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ Use this to paginate through the search results. For example, if you want to get

const searchApifyDocsToolInputSchema = z.toJSONSchema(searchApifyDocsToolArgsSchema) as ToolInputSchema;

export const searchApifyDocsTool: ToolEntry = Object.freeze({
export const searchApifyDocs: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.DOCS_SEARCH,
title: 'Search Apify docs',
Expand Down
52 changes: 26 additions & 26 deletions src/tools/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,28 @@
import { HelperTools } from '../const.js';
import type { ToolEntry } from '../types.js';
import { ServerMode } from '../types.js';
import { addTool } from './actors/add_actor.js';
import { appsCallActor, defaultCallActor } from './actors/call_actor.js';
import { defaultFetchActorDetails } from './actors/fetch_actor_details.js';
import { defaultSearchActors } from './actors/search_actors.js';
import { fetchApifyDocsTool } from './docs/fetch_apify_docs.js';
import { searchApifyDocsTool } from './docs/search_apify_docs.js';
import { addActor } from './actors/add_actor.js';
import { callActorApps, callActorDefault } from './actors/call_actor.js';
import { fetchActorDetails } from './actors/fetch_actor_details.js';
import { searchActors } from './actors/search_actors.js';
import { fetchApifyDocs } from './docs/fetch_apify_docs.js';
import { searchApifyDocs } from './docs/search_apify_docs.js';
import { abortActorRun } from './runs/abort_actor_run.js';
import { defaultGetActorRun } from './runs/get_actor_run.js';
import { getActorRun } from './runs/get_actor_run.js';
import { getActorRunList } from './runs/get_actor_run_list.js';
import { getActorRunLog } from './runs/get_actor_run_log.js';
import { getUserRunsList } from './runs/run_collection.js';
import { getUserDatasetsList } from './storage/dataset_collection.js';
import { getDataset } from './storage/get_dataset.js';
import { getDatasetItems } from './storage/get_dataset_items.js';
import { getDatasetList } from './storage/get_dataset_list.js';
import { getDatasetSchema } from './storage/get_dataset_schema.js';
import { getKeyValueStore } from './storage/get_key_value_store.js';
import { getKeyValueStoreKeys } from './storage/get_key_value_store_keys.js';
import { getKeyValueStoreList } from './storage/get_key_value_store_list.js';
import { getKeyValueStoreRecord } from './storage/get_key_value_store_record.js';
import { getUserKeyValueStoresList } from './storage/key_value_store_collection.js';
import { appsCallActorWidget } from './widgets/call_actor_widget.js';
import { fetchActorDetailsWidgetTool } from './widgets/fetch_actor_details_widget.js';
import { getActorRunWidgetTool } from './widgets/get_actor_run_widget.js';
import { searchActorsWidgetTool } from './widgets/search_actors_widget.js';
import { callActorWidget } from './widgets/call_actor_widget.js';
import { fetchActorDetailsWidget } from './widgets/fetch_actor_details_widget.js';
import { getActorRunWidget } from './widgets/get_actor_run_widget.js';
import { searchActorsWidget } from './widgets/search_actors_widget.js';

type ModeMap = Partial<Record<ServerMode, ToolEntry>>;

Expand All @@ -64,24 +64,24 @@ function isModeMap(entry: CategoryToolEntry): entry is ModeMap {
* Use {@link getCategoryTools} to resolve entries into concrete ToolEntry arrays for a given mode.
*/
export const toolCategories = {
experimental: [addTool],
experimental: [addActor],
actors: [
defaultSearchActors,
defaultFetchActorDetails,
searchActors,
fetchActorDetails,
// call-actor is identical between modes; apps mode appends a widget addendum to the description.
{ default: defaultCallActor, apps: appsCallActor },
{ default: callActorDefault, apps: callActorApps },
],
docs: [searchApifyDocsTool, fetchApifyDocsTool],
runs: [defaultGetActorRun, getUserRunsList, getActorRunLog, abortActorRun],
docs: [searchApifyDocs, fetchApifyDocs],
runs: [getActorRun, getActorRunList, getActorRunLog, abortActorRun],
storage: [
getDataset,
getDatasetItems,
getDatasetSchema,
getKeyValueStore,
getKeyValueStoreKeys,
getKeyValueStoreRecord,
getUserDatasetsList,
getUserKeyValueStoresList,
getDatasetList,
getKeyValueStoreList,
],
dev: [],
} satisfies Record<string, CategoryToolEntry[]>;
Expand Down Expand Up @@ -146,8 +146,8 @@ export const toolCategoriesEnabledByDefault: (typeof CATEGORY_NAMES)[number][] =
* the programmatic data tool. To get both, select the base (or both explicitly).
*/
export const WIDGET_BY_BASE_TOOL: ReadonlyMap<HelperTools, ToolEntry> = new Map([
[HelperTools.STORE_SEARCH, searchActorsWidgetTool],
[HelperTools.ACTOR_GET_DETAILS, fetchActorDetailsWidgetTool],
[HelperTools.ACTOR_CALL, appsCallActorWidget],
[HelperTools.ACTOR_RUNS_GET, getActorRunWidgetTool],
[HelperTools.STORE_SEARCH, searchActorsWidget],
[HelperTools.ACTOR_GET_DETAILS, fetchActorDetailsWidget],
[HelperTools.ACTOR_CALL, callActorWidget],
[HelperTools.ACTOR_RUNS_GET, getActorRunWidget],
]);
2 changes: 1 addition & 1 deletion src/tools/runs/get_actor_run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
/**
* Default mode `get-actor-run` — returns without any widget metadata.
*/
export const defaultGetActorRun: ToolEntry = Object.freeze({
export const getActorRun: ToolEntry = Object.freeze({
...getActorRunMetadata,
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyClient: client, apifyToken, progressTracker, mcpSessionId, extra } = toolArgs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const getUserRunsListArgs = z.object({
/**
* https://docs.apify.com/api/v2/act-runs-get
*/
export const getUserRunsList: ToolEntry = Object.freeze({
export const getActorRunList: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.ACTOR_RUN_LIST_GET,
title: 'Get user runs list',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const getUserDatasetsListArgs = z.object({
/**
* https://docs.apify.com/api/v2/datasets-get
*/
export const getUserDatasetsList: ToolEntry = Object.freeze({
export const getDatasetList: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.DATASET_LIST_GET,
title: 'Get user datasets list',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const getUserKeyValueStoresListArgs = z.object({
/**
* https://docs.apify.com/api/v2/key-value-stores-get
*/
export const getUserKeyValueStoresList: ToolEntry = Object.freeze({
export const getKeyValueStoreList: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.KEY_VALUE_STORE_LIST_GET,
title: 'Get user key-value stores list',
Expand Down
2 changes: 1 addition & 1 deletion src/tools/widgets/call_actor_widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const CALL_ACTOR_WIDGET_DESCRIPTION = dedent`
Input: actor name and input JSON; callOptions (memory, timeout) are optional.
`;

export const appsCallActorWidget: ToolEntry = Object.freeze({
export const callActorWidget: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.ACTOR_CALL_WIDGET,
title: 'Call Actor (widget)',
Expand Down
2 changes: 1 addition & 1 deletion src/tools/widgets/fetch_actor_details_widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const FETCH_ACTOR_DETAILS_WIDGET_DESCRIPTION = dedent`
Input: the Actor ID or full name only. Output fields are fixed by the widget contract.
`;

export const fetchActorDetailsWidgetTool: ToolEntry = Object.freeze({
export const fetchActorDetailsWidget: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.ACTOR_GET_DETAILS_WIDGET,
title: 'Fetch Actor details (widget)',
Expand Down
2 changes: 1 addition & 1 deletion src/tools/widgets/get_actor_run_widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const GET_ACTOR_RUN_WIDGET_DESCRIPTION = dedent`
${HelperTools.ACTOR_RUNS_GET} instead — it returns the same data without rendering a widget.
`;

export const getActorRunWidgetTool: ToolEntry = Object.freeze({
export const getActorRunWidget: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.ACTOR_RUNS_GET_WIDGET,
title: 'Get Actor run (widget)',
Expand Down
2 changes: 1 addition & 1 deletion src/tools/widgets/search_actors_widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const SEARCH_ACTORS_WIDGET_DESCRIPTION = dedent`
Input: keywords (plus optional limit/offset). Output fields are fixed by the widget contract.
`;

export const searchActorsWidgetTool: ToolEntry = Object.freeze({
export const searchActorsWidget: ToolEntry = Object.freeze({
type: TOOL_TYPE.INTERNAL,
name: HelperTools.STORE_SEARCH_WIDGET,
title: 'Search Actors (widget)',
Expand Down
12 changes: 6 additions & 6 deletions src/utils/tools_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import log from '@apify/log';

import { defaults, HelperTools } from '../const.js';
import type { PaymentProvider } from '../payments/types.js';
import { addTool } from '../tools/actors/add_actor.js';
import { addActor } from '../tools/actors/add_actor.js';
import { getActorsAsTools } from '../tools/index.js';
import {
CATEGORY_NAME_SET,
Expand All @@ -19,7 +19,7 @@ import {
WIDGET_BY_BASE_TOOL,
} from '../tools/registry.js';
import { abortActorRun } from '../tools/runs/abort_actor_run.js';
import { defaultGetActorRun } from '../tools/runs/get_actor_run.js';
import { getActorRun } from '../tools/runs/get_actor_run.js';
import { getDatasetItems } from '../tools/storage/get_dataset_items.js';
import { getKeyValueStoreRecord } from '../tools/storage/get_key_value_store_record.js';
import type { ActorStore, Input, ToolCategory, ToolEntry } from '../types.js';
Expand All @@ -31,7 +31,7 @@ import { SERVER_MODES, ServerMode, TOOL_TYPE } from '../types.js';
* fetch items → fetch KV record → abort.
*/
export const AUTO_INJECTED_TOOLS: readonly ToolEntry[] = [
defaultGetActorRun,
getActorRun,
getDatasetItems,
getKeyValueStoreRecord,
abortActorRun,
Expand Down Expand Up @@ -243,12 +243,12 @@ export function getToolsForServerMode(
result.push(...internalSelections);
// If add-actor mode is enabled, ensure add-actor tool is available alongside selected tools.
if (addActorEnabled && !selectorsExplicitEmpty && !actorsExplicitlyEmpty) {
const hasAddActor = result.some((e) => e.name === addTool.name);
if (!hasAddActor) result.push(addTool);
const hasAddActor = result.some((e) => e.name === addActor.name);
if (!hasAddActor) result.push(addActor);
}
} else if (addActorEnabled && !actorsExplicitlyEmpty) {
// No selectors: either expose only add-actor (when enabled), or default categories
result.push(addTool);
result.push(addActor);
} else if (!actorsExplicitlyEmpty) {
// Use mode-resolved default categories
for (const cat of toolCategoriesEnabledByDefault) {
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/internals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import log from '@apify/log';

import { ApifyClient } from '../../src/apify_client.js';
import { ActorsMcpServer } from '../../src/index.js';
import { addTool } from '../../src/tools/actors/add_actor.js';
import { addActor } from '../../src/tools/actors/add_actor.js';
import { getActorsAsTools } from '../../src/tools/index.js';
import { actorNameToToolName } from '../../src/tools/utils.js';
import type { Input } from '../../src/types.js';
Expand Down Expand Up @@ -44,7 +44,7 @@ describe('MCP server internals integration tests', () => {
// enableAddingActors=true seeds add-actor + 4 auto-injected helpers (get-actor-run, dataset, kv, abort);
// then ACTOR_NORMAL_MODE is added on top.
const expectedToolNames = [
addTool.name,
addActor.name,
'get-actor-run',
'get-dataset-items',
'get-key-value-store-record',
Expand Down Expand Up @@ -94,7 +94,7 @@ describe('MCP server internals integration tests', () => {
expect(toolNotificationCount).toBe(1);
expect(latestTools.length).toBe(numberOfTools + 1);
expect(latestTools).toContain(actor);
expect(latestTools).toContain(addTool.name);
expect(latestTools).toContain(addActor.name);
// No default actors are present when only add-actor is enabled by default

// Remove the Actor
Expand All @@ -104,7 +104,7 @@ describe('MCP server internals integration tests', () => {
expect(toolNotificationCount).toBe(2);
expect(latestTools.length).toBe(numberOfTools);
expect(latestTools).not.toContain(actor);
expect(latestTools).toContain(addTool.name);
expect(latestTools).toContain(addActor.name);
// No default actors are present by default in this mode
});

Expand Down
18 changes: 9 additions & 9 deletions tests/unit/mcp.server.capability_gating.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
import { HelperTools, SERVER_MODE_AUTO_DETECTION_ENABLED } from '../../src/const.js';
import { ActorsMcpServer } from '../../src/mcp/server.js';
import { RESOURCE_MIME_TYPE } from '../../src/resources/widgets.js';
import { appsCallActor } from '../../src/tools/actors/call_actor.js';
import { defaultSearchActors } from '../../src/tools/actors/search_actors.js';
import { searchActorsWidgetTool } from '../../src/tools/widgets/search_actors_widget.js';
import { callActorApps } from '../../src/tools/actors/call_actor.js';
import { searchActors } from '../../src/tools/actors/search_actors.js';
import { searchActorsWidget } from '../../src/tools/widgets/search_actors_widget.js';
import type { ServerModeOption } from '../../src/types.js';
import { ServerMode } from '../../src/types.js';

Expand Down Expand Up @@ -106,8 +106,8 @@ describe('ActorsMcpServer initialize handler', () => {

// After initialize (apps mode): composed with APPS-mode variants
// search-actors is mode-independent (data-only); search-actors-widget is the apps-only UI variant auto-added in apps mode.
expect(server.tools.get(HelperTools.STORE_SEARCH)).toBe(defaultSearchActors);
expect(server.tools.get(HelperTools.STORE_SEARCH_WIDGET)).toBe(searchActorsWidgetTool);
expect(server.tools.get(HelperTools.STORE_SEARCH)).toBe(searchActors);
expect(server.tools.get(HelperTools.STORE_SEARCH_WIDGET)).toBe(searchActorsWidget);
},
);

Expand Down Expand Up @@ -154,9 +154,9 @@ describe('ActorsMcpServer initialize handler', () => {

await dispatchInitialize(server, makeInitializeRequest(true));

expect(server.tools.get(HelperTools.STORE_SEARCH)).toBe(defaultSearchActors);
expect(server.tools.get(HelperTools.ACTOR_CALL)).toBe(appsCallActor);
expect(server.tools.get(HelperTools.STORE_SEARCH_WIDGET)).toBe(searchActorsWidgetTool);
expect(server.tools.get(HelperTools.STORE_SEARCH)).toBe(searchActors);
expect(server.tools.get(HelperTools.ACTOR_CALL)).toBe(callActorApps);
expect(server.tools.get(HelperTools.STORE_SEARCH_WIDGET)).toBe(searchActorsWidget);
},
);

Expand All @@ -176,7 +176,7 @@ describe('ActorsMcpServer initialize handler', () => {

await dispatchInitialize(server, makeInitializeRequest(true));

expect(server.tools.get(HelperTools.STORE_SEARCH_WIDGET)).toBe(searchActorsWidgetTool);
expect(server.tools.get(HelperTools.STORE_SEARCH_WIDGET)).toBe(searchActorsWidget);
},
);
});
Loading
Loading