Skip to content

Latest commit

 

History

History
200 lines (157 loc) · 5.03 KB

File metadata and controls

200 lines (157 loc) · 5.03 KB

Customization

Adding Your Own LLM Provider

MCP Server Template

Create a new server following this template:

#!/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

{
  "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).