Skip to content
Merged
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: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The codebase is organized into logical modules:

- Entry points:
- `src/index.ts` - Main library export (`ActorsMcpServer` class)
- `src/index-internals.ts` - Internal exports for testing and advanced usage
- `src/index_internals.ts` - Internal exports for testing and advanced usage
- `src/stdio.ts` - Standard input/output entry point (CLI, used for Docker)
- `src/main.ts` - Actor entry point (for Apify platform)
- `src/input.ts` - Input processing and validation
Expand Down Expand Up @@ -195,7 +195,7 @@ We use **4 spaces** for indentation (configured in `.editorconfig`).
- **Constants**: Use uppercase `SNAKE_CASE` for global, immutable constants (e.g., `ACTOR_MAX_MEMORY_MBYTES`, `SERVER_NAME`)
- **Functions & Variables**: Use `camelCase` format (e.g., `fetchActorDetails`, `actorClient`)
- **Classes, Types, Interfaces**: Use `PascalCase` format (e.g., `ActorsMcpServer`, `ActorDetailsResult`)
- **Files & Folders**: Use lowercase `snake_case` format (e.g., `actor_details.ts`, `key_value_store.ts`)
- **Files & Folders**: Use lowercase `snake_case` format (e.g., `actor_details.ts`, `key_value_store.ts`). **NEVER use kebab-case** (`kebab-case.ts`) for file or folder names — always use underscores, not hyphens.
- **Booleans**: Prefix with `is`, `has`, or `should` (e.g., `isValid`, `hasFinished`, `shouldRetry`)
- **Units**: Suffix with the unit of measure (e.g., `intervalMillis`, `maxMemoryBytes`)
- **Date/Time**: Suffix with `At` (e.g., `createdAt`, `updatedAt`)
Expand Down Expand Up @@ -283,10 +283,10 @@ We use **4 spaces** for indentation (configured in `.editorconfig`).
### Common patterns

- **Tool implementation**: Tools are defined in `src/tools/` using Zod schemas for validation
- **Actor interaction**: Use `src/utils/apify-client.ts` for Apify API calls, never call Apify API directly
- **Actor interaction**: Use `src/utils/apify_client.ts` for Apify API calls, never call Apify API directly
- **Error responses**: Return user-friendly error messages with suggestions
- **Input validation**: Always validate tool inputs with Zod before processing
- **Caching**: Use TTL-based caching for Actor schemas and details (see `src/utils/ttl-lru.ts`)
- **Caching**: Use TTL-based caching for Actor schemas and details (see `src/utils/ttl_lru.ts`)
- **Constants and Tool Names**: Always use constants and never magic or hardcoded values. When referring to tools, ALWAYS use the `HelperTools` enum.
- **Exception**: Integration tests (`tests/integration/`) must use hardcoded strings for tool names. This ensures tests fail if a tool is renamed, helping to prevent accidental breaking changes.

Expand Down
2 changes: 1 addition & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tests/
Key entry points:

- `src/index.ts` - Main library export (`ActorsMcpServer` class)
- `src/index-internals.ts` - Internal exports for testing / advanced usage
- `src/index_internals.ts` - Internal exports for testing / advanced usage
- `src/stdio.ts` - Standard input/output (CLI) entry point
- `src/main.ts` - Actor entry point (standby server / debugging)
- `src/input.ts` - Input processing and validation
Expand Down
2 changes: 1 addition & 1 deletion evals/create-dataset.ts → evals/create_dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { hideBin } from 'yargs/helpers';
import log from '@apify/log';

import { sanitizeHeaderValue, validatePhoenixEnvVars } from './config.js';
import { loadTestCases, filterByCategory, filterById, type TestCase } from './evaluation-utils.js';
import { loadTestCases, filterByCategory, filterById, type TestCase } from './evaluation_utils.js';

