# Customization
## Adding Your Own LLM Provider
### MCP Server Template
Create a new server following this template:
```javascript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { spawn } from "child_process";
function log(msg) {
console.error(`[YourLLM MCP] ${msg}`);
}
function detectError(output) {
const text = output.toLowerCase();
// Add your provider-specific error patterns
if (text.includes("rate limit") || text.includes("quota")) {
return {
isError: true,
errorType: "QUOTA_EXCEEDED",
message: "YourLLM quota exceeded.",
};
}
if (text.includes("unauthorized") || text.includes("invalid key")) {
return {
isError: true,
errorType: "AUTH_ERROR",
message: "YourLLM auth failed. Check credentials.",
};
}
return null;
}
function runLLM(prompt, options = {}) {
const { timeoutMs = 90000 } = options;
return new Promise((resolve, reject) => {
const proc = spawn("your-cli-tool", ["-p", prompt], {
stdio: ["pipe", "pipe", "pipe"],
env: { ...process.env },
});
let stdout = "";
let stderr = "";
let killed = false;
const timer = setTimeout(() => {
killed = true;
proc.kill("SIGTERM");
setTimeout(() => {
try { if (!proc.killed) proc.kill("SIGKILL"); } catch {}
}, 5000);
}, timeoutMs);
proc.stdout.on("data", (d) => { stdout += d.toString(); });
proc.stderr.on("data", (d) => { stderr += d.toString(); });
proc.stdin.end();
proc.on("close", (exitCode) => {
clearTimeout(timer);
if (killed) reject(new Error(`Timeout after ${timeoutMs/1000}s`));
else resolve({ stdout, stderr, exitCode });
});
proc.on("error", (err) => {
clearTimeout(timer);
reject(err);
});
});
}
const mcpServer = new McpServer({
name: "yourllm-mcp",
version: "1.0.0",
});
mcpServer.registerTool(
"yourllm_chat",
{
description: "Send a prompt to YourLLM",
inputSchema: {
prompt: z.string().describe("The prompt to send"),
timeout: z.number().default(90).describe("Timeout in seconds"),
},
},
async ({ prompt, timeout = 90 }) => {
try {
log(`Chat: ${prompt.length} chars`);
const startTime = Date.now();
const { stdout, stderr } = await runLLM(prompt, {
timeoutMs: timeout * 1000,
});
const combined = stdout + stderr;
const error = detectError(combined);
if (error) {
return { content: [{ type: "text", text: error.message }], isError: true };
}
const response = stdout.trim();
if (!response) {
return { content: [{ type: "text", text: "No response" }], isError: true };
}
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
log(`OK in ${elapsed}s`);
return { content: [{ type: "text", text: response }] };
} catch (error) {
const known = detectError(error.message);
if (known) return { content: [{ type: "text", text: known.message }], isError: true };
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
}
}
);
async function main() {
const transport = new StdioServerTransport();
await mcpServer.connect(transport);
log("Started and ready");
}
main().catch(console.error);
```
### Package.json Template
```json
{
"name": "@claude-concilium/mcp-yourllm",
"version": "1.0.0",
"description": "MCP server for YourLLM",
"main": "server.js",
"bin": { "mcp-yourllm": "./server.js" },
"type": "module",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.20.2",
"zod": "^3.25.76"
}
}
```
## Modifying the Fallback Chain
The fallback chain is defined in the Concilium skill (`skill/ai-concilium.md`). Edit the protocol section to change the order:
```
# Default chain:
OpenAI → Qwen → DeepSeek
Gemini → Qwen → DeepSeek
# Example: Add your LLM as first fallback:
OpenAI → YourLLM → Qwen → DeepSeek
Gemini → YourLLM → Qwen → DeepSeek
```
Update the skill's "Error Handling" section accordingly.
## Custom Prompt Strategies
### Code Review (default)
Both agents get the same diff with slightly different framing:
- Agent A: brief description + key changes
- Agent B: full diff + detailed context
### Architecture Decision
Ask different questions to different agents:
- Agent A: "What are the tradeoffs of approach X vs Y?"
- Agent B: "Design a solution for [problem] given [constraints]"
### Debugging
Provide the same error context but ask for different analysis:
- Agent A: "What could cause this error? List top 3 hypotheses."
- Agent B: "Trace the code path that leads to this error. What's wrong?"
## Adjusting Timeouts
Default timeouts are set per tool. Override in your MCP calls:
```
mcp__openai__openai_chat:
prompt: "..."
timeout: 180 # Override default 90s for complex prompts
```
For large codebases, use `gemini_analyze` with its 180s default (can be increased further).