Skip to main content
Glama

bluesky-mcp-server

Get Bluesky Social Graph

bsky_get_follows
Read-onlyIdempotent

Fetch the social graph edges for a Bluesky account — who follows them, or who they follow. Returns paginated actor profiles (handle, DID, displayName, bio, pronouns when set, and Bluesky verification status) plus a summary of the subject account. Follower, following, and post counts and the website are not on this view, for the listed accounts or the subject — bsky_get_profile returns them for one account. Accounts with large social graphs return only the first page; use cursor pagination to walk through the full list, or sort "top" to put the accounts Bluesky ranks most prominent first.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sortNoOrder of the list. "latest" (Bluesky's default, and what omitting this gives) puts the most recent follows first; "top" is Bluesky's own ranking, which surfaces prominent accounts but is not a follower-count order. Pass a cursor back with the same sort it came from.
actorYesHandle (e.g. "alice.bsky.social") or DID of the account to query. A leading "@" and the account's bsky.app page ("https://bsky.app/profile/alice.bsky.social") are accepted and read as the handle or DID they carry. A bare name without a dot is not a handle — use bsky_search_actors to resolve one.
limitNoMaximum number of actors to return per page (1–100). Default 25.
cursorNoOpaque pagination cursor from a previous response. Omit for the first page.
directionYes"followers" returns accounts that follow this actor. "following" returns accounts this actor follows.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
capNoThe limit applied to this page.
errorNoPresent when the call failed. Absent on success.
shownNoNumber of actors returned on this page.
actorsNoActors in the requested direction of the social graph.
cursorNoOpaque cursor for the next page. Absent on the last page.
noticeNoGuidance when the result set is empty or constrained.
subjectNoProfile summary of the queried actor.
truncatedNoTrue when Bluesky returned a cursor, whatever this page held. A cursor is not proof more accounts exist: the next page can come back empty when the remaining accounts are unavailable.
totalReturnedNoNumber of actors in this response page.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed2 schema fields changed
    • addedOutput schema / properties / actors / items / properties / verification
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Bluesky verification of this account — what tells it from a look-alike handle. Absent when Bluesky sent none. Who issued it is on bsky_get_profile.",
      +  "properties": {
      +    "trustedVerifierStatus": {
      +      "description": "Whether this account is itself a trusted verifier — same values as verifiedStatus.",
      +      "type": "string"
      +    },
      +    "verifiedStatus": {
      +      "description": "Whether a trusted verifier verified this account: \"valid\", \"invalid\" (verified once, no longer holds), or \"none\". Passed through as Bluesky sends it, so another value may appear.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "verifiedStatus",
      +    "trustedVerifierStatus"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / properties / subject / properties / verification
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Bluesky verification of this account — what tells it from a look-alike handle. Absent when Bluesky sent none. Who issued it is on bsky_get_profile.",
      +  "properties": {
      +    "trustedVerifierStatus": {
      +      "description": "Whether this account is itself a trusted verifier — same values as verifiedStatus.",
      +      "type": "string"
      +    },
      +    "verifiedStatus": {
      +      "description": "Whether a trusted verifier verified this account: \"valid\", \"invalid\" (verified once, no longer holds), or \"none\". Passed through as Bluesky sends it, so another value may appear.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "verifiedStatus",
      +    "trustedVerifierStatus"
      +  ],
      +  "type": "object"
      +}
  2. Changed4 schema fields changed
    • changedInput schema / properties / actor / description
      Previous value: -"Handle (e.g. \"alice.bsky.social\") or DID of the account to query. A bare name without a dot is not a handle — use bsky_search_actors to resolve one."New value: +"Handle (e.g. \"alice.bsky.social\") or DID of the account to query. A leading \"@\" and the account's bsky.app page (\"https://bsky.app/profile/alice.bsky.social\") are accepted and read as the handle or DID they carry. A bare name without a dot is not a handle — use bsky_search_actors to resolve one."
    • changedInput schema / properties / actor / maxLength
      Previous value: -253New value: +2048
    • changedInput schema / properties / actor / pattern
      Previous value: -"^(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?|did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-])$"New value: +"^(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?|did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]|@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?|https:\\/\\/bsky\\.app\\/profile\\/(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?|did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-])\\/?(?:[?#].*)?)$"
    • addedInput schema / properties / sort
      Added value: +{
      +  "description": "Order of the list. \"latest\" (Bluesky's default, and what omitting this gives) puts the most recent follows first; \"top\" is Bluesky's own ranking, which surfaces prominent accounts but is not a follower-count order. Pass a cursor back with the same sort it came from.",
      +  "enum": [
      +    "latest",
      +    "top"
      +  ],
      +  "type": "string"
      +}
  3. Changed4 schema fields changed
    • removedOutput schema / properties / actors / items / properties / followersCount
      Removed value: -{
      -  "description": "Number of followers.",
      -  "type": "number"
      -}
    • removedOutput schema / properties / subject / properties / followersCount
      Removed value: -{
      -  "description": "Subject's follower count.",
      -  "type": "number"
      -}
    • removedOutput schema / properties / subject / properties / followsCount
      Removed value: -{
      -  "description": "Subject's following count.",
      -  "type": "number"
      -}
    • changedOutput schema / properties / truncated / description
      Previous value: -"True when more actors exist beyond this page (a cursor was returned)."New value: +"True when Bluesky returned a cursor, whatever this page held. A cursor is not proof more accounts exist: the next page can come back empty when the remaining accounts are unavailable."
  4. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "actors",
      +      "subject",
      +      "totalReturned"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode. Declared by this tool: `actor_not_found`: The actor handle or DID does not resolve to an existing account. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "actor_not_found"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "actors",
      -  "subject",
      -  "totalReturned"
      -]
  5. Changed2 schema fields changed
    • addedOutput schema / properties / actors / items / properties / pronouns
      Added value: +{
      +  "description": "Free-form pronouns the account set, e.g. \"they/he\". Absent when it set none. Account-authored text bounded only by length, not a fixed vocabulary — read it as written rather than parsing it.",
      +  "type": "string"
      +}
    • addedOutput schema / properties / subject / properties / pronouns
      Added value: +{
      +  "description": "Free-form pronouns the subject account set, e.g. \"they/he\". Absent when it set none.",
      +  "type": "string"
      +}
  6. Changed3 schema fields changed
    • changedInput schema / properties / actor / description
      Previous value: -"Handle (e.g. \"alice.bsky.social\") or DID of the account to query."New value: +"Handle (e.g. \"alice.bsky.social\") or DID of the account to query. A bare name without a dot is not a handle — use bsky_search_actors to resolve one."
    • addedInput schema / properties / actor / minLength
      Added value: +1
    • addedInput schema / properties / actor / pattern
      Added value: +"^(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?|did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-])$"
  7. Changed3 schema fields changed
    • addedOutput schema / properties / cap
      Added value: +{
      +  "description": "The limit applied to this page.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / shown
      Added value: +{
      +  "description": "Number of actors returned on this page.",
      +  "type": "number"
      +}
    • addedOutput schema / properties / truncated
      Added value: +{
      +  "description": "True when more actors exist beyond this page (a cursor was returned).",
      +  "type": "boolean"
      +}
  8. First observed

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint, openWorldHint, and idempotentHint already set, the description adds value beyond annotations: it warns that large graphs return only the first page, points to cursor pagination, and clarifies that the 'top' sort is Bluesky's ranking, not follower-count order. No contradiction with the readOnlyHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A dense, compact description that front-loads the core purpose and immediately scopes the tool's output. Every sentence earns its place: the exclusions, the pagination warning, the sort nuance, and the sibling references are all necessary for correct use. The alignment is high and no repetition of schema text exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the shape of returned data and explicitly notes what is absent, accounts for pagination and sorting, and routes the agent to sibling tools for different data. An output schema exists, so return-value detail does not need to be fully restated. Nothing essential for selecting or correctly invoking the tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds meaning beyond the schema: it explains the behavior of 'top' vs 'latest', that omitting sort defaults to latest, and that cursor must be passed back with the same sort it came from. This provides genuinely useful operational semantics for each parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States the specific verb 'Fetch the social graph edges for a Bluesky account' and the two directions, distinguishing it from siblings that return feeds, posts, or single profiles. It names the resource (actor social graph) and even preempts what is not included, so an agent can confidently select it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly gives the alternative when the other counts/website are needed ('bsky_get_profile returns them for one account') and when a handle needs resolving ('use bsky_search_actors'). Also gives direct guidance on cursor pagination and sort 'top'. This exceeds a minimum-viable description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.