#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { generateText } from "ai";
import { createOpenAI } from "@ai-sdk/openai";
import { createAnthropic } from "@ai-sdk/anthropic";
import { buildEvaluationPrompt } from "./prompt.js";
const server = new Server(
{
name: "prompt-evaluator",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "evaluate",
description: "Evaluate a prompt using AI analysis",
inputSchema: {
type: "object",
properties: {
prompt: {
type: "string",
description: "The prompt to evaluate",
},
},
required: ["prompt"],
},
},
{
name: "ping",
description: "Simple ping test to verify connection",
inputSchema: {
type: "object",
properties: {},
},
},
],
};
});
// Helper to get the right model provider
function getModel(modelName: string, apiKey: string) {
// Map our simplified names to actual model IDs
const modelMap: Record<
string,
{ provider: "openai" | "anthropic"; modelId: string }
> = {
o3: { provider: "openai", modelId: "o3-2025-04-16" },
"opus-4": { provider: "anthropic", modelId: "claude-opus-4-20250514" },
"sonnet-4": { provider: "anthropic", modelId: "claude-sonnet-4-20250514" },
};
const model = modelMap[modelName];
if (!model) {
throw new Error(
`Unsupported model: ${modelName}. Use: o3, opus-4, or sonnet-4`
);
}
if (model.provider === "openai") {
const openai = createOpenAI({
apiKey,
baseURL: process.env.OPENAI_BASE_URL,
});
return openai(model.modelId);
} else {
const anthropic = createAnthropic({
apiKey,
baseURL: process.env.ANTHROPIC_BASE_URL,
});
return anthropic(model.modelId);
}
}
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (request.params.name) {
case "ping":
return {
content: [
{
type: "text",
text: "Pong! MCP server is connected and working.",
},
],
};
case "evaluate":
const { prompt } = request.params.arguments as { prompt: string };
// Get config from environment variables
const modelName = process.env.PROMPT_EVAL_MODEL || "sonnet-4";
const apiKey = process.env.PROMPT_EVAL_API_KEY;
if (!apiKey) {
return {
content: [
{
type: "text",
text: "Error: PROMPT_EVAL_API_KEY not configured. Please set it in your .mcp.json file.",
},
],
};
}
try {
const result = await generateText({
model: getModel(modelName, apiKey),
prompt: buildEvaluationPrompt(prompt),
maxTokens: 1000,
});
return {
content: [
{
type: "text",
text: result.text,
},
],
};
} catch (error) {
console.error("Error calling AI API:", error);
throw new Error(
`Failed to evaluate prompt: ${
error instanceof Error ? error.message : "Unknown error"
}`
);
}
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Prompt Evaluator MCP server running (with Vercel AI SDK)");
}
main().catch((error) => {
console.error("Server error:", error);
process.exit(1);
});