MCP server for interacting with Bluesky Social (ATProto protocol)
This server has 7 tools with PARTIAL schema coverage and INCONSISTENT description quality. All tools have descriptions, but many parameters lack proper type constraints and descriptions. Schema definitions are visible in source but incomplete, several parameters are missing descriptions or type clarifications. No tool annotations (readOnlyHint/destructiveHint). Output schemas are not formally documented. Error handling exists but is generic. The server treats credentials via environment variables (correct) but lacks audit logging, rate limiting, and fine-grained permission gates. Overall, this is a fair-to-poor implementation typical of early-stage community servers.
Check if the current session is authenticated. Authentication happens automatically using environment variables: - BLUESKY_IDENTIFIER: Required - your Bluesky handle - BLUESKY_APP_PASSWORD: Required - your app password - BLUESKY_SERVICE_URL: Optional - defaults to https://bsky.social
Get users who follow an account.
Get users followed by an account.
Get a user profile.
Like a post.
Send a post to Bluesky.
check_auth_status has NO input schema definition (empty {} input).
Parameters lack actionable descriptions. 'handle' is described as 'Optional handle to get profile for' but no format guidance (e.g., 'username like @alice or DID'). 'limit' says '1-100' in description but no explicit min/max constraints in schema. 'cursor' and 'like_uri' are vague about format.
Tool descriptions are too short (40-55 chars for like_post, unlike_post, get_profile). Descriptions do not explain WHEN to use (vs similar tool), prerequisites, or expected side effects. get_profile description is 17 chars, 'Get a user profile.', below actionable threshold.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 52 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 0 | - | v1 |
Unlike a previously liked post.
No tool annotations. Tools like like_post, unlike_post, and send_post modify state but lack destructiveHint or idempotentHint. This forces LLMs to reason about side effects instead of relying on metadata. Pattern:tool requires annotation.
No output schemas documented. Tools return dicts with 'status' and data fields, but structure is not formally specified. LLMs cannot predict field names or types. Example: get_profile returns {'status', 'profile'}, what fields are in profile? Is it a dict, string, or object?
Error handling is generic. All tools catch Exception and return {'status': 'error', 'message': str(e)}. This violates recovery-guide pattern, errors should guide LLM on next steps. Example: 'User not found. Try search_users() with a partial name.' Not implemented.
No pagination result limits enforced. get_follows and get_followers default limit=50 but cap at 100, acceptable. However, response fields (follows_data, followers_data) are not described. Does the response include total_count? next_cursor? Without documented pagination schema, LLMs cannot chain calls.
send_post has complex optional parameters (reply_to, embed, facets) described as generic 'objects' with no schema. LLMs cannot know what fields to include. Example: embed is 'Optional embed object (images, external links, records, or video)', what properties does an embed object require?
No permission gates or audit logging. Tools like send_post and unlike_post modify state, but no checks for user authorization or call logging. Pattern:permission-gate not followed. No context about who called, when, with what params, and what succeeded/failed.
Composition: Users speak 'send a post to @alice', but send_post requires profile_identify (handle or DID). Tool accepts identifiers but does NOT resolve them. If agent passes unknown handle, error is generic. No guidance on how to find valid handles.
Credibility: like_post and unlike_post are NOT idempotent. Calling like_post twice on the same post may fail the second time (already liked). No confirm_before_execute pattern. Agents may retry destructive calls without safeguards.