Skip to main content
Glama
N-Graves
by N-Graves
README.md
# devto-mcp-server

A [Model Context Protocol](https://modelcontextprotocol.io) server for the **Dev.to / Forem API**.

Every one of Forem's 139 published operations is accounted for: 49 are reachable through this server, and the other 90 are listed with the reason they are not. That claim is checked by a test against Forem's own OpenAPI spec, so when Forem ships an endpoint the build goes red rather than the README quietly becoming untrue.

MIT licensed.

## Install

```bash
npm install -g @nasdigitaluk/devto-mcp
```

Get an API key from **dev.to → Settings → Extensions → API Keys**.

```json
{
  "mcpServers": {
    "devto": {
      "command": "devto-mcp",
      "env": { "DEVTO_API_KEY": "your-key-here" }
    }
  }
}
```

That is the whole setup. There is no account to register, no capability to grant and no service to run alongside it — the API key is the authorization.

## Configuration

| Variable | |
|---|---|
| `DEVTO_API_KEY` | **Required.** |
| `DEVTO_BASE_URL` | Point at a self-hosted Forem instance. Defaults to `https://dev.to`. |
| `MCP_READ_ONLY=1` | Refuse anything that changes state. |
| `MCP_NO_DESTRUCTIVE=1` | Allow writes, refuse unpublishing. |

## Tools

Nine tools cover 49 operations. That ratio is deliberate: every tool's name and description is paid for in the model's context window on every turn, used or not, so the common path gets purpose-built tools and the long tail goes through one dispatcher.

| Tool | |
|---|---|
| `devto_list_operations` | Browse the catalogue, including what is excluded and why. Start here. |
| `devto_call` | Call any covered operation by id. |
| `devto_get_me` | The authenticated profile. |
| `devto_list_my_articles` | Your own articles. Defaults to **all**, see below. |
| `devto_create_article` | Create. Drafts unless you ask otherwise. |
| `devto_update_article` | Edit content. Never changes publish state. |
| `devto_publish_article` | Publish a draft. Its own tool, deliberately. |
| `devto_unpublish_article` | Take one down. Marked destructive. |
| `devto_get_analytics` | All eight of Forem's reports. |

### Three behaviours worth knowing

**Listing your articles defaults to `all`.** `/articles/me` returns *published* articles only. An account whose work is all drafts looks completely empty through it, which is exactly what happened in the server this was rewritten from — six real drafts, and the tool reported two articles.

**Creating an article makes a draft.** Publishing is immediate and public, so it is a decision rather than a default: pass `published: true`, or use `devto_publish_article` afterwards.

**Editing never changes publish state.** Publishing is a separate tool so that fixing a typo can never take a live article down, and unpublishing can never happen as a side effect of an edit.

## What is excluded, and why

Forem's API is one spec serving both hosted dev.to and self-hosted instances, so a large part of it is for whoever operates the instance rather than whoever writes on it.

| Excluded | Count | Why |
|---|---|---|
| Admin-tagged endpoints | 26 | Need an admin key on a self-hosted Forem. |
| Moderation actions | 8 | Suspend, spam, limited, trusted, unpublish-user. Forem tags these `users`, not `admin`, but they need moderator privileges an author key does not carry. |
| Segments, surveys, billboards, concepts | 24 | Instance features, administered by the operator. |
| Pages, events, subforems, recommendation lists | 15 | Instance structure. |
| Badge and organisation **mutations** | 8 | Minting a badge or creating an organisation is instance administration. The reads are covered. |
| Health checks | 3 | Report on the server, not on your account. |
| Agent sessions | 5 | Forem's own feature; unrelated to MCP. |
| The spec endpoint | 1 | Already vendored in this repo. |

`devto_list_operations` with `include_excluded: true` gives the same information at runtime, per operation.

The exclusions are enforced rather than documented: asking `devto_call` for `suspendUser` returns the reason, not a 403 from Forem after the fact.

## Refreshing the catalogue

```bash
curl -o vendor/forem-openapi.json \
  https://raw.githubusercontent.com/forem/forem/main/swagger/v1/api_v1.json
npm run generate
npm test
```

The coverage test names anything newly unclassified. Classify it in `scripts/generate-operations.mjs` and regenerate.

## Testing

```bash
npm test                  # 21 tests
npm run build
node scripts/smoke.mjs    # real MCP over stdio, 9 checks
```

The smoke test is the one that matters. It speaks actual MCP to the built server with `FLEET_BOARD_URL` and `OPENCLAW_MCP_AGENT_ID` explicitly cleared, and asserts that no tool asks for an `agent_id`, that no private vocabulary appears in any description, and that a read tool works with nothing else running.

That is not hypothetical. This server was extracted from one where every write tool called a private task board at `127.0.0.1:8420` and **failed closed** — so cloned by anyone else, every write tool was permanently broken, and `agent_id` was a required field on all of them.

## Built on

[`@nasdigitaluk/mcp-server-core`](https://github.com/N-Graves/mcp-server-core) — the hardened fetch layer, pluggable authorization, error sanitisation and coverage checking shared across this family of servers.

## Licence

MIT.

TDQS

A4.1/5.0

Scored across 9 tools

Disambiguation5/5

The purpose-built tools each target a distinct action/resource: profile, own articles, create/update/publish/unpublish, and analytics. devto_call is explicitly scoped to operations not covered by the purpose-built tools, so its overlap is intentional and clear.

Naming Consistency4/5

All tools share the devto_ prefix and use snake_case, mostly following a verb_noun pattern. The only notable deviation is devto_call, which is a verb without an explicit object, but this is minor and still predictable in context.

Tool Count5/5

9 tools is a well-scoped set: seven focused article/profile/analytics operations plus a discovery/call pair that prevents the surface from needing dozens of purpose-built tools. Each tool earns its place.

Completeness5/5

The set covers the core article lifecycle—create, list, update, publish, unpublish—plus profile and analytics, and explicitly documents why delete is not available. The devto_list_operations/devto_call pair also provides access to all other reachable Forem API operations, so no major gaps remain.

Maintenance

ActivityMaintained
ResponsivenessNo issues