Skip to main content
Glama

anilist-mcp

MIT License
112
54
  • Apple
  • Linux
index.ts4.64 kB
#!/usr/bin/env node import express, { Request, Response } from "express"; import cors from "cors"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import AniList from "@yuna0x0/anilist-node"; import dotenv from "dotenv"; import { z } from "zod"; import { registerAllTools } from "./tools/index.js"; import { ConfigSchema } from "./utils/schemas.js"; import { ANILIST_TOKEN_HEADER } from "./utils/constants.js"; dotenv.config({ quiet: true }); const app = express(); const PORT = process.env.PORT || 8081; // CORS configuration for browser-based MCP clients app.use( cors({ origin: process.env.CORS_ORIGIN?.split(",") || "*", exposedHeaders: ["Mcp-Session-Id", ANILIST_TOKEN_HEADER], allowedHeaders: ["Content-Type", "mcp-session-id", ANILIST_TOKEN_HEADER], }), ); app.use(express.json()); // Parse configuration from header or query parameters (for Smithery) function parseConfig(req: Request) { const anilistTokenHeader = req.headers[ANILIST_TOKEN_HEADER.toLowerCase()]; if ( typeof anilistTokenHeader === "string" && anilistTokenHeader.trim().length > 0 ) { return { anilistToken: anilistTokenHeader }; } // Smithery passes config as base64-encoded JSON in query parameters const configParam = req.query.config; if (typeof configParam === "string" && configParam.trim().length > 0) { return JSON.parse(Buffer.from(configParam, "base64").toString()); } return {}; } // Create MCP server with AniList integration function createServer({ config }: { config: z.infer<typeof ConfigSchema> }) { const server = new McpServer({ name: "anilist-mcp", version: "1.3.6", }); // Initialize AniList client with token from config or environment const anilist = new AniList(config.anilistToken); // Register all tools registerAllTools(server, anilist, config); return server; } // Handle MCP requests at /mcp endpoint app.post("/mcp", async (req: Request, res: Response) => { try { // Parse configuration const rawConfig = parseConfig(req); // Validate and parse configuration const config = ConfigSchema.parse({ anilistToken: rawConfig.anilistToken || process.env.ANILIST_TOKEN, }); const server = createServer({ config }); const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, }); // Clean up on request close res.on("close", () => { transport.close(); server.close(); }); await server.connect(transport); await transport.handleRequest(req, res, req.body); } catch (error) { console.error("Error handling MCP request:", error); if (!res.headersSent) { res.status(500).json({ jsonrpc: "2.0", error: { code: -32603, message: "Internal server error" }, id: null, }); } } }); // SSE notifications not supported in stateless mode app.get("/mcp", async (req: Request, res: Response) => { res.writeHead(405).end( JSON.stringify({ jsonrpc: "2.0", error: { code: -32000, message: "Method not allowed.", }, id: null, }), ); }); // Session termination not needed in stateless mode app.delete("/mcp", async (req: Request, res: Response) => { res.writeHead(405).end( JSON.stringify({ jsonrpc: "2.0", error: { code: -32000, message: "Method not allowed.", }, id: null, }), ); }); // Main function to start the server in the appropriate mode async function main() { const transport = process.env.TRANSPORT || "stdio"; if (transport === "http") { // Run in HTTP mode app.listen(PORT, () => { console.log(`MCP HTTP Server listening on port ${PORT}`); }); } else { if (transport !== "stdio") { console.warn( `Unknown TRANSPORT "${transport}", defaulting to "stdio" mode.`, ); } // Run in STDIO mode for backward compatibility const config = ConfigSchema.parse({ anilistToken: process.env.ANILIST_TOKEN, }); // Create server with configuration const server = createServer({ config }); // Start receiving messages on stdin and sending messages on stdout const stdioTransport = new StdioServerTransport(); await server.connect(stdioTransport); console.error("MCP Server running in stdio mode"); } } // Start the server main().catch((error) => { console.error("Server error:", error); process.exit(1); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yuna0x0/anilist-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server