// Set log level to debug
log.setLevel(log.LEVELS.INFO);
Expand Down
2 changes: 1 addition & 1 deletion evals/eval-single.ts → evals/eval_single.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
createToolSelectionLLMEvaluator,
loadTestCases, filterById,
type TestCase
} from './evaluation-utils.js';
} from './evaluation_utils.js';
import { PASS_THRESHOLD, sanitizeHeaderValue } from './config.js';

dotenv.config({ path: '.env' });
Expand Down
10 changes: 5 additions & 5 deletions evals/evaluation-utils.ts → evals/evaluation_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { createClassifierFn } from '@arizeai/phoenix-evals';

import log from '@apify/log';

import { ApifyClient } from '../src/apify-client.js';
import { getToolPublicFieldOnly, processParamsGetTools } from '../src/index-internals.js';
import { ApifyClient } from '../src/apify_client.js';
import { getToolPublicFieldOnly, processParamsGetTools } from '../src/index_internals.js';
import type { ToolBase, ToolEntry } from '../src/types.js';
import {
SYSTEM_PROMPT,
Expand All @@ -20,16 +20,16 @@ import {
TEMPERATURE,
sanitizeHeaderValue
} from './config.js';
import { loadTestCases as loadTestCasesShared, filterByCategory, filterById } from './shared/test-case-loader.js';
import { transformToolsToOpenAIFormat } from './shared/openai-tools.js';
import { loadTestCases as loadTestCasesShared, filterByCategory, filterById } from './shared/test_case_loader.js';
import { transformToolsToOpenAIFormat } from './shared/openai_tools.js';
import type { ToolSelectionTestCase, TestData } from './shared/types.js';

// Re-export types for backwards compatibility
export type TestCase = ToolSelectionTestCase;
export type { TestData } from './shared/types.js';

// Re-export shared functions for backwards compatibility
export { filterByCategory, filterById } from './shared/test-case-loader.js';
export { filterByCategory, filterById } from './shared/test_case_loader.js';

type ExampleInputOnly = { input: Record<string, unknown>, metadata?: Record<string, unknown>, output?: never };

Expand Down
2 changes: 1 addition & 1 deletion evals/run-evaluation.ts → evals/run_evaluation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
loadTools,
createOpenRouterTask,
createToolSelectionLLMEvaluator
} from './evaluation-utils.js';
} from './evaluation_utils.js';
import {
DATASET_NAME,
MODELS_TO_EVALUATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Filter test cases by line ranges
*/

import type { LineRange } from './line-range-parser.js';
import type { LineRange } from './line_range_parser.js';

/**
* Type for test cases with line number metadata
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
// eslint-disable-next-line import/extensions
import type { ChatCompletionMessageParam, ChatCompletionTool } from 'openai/resources/chat/completions';

import { mcpToolsToOpenAiTools } from '../shared/openai-tools.js';
import { mcpToolsToOpenAiTools } from '../shared/openai_tools.js';
import { AGENT_SYSTEM_PROMPT, MAX_CONVERSATION_TURNS, MODELS } from './config.js';
import type { LlmClient } from './llm-client.js';
import type { McpClient } from './mcp-client.js';
import type { LlmClient } from './llm_client.js';
import type { McpClient } from './mcp_client.js';
import type { ConversationHistory, ConversationTurn } from './types.js';

export type ConversationExecutorOptions = {
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* Output formatter for evaluation results
*/

import type { WorkflowTestCase } from './test-cases-loader.js';
import type { WorkflowTestCase } from './test_cases_loader.js';
import type { ConversationHistory } from './types.js';
import type { JudgeResult } from './workflow-judge.js';
import type { JudgeResult } from './workflow_judge.js';

/**
* Single evaluation result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';

import type { EvaluationResult, ResultsDatabase, TestResultRecord } from './output-formatter.js';
import type { EvaluationResult, ResultsDatabase, TestResultRecord } from './output_formatter.js';

/**
* Build composite key for storing results
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ import pLimit from 'p-limit';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';

import { filterByLineRanges } from '../shared/line-range-filter.js';
import type { LineRange } from '../shared/line-range-parser.js';
import { checkRangesOutOfBounds, parseLineRanges, validateLineRanges } from '../shared/line-range-parser.js';
import { filterByLineRanges } from '../shared/line_range_filter.js';
import type { LineRange } from '../shared/line_range_parser.js';
import { checkRangesOutOfBounds, parseLineRanges, validateLineRanges } from '../shared/line_range_parser.js';
import { DEFAULT_TOOL_TIMEOUT_SECONDS, MODELS } from './config.js';
import { executeConversation } from './conversation-executor.js';
import { LlmClient } from './llm-client.js';
import { McpClient } from './mcp-client.js';
import type { EvaluationResult } from './output-formatter.js';
import { formatDetailedResult, formatResultsTable } from './output-formatter.js';
import { executeConversation } from './conversation_executor.js';
import { LlmClient } from './llm_client.js';
import { McpClient } from './mcp_client.js';
import type { EvaluationResult } from './output_formatter.js';
import { formatDetailedResult, formatResultsTable } from './output_formatter.js';
import {
loadResultsDatabase,
saveResultsDatabase,
updateResultsWithEvaluations,
} from './results-writer.js';
import type { WorkflowTestCase, WorkflowTestCaseWithLineNumbers } from './test-cases-loader.js';
import { filterTestCases, loadTestCases, loadTestCasesWithLineNumbers } from './test-cases-loader.js';
import { evaluateConversation } from './workflow-judge.js';
} from './results_writer.js';
import type { WorkflowTestCase, WorkflowTestCaseWithLineNumbers } from './test_cases_loader.js';
import { filterTestCases, loadTestCases, loadTestCasesWithLineNumbers } from './test_cases_loader.js';
import { evaluateConversation } from './workflow_judge.js';

type CliArgs = {
category?: string;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
import fs from 'node:fs';
import path from 'node:path';

import type { TestCaseWithLineNumbers } from '../shared/line-range-filter.js';
import { filterTestCases as filterTestCasesShared, loadTestCases as loadTestCasesShared } from '../shared/test-case-loader.js';
import type { TestCaseWithLineNumbers } from '../shared/line_range_filter.js';
import { filterTestCases as filterTestCasesShared, loadTestCases as loadTestCasesShared } from '../shared/test_case_loader.js';
import type { WorkflowTestCase } from '../shared/types.js';

// Re-export WorkflowTestCase type for backwards compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type { ResponseFormatJSONSchema } from 'openai/resources/shared';

import type { WorkflowTestCase } from '../shared/types.js';
import { JUDGE_PROMPT_TEMPLATE, MODELS } from './config.js';
import type { LlmClient } from './llm-client.js';
import type { LlmClient } from './llm_client.js';
import type { ConversationHistory } from './types.js';

/**
Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"main": "dist/index.js",
"exports": {
".": "./dist/index.js",
"./internals": "./dist/index-internals.js",
"./internals.js": "./dist/index-internals.js",
"./internals": "./dist/index_internals.js",
"./internals.js": "./dist/index_internals.js",
"./manifest.json": "./manifest.json"
},
"bin": {
Expand Down Expand Up @@ -83,7 +83,7 @@
},
"scripts": {
"start": "npm run start:standby",
"dev": "node scripts/dev-standby.js",
"dev": "node scripts/dev_standby.js",
"start:standby": "APIFY_META_ORIGIN=\"STANDBY\" tsx src/main.ts",
"build": "npm run build:core && npm run build:web",
"build:core": "tsc -b src",
Expand All @@ -95,14 +95,14 @@
"lint:fix": "eslint . --fix",
"type-check": "tsc -p tsconfig.json --noEmit",
"check": "npm run type-check && npm run lint",
"check:widgets": "tsx scripts/check-widgets.ts",
"check:widgets": "tsx scripts/check_widgets.ts",
"test": "npm run test:unit",
"test:unit": "vitest run tests/unit",
"test:integration": "npm run build && vitest run tests/integration",
"inspector:stdio": "npx @modelcontextprotocol/inspector -e APIFY_TOKEN=$APIFY_TOKEN -- node dist/stdio.js",
"evals:create-dataset": "tsx evals/create-dataset.ts",
"evals:run": "tsx evals/run-evaluation.ts",
"evals:workflow": "npm run build && tsx evals/workflows/run-workflow-evals.ts"
"evals:create-dataset": "tsx evals/create_dataset.ts",
"evals:run": "tsx evals/run_evaluation.ts",
"evals:workflow": "npm run build && tsx evals/workflows/run_workflow_evals.ts"
},
"author": "Apify",
"license": "MIT"
Expand Down
10 changes: 5 additions & 5 deletions res/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Technical analysis of Algolia search API responses for each documentation source
- Recommendations for response processing logic
- **Use case**: Understand what data is actually returned by Algolia to inform simplification decisions

### [mcp-server-refactor-analysis.md](./mcp-server-refactor-analysis.md)
### [mcp_server_refactor_analysis.md](./mcp_server_refactor_analysis.md)
Implementation plan for migrating from low-level `Server` to high-level `McpServer` API.

**Structure:**
Expand All @@ -30,19 +30,19 @@ Implementation plan for migrating from low-level `Server` to high-level `McpServ
- Testing strategy
- **Use case**: Reference for implementing the MCP SDK migration

### [mcp-resources-analysis.md](./mcp-resources-analysis.md)
### [mcp_resources_analysis.md](./mcp_resources_analysis.md)
Current MCP resources behavior and constraints (Skyfire readme and OpenAI widgets).
- Handler locations and low-level MCP usage
- Resource list/read behavior and error handling
- **Use case**: Baseline reference before refactoring resources

### [mcp-resources-refactor-analysis.md](./mcp-resources-refactor-analysis.md)
### [mcp_resources_refactor_analysis.md](./mcp_resources_refactor_analysis.md)
Refactor plan for modularizing existing resource handling (no new resources).
- Minimal resource service API (list/read/templates)
- Behavior-preserving steps and non-goals
- **Use case**: Step-by-step guide for refactoring without behavior change

### [tool-mode-separation-plan.md](./tool-mode-separation-plan.md)
### [tool_mode_separation_plan.md](./tool_mode_separation_plan.md)
Implementation plan for separating UI-mode (OpenAI) and normal-mode tool behavior into independent modules.

**Key approach:** Actor Executor pattern + separate tool definitions per mode + shared core logic layer.
Expand All @@ -58,7 +58,7 @@ Implementation plan for separating UI-mode (OpenAI) and normal-mode tool behavio
- Directory structure and complete file manifest with PR assignments
- **Use case**: Reference for implementing the UI/normal mode tool separation

### [patterns-for-simplification.md](./patterns-for-simplification.md)
### [patterns_for_simplification.md](./patterns_for_simplification.md)
Analysis of patterns from the **official TypeScript MCP SDK** and **FastMCP** framework that could simplify the codebase.

**Key patterns identified:**
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 5 additions & 6 deletions src/actor/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ import express from 'express';
import log from '@apify/log';
import { parseBooleanOrNull } from '@apify/utilities';

import { ApifyClient } from '../apify-client.js';
import { ApifyClient } from '../apify_client.js';
import { ActorsMcpServer } from '../mcp/server.js';
import type { ApifyRequestParams, UiMode } from '../types.js';
import type { ApifyRequestParams } from '../types.js';
import { parseUiMode } from '../types.js';
import { getHelpMessage, HEADER_READINESS_PROBE, Routes, TransportType } from './const.js';
import { getActorRunData } from './utils.js';

Expand Down Expand Up @@ -90,8 +91,7 @@ export function createExpressApp(
?? parseBooleanOrNull(process.env.TELEMETRY_ENABLED)
?? true;

const uiModeParam = urlParams.get('ui') as UiMode | undefined;
const uiMode = uiModeParam ?? process.env.UI_MODE as UiMode | undefined;
const uiMode = parseUiMode(urlParams.get('ui')) ?? parseUiMode(process.env.UI_MODE);

// Extract payment mode parameter - if payment=skyfire, enable skyfire mode
const paymentParam = urlParams.get('payment');
Expand Down Expand Up @@ -223,8 +223,7 @@ export function createExpressApp(
?? parseBooleanOrNull(process.env.TELEMETRY_ENABLED)
?? true;

const uiModeParam = urlParams.get('ui') as UiMode | undefined;
const uiMode = uiModeParam ?? process.env.UI_MODE as UiMode | undefined;
const uiMode = parseUiMode(urlParams.get('ui')) ?? parseUiMode(process.env.UI_MODE);

// Extract payment mode parameter - if payment=skyfire, enable skyfire mode
const paymentParam = urlParams.get('payment');
Expand Down
File renamed without changes.
20 changes: 12 additions & 8 deletions src/index-internals.ts → src/index_internals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@
This file provides essential internal functions for Apify MCP servers, serving as an internal library.
*/

import { ApifyClient } from './apify-client.js';
import { ApifyClient } from './apify_client.js';
import { APIFY_FAVICON_URL, defaults, HelperTools, SERVER_NAME, SERVER_TITLE } from './const.js';
import { processParamsGetTools } from './mcp/utils.js';
import { getServerCard } from './server_card.js';
import { addTool } from './tools/common/helpers.js';
import { defaultTools, getActorsAsTools, getUnauthEnabledToolCategories, toolCategories,
import { addTool } from './tools/common/add_actor.js';
import { getActorsAsTools, getCategoryTools, getDefaultTools, getUnauthEnabledToolCategories,
toolCategoriesEnabledByDefault, unauthEnabledTools } from './tools/index.js';
import { actorNameToToolName } from './tools/utils.js';
import type { ActorStore, ServerCard, ToolCategory, UiMode } from './types.js';
import type { ActorStore, ServerCard, ServerMode, ToolCategory, UiMode } from './types.js';
import { parseUiMode, SERVER_MODES } from './types.js';
import { parseCommaSeparatedList, parseQueryParamList, readJsonFile } from './utils/generic.js';
import { redactSkyfirePayId } from './utils/logging.js';
import { getExpectedToolNamesByCategories } from './utils/tool-categories-helpers.js';
import { getExpectedToolNamesByCategories } from './utils/tool_categories_helpers.js';
import { getToolPublicFieldOnly } from './utils/tools.js';
import { TTLLRUCache } from './utils/ttl-lru.js';
import { TTLLRUCache } from './utils/ttl_lru.js';

export {
APIFY_FAVICON_URL,
Expand All @@ -28,9 +29,12 @@ export {
SERVER_NAME,
SERVER_TITLE,
defaults,
defaultTools,
getDefaultTools,
addTool,
toolCategories,
getCategoryTools,
parseUiMode,
SERVER_MODES,
type ServerMode,
toolCategoriesEnabledByDefault,
type ActorStore,
type ServerCard,
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { ActorCallOptions } from 'apify-client';
import log from '@apify/log';

import { createExpressApp } from './actor/server.js';
import { ApifyClient } from './apify-client.js';
import { ApifyClient } from './apify_client.js';
import { processInput } from './input.js';
import { callActorGetDataset } from './tools/index.js';
import type { Input } from './types.js';
Expand Down
2 changes: 1 addition & 1 deletion src/mcp/actors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ActorDefinition } from 'apify-client';

import { ApifyClient } from '../apify-client.js';
import { ApifyClient } from '../apify_client.js';
import { MCP_STREAMABLE_ENDPOINT } from '../const.js';
import type { ActorDefinitionPruned } from '../types.js';
import { parseCommaSeparatedList } from '../utils/generic.js';
Expand Down
Loading