{"_id":"@chrptvn/mcp-server-devto","name":"@chrptvn/mcp-server-devto","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@chrptvn/mcp-server-devto","version":"1.0.0","description":"MCP server for dev.to — developer blogging platform powered by Forem","type":"module","main":"dist/index.js","bin":{"mcp-server-devto":"dist/index.js"},"scripts":{"build":"tsc","dev":"tsc --watch","start":"node dist/index.js"},"dependencies":{"@modelcontextprotocol/sdk":"^1.0.0","zod":"^3.23.8"},"devDependencies":{"@types/node":"^22.0.0","typescript":"^5.6.0"},"_id":"@chrptvn/mcp-server-devto@1.0.0","gitHead":"a8638734444b0313ac3b7d69e1859958a68dc1e0","types":"./dist/index.d.ts","_nodeVersion":"22.21.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-Nt8e9f1LRaRMfRpRf49r8N4eTtrl5cbQ6HklBGGicueSPuuukU3PP/NrriqVHqI3UwvmH9YNdkInJl0WnADskw==","shasum":"0cd3bc737cad35936d30b4aeccb9600de6b4b949","tarball":"https://registry.npmjs.org/@chrptvn/mcp-server-devto/-/mcp-server-devto-1.0.0.tgz","fileCount":33,"unpackedSize":84670,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCkCZ1w5PoK0l6gh5QS9jrjGCICrbjtJUJiLkrEDtbCPgIgGnJB0OULcUfffVnOjBn6S500nkWHf3Hk2mGd+cr45U0="}]},"_npmUser":{"name":"chrptvn","email":"chrptvn@gmail.com"},"directories":{},"maintainers":[{"name":"chrptvn","email":"chrptvn@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-server-devto_1.0.0_1772300073015_0.48962692593438395"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-28T17:34:32.943Z","1.0.0":"2026-02-28T17:34:33.160Z","modified":"2026-02-28T17:34:33.356Z"},"maintainers":[{"name":"chrptvn","email":"chrptvn@gmail.com"}],"description":"MCP server for dev.to — developer blogging platform powered by Forem","readme":"# dev.to MCP Server\n\nAn MCP (Model Context Protocol) server for [dev.to](https://dev.to) — the developer blogging and community platform powered by [Forem](https://forem.com). Covers the full Forem REST API with 40 tools for articles, comments, users, organizations, tags, reactions, and more.\n\n## Prerequisites\n\n- **Node.js** v18 or higher\n- A **dev.to API key** — go to [dev.to/settings/extensions](https://dev.to/settings/extensions), scroll to \"DEV API Keys\", and generate a key.\n\n> **Note:** Many tools are public and work without an API key. An API key is only required for authenticated endpoints (creating/updating content, accessing your profile, reactions, etc.).\n\n## Setup\n\n### 1. Build\n\n```bash\nnpm install\nnpm run build\n```\n\n### 2. Configure your MCP client\n\nSet `DEVTO_API_KEY` as an environment variable. Pick your client below:\n\n#### GitHub Copilot CLI\n\nEdit `~/.copilot/mcp-config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"devto\": {\n      \"type\": \"local\",\n      \"command\": \"node\",\n      \"args\": [\"/path/to/mcp-servers/servers/devto/dist/index.js\"],\n      \"env\": {\n        \"DEVTO_API_KEY\": \"your_api_key_here\"\n      },\n      \"tools\": [\"*\"]\n    }\n  }\n}\n```\n\n#### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"devto\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/mcp-servers/servers/devto/dist/index.js\"],\n      \"env\": {\n        \"DEVTO_API_KEY\": \"your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\n#### Cursor\n\nEdit `~/.cursor/mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"devto\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/mcp-servers/servers/devto/dist/index.js\"],\n      \"env\": {\n        \"DEVTO_API_KEY\": \"your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\n#### VS Code\n\nEdit `.vscode/mcp.json` in your workspace:\n\n```json\n{\n  \"servers\": {\n    \"devto\": {\n      \"type\": \"stdio\",\n      \"command\": \"node\",\n      \"args\": [\"/path/to/mcp-servers/servers/devto/dist/index.js\"],\n      \"env\": {\n        \"DEVTO_API_KEY\": \"your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\n## Available Tools (40)\n\nLegend: 🌐 Public (no API key needed) · 🔐 Auth required · 🛡️ Admin/mod only\n\n---\n\n### Articles (12)\n\n#### `list_articles` 🌐\nList articles with optional filters.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number (default: 1) |\n| `per_page` | number | No | Items per page (default: 30, max: 1000) |\n| `tag` | string | No | Filter by single tag slug |\n| `tags` | string | No | Comma-separated tags to include |\n| `tags_exclude` | string | No | Comma-separated tags to exclude |\n| `username` | string | No | Filter by author username |\n| `state` | `fresh` \\| `rising` \\| `all` | No | Filter by article state |\n| `top` | number | No | Top articles from the last N days |\n| `collection_id` | number | No | Filter by collection ID |\n\n#### `list_latest_articles` 🌐\nList the latest articles ordered by publish date.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page |\n\n#### `get_article_by_id` 🌐\nGet a specific article by its numeric ID.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The article ID |\n\n#### `get_article_by_path` 🌐\nGet a specific article by author username and slug.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `username` | string | Yes | The author's username |\n| `slug` | string | Yes | The article slug |\n\n#### `list_videos` 🌐\nList articles with video content.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page (default: 24) |\n\n#### `create_article` 🔐\nCreate a new article. New articles are drafts by default.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `title` | string | Yes | Article title |\n| `body_markdown` | string | No | Article body in Markdown |\n| `published` | boolean | No | Publish immediately (default: false = draft) |\n| `tags` | string[] | No | Array of tag strings |\n| `series` | string | No | Series name to add this article to |\n| `canonical_url` | string | No | Canonical URL if cross-posting |\n| `description` | string | No | Article description/summary |\n| `main_image` | string | No | Cover image URL |\n| `organization_id` | number | No | Publish under an organization |\n\n#### `update_article` 🔐\nUpdate an existing article you own.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The article ID to update |\n| `title` | string | No | New title |\n| `body_markdown` | string | No | New body in Markdown |\n| `published` | boolean | No | Publish or unpublish |\n| `tags` | string[] | No | New tag list |\n| `series` | string | No | Series name |\n| `canonical_url` | string | No | Canonical URL |\n| `description` | string | No | Description |\n| `main_image` | string | No | Cover image URL |\n| `organization_id` | number | No | Organization ID |\n\n#### `list_my_articles` 🔐\nList the authenticated user's articles (most recent first).\n\n#### `list_my_published_articles` 🔐\nList only the authenticated user's published articles.\n\n#### `list_my_unpublished_articles` 🔐\nList only the authenticated user's unpublished (draft) articles.\n\n#### `list_all_my_articles` 🔐\nList all of the authenticated user's articles (published and drafts).\n\n> The above four listing tools accept optional `page` and `per_page` parameters.\n\n#### `unpublish_article` 🛡️\nUnpublish an article (admin/moderator only).\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The article ID |\n| `note` | string | No | Reason for unpublishing |\n\n---\n\n### Comments (2)\n\n#### `list_comments` 🌐\nList comments for an article or podcast episode.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `a_id` | number | No | Article ID |\n| `p_id` | number | No | Podcast episode ID |\n\n#### `get_comment` 🌐\nGet a single comment and all its descendants (full thread).\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | string | Yes | The comment ID code |\n\n---\n\n### Users (5)\n\n#### `get_current_user` 🔐\nGet the authenticated user's profile. No parameters.\n\n#### `get_user` 🔐\nGet any user's profile by ID or username.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number \\| string | Yes | User ID or username |\n\n#### `unpublish_user` 🛡️\nUnpublish all of a user's articles and comments.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The user ID |\n\n#### `suspend_user` 🛡️\nSuspend a user, preventing them from posting.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The user ID |\n\n#### `invite_user` 🛡️\nInvite a new user to the platform (super_admin only).\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `email` | string | Yes | Email address |\n| `name` | string | Yes | Full name |\n\n---\n\n### Organizations (3)\n\n#### `get_organization` 🌐\nGet an organization's profile.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `username` | string | Yes | Organization username |\n\n#### `list_organization_users` 🌐\nList members of an organization.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `username` | string | Yes | Organization username |\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page |\n\n#### `list_organization_articles` 🌐\nList articles published by an organization.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `username` | string | Yes | Organization username |\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page |\n\n---\n\n### Tags (2)\n\n#### `list_tags` 🌐\nList popular tags ordered by usage.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page (default: 10) |\n\n#### `list_followed_tags` 🔐\nList tags the authenticated user follows. No parameters.\n\n---\n\n### Followers (1)\n\n#### `list_followers` 🔐\nList users who follow the authenticated user.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page (default: 80) |\n| `sort` | string | No | Sort field (default: `created_at`) |\n\n---\n\n### Podcast Episodes (1)\n\n#### `list_podcast_episodes` 🌐\nList podcast episodes.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page |\n| `username` | string | No | Filter by podcast username |\n\n---\n\n### Profile Images (1)\n\n#### `get_profile_image` 🔐\nGet a user's or organization's profile image URLs.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `username` | string | Yes | Username to fetch the image for |\n\n---\n\n### Reactions (2)\n\n#### `create_reaction` 🔐\nAdd a reaction to an article, comment, or user.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `category` | `like` \\| `unicorn` \\| `exploding_head` \\| `raised_hands` \\| `fire` | Yes | Reaction type |\n| `reactable_id` | number | Yes | ID of the item |\n| `reactable_type` | `Article` \\| `Comment` \\| `User` | Yes | Type of item |\n\n#### `toggle_reaction` 🔐\nToggle a reaction — creates it if absent, removes it if already present. Same parameters as `create_reaction`.\n\n---\n\n### Reading List (1)\n\n#### `list_reading_list` 🔐\nList the authenticated user's reading list.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `page` | number | No | Page number |\n| `per_page` | number | No | Items per page (default: 30) |\n\n---\n\n### Pages (5)\n\n#### `list_pages` 🌐\nList all custom pages. No parameters.\n\n#### `get_page` 🌐\nGet a specific custom page.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The page ID |\n\n#### `create_page` 🔐\nCreate a new custom page.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `title` | string | Yes | Page title |\n| `slug` | string | Yes | URL slug |\n| `description` | string | Yes | Page description |\n| `template` | `contained` \\| `full_within_layout` \\| `nav_bar_included` \\| `json` | Yes | Layout template |\n| `body_markdown` | string | No | Body in Markdown |\n| `body_json` | string | No | Body as JSON (for `json` template) |\n| `is_top_level_path` | boolean | No | Use top-level URL path |\n\n#### `update_page` 🔐\nUpdate an existing custom page. Accepts the same fields as `create_page` (all optional) plus `id`.\n\n#### `delete_page` 🔐\nDelete a custom page.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The page ID |\n\n---\n\n### Display Ads (5) 🛡️\n\n> All display ad tools require admin privileges.\n\n#### `list_display_ads`\nList all display ads. No parameters.\n\n#### `get_display_ad`\nGet a specific display ad by ID.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The ad ID |\n\n#### `create_display_ad`\nCreate a new display ad.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `name` | string | Yes | Internal name |\n| `body_markdown` | string | Yes | Ad body in Markdown |\n| `placement_area` | string | Yes | Where the ad is displayed |\n| `approved` | boolean | No | Approval status |\n| `published` | boolean | No | Whether the ad is live |\n| `tag_list` | string | No | Comma-separated tag targeting |\n| `type_of` | `in_house` \\| `community` \\| `external` | No | Ad type |\n\n#### `update_display_ad`\nUpdate an existing display ad. Same fields as `create_display_ad` (all optional) plus `id`.\n\n#### `unpublish_display_ad`\nUnpublish a display ad.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The ad ID |\n\n---\n\n## Error Handling\n\nWhen an API call fails, the tool returns `isError: true` with a message in the format:\n\n```\n[<status_code>] <error_message>\n```\n\n| Status | Meaning |\n|--------|---------|\n| 401 | Missing or invalid API key |\n| 403 | Insufficient privileges (admin/mod required) |\n| 404 | Resource does not exist |\n| 422 | Validation error (invalid parameters) |\n| 429 | Rate limit exceeded |\n| 500 | dev.to server error |\n\n## Rate Limits\n\ndev.to does not publish hard rate limit numbers. Handle `429 Too Many Requests` responses gracefully with backoff. For best results, avoid making large numbers of requests in rapid succession.\n","readmeFilename":"README.md","_rev":"1-e616b89a2373eed94d53c9ef53f0a3f5"}