ask-coding-advisors
Get coding assistance by querying three AI specialists simultaneously with automatic premium fallback, returning multiple expert opinions for debugging and problem-solving.
Instructions
Queries three OpenRouter coding specialists (free tier) and falls back to premium models when rate limited.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| question | Yes | ||
| context | No |
Implementation Reference
- src/server.ts:36-42 (schema)Zod input schema definition for the 'ask-coding-advisors' tool, specifying 'question' (required, 4-4000 chars) and optional 'context' (max 12000 chars).const inputSchema = z.object({ question: z .string() .min(4, 'Bitte fasse dein Problem in mindestens vier Zeichen zusammen.') .max(4000, 'Question too long (4k char cap).'), context: z.string().max(12000).optional(), });
- src/server.ts:44-87 (registration)MCP server registration of the 'ask-coding-advisors' tool, including title, description, input schema reference, and the handler function.server.registerTool( 'ask-coding-advisors', { title: 'Ask Coding Advisors', description: 'Queries three OpenRouter coding specialists (free tier) and falls back to premium models when rate limited.', inputSchema, }, async (args) => { const input: ToolInput = typeof args.context === 'string' && args.context.length > 0 ? { question: args.question, context: args.context } : { question: args.question }; try { const batch = await coordinator.advise(input); const formatted = formatBatch(batch); return { content: [ { type: 'text', text: formatted, }, ], }; } catch (error) { const prefix = 'Coding advisor tool failed'; const message = error instanceof Error ? `${prefix}: ${error.message}` : `${prefix}: ${String(error)}`; const isRetryable = error instanceof RateLimitError || error instanceof OpenRouterError; return { isError: isRetryable, content: [ { type: 'text', text: message, }, ], }; } } );
- src/server.ts:52-86 (handler)The handler function registered for the tool. Parses args, calls CodingAdvisorCoordinator.advise(), formats results with formatBatch, handles errors including rate limits.async (args) => { const input: ToolInput = typeof args.context === 'string' && args.context.length > 0 ? { question: args.question, context: args.context } : { question: args.question }; try { const batch = await coordinator.advise(input); const formatted = formatBatch(batch); return { content: [ { type: 'text', text: formatted, }, ], }; } catch (error) { const prefix = 'Coding advisor tool failed'; const message = error instanceof Error ? `${prefix}: ${error.message}` : `${prefix}: ${String(error)}`; const isRetryable = error instanceof RateLimitError || error instanceof OpenRouterError; return { isError: isRetryable, content: [ { type: 'text', text: message, }, ], }; } } );
- src/codingAdvisors.ts:18-57 (handler)Core execution logic in CodingAdvisorCoordinator.advise(): Builds model lineup, tries up to 3 free models first, falls back to paid if rate-limited or insufficient, collects responses.async advise(input: ToolInput): Promise<AdvisorBatchResult> { const answers: AdvisorCallResult[] = []; const lineup = buildModelLineup(input); let fallbackTriggered = false; const freePool = this.freeDisabled ? [] : lineup.free; for (const spec of freePool) { if (answers.length >= 3) break; const outcome = await this.tryModel(spec, lineup.tags, input, false); if (outcome?.type === 'rate-limit') { fallbackTriggered = true; break; } if (outcome?.result) { answers.push(outcome.result); } if (this.freeDisabled) { break; } } if (answers.length < 3) { fallbackTriggered = true; for (const spec of lineup.paid) { if (answers.length >= 3) break; const outcome = await this.tryModel(spec, lineup.tags, input, true); if (outcome?.result) { answers.push(outcome.result); } } } if (answers.length < 3) { throw new Error('Keine gesunden OpenRouter-Modelle verfügbar – bitte später erneut versuchen.'); } return { answers, fallbackTriggered }; }
- src/server.ts:96-118 (helper)Helper function to format the batch of advisor responses into a readable markdown-like text with headers, tiers, latency, and usage.function formatBatch(batch: AdvisorBatchResult): string { const header = batch.fallbackTriggered ? '⚠️ OpenRouter rate limit hit — switched to paid fallbacks for the remaining slots.\n' : ''; const body = batch.answers .map((answer, index) => { const tier = answer.isFree ? 'free tier' : answer.usedFallback ? 'paid fallback' : 'paid'; const latency = formatLatency(answer.latencyMs); const usageBits = formatUsage(answer.usage); return [ `Advisor ${index + 1}: ${answer.modelLabel} (${tier})`, `Focus: ${answer.focus}`, `Latency: ${latency}${usageBits ? ` | Usage: ${usageBits}` : ''}`, '', answer.responseText, ].join('\n'); }) .join('\n\n---\n\n'); return header + body; }