Skip to main content
Glama
cameronrye

AT Protocol MCP Server

search_posts

Read-only

Search Bluesky posts by keyword with filters for author, language, date range, mentions, domain, and URL. Returns paginated results sorted by recency or engagement.

Instructions

Search for posts on Bluesky using full-text queries with optional filters for author, language, date range, mentions, domain, and URL. Returns a paginated list of matching posts sorted by recency or engagement. Requires authentication (app password). Use search_actors to find users instead of posts. Subject to per-tool rate limiting.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
qYesFull-text search query string (1–300 characters). Supports keywords and hashtags (e.g. "#bluesky launch").
limitNoMaximum number of posts to return per page (1–100, default 25).
cursorNoOpaque pagination cursor from the previous response cursor field; omit for the first page.
sortNoSort order for results: "latest" returns newest posts first (default), "top" returns most-engaged posts first.latest
sinceNoISO 8601 datetime lower bound (inclusive) for post creation time (e.g. "2024-01-01T00:00:00Z"). Omit to search all time.
untilNoISO 8601 datetime upper bound (exclusive) for post creation time (e.g. "2024-12-31T23:59:59Z"). Omit for no upper bound.
mentionsNoFilter to posts that mention this handle or DID (e.g. "alice.bsky.social" or "did:plc:...").
authorNoFilter to posts authored by this handle or DID (e.g. "alice.bsky.social" or "did:plc:..."). Requires a non-empty q term.
langNoBCP-47 language tag to filter posts by language (e.g. "en", "en-US", "pt-BR").
domainNoFilter to posts containing links from this domain (e.g. "bsky.app"). Do not include protocol or path.
urlNoFilter to posts containing this exact URL (must be a fully-qualified URL, e.g. "https://example.com/article").

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
successYesWhether the search request completed successfully.
postsYesArray of posts matching the search query.
cursorNoOpaque pagination cursor to pass as cursor in the next call; absent when no further pages exist.
hasMoreYesTrue when a subsequent page of results is available.
searchQueryYesThe search query string that was executed.
totalResultsNoApproximate total number of matching posts reported by the API, if available.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.6.2
    • removedInput schema / additionalProperties
      Removed value: -false
  2. Changed12 schema fields changedv0.6.0
    • addedInput schema / properties / author / description
      Added value: +"Filter to posts authored by this handle or DID (e.g. \"alice.bsky.social\" or \"did:plc:...\"). Requires a non-empty q term."
    • addedInput schema / properties / cursor / description
      Added value: +"Opaque pagination cursor from the previous response cursor field; omit for the first page."
    • addedInput schema / properties / domain / description
      Added value: +"Filter to posts containing links from this domain (e.g. \"bsky.app\"). Do not include protocol or path."
    • addedInput schema / properties / lang / description
      Added value: +"BCP-47 language tag to filter posts by language (e.g. \"en\", \"en-US\", \"pt-BR\")."
    • addedInput schema / properties / limit / description
      Added value: +"Maximum number of posts to return per page (1–100, default 25)."
    • addedInput schema / properties / mentions / description
      Added value: +"Filter to posts that mention this handle or DID (e.g. \"alice.bsky.social\" or \"did:plc:...\")."
    • addedInput schema / properties / q / description
      Added value: +"Full-text search query string (1–300 characters). Supports keywords and hashtags (e.g. \"#bluesky launch\")."
    • addedInput schema / properties / since / description
      Added value: +"ISO 8601 datetime lower bound (inclusive) for post creation time (e.g. \"2024-01-01T00:00:00Z\"). Omit to search all time."
    • addedInput schema / properties / sort / description
      Added value: +"Sort order for results: \"latest\" returns newest posts first (default), \"top\" returns most-engaged posts first."
    • addedInput schema / properties / until / description
      Added value: +"ISO 8601 datetime upper bound (exclusive) for post creation time (e.g. \"2024-12-31T23:59:59Z\"). Omit for no upper bound."
    • addedInput schema / properties / url / description
      Added value: +"Filter to posts containing this exact URL (must be a fully-qualified URL, e.g. \"https://example.com/article\")."
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "properties": {
      +    "cursor": {
      +      "description": "Opaque pagination cursor to pass as cursor in the next call; absent when no further pages exist.",
      +      "type": "string"
      +    },
      +    "hasMore": {
      +      "description": "True when a subsequent page of results is available.",
      +      "type": "boolean"
      +    },
      +    "posts": {
      +      "description": "Array of posts matching the search query.",
      +      "items": {
      +        "properties": {
      +          "author": {
      +            "description": "Profile of the post author.",
      +            "properties": {
      +              "avatar": {
      +                "description": "URL of the author avatar image.",
      +                "type": "string"
      +              },
      +              "did": {
      +                "description": "Decentralized identifier of the author.",
      +                "type": "string"
      +              },
      +              "displayName": {
      +                "description": "Display name of the author.",
      +                "type": "string"
      +              },
      +              "handle": {
      +                "description": "Handle of the author (e.g. alice.bsky.social).",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "did",
      +              "handle"
      +            ],
      +            "type": "object"
      +          },
      +          "cid": {
      +            "description": "Content identifier (CID) of the post.",
      +            "type": "string"
      +          },
      +          "indexedAt": {
      +            "description": "ISO 8601 timestamp when the post was indexed.",
      +            "type": "string"
      +          },
      +          "likeCount": {
      +            "description": "Number of likes.",
      +            "type": "number"
      +          },
      +          "record": {
      +            "description": "The raw post record.",
      +            "properties": {
      +              "createdAt": {
      +                "description": "ISO 8601 creation timestamp.",
      +                "type": "string"
      +              },
      +              "langs": {
      +                "description": "BCP-47 language tags declared by the author.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "tags": {
      +                "description": "Hashtags attached to the post.",
      +                "items": {
      +                  "type": "string"
      +                },
      +                "type": "array"
      +              },
      +              "text": {
      +                "description": "Plain text content of the post.",
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "text",
      +              "createdAt"
      +            ],
      +            "type": "object"
      +          },
      +          "replyCount": {
      +            "description": "Number of replies to the post.",
      +            "type": "number"
      +          },
      +          "repostCount": {
      +            "description": "Number of reposts.",
      +            "type": "number"
      +          },
      +          "uri": {
      +            "description": "AT-URI of the post (at://did/.../rkey).",
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "uri",
      +          "cid",
      +          "author",
      +          "record",
      +          "indexedAt"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "searchQuery": {
      +      "description": "The search query string that was executed.",
      +      "type": "string"
      +    },
      +    "success": {
      +      "description": "Whether the search request completed successfully.",
      +      "type": "boolean"
      +    },
      +    "totalResults": {
      +      "description": "Approximate total number of matching posts reported by the API, if available.",
      +      "type": "number"
      +    }
      +  },
      +  "required": [
      +    "success",
      +    "posts",
      +    "hasMore",
      +    "searchQuery"
      +  ],
      +  "type": "object"
      +}
  3. Changed4 schema fields changedv0.3.0
    • removedInput schema / $schema
      Removed value: -"http://json-schema.org/draft-07/schema#"
    • removedInput schema / properties / lang / maxLength
      Removed value: -2
    • removedInput schema / properties / lang / minLength
      Removed value: -2
    • addedInput schema / properties / lang / pattern
      Added value: +"^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8})*$"
  4. First observedv0.2.1

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true and openWorldHint=true. The description adds further behavioral context: authentication requirement, per-tool rate limiting, and paginated results sorted by recency or engagement. No contradictions.

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?

Two sentences efficiently convey the core action, filters, pagination, authentication, sibling tool, and rate limiting. No redundant information; every sentence 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 presence of an output schema (not shown but indicated), the description adequately covers the tool's purpose, filter capabilities, pagination, authentication, and rate limits. It is complete for a search tool of this complexity.

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 baseline is 3. The description adds value by summarizing the types of filters (author, language, date range, mentions, domain, URL) and mentioning pagination (cursor), going beyond what the schema provides individually.

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 clearly states it searches for posts on Bluesky using full-text queries with optional filters. It distinguishes from sibling tools like search_actors by specifying the tool's scope (posts vs. users).

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?

The description provides explicit guidance: requires authentication (app password), subject to per-tool rate limiting, and suggests using search_actors to find users instead of posts. This helps the agent choose the right tool.

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