MCP server for publishing blog posts to GitHub repository
Server implements 5 tools for blog management with proper TypeScript types and reasonable JSON schemas. Tool naming follows verb_noun pattern (publish_blog_post, get_blog_post, etc.). All tools have descriptions and input schemas. However, parameter descriptions lack detail, output schemas are undocumented, and error handling provides minimal recovery guidance. The server demonstrates basic quality but falls short of production-grade standards in several critical dimensions.
Delete an existing blog post from the repository
Read the content of a specific blog post
List existing blog posts in the repository
Publish a new blog post to the GitHub repository
Update an existing blog post
Output schemas are not documented. Tool responses return unstructured text in a 'content' array with type/text objects. LLMs cannot plan downstream operations or extract structured data without knowing the response schema (field names, types, nesting).
list_blog_posts has no input schema documented. Tool accepts no parameters but schema lacks description of what the list returns (file count, pagination, sorting). The response format is also undocumented.
Parameter descriptions are generic and lack constraints. For example, 'filename' is described as 'The filename of the blog post to read (with .md extension)' but does not specify allowed characters, length limits, or path traversal protections. 'tags' lacks detail on format (comma-separated? array? max count?).
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 61 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 46 | - | v1 |
No pagination support on list_blog_posts. As documented, if a repository has many blog posts, the response could list hundreds of files, exhausting context. No limit, offset, or cursor parameters are provided.
Error handling provides minimal recovery guidance. Errors throw McpError with messages like 'Failed to publish blog post: ...' but do not guide the LLM on next steps. For example, when publish_blog_post fails due to duplicate filename, the response says 'Use update_blog_post to modify it', good, but other errors (network, auth) lack actionable guidance.
No confirmation or dry-run pattern for destructive operations. delete_blog_post modifies state irreversibly without offering a preview or requiring explicit confirmation. Agents can make mistakes and permanently delete content.
update_blog_post requires 'filename' but all other fields (title, content, tags, etc.) are optional. This is appropriate for partial updates, but the description does not clarify that at least one field besides filename is required; passing only filename results in an error 'Content is required' rather than a clear up-front constraint.
Tool descriptions under 100 characters lack context on use cases and prerequisites. For example, 'List existing blog posts in the repository' does not explain when to call this (discovery phase, planning) or what the LLM should do with the result. Descriptions average ~50 chars; production baseline is 194 chars.
No error classification (retryable, user-fixable, fatal). An LLM does not know whether to retry a network error, ask the user to provide a missing filename, or abort. McpError types hint at this but are not consistently applied or documented.
GITHUB_TOKEN, REPO_OWNER, and REPO_NAME are correctly injected via environment variables (not tool parameters), which is secure. However, there is no documentation of required scopes, permissions, or what capabilities the token must have. The server throws a generic error if env vars are missing but does not guide setup.