Skip to main content
Glama

Readwise MCP Server

by IAmAlexander
Dockerfile6.1 kB
FROM node:20-alpine WORKDIR /app COPY . ./ # Install dependencies RUN npm install # Build the application - we'll run in JS mode to avoid TypeScript errors RUN npm run build || echo "Build failed but continuing" # Create a simple entry point that uses the Readwise API RUN echo 'const { ReadwiseAPI } = require("./src/api/readwise-api.js");\n\ const { createServer } = require("http");\n\ const process = require("process");\n\ \n\ // Basic logging\n\ const log = (msg) => {\n\ const debug = process.env.DEBUG === "true";\n\ if (debug) {\n\ console.log(`[${new Date().toISOString()}] ${msg}`);\n\ }\n\ };\n\ \n\ // Main function\n\ async function main() {\n\ // Check if Readwise API token is set\n\ const apiToken = process.env.READWISE_API_TOKEN;\n\ if (!apiToken) {\n\ console.error("ERROR: READWISE_API_TOKEN environment variable is required");\n\ process.exit(1);\n\ }\n\ \n\ // Create API client\n\ const readwiseApi = new ReadwiseAPI({ apiKey: apiToken });\n\ \n\ // Create basic server that responds to /health\n\ const port = parseInt(process.env.PORT || "3001", 10);\n\ const httpServer = createServer((req, res) => {\n\ if (req.url === "/health") {\n\ res.writeHead(200, { "Content-Type": "application/json" });\n\ res.end(JSON.stringify({ status: "ok", transport: "stdio" }));\n\ return;\n\ }\n\ \n\ res.writeHead(404);\n\ res.end();\n\ });\n\ \n\ // Start HTTP server\n\ httpServer.listen(port, () => {\n\ log(`Readwise MCP Server started on port ${port}`);\n\ });\n\ \n\ // Handle STDIO\n\ process.stdin.on("data", async (data) => {\n\ try {\n\ const input = JSON.parse(data.toString());\n\ log(`Received request: ${JSON.stringify(input)}`);\n\ \n\ // Handle basic protocol messages\n\ if (input.method === "initialize") {\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ result: {\n\ capabilities: {\n\ tools: {\n\ getBooks: {\n\ description: "Get books from Readwise",\n\ parameters: {}\n\ },\n\ getHighlights: {\n\ description: "Get highlights from Readwise",\n\ parameters: {}\n\ }\n\ }\n\ }\n\ }\n\ }) + "\\n");\n\ } else if (input.method === "mcp/list_tools") {\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ result: {\n\ tools: [\n\ {\n\ name: "getBooks",\n\ description: "Get books from Readwise",\n\ parameters: {}\n\ },\n\ {\n\ name: "getHighlights",\n\ description: "Get highlights from Readwise",\n\ parameters: {}\n\ }\n\ ]\n\ }\n\ }) + "\\n");\n\ } else if (input.method === "mcp/call_tool" && input.params.name === "getBooks") {\n\ try {\n\ const books = await readwiseApi.getBooks();\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ result: {\n\ content: [\n\ {\n\ type: "text",\n\ text: JSON.stringify(books)\n\ }\n\ ]\n\ }\n\ }) + "\\n");\n\ } catch (error) {\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ result: {\n\ isError: true,\n\ content: [\n\ {\n\ type: "text",\n\ text: `Error fetching books: ${error.message}`\n\ }\n\ ]\n\ }\n\ }) + "\\n");\n\ }\n\ } else if (input.method === "mcp/call_tool" && input.params.name === "getHighlights") {\n\ try {\n\ const highlights = await readwiseApi.getHighlights();\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ result: {\n\ content: [\n\ {\n\ type: "text",\n\ text: JSON.stringify(highlights)\n\ }\n\ ]\n\ }\n\ }) + "\\n");\n\ } catch (error) {\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ result: {\n\ isError: true,\n\ content: [\n\ {\n\ type: "text",\n\ text: `Error fetching highlights: ${error.message}`\n\ }\n\ ]\n\ }\n\ }) + "\\n");\n\ }\n\ } else {\n\ // Default response for unhandled methods\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: input.id,\n\ error: {\n\ code: -32601,\n\ message: `Method ${input.method} not found`\n\ }\n\ }) + "\\n");\n\ }\n\ } catch (error) {\n\ log(`Error processing request: ${error.message}`);\n\ process.stdout.write(JSON.stringify({\n\ jsonrpc: "2.0",\n\ id: null,\n\ error: {\n\ code: -32700,\n\ message: `Parse error: ${error.message}`\n\ }\n\ }) + "\\n");\n\ }\n\ });\n\ \n\ // Handle cleanup\n\ process.on("SIGINT", () => {\n\ log("Shutting down...");\n\ httpServer.close();\n\ process.exit(0);\n\ });\n\ \n\ log("Server ready to process requests");\n\ }\n\ \n\ main().catch(error => {\n\ console.error("Fatal error:", error);\n\ process.exit(1);\n\ });' > dist/simplified-server.js # Command will be provided by smithery.yaml CMD ["node", "dist/simplified-server.js"]

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/IAmAlexander/readwise-mcp'

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