Skip to main content
Glama
index.ts•8.6 kB
import { config } from 'dotenv'; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import MediumAuth from './auth'; import MediumClient from './client'; // Load environment variables config(); class MediumMcpServer { private server: McpServer; private mediumClient: MediumClient; private auth: MediumAuth; constructor() { // Initialize authentication this.auth = new MediumAuth(); // Initialize Medium client this.mediumClient = new MediumClient(this.auth); // Create MCP server instance this.server = new McpServer({ name: "medium-mcp-server", version: "1.0.0" }); this.registerTools(); } private registerTools() { // Tool for publishing articles this.server.tool( "publish-article", "Publish a new article on Medium", { title: z.string().min(1, "Title is required"), content: z.string().min(10, "Content must be at least 10 characters"), tags: z.array(z.string()).max(5, "Maximum 5 tags allowed").optional(), publicationId: z.string().optional(), publishStatus: z.enum(['public', 'draft', 'unlisted']).optional(), notifyFollowers: z.boolean().optional() }, async (args) => { try { const publishResult = await this.mediumClient.publishArticle({ title: args.title, content: args.content, tags: args.tags, publicationId: args.publicationId, publishStatus: args.publishStatus, notifyFollowers: args.notifyFollowers }); return { content: [ { type: "text", text: JSON.stringify(publishResult, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error publishing article: ${error.message}` } ] }; } } ); // Tool for updating articles this.server.tool( "update-article", "Update an existing article on Medium", { articleId: z.string().min(1, "Article ID is required"), title: z.string().optional(), content: z.string().optional(), tags: z.array(z.string()).max(5, "Maximum 5 tags allowed").optional(), publishStatus: z.enum(['public', 'draft', 'unlisted']).optional() }, async (args) => { try { const updateResult = await this.mediumClient.updateArticle({ articleId: args.articleId, title: args.title, content: args.content, tags: args.tags, publishStatus: args.publishStatus }); return { content: [ { type: "text", text: JSON.stringify(updateResult, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error updating article: ${error.message}` } ] }; } } ); // Tool for deleting articles this.server.tool( "delete-article", "Delete an article or draft from Medium", { articleId: z.string().min(1, "Article ID is required") }, async (args) => { try { const deleteResult = await this.mediumClient.deleteArticle(args.articleId); return { content: [ { type: "text", text: `Article ${args.articleId} deleted successfully` } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error deleting article: ${error.message}` } ] }; } } ); // Tool for getting article details this.server.tool( "get-article", "Get details of a specific article", { articleId: z.string().min(1, "Article ID is required") }, async (args) => { try { const article = await this.mediumClient.getArticle(args.articleId); return { content: [ { type: "text", text: JSON.stringify(article, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error retrieving article: ${error.message}` } ] }; } } ); // Tool for retrieving user publications this.server.tool( "get-publications", "Retrieve user's publications", {}, async () => { try { const publications = await this.mediumClient.getUserPublications(); return { content: [ { type: "text", text: JSON.stringify(publications, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error retrieving publications: ${error.message}` } ] }; } } ); // Tool for getting user drafts this.server.tool( "get-drafts", "Retrieve user's draft articles", {}, async () => { try { const drafts = await this.mediumClient.getDrafts(); return { content: [ { type: "text", text: JSON.stringify(drafts, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error retrieving drafts: ${error.message}` } ] }; } } ); // Tool for getting user profile this.server.tool( "get-user-profile", "Retrieve authenticated user's profile information", {}, async () => { try { const profile = await this.mediumClient.getUserProfile(); return { content: [ { type: "text", text: JSON.stringify(profile, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error retrieving user profile: ${error.message}` } ] }; } } ); // Tool for searching articles this.server.tool( "search-articles", "Search and filter Medium articles", { keywords: z.array(z.string()).optional(), publicationId: z.string().optional(), tags: z.array(z.string()).optional() }, async (args) => { try { const articles = await this.mediumClient.searchArticles({ keywords: args.keywords, publicationId: args.publicationId, tags: args.tags }); return { content: [ { type: "text", text: JSON.stringify(articles, null, 2) } ] }; } catch (error: any) { return { isError: true, content: [ { type: "text", text: `Error searching articles: ${error.message}` } ] }; } } ); } // Method to start the server async start() { // Authenticate first await this.auth.authenticate(); const transport = new StdioServerTransport(); await this.server.connect(transport); console.error("🚀 MediumMCP Server Initialized"); } } // Main execution async function main() { const server = new MediumMcpServer(); await server.start(); } main().catch(error => { console.error("Fatal error:", error); process.exit(1); });

Latest Blog Posts

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/aliiqbal208/medium-mcp'

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