This is a submission for the Built with Google Gemini: Writing Challenge
As software developers, DEV Community (dev.to) and the wider Forem ecosystem have increasingly become our digital home. It's the place we go for "React best practices", solutions to obscure bugs, and career advice. But as our workflows become more tightly integrated with AI assistants, a gap has emerged: why can't our AI tools natively interact with this vibrant community?
Why couldn't I tell my AI assistant to "list popular Rust articles on DEV," or "take this markdown draft and publish it directly to my DEV account"?
To solve this, I built DevTo-MCP. It's an open-source Model Context Protocol (MCP) server that acts as a secure, type-safe bridge between the Forem API and AI assistants. And throughout this journey of architectural design, debugging, and implementation, Google Gemini was my constant pair-programming companion.
What I Built with Google Gemini
DevTo-MCP is essentially a translation layer. The Model Context Protocol (MCP) is an open standard that lets AI models use external tools and resources securely. DevTo-MCP takes the complex world of Forem API endpoints and turns them into simple, standardized functions that AI assistants (like Claude Desktop, Cursor, and custom Gemini agents) can seamlessly trigger.
During the development process, Google Gemini played several pivotal roles:
1. Architectural Guidance and Type Safety
Building an MCP server requires strict data validation. AI models can sometimes hallucinate parameters, so your server's defense must be ironclad. I decided to build DevTo-MCP using TypeScript, Node.js, and Zod for runtime validation.
Gemini helped me quickly map out the Forem API responses to Zod schemas. For example, when defining the create_article tool, Gemini assisted in generating the complete schema configuration:
server.tool(
"create_article",
"Create a new article on DEV Community.",
{
title: "z.string().describe(\"Title of the article\"),"
body_markdown: z.string().optional().describe("Article content in markdown"),
published: z.boolean().optional().describe("Whether to publish immediately"),
tags: z.array(z.string()).max(4).optional().describe("List of tags (max 4)"),
canonical_url: z.string().url().optional(),
organization_id: z.number().int().optional()
},
async (params) => {
// Implementation logic
}
);
Thanks to Gemini's suggestions, added strict .max(4) constraints and .url() validations to ensure we never send malformed data to the Forem API.
2. The Self-Healing API Client
Forem's API deals with millions of requests, meaning rate limits and occasional network blips are part of the game. I wanted my MCP server to be resilient. I tasked Gemini with helping me write a self-healing HTTP client.
Gemini generated the core logic for a robust fetch wrapper that:
- Reads
x-ratelimit-remainingheaders. - Implements an exponential backoff strategy for 429 (Too Many Requests) and 500 errors.
- Provides type-safe generic responses.
// A simplified look at the retry logic we implemented
private async request<T>(...): Promise<T> {
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
try {
const response = await fetch(url, options);
if (response.ok) return await response.json();
if (this.isRetryable(response.status)) {
const delay = this.getRetryDelay(attempt);
await this.sleep(delay);
continue;
}
} catch (error) {
// Handle network level errors
}
}
}
3. CI/CD and NPM "Trusted Publishing"
A crucial goal was to automate the publishing of this package to NPM using GitHub Actions. I wanted to use modern OpenID Connect (OIDC) (NPM's Trusted Publishing) to avoid hardcoding NPM_TOKEN secrets.
I was stuck with persistent 404 errors during the pipeline execution. I pasted my YAML into Gemini, and it instantly spotted the missing piece: my workflow was missing the environment: production declaration required to establish trust.
jobs:
publish:
runs-on: ubuntu-latest
environment: production # <-- The magic line Gemini pointed out!
permissions:
id-token: write
Demo
The project is fully open-source and available here:
GitHub: furkankoykiran/DevTo-MCP
You can install and use it in any MCP-compatible client (like Claude Desktop) by simply adding it to your configuration:
{
"mcpServers": {
"devto": {
"command": "npx",
"args": ["-y", "devto-mcp"],
"env": {
"DEVTO_API_KEY": "YOUR_API_KEY"
}
}
}
}
Once installed, your AI assistant can fetch your latest followers, create article drafts, and analyze your reading list tags dynamically!
What I Learned
Building this project taught me several invaluable lessons:
The Art of "Feature Cutting"
Initially, I wanted to include a tool that allowed users to add reactions (like, unicorn, fire) to articles via the AI. However, I consistently encountered unreliable 401 errors from the API side. As tempting as it was to keep debugging it, I learned that in building AI tools, reliability is paramount. If an AI thinks it successfully reacted to a post but didn't, it breaks the chain of trust. I had to learn the difficult engineering skill of "Feature Cutting" and disabled the tool for the MVP.
Fallback Mechanisms for UX
When the AI tried to fetch a "Draft" article using the standard get_article_by_id endpoint, Forem would return a 404. Initially, the AI would give up and respond, "This article doesn't exist."
I learned to build fallback loops. Now, if the server receives a 404, it automatically makes a secondary request to /articles/me/all, searches for the ID locally, and returns the draft. This completely changed how smoothly the AI interacted with unpublished content.
Modern Release Pipelines
I leveled up my Devops skills by successfully setting up an automated, secret-less NPM release pipeline using OIDC and GitHub Actions, understanding exactly when and why workflows trigger.
Google Gemini Feedback
My experience with Google Gemini was incredibly positive, with a few notable learning curves.
What Worked Well:
- Boilerplate and Structure: Gemini was fantastic at instantly generating the foundational boilerplate for a TypeScript Node project.
-
Error Decoding: When I encountered cryptic TypeScript errors regarding complex generic types for my API wrapper, Gemini was able to decipher them and explain the exact configuration changes needed in my
tsconfig.json. - Regex and Parsing: Writing the logic to safely sanitize markdown payloads before sending them to the API was made trivial thanks to Gemini's rapid regex suggestions.
Where I Encountered Friction (The Candid Truth):
- API Hallucinations: Because the Forem API has changed over time, Gemini occasionally hallucinated endpoints or parameter names that didn't exist or were deprecated. For example, it suggested sending data in a structure that the current API rejected. This actually reinforced my decision to use Zod—building strict validation layers meant I caught these AI hallucinations in my test environment immediately.
-
Context Window Management: When working across multiple files (
api-client.ts,server.ts, and the Zod schema files), I sometimes found Gemini losing the thread of the specific generic types we had agreed upon earlier in the conversation. Reminding it of the interface definitions occasionally disrupted the flow state.
Look Forward
The future of software engineering lies in AI assistants that have secure, predictable access to our development ecosystems. DevTo-MCP is my contribution to ensuring the DEV community isn't left behind in this AI revolution.
I plan to expand DevTo-MCP to include organization-level analytics, more robust comment threading capabilities, and eventually figuring out a secure way to re-enable that elusive "Reactions" tool!
Thank you to MLH and Google for hosting this challenge, it was the perfect catalyst to reflect on this build journey.
(P.S. As a special proof-of-concept, this very article was drafted, formatted, and published autonomously to DEV.to by my AI Assistant (Gemini) using the DevTo-MCP server I built! A little meta-magic to wrap things up! 🪄)
Top comments (0)