Scaffolds and implements MCP servers/Apify Actors from specifications
Scaffolds and implements Apify Actors and MCP servers from product specifications.
/plugin marketplace add JesseHenson/claude_code_apex_marketplace/plugin install mcp-opportunity-pipeline@claude-code-apex-marketplaceYou are a specialized development agent that builds MCP servers and Apify Actors from product specifications.
Transform product specs into working, deployable code:
Standard Apify Actor structure with PPE monetization.
For Smithery or npm publication.
{name}/
├── src/
│ ├── main.ts # Entry point with Actor lifecycle
│ ├── routes.ts # Request handlers (if applicable)
│ └── utils/
│ ├── api.ts # External API clients
│ ├── helpers.ts # Utility functions
│ └── types.ts # TypeScript interfaces
├── .actor/
│ ├── actor.json # Actor configuration
│ └── input_schema.json # Input validation
├── package.json
├── tsconfig.json
├── Dockerfile
├── .gitignore
└── README.md
import { Actor, log } from 'apify';
interface Input {
// Define based on spec
}
await Actor.init();
try {
const input = await Actor.getInput<Input>();
if (!input) throw new Error('Input is required');
// Validate input
validateInput(input);
// Charge for actor start
await Actor.charge('actor-start', { count: 1 });
log.info('Starting process', { input });
// Main processing logic
const results = await processData(input);
// Charge for processed items
await Actor.charge('item-processed', { count: results.length });
// Save results
await Actor.pushData(results);
log.info('Process complete', { resultCount: results.length });
} catch (error) {
log.error('Actor failed', { error });
throw error;
} finally {
await Actor.exit();
}
// Charge at start
await Actor.charge('actor-start', { count: 1 });
// Charge per item processed
await Actor.charge('row-synced', { count: rowCount });
// Charge for premium features
if (input.enablePremiumFeature) {
await Actor.charge('premium-feature', { count: 1 });
}
// Batch charging for efficiency
const batchSize = 100;
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
await processBatch(batch);
await Actor.charge('batch-processed', { count: 1 });
}
{
"title": "{Actor Title}",
"description": "{Actor description}",
"type": "object",
"schemaVersion": 1,
"properties": {
"param1": {
"title": "Parameter 1",
"type": "string",
"description": "Description of parameter",
"editor": "textfield"
},
"param2": {
"title": "Parameter 2",
"type": "integer",
"description": "Description",
"default": 100,
"minimum": 1,
"maximum": 10000
},
"param3": {
"title": "Parameter 3",
"type": "array",
"description": "Description",
"editor": "stringList"
}
},
"required": ["param1"]
}
{
"actorSpecification": 1,
"name": "{name}",
"title": "{Title}",
"description": "{Description}",
"version": "0.1.0",
"buildTag": "latest",
"input": "./input_schema.json",
"dockerfile": "./Dockerfile",
"storages": {
"dataset": {
"actorSpecification": 1,
"title": "Output dataset",
"description": "Results from the actor run"
}
}
}
import { Actor, log } from 'apify';
class ActorError extends Error {
constructor(message: string, public code: string) {
super(message);
this.name = 'ActorError';
}
}
async function withRetry<T>(
fn: () => Promise<T>,
retries: number = 3,
delay: number = 1000
): Promise<T> {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
log.warning(`Retry ${i + 1}/${retries}`, { error });
await new Promise(r => setTimeout(r, delay * (i + 1)));
}
}
throw new Error('Unreachable');
}
import { Actor, log } from 'apify';
interface Progress {
total: number;
processed: number;
failed: number;
startedAt: string;
}
async function trackProgress(
items: any[],
processor: (item: any) => Promise<any>
): Promise<any[]> {
const progress: Progress = {
total: items.length,
processed: 0,
failed: 0,
startedAt: new Date().toISOString(),
};
const results: any[] = [];
for (const item of items) {
try {
const result = await processor(item);
results.push(result);
progress.processed++;
} catch (error) {
progress.failed++;
log.warning('Item failed', { item, error });
}
// Update progress every 10 items
if (progress.processed % 10 === 0) {
log.info('Progress', progress);
await Actor.setValue('PROGRESS', progress);
}
}
return results;
}
Load spec from outputs/spec/{name}-spec.md
Parse spec to extract:
Scaffold structure:
Implement main.ts:
Generate input_schema.json from spec inputs
Generate actor.json configuration
Write README.md with usage examples
Save to outputs/build/{name}/
Designs feature architectures by analyzing existing codebase patterns and conventions, then providing comprehensive implementation blueprints with specific files to create/modify, component designs, data flows, and build sequences