Open-source software for Joomla, Gitea, and web platforms. Home of MokoSuite, MokoGitea, and MokoCLI.
Tennessee
standards/coding-typescript.-
TypeScript Coding Standards
Standards for MCP servers and Node.js tooling in the mokoplatform monorepo.
TypeScript Configuration
All projects must use strict mode:
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}
Async Patterns
- Always use
async/await— never raw.then()/.catch()chains - Wrap top-level async calls in try/catch with proper error logging
- Use
Promise.all()for independent concurrent operations - Use
Promise.allSettled()when partial failure is acceptable
async function fetchSiteHealth(connections: Connection[]): Promise<HealthResult[]> {
const results = await Promise.allSettled(
connections.map(conn => checkHealth(conn))
);
return results.map((result, i) => ({
connection: connections[i].name,
status: result.status === 'fulfilled' ? 'up' : 'down',
error: result.status === 'rejected' ? result.reason.message : undefined,
}));
}
Runtime Validation with Zod
Use Zod for all external data validation — configs, API responses, user input:
import { z } from 'zod';
const ConnectionSchema = z.object({
name: z.string(),
url: z.string().url(),
token: z.string().min(1),
timeout: z.number().positive().default(30000),
});
type Connection = z.infer<typeof ConnectionSchema>;
function loadConfig(path: string): Connection[] {
const raw = JSON.parse(readFileSync(path, 'utf-8'));
return z.array(ConnectionSchema).parse(raw.connections);
}
MCP Server Structure
Standard MCP server layout:
servers/{name}/
├── src/
│ ├── index.ts # Entry point, server setup
│ ├── tools/ # Tool implementations
│ │ ├── backup.ts
│ │ └── status.ts
│ ├── config.ts # Config loading and validation
│ └── types.ts # Shared type definitions
├── package.json
├── tsconfig.json
└── dist/ # Build output (gitignored)
Config File Pattern
MCP configs live at ~/.mcp_moko{name}.json:
interface McpConfig {
connections: Record<string, {
url: string;
token: string;
[key: string]: unknown;
}>;
defaults?: {
connection?: string;
timeout?: number;
};
}
Tool Registration
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'backup_run',
description: 'Start a backup for the specified target',
inputSchema: {
type: 'object',
properties: {
target: { type: 'string', description: 'Backup target name' },
profile: { type: 'string', description: 'Backup profile ID' },
},
required: ['target'],
},
},
],
}));
Error Handling
- Define custom error classes per domain
- Always include context in error messages
- Never swallow errors silently — log or rethrow
class McpError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode?: number,
) {
super(message);
this.name = 'McpError';
}
}
class ConnectionError extends McpError {
constructor(connection: string, cause: Error) {
super(
`Failed to connect to ${connection}: ${cause.message}`,
'CONNECTION_FAILED',
);
}
}
Naming Conventions
- Files: kebab-case (
backup-engine.ts,health-check.ts) - Classes/interfaces: PascalCase (
BackupEngine,HealthResult) - Functions/variables: camelCase (
runBackup,siteUrl) - Constants: UPPER_SNAKE_CASE (
MAX_RETRIES,DEFAULT_TIMEOUT) - Type parameters: single uppercase letter or descriptive (
T,TResult) - Enums: PascalCase members (
BackupStatus.Running)
Prohibited Patterns
anytype — useunknownand narrow with type guards@ts-ignore— fix the type error insteadrequire()— use ES module imports- Mutable global state — pass config through constructors
console.login production — use structured logging
Pages