index.ts•5.76 kB
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
CallToolRequestSchema,
ErrorCode,
McpError,
} from "@modelcontextprotocol/sdk/types.js";
import axios, { AxiosInstance } from "axios";
import { z } from "zod";
import dotenv from "dotenv";
dotenv.config();
const GPTZERO_API_KEY = process.env.GPTZERO_API_KEY;
if (!GPTZERO_API_KEY) {
console.error("Error: GPTZERO_API_KEY environment variable is required");
console.error("Set your API key: export GPTZERO_API_KEY=your_key_here");
process.exit(1);
}
class GPTZeroClient {
private api: AxiosInstance;
constructor(apiKey: string) {
this.api = axios.create({
baseURL: "https://api.gptzero.me/v2",
headers: {
"x-api-key": apiKey,
"Content-Type": "application/json",
},
});
}
async detectText(document: string, multilingual = false) {
const response = await this.api.post("/predict/text", {
document,
multilingual,
});
return response.data;
}
async getModelVersions() {
const response = await this.api.get("/model-versions/ai-scan");
return response.data;
}
}
const DetectTextSchema = z.object({
document: z.string().describe("The text document you want to analyze for AI detection"),
multilingual: z.boolean().optional().default(false).describe("Enable multilingual detection (supports French and Spanish)"),
});
async function main() {
const client = new GPTZeroClient(GPTZERO_API_KEY!);
const server = new Server({
name: "gptzero-mcp",
version: "0.1.0",
}, {
capabilities: {
tools: {},
},
});
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "gptzero_detect",
description: "Detect if text was generated by AI. Returns probability scores for AI, human, and mixed content.",
inputSchema: {
type: "object",
properties: {
document: {
type: "string",
description: "The text document you want to analyze for AI detection",
},
multilingual: {
type: "boolean",
description: "Enable multilingual detection (supports French and Spanish)",
default: false,
},
},
required: ["document"],
},
},
{
name: "gptzero_model_versions",
description: "Get available GPTZero model versions",
inputSchema: {
type: "object",
properties: {},
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
try {
const { name, arguments: args } = request.params;
switch (name) {
case "gptzero_detect": {
const { document, multilingual } = DetectTextSchema.parse(args);
const result = await client.detectText(document, multilingual);
// Extract key metrics from the first document
const doc = result.documents[0];
const summary = {
predicted_class: doc.predicted_class,
confidence: doc.confidence_category,
probabilities: doc.class_probabilities,
result_message: doc.result_message,
average_generated_prob: doc.average_generated_prob,
completely_generated_prob: doc.completely_generated_prob,
};
return {
content: [
{
type: "text",
text: `AI Detection Result:\n\n` +
`Prediction: ${summary.predicted_class}\n` +
`Confidence: ${summary.confidence}\n` +
`Message: ${summary.result_message}\n\n` +
`Probabilities:\n` +
`- AI: ${(summary.probabilities.ai * 100).toFixed(1)}%\n` +
`- Human: ${(summary.probabilities.human * 100).toFixed(1)}%\n` +
`- Mixed: ${(summary.probabilities.mixed * 100).toFixed(1)}%\n\n` +
`Full analysis:\n${JSON.stringify(result, null, 2)}`,
},
],
};
}
case "gptzero_model_versions": {
const versions = await client.getModelVersions();
return {
content: [
{
type: "text",
text: `Available GPTZero model versions:\n\n${versions.join("\n")}`,
},
],
};
}
default:
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
} catch (error: any) {
if (error instanceof z.ZodError) {
throw new McpError(
ErrorCode.InvalidParams,
`Invalid parameters: ${error.errors.map((e) => e.message).join(", ")}`
);
}
if (error.response?.status === 401) {
throw new McpError(
ErrorCode.InvalidRequest,
"Invalid GPTZero API key. Check your GPTZERO_API_KEY environment variable."
);
}
if (error.response?.status === 429) {
throw new McpError(
ErrorCode.InternalError,
"GPTZero API rate limit exceeded. Please wait and try again."
);
}
throw new McpError(
ErrorCode.InternalError,
error.message || "An unexpected error occurred"
);
}
});
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("GPTZero MCP server running");
}
main().catch((error) => {
console.error("Fatal error:", error);
process.exit(1);
});