Skip to main content
Glama

bluesky-mcp-server

Get Bluesky Post Quotes

bsky_get_post_quotes
Read-onlyIdempotent

Read the quote posts behind a Bluesky post's "quoteCount" — the posts that embed it with commentary of their own. Sort latest (default) is newest first; top is descending like count as ordered by Bluesky. On Bluesky this is where much of the reaction to a post lives; bsky_get_post_thread returns replies only. Accepts the post's AT-URI (at:///app.bsky.feed.post/) from the "uri" field of any returned post, or its bsky.app URL (https://bsky.app/profile//post/); a handle costs one extra lookup. Returns each quote post with full text, author, engagement counts, and AT-URI. Each result's embed names the queried post by AT-URI and CID only — its text is not repeated on every result — and keeps any media the quoting post attached. "quoteCount" is an upper bound on what this returns: Bluesky's counter keeps quotes that have left the index. Supports cursor pagination.

Input Schema

NameRequiredDescriptionDefault
uriYesThe post whose quotes to read — its AT-URI, e.g. "at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.post/3l6oveex3ii2l", or its bsky.app URL, e.g. "https://bsky.app/profile/bsky.app/post/3l6oveex3ii2l"; a trailing "/", "?…", or "#…" on the URL is ignored. Posts only — a feed, profile, or list address is rejected.
sortNoProvider ordering: latest is newest first (default); top is descending like count. Reuse cursors with the same post and sort.latest
limitNoMaximum number of quote posts to return; values above 100 are clamped with notice unless strict limits are configured. Default 25. Pages often hold fewer than the limit and still continue — follow the cursor, not the count. A page that would pass the 48,000-byte response budget comes back with fewer quotes and "budgetCapped: true"; its cursor continues from the first quote it left out.
cursorNoOpaque pagination cursor from a previous response for the same post and sort, passed back unchanged. Omit for the first page.

Output Schema

NameRequiredDescriptionDefault
capNoThe limit applied to this page.
uriNoAT-URI of the post whose quotes these are, in DID form — the form Bluesky was asked in, whatever form the input took.
sortNoApplied provider ordering: latest is newest first; top is descending like count.
errorNoPresent when the call failed. Absent on success.
postsNoPosts quoting the queried post, in the applied sort order.
shownNoNumber of quote posts returned on this page.
cursorNoOpaque cursor for the next page. Absent when there are no more quotes.
noticeNoGuidance on the page: that more quotes can be fetched with the returned cursor, or why the page is empty — the post has no readable quotes, or the last page was reached.
truncatedNoTrue when Bluesky returned a cursor, whatever this page held — pages often come back short of the limit with more behind them.
budgetCappedNoTrue when a page of the requested limit would have passed this server's 48,000-byte response budget, so Bluesky was asked again for fewer quotes and that page was returned whole. The cursor comes from that same response, so paging on from it skips nothing. Independent of "truncated", which still means only that a cursor was returned.
totalReturnedNoNumber of quote posts in this response page.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed9 schema fields changed
    • changedInput schema / properties / cursor / description
      Previous value: -"Opaque pagination cursor from a previous response for the same post, passed back unchanged. Omit for the first page."New value: +"Opaque pagination cursor from a previous response for the same post and sort, passed back unchanged. Omit for the first page."
    • changedInput schema / properties / limit / description
      Previous value: -"Maximum number of quote posts to return (1–100). Default 25. Pages often hold fewer than the limit and still continue — follow the cursor, not the count. A page that would pass the 48,000-byte response budget comes back with fewer quotes and \"budgetCapped: true\"; its cursor continues from the first quote it left out."New value: +"Maximum number of quote posts to return; values above 100 are clamped with notice unless strict limits are configured. Default 25. Pages often hold fewer than the limit and still continue — follow the cursor, not the count. A page that would pass the 48,000-byte response budget comes back with fewer quotes and \"budgetCapped: true\"; its cursor continues from the first quote it left out."
    • changedInput schema / properties / limit / maximum
      Previous value: -100New value: +9007199254740991
    • addedInput schema / properties / sort
      Added value: +{
      +  "default": "latest",
      +  "description": "Provider ordering: latest is newest first (default); top is descending like count. Reuse cursors with the same post and sort.",
      +  "enum": [
      +    "latest",
      +    "top"
      +  ],
      +  "type": "string"
      +}
    • changedOutput schema / anyOf
      Previous value: -[
      -  {
      -    "not": {
      -      "required": [
      -        "error"
      -      ]
      -    },
      -    "required": [
      -      "uri",
      -      "posts",
      -      "totalReturned"
      -    ]
      -  },
      -  {
      -    "required": [
      -      "error"
      -    ]
      -  }
      -]New value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "uri",
      +      "sort",
      +      "posts",
      +      "totalReturned"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • changedOutput schema / properties / posts / description
      Previous value: -"Posts quoting the queried post, newest first."New value: +"Posts quoting the queried post, in the applied sort order."
    • changedOutput schema / properties / posts / items / properties / embed / description
      Previous value: -"The embed on this quote post. On every result it is a \"record\" embed pointing at the queried post, cut back to what the quoting post itself carries: { uri, cid, recordKind?, media? } — uri and cid address the queried post (the revision this quote points at), recordKind is set only when that post is unreadable (\"notFound\" | \"blocked\" | \"detached\"), and media is the image/video/link the quoting post attached alongside the quote. The queried post's own text, author, and attachments are not restated on each result. Other shapes, should an embed point elsewhere: images: { images: [{ url, alt }] }; external: { uri, title, description }; record: { uri, cid, text?, authorHandle?, embeds?, media?, omittedEmbeds?, recordKind? }; video: { playlist?, thumbnail?, presentation? }; unknown: { raw }."New value: +"The embed on this quote post. On every result it is a \"record\" embed pointing at the queried post, cut back to what the quoting post itself carries: { uri, cid, recordKind?, media? } — uri and cid address the queried post (the revision this quote points at), recordKind is set only when that post is unreadable (\"notFound\" | \"blocked\" | \"detached\"), and media is the image/video/link the quoting post attached alongside the quote. The queried post's own text, author, and attachments are not restated on each result. Other shapes, should an embed point elsewhere: images: { images: [{ url, alt }] }; external: { uri, title, description }; record: { uri, cid, text?, facets?, authorHandle?, embeds?, media?, omittedEmbeds?, recordKind? } — facets retain UTF-8 byte ranges and full link, mention, or tag features; video: { playlist?, thumbnail?, presentation? }; unknown: { raw }."
    • addedOutput schema / properties / posts / items / properties / facets
      Added value: +{
      +  "description": "Rich-text facets on the unchanged commentary, with UTF-8 byte ranges and full link, mention, or tag values.",
      +  "items": {
      +    "additionalProperties": {},
      +    "description": "One rich-text annotation on the original post text.",
      +    "properties": {
      +      "features": {
      +        "description": "Features applied to this range, in upstream order.",
      +        "items": {
      +          "anyOf": [
      +            {
      +              "additionalProperties": {},
      +              "description": "Link destination.",
      +              "properties": {
      +                "$type": {
      +                  "const": "app.bsky.richtext.facet#link",
      +                  "description": "Link feature.",
      +                  "type": "string"
      +                },
      +                "uri": {
      +                  "description": "Complete destination URI, independent of abbreviated display text.",
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "$type",
      +                "uri"
      +              ],
      +              "type": "object"
      +            },
      +            {
      +              "additionalProperties": {},
      +              "description": "Mention identity.",
      +              "properties": {
      +                "$type": {
      +                  "const": "app.bsky.richtext.facet#mention",
      +                  "description": "Mention feature.",
      +                  "type": "string"
      +                },
      +                "did": {
      +                  "description": "Mentioned account DID.",
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "$type",
      +                "did"
      +              ],
      +              "type": "object"
      +            },
      +            {
      +              "additionalProperties": {},
      +              "description": "Tag value.",
      +              "properties": {
      +                "$type": {
      +                  "const": "app.bsky.richtext.facet#tag",
      +                  "description": "Tag feature.",
      +                  "type": "string"
      +                },
      +                "tag": {
      +                  "description": "Tag text without the leading hash.",
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "$type",
      +                "tag"
      +              ],
      +              "type": "object"
      +            },
      +            {
      +              "additionalProperties": {},
      +              "description": "An open-union feature whose complete fields are retained as literal metadata.",
      +              "properties": {
      +                "$type": {
      +                  "description": "An upstream feature type other than the known link, mention, or tag types.",
      +                  "type": "string"
      +                }
      +              },
      +              "required": [
      +                "$type"
      +              ],
      +              "type": "object"
      +            }
      +          ],
      +          "description": "A known link, mention, or tag feature, or an upstream extension variant."
      +        },
      +        "type": "array"
      +      },
      +      "index": {
      +        "additionalProperties": {},
      +        "description": "UTF-8 byte range; these are not JavaScript string indices. Additional upstream fields are retained.",
      +        "properties": {
      +          "byteEnd": {
      +            "description": "Exclusive UTF-8 byte offset in the original text.",
      +            "maximum": 9007199254740991,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "byteStart": {
      +            "description": "Inclusive UTF-8 byte offset in the original text.",
      +            "maximum": 9007199254740991,
      +            "minimum": 0,
      +            "type": "integer"
      +          }
      +        },
      +        "required": [
      +          "byteStart",
      +          "byteEnd"
      +        ],
      +        "type": "object"
      +      }
      +    },
      +    "required": [
      +      "index",
      +      "features"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / sort
      Added value: +{
      +  "description": "Applied provider ordering: latest is newest first; top is descending like count.",
      +  "enum": [
      +    "latest",
      +    "top"
      +  ],
      +  "type": "string"
      +}
  2. Changed3 schema fields changed
    • changedInput schema / properties / limit / description
      Previous value: -"Maximum number of quote posts to return (1–100). Default 25. Pages often hold fewer than the limit and still continue — follow the cursor, not the count."New value: +"Maximum number of quote posts to return (1–100). Default 25. Pages often hold fewer than the limit and still continue — follow the cursor, not the count. A page that would pass the 48,000-byte response budget comes back with fewer quotes and \"budgetCapped: true\"; its cursor continues from the first quote it left out."
    • addedOutput schema / properties / budgetCapped
      Added value: +{
      +  "description": "True when a page of the requested limit would have passed this server's 48,000-byte response budget, so Bluesky was asked again for fewer quotes and that page was returned whole. The cursor comes from that same response, so paging on from it skips nothing. Independent of \"truncated\", which still means only that a cursor was returned.",
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / posts / items / properties / author / properties / verification
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Bluesky verification of the author — what tells a verified account from a look-alike handle. Absent when Bluesky sent none. Who issued it is on bsky_get_profile.",
      +  "properties": {
      +    "trustedVerifierStatus": {
      +      "description": "Whether the author is itself a trusted verifier — same values as verifiedStatus.",
      +      "type": "string"
      +    },
      +    "verifiedStatus": {
      +      "description": "Whether a trusted verifier verified the author: \"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"
      +}
  3. Added

TDQS

A4.8/5.0
Behavior5/5

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

With readOnlyHint, openWorldHint, and idempotentHint already present, the description adds meaningful behavior beyond annotations: quoteCount is an upper bound because Bluesky retains departed quotes, embeds identify the queried post by AT-URI and CID without repeating its text, and media from quoting posts is preserved.

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

Conciseness4/5

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

The description is front-loaded and appropriately sized for a tool with format, ordering, pagination, and return-shape nuances. It is slightly longer than strictly necessary because some return details overlap with the output schema, but the added behavioral context mostly earns its place.

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?

Given the annotations, full schema coverage, and an output schema, the description supplies all the context an agent needs: what the tool returns, how quoteCount relates to results, input formats, ordering, and pagination. No material gap remains for correct invocation.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already defines uri, sort, limit, and cursor in detail. The description adds some useful nuance beyond the schema, notably that accepting a handle costs one extra lookup and that cursors are tied to the same post and sort.

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?

The description uses a specific verb and resource: read quote posts behind a Bluesky post's quoteCount. It explicitly distinguishes this from bsky_get_post_thread, which returns replies only, so an agent can select this tool without inspecting the schema.

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?

It names the relevant alternative, bsky_get_post_thread, and explains that quote posts are where reaction content lives whereas replies are separate. This gives clear selection guidance between the two closely related tools.

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.