mcpField
B
bluesky-mcp-server

bluesky-mcp-server

远程服务
github.com/cyanheads社交媒体26 天前更新
代码仓库

关于 bluesky-mcp-server

bluesky-mcp-server 让 MCP 客户端读取 Bluesky 的公开个人资料、帖子、信息流、讨论串和趋势,并可选启用需身份验证的全文帖子搜索。它支持 stdio 和 Streamable HTTP,也提供公开托管端点。

主要功能

  1. 01搜索帖子和账号
  2. 02读取个人资料及作者信息流
  3. 03获取讨论串和引用帖
  4. 04浏览信息流与热门趋势
  5. 05访问公开个人资料资源

适用场景

  1. 01按作者、主题或日期研究帖子
  2. 02查看讨论及其引用帖
  3. 03探索热门趋势及相关信息流
  4. 04为 Agent 获取个人资料上下文

MCP 相关

该服务提供 10 个用于搜索和读取 Bluesky 数据的工具,以及可按账号标识访问的个人资料资源。它支持 stdio 和 Streamable HTTP;只有配置应用密码凭据后,才提供全文帖子搜索。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://bluesky.caseyjhand.com/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npm@cyanheads/bluesky-mcp-server0.6.0

工具

8
参数类型必填说明
actorstring是要查询的用户句柄(例如 "bsky.app"、"alice.bsky.social")或 DID(例如 "did:plc:z72i7hdynmk6r22z27h6tvur")。接受前导 "@"("@bsky.app")和账号的 bsky.app 页面("https://bsky.app/profile/bsky.app"),并将其解析为其中包含的句柄或 DID。不带点号的裸名称不是句柄——请使用 bsky_search_actors 进行解析。

详细介绍

@cyanheads/bluesky-mcp-server

搜索 Bluesky 帖子和信息流;读取个人资料、讨论串和趋势。支持 STDIO 或 Streamable HTTP。

10 个工具 • 1 个资源

版本 许可证 Docker MCP SDK npm TypeScript Bun

安装到 Claude Desktop 安装到 Cursor 安装到 VS Code

框架

公开托管服务: https://bluesky.caseyjhand.com/mcp


概述

无需账号即可浏览 Bluesky:查看个人资料、搜索信息流目录、了解热门话题及相关信息流,以及浏览自定义信息流、作者信息流、讨论串和引用帖子。在需要输入链接或账号的地方,均可粘贴 bsky.app 链接或 @handle;添加可选的应用密码即可解锁全文帖子搜索。

工具
工具描述
bsky_search_posts在 Bluesky 公开帖子中进行全文搜索,并支持按作者、提及、语言、标签、域名、URL、日期和排序方式筛选 — 仅在配置了应用密码时提供
bsky_get_profile按句柄或 DID 获取 Bluesky 用户的公开个人资料 — 用于解析句柄↔DID
bsky_get_feed读取 feed 生成器的帖子 — 趋势 feed、Discover 或任何自定义 feed — 可通过 AT-URI 或 bsky.app URL 获取
bsky_get_author_feed获取用户近期帖子,按最新优先排序,并可按帖子类型筛选
bsky_get_post_thread通过 AT-URI 或 bsky.app URL 获取帖子的对话 — 向上追溯父级链,向下展开回复树,并显示 Bluesky 计数但未返回的内容
bsky_get_post_quotes读取某帖子的 quoteCount 对应的引用帖子,按最新优先或按点赞数排序 — 帖子的许多反响都在其中
bsky_search_actors按名称或句柄片段查找 Bluesky 账号
bsky_search_feeds搜索公开 feed 目录中的名称和描述,然后使用 bsky_get_feed 读取返回的 feedUri
bsky_get_follows分页读取社交关系边 — 某用户关注了谁,或谁关注了该用户
bsky_get_trending获取 Bluesky 上的实时热门话题,包括故事摘要、帖子数、类别、状态、推动各话题的账号,以及汇集相关帖子的 feed
资源
资源描述
bsky://profile/{actor}Bluesky 用户的公开个人资料,可通过句柄或 DID 访问

所有资源数据也可通过工具获取。程序化访问请使用 bsky_get_profile,或使用 bsky://profile/{actor} 直接注入个人资料上下文。

能力参考

bsky_search_posts 工具
  • Bluesky 拒绝在未登录账号的情况下搜索帖子,因此只有设置了 BLUESKY_IDENTIFIER 和 BLUESKY_APP_PASSWORD 时才会注册此工具;否则它不会出现在 tools/list 中(参见帖子搜索)
  • 搜索会通过该账号的 PDS 执行;首次搜索时会登录,之后会重用并刷新会话,登录遭拒后不会重试。失败会显示为 search_auth_failed(登录或会话续期遭拒)、search_login_limited(账号的每日登录次数已用尽——错误信息会说明何时可以恢复搜索),或 search_refused(Bluesky 拒绝了搜索)
  • 筛选条件:作者和被提及的账号(handle 或 DID,也可使用 @handle 或 bsky.app 个人资料 URL——mentions 仅匹配富文本提及)、两字母语言代码、话题标签(带或不带 #)、链接中的 domain(不带协议的主机名,会移除开头的 www.)或精确 url(文本链接或链接卡片中的 URL)、since/until,以及 top/latest 排序;每次调用最多返回 100 条结果,可通过不透明游标分页
  • since/until 按每条帖子的排序时间进行比较,即 createdAt 和 indexedAt 中较早的时间,精确到秒且包含边界;单独的日期按 UTC 00:00:00 处理,因此 until: "2026-01-01" 会涵盖整个 2025-12-31
  • 标识符、语言、域名、URL 和日期输入会在调用上游之前进行模式验证。三字母语言代码("fil"、"eng")会被拒绝,因为 Bluesky 搜索会忽略它们并返回未筛选的结果;发送的代码会转换为小写,后续子标签虽可接受,但会被上游忽略(en-US 会按 en 筛选)
  • 当 Bluesky 拒绝某个参数时,会通过 upstream_rejected_filter 错误原因显示其自身的说明,而不是只显示状态码;无法解码的游标会在一次请求后以 invalid_cursor 失败
  • hitsTotal 是 Bluesky 给出的估算值,绝非精确计数:低于 10,000 时,它是分页结果数量的上限(Bluesky 会先计数,再剔除不会返回的帖子);恰好为 10,000(上限)则表示“至少有这么多”;truncated/shown/cap 的值取决于返回的游标;如果没有更多匹配项,Bluesky 会省略该游标
  • 如果某一页在任一响应通道上会超出 48,000 字节的响应预算,则会按能够容纳的 limit 重新搜索并完整返回该页——budgetCapped: true,且 hitsTotal 和游标取自该次响应
  • 嵌入内容会规范化为由 type 区分的联合类型(images、external、record、video、unknown);引用帖子会保留其自身的附件,最多嵌套 3 层;omittedEmbeds 用于统计更深层级中省略的内容,recordKind 用于说明引用的帖子已删除、被屏蔽、已分离或并非帖子
  • 审核标签会原样显示,不做筛选

帖子工具会将可选的富文本 facets 与原始文本分开保留:UTF-8 字节范围(包含 byteStart,不包含 byteEnd),以及完整的链接 URI、提及的 DID 和标签。无法识别的特征变体和上游的其他字段会作为字面元数据在两个响应通道上保留。引用帖子会在现有嵌入深度限制内保留其自身的 facets。两个响应通道都会将此元数据计入响应预算;bsky_get_post_quotes 会省略所查询目标帖子的 facets,以及重复呈现的文本。

bsky_get_feed 工具
  • 接受动态源生成器 AT-URI(at://<handle-or-did>/app.bsky.feed.generator/<rkey>)或其 bsky.app 页面(https://bsky.app/profile/<handle-or-did>/feed/<rkey>;任何末尾的 /、?… 或 #… 都会被忽略);趋势的 feedUri 可直接使用,Discover 为 at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot
  • 所有者为 handle 时会额外查询一次(resolveHandle),所有者为 DID 时则无需查询;其他任何 collection(例如帖子 AT-URI)都会在上游调用前被拒绝
  • 被动态源置顶的帖子带有 pinned: true;转帖带有 repostedBy/repostedAt
  • 每次调用最多返回 100 条帖子,通过游标分页;如果动态源返回的帖子少于 limit,但后面还有更多内容,游标会注明结果已截断
  • 如果某一页会超过 48,000 字节的响应预算,则会使用合适的 limit 重新请求并完整返回该页,并标记 budgetCapped: true;排名动态源会在每次请求时重新排名,因此帖子和游标仍来自同一响应
  • feed_not_found(动态源或 handle 不存在)、feed_unavailable(动态源生成器未响应——不会重试,因此不可用的动态源会快速失败)、feed_requires_login(个性化动态源)
  • 始终以未认证状态调用,即使已设置搜索凭据也是如此

bsky_get_profile 工具
  • 接受 handle 或 DID,也接受 @handle 或账号的 bsky.app 页面(https://bsky.app/profile/<handle-or-did>);返回 displayName、handle、DID、简介、代词、网站、关注者/关注/帖子数量、头像、审核标签和置顶帖 AT-URI
  • 如果账号未设置 website 和 pronouns,则不会返回这两个字段;可选的 links 会单独于 website 携带按顺序排列的个人资料按钮,每条记录包含 URI/CID、完整目标 URL、可选标题/图标和审核标签(val、src?、cts?)。未提供的数组保持省略,显式提供的空数组则保持为空;个人资料资源会返回相同字段
  • verification 携带 Bluesky 的完整验证状态——verifiedStatus 和 trustedVerifierStatus(valid、invalid 或 none,原样传递),以及受信任验证者签发的每项验证信息,包括签发者、有效性、日期和记录 AT-URI;如果 Bluesky 未发送验证信息,则省略此字段
  • 简介会在 content[] 中以 Markdown 引用块呈现,因为这是账号撰写的文本,可能包含自身的 Markdown 结构
  • 如果 handle 无法解析,则返回 actor_not_found——请先使用 bsky_search_actors 解析 handle
  • 用于 handle↔DID 转换的主要解析工具——已知 handle、但需要 DID 或 AT-URI 的其他工具调用前,请先使用此工具

bsky_get_author_feed 工具
  • 接受 handle 或 DID,也接受 @handle 或账号的 bsky.app 页面
  • filter:posts_with_replies、posts_no_replies(默认值,不包含回复)和 posts_and_author_threads 会包含转帖;posts_with_media(作者本人发布的带图片或视频的帖子,不含链接卡片)和 posts_with_video 不会返回任何内容
  • include_pins: true 会添加个人资料中的置顶帖,并标记为 pinned: true,在第一页置顶——不计入 limit,且无论是否符合 filter 都会添加
  • 转帖带有 repostedBy 和 repostedAt;author 始终指明实际撰写帖子的用户
  • 在包含转帖的筛选条件下,转帖也计入 limit,因此大量转帖账号返回的本人帖子可能远少于 limit 所示数量;只要存在转帖,originalPosts/reposts 就会报告实际数量拆分
  • 每次调用最多返回 100 条帖子,通过游标分页;如果某一页会超过 48,000 字节的响应预算,则会使用合适的 limit 重新请求(置顶帖不计入),并标记 budgetCapped: true,其游标会从第一条未返回的帖子继续
  • 如果 handle 或 DID 无法解析,则返回 actor_not_found;如果 Bluesky 无法解码传入的游标,则在请求一次后返回 invalid_cursor(Bluesky 会对此类游标返回 HTTP 500,而其他 HTTP 500 通常会重试)

bsky_get_post_thread 工具
  • 接受帖子的 AT-URI 或其 bsky.app 页面(https://bsky.app/profile/<handle-or-did>/post/<rkey>,末尾的 /、?… 或 #… 会被忽略)
  • 仅包含回复——引用帖位于 bsky_get_post_quotes
  • depth(回复层级,默认值为 6,最大值为 10——无论请求的深度是多少,这都是 Bluesky 自身的上限)和 parent_height(父级链高度,默认值为 80,最大值为 100)
  • 如果某个节点返回的回复数少于其自身的 replyCount,该节点会带有 truncated: true、unreturnedReplies(上限值,并非精确的缺失数量)和 truncationReason("depth"——获取该节点的 AT-URI 以继续,或 "unavailable"——无法通过请求补齐缺失内容)
  • 当父级链在距离会话根节点 parent_height 层处停止时,最顶层节点会带有 parentChainTruncated: true——可通过将该节点的 AT-URI 作为独立线程获取来补齐
  • 若线程响应超过 48,000 字节的预算,则保留目标帖子,然后按从近到远的顺序保留父级,再逐层保留回复,并在完整帖子之间截断:补充信息中包含 budgetCapped 和 budgetOmitted(省略的帖子数),目标帖子上包含 budgetOmittedReplyUris,保留的回复上包含 budgetOmittedReplies,保留的最顶层父级上包含 budgetOmittedParents——获取这些 AT-URI 即可读取所有省略内容
  • 如果设置了作者的回复权限限制,则显示该限制(谁可以回复)以及作者隐藏的任何回复的 AT-URI;已删除的帖子返回 notFound: true,被屏蔽的帖子返回 blocked: true
  • 回复深度显示在作者标题上(### ↳2 Name),而不是通过缩进表示,因此深层嵌套的回复不会进入 Markdown 代码块
  • AT-URI 无法解析时会返回 invalid_at_uri 和 post_not_found 错误;AT-URI 可从任何返回帖子的 uri 字段中获取
  • 在发出任何请求之前,都会拒绝信息流生成器 AT-URI(app.bsky.feed.generator),并返回 uri_is_feed,指向 bsky_get_feed

bsky_get_post_quotes 工具
  • 接受帖子的 AT-URI 或其 bsky.app 页面;其他任何集合都会在调用上游之前被拒绝
  • DID 权限的帖子需要一次请求;句柄需要额外进行一次查找(resolveHandle),因为 getQuotes 对句柄权限返回空列表
  • 每条结果都引用同一帖子,因此每条结果的嵌入内容仅保留该帖子的 AT-URI 和 CID、其不可读时的 recordKind,以及引用帖附带的任何媒体——不会在每个条目中重复查询帖子的文本和附件
  • 每次调用最多返回 100 条引用;sort: latest(默认值)按时间从新到旧排列,sort: top 则按 Bluesky 排序后的点赞数降序排列。两个接口都会返回实际应用的 sort;使用同一帖子和排序方式传回游标。截断情况会通过游标说明,因为即使后面还有内容,页面返回的条目数也经常少于 limit
  • 若页面响应超过 48,000 字节的预算,则会以适合的 limit 重新请求,并标记 budgetCapped: true;其游标会从第一条被省略的引用开始继续
  • quoteCount 是此处返回数量的上限——Bluesky 的计数器会保留已从索引中移除的引用
  • 如果帖子不存在或其句柄无法解析,则返回 post_not_found(会通过一次 getPosts 检查空的第一页);对于 Bluesky 无法解码的游标,会在发出一次请求后返回 invalid_cursor

bsky_search_actors 工具
  • 返回按排名排序的个人资料,包含 handle、DID、displayName、bio,以及已设置的代词;不包含关注者数、关注数或帖子数,也不包含 website,只有 bsky_get_profile 会返回该字段
  • 如果 Bluesky 提供了验证状态,每个账号都会包含两种状态(verification.verifiedStatus、verification.trustedVerifierStatus),可据此区分已验证账号与仿冒 handle;验证的颁发方见 bsky_get_profile
  • 简介会以 Markdown 引用块的形式显示在 content[] 中,因为这是账号作者撰写的文本
  • 每次调用最多返回 100 条结果,通过游标分页;每页通常少于 limit 条,但仍可继续翻页,最后一页不带游标
  • Bluesky 无法解码传入的游标时,会在一次请求后返回 invalid_cursor(此类请求会收到 HTTP 400)
  • 已知名称但尚未确认 handle 时,可先用此工具,再调用 bsky_get_profile 或 bsky_get_author_feed

bsky_search_feeds 工具
  • 搜索提供方公开的信息流目录元数据,而非帖子文本;按提供方的顺序返回 feedUri、displayName、可选的 description,以及创建者的 DID/handle 和可选的显示名称
  • 始终无需密钥,即使已配置帖子搜索凭据也是如此;将返回的 feedUri 直接传给 bsky_get_feed 即可读取其中的帖子
  • query 为必填项;limit 默认为 25,并根据统一的限制策略上限设为 100。使用相同的查询传入不透明的 cursor;只要存在游标就表示还有后续内容,即使当前页为空也是如此
  • 使用不稳定的 app.bsky.unspecced.getPopularFeedGenerators,该接口可能变更或消失;catalog_unavailable 时可通过 bsky_get_trending 恢复。这是用于发现内容的工具,并非完整枚举
  • 信息流名称、说明和创建者身份会作为带引文的第三方数据呈现;提供的空白值与省略的字段会保持区分

bsky_get_follows 工具
  • direction:followers(关注该账号的人)或 following(该账号关注的人)
  • sort:latest(Bluesky 的默认值,最近关注的账号排在前面)或 top(Bluesky 自行排列的知名账号,不按关注者数量排序);传回游标时须使用相同的 sort
  • 接受 handle 或 DID,也接受 @handle 或账号的 bsky.app 页面
  • 返回分页个人资料(handle、DID、displayName、bio、已设置的代词、验证状态),以及账号主体自己的个人资料摘要,其中也包含其验证状态
  • 此视图中的列表和账号主体均不包含关注者数、关注数、帖子数或 website;需要这些信息时,请使用 bsky_get_profile 查询
  • 每页最多 100 条,通过游标分页。如果剩余账号都无法解析,游标可能会指向空页;响应会将其报告为列表末尾
  • handle 或 DID 无法解析时返回 actor_not_found

bsky_get_trending 工具
  • 返回趋势话题,包含显示名称、Bluesky 的一句话故事摘要(description)、帖子数、类别、状态(例如 hot、cooling、stale)、开始时间,以及每个话题最多 5 个推动该趋势的代表性账号
  • 每个趋势都由一个信息流生成器提供支持:feedUri 是该信息流的 AT-URI,从趋势的 link 中解析得出;bsky_get_feed 可读取其中的帖子;topic 是信息流的记录键,而非搜索词
  • 无游标;返回当前快照,最多 limit 条(默认为 10,最大为 25,这是 Bluesky 自身的上限);truncated 表示趋势话题数量多于 limit,因此当 limit 为 25 时不会出现
  • 使用不稳定的 app.bsky.unspecced.getTrends 接口,Bluesky 可能会在不另行通知的情况下更改该接口

bsky://profile/{actor} 资源
  • 以可注入上下文的形式返回与 bsky_get_profile 相同的字段:displayName、handle、DID、bio、pronouns、website、关注者/关注人数/帖子数量、头像、审核标签、置顶帖子的 AT-URI、完整的验证状态
  • 可通过 {actor} 中的 handle 或 DID 寻址,支持带或不带前导 @(bsky://profile/@bsky.app)
  • 当 handle 无法解析时返回 actor_not_found

功能

基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none / jwt / oauth)、可切换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1),并提供结构化日志记录和可选的 OpenTelemetry 跟踪。

Bluesky 专属功能:

  • 十个工具中有九个无需凭据即可读取 api.bsky.app;bsky_search_posts 通过可选的应用密码会话运行,没有该会话时不提供此工具
  • 支持将分享链接作为输入:在需要账号的地方接受 @handle 和 bsky.app 个人资料 URL,在需要帖子或信息流的地方接受 bsky.app 帖子或信息流 URL;请求前会将链接重写为其指向的 handle、DID 或 AT-URI
  • 使用单一的 BlueskyService 封装 AT Protocol AppView;每个请求的超时时间为 15 秒;上游出现暂时性故障时会重试(最多 3 次,基础间隔为 500ms;登录请求或已映射为工具错误的故障不会重试);使用带版本号的 User-Agent
  • 所有错误中均不包含 HTML:Bluesky 边缘节点返回的拦截页面会从错误数据中移除,仅保留状态
  • Embed 规范化:将原始的嵌套 AT Protocol embed 对象展平为简洁的、由 type 区分的联合类型
  • 原样呈现审核标签,不作过滤
  • 在每个工具的描述中首次出现时,解释 AT Protocol 标识符类型(handle、DID、AT-URI)

便于 Agent 使用的输出:

  • 每篇帖子都带有 AT-URI,可直接串联 bsky_search_feeds 或 bsky_get_trending → bsky_get_feed → bsky_get_post_thread,无需额外步骤
  • 为 Agent 选择或引用的每个账号提供验证信息:所有五个帖子工具中的帖子作者、actor 搜索结果和关注关系图,都会在作者的 DID 行中包含 Bluesky 的 verifiedStatus / trustedVerifierStatus;bsky_get_profile 还会说明每项验证由谁签发
  • 由判别字段区分的 embed 联合类型:type: "images" | "external" | "record" | "video" | "unknown" 让调用方可以根据数据分支处理,而不必解析 $type 字符串;未映射的 lexicon 类型会以 unknown 形式返回,并附带其原始 $type,而不会消失
  • 将第三方文本渲染为 Markdown 引用块:帖子正文、个人简介、替代文本和链接卡片文本会在 content[] 中渲染为以 > 开头的引用块,因此帖子的标题或代码围栏不会与服务端结构合并;以行内形式渲染的值(显示名称、代词、主题名称)也会将换行符折叠为空格,原因相同。两种形式中的 Markdown 和 CommonMark 渲染器会处理的原始 HTML——包括强调、链接、图片、代码、列表、标题、标签和实体——都会转义,因此用户文本会按原样显示;URL 仍可复制,structuredContent 中的所有字符串均保持不变。每个引用块都会在服务端写入下一行内容前结束,因此渲染客户端不会将帖子的计数或标签合并到引用块中
  • 明确说明截断范围:线程和分页的缺失内容(truncated、unreturnedReplies、parentChainTruncated、达到 10,000 上限的 hitsTotal)会以范围而非测量值的形式报告
  • 每个返回帖子的工具在每种输出形式上都有 48,000 字节的响应预算,按渲染后的输出计算,且仅会在完整帖子之间截断;分页会以符合预算的 limit 重新请求,因此游标仍会从页面结束处继续;线程会通过 AT-URI 标记未返回的帖子;如果发生其中任一情况,budgetCapped 会说明原因;未超出预算的响应保持不变

开始使用

公共托管实例

直接连接,无需安装:

{
  "mcpServers": {
    "bluesky-mcp-server": {
      "type": "streamable-http",
      "url": "https://bluesky.caseyjhand.com/mcp"
    }
  }
}
自托管 / 本地

将以下内容添加到 MCP 客户端配置文件中。无需 API 密钥;要启用帖子搜索,请将 BLUESKY_IDENTIFIER 和 BLUESKY_APP_PASSWORD 添加到 env。

{
  "mcpServers": {
    "bluesky-mcp-server": {
      "type": "stdio",
      "command": "bunx",
      "args": ["@cyanheads/bluesky-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

也可以使用 npx(无需 Bun):

{
  "mcpServers": {
    "bluesky-mcp-server": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@cyanheads/bluesky-mcp-server@latest"],
      "env": {
        "MCP_TRANSPORT_TYPE": "stdio",
        "MCP_LOG_LEVEL": "info"
      }
    }
  }
}

也可以使用 Docker:

{
  "mcpServers": {
    "bluesky-mcp-server": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "MCP_TRANSPORT_TYPE=stdio",
        "ghcr.io/cyanheads/bluesky-mcp-server:latest"
      ]
    }
  }
}

对于 Streamable HTTP,请设置传输方式并启动服务:

MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
先决条件
  • Bun v1.4.0 或更高版本(或 Node.js v24+)。
  • 除帖子搜索外,其他功能均无需 API 密钥或账户。请参阅帖子搜索以启用此功能。
安装
  1. 克隆代码库:
git clone https://github.com/cyanheads/bluesky-mcp-server.git
  1. 进入目录:
cd bluesky-mcp-server
  1. 安装依赖项:
bun install
  1. 配置环境(可选):
cp .env.example .env
# edit .env to override any framework defaults

配置

此服务无需 API 密钥。以下配置均为可选项。

变量描述默认值
BLUESKY_IDENTIFIER执行帖子搜索的账户的 Handle、DID 或电子邮件。请与 BLUESKY_APP_PASSWORD 一起设置,或两者都不设置。—
BLUESKY_APP_PASSWORD该账户的应用密码。未同时设置这两个变量时,不会提供 bsky_search_posts。—
BLUESKY_CLAMP_READ_LIMITS读取限制策略:将超出限制的请求限制在现有上限内,并披露请求值和应用值;设为 false 可恢复为拒绝请求。true
MCP_TRANSPORT_TYPE传输方式:stdio 或 httpstdio
MCP_SESSION_MODEHTTP 会话模式:stateful、stateless 或 auto。未设置或为空时,服务会根据自身的 createApp({ sessionMode }) 声明解析为 stateless;显式设置的值仍会覆盖此默认值。stateless
MCP_HTTP_PORTHTTP 服务端口3010
MCP_AUTH_MODE身份验证模式:none、jwt 或 oauthnone
MCP_LOG_LEVEL日志级别(RFC 5424)info
LOGS_DIR日志文件目录(仅 Node.js)<project-root>/logs
STORAGE_PROVIDER_TYPE存储后端in-memory
OTEL_ENABLED启用 OpenTelemetry 插桩false

完整的可选覆盖项列表请参阅 .env.example。

帖子搜索

Bluesky 要求用户登录后才能调用 app.bsky.feed.searchPosts,因此只有同时设置 BLUESKY_IDENTIFIER 和 BLUESKY_APP_PASSWORD 时才会注册 bsky_search_posts。只设置其中一个变量会导致启动失败,并显示缺少的变量名称。

  • 使用专用账户和标准(非特权)应用密码——可在“设置”→“隐私与安全”→“应用密码”下创建。服务无需访问私信。
  • 所有调用者的搜索都会使用该账户执行。 AppView 会排除与该账户存在任一方向屏蔽关系的账户所发布的帖子;但不会应用静音设置。在共享实例上,任何人都可以屏蔽该账户,从而使自己的帖子不出现在搜索结果中。
  • 登录次数有限。 Bluesky 将每个账户的 createSession 次数限制在每天约 10 次,因此服务会在首次搜索时登录——启动时不会登录——并复用会话;访问令牌过期时会刷新,仅在刷新遭拒时重新登录。登录遭拒后,服务不会重试,直到进程重启。如果 Bluesky 在登录或刷新时返回 429,所有搜索都会失败并返回 search_login_limited,在其指定的 ratelimit-reset 时间之前不会发送请求(如果未指定,则等待 15 分钟),之后再重新登录。
  • 凭据和令牌仅保留在内存中;它们不会出现在日志、错误信息或工具输出中,其他工具也不会发送它们。

运行服务

本地开发
  • 构建并运行:

    # One-time build
    bun run rebuild
    
    # Run the built server
    bun run start:stdio
    # or
    bun run start:http
    
  • 运行检查和测试:

    bun run devcheck   # Lint, format, typecheck, security
    bun run test       # Vitest test suite
    bun run lint:mcp   # Validate MCP definitions against spec
    
Docker
docker build -t bluesky-mcp-server .
docker run --rm -p 3010:3010 bluesky-mcp-server

Dockerfile 默认使用 HTTP 传输、无状态会话模式,并将日志写入 /var/log/bluesky-mcp-server。默认会安装 OpenTelemetry 对等依赖项;构建时使用 --build-arg OTEL_ENABLED=false 可将其省略。

项目结构

目录用途
src/index.tscreateApp() 入口——读取配置、注册工具和资源,并初始化服务。
src/config读取限制策略,以及用于启用帖子搜索的可选应用密码对。
src/services/blueskyAT Protocol HTTP 客户端——公开 AppView 读取、应用密码搜索会话、重试、超时和 User-Agent。
src/mcp-server/tools工具定义(*.tool.ts)——十个只读 Bluesky 工具。
src/mcp-server/resources资源定义(*.resource.ts)——bsky://profile/{actor}。
tests/与 src/ 结构对应的单元测试和集成测试。

开发指南

开发指南和架构规则请参阅 CLAUDE.md。简要说明:

  • 处理程序抛出异常,框架负责捕获——工具逻辑中不要使用 try/catch
  • 使用 ctx.log 进行请求范围的日志记录,使用 ctx.state 进行租户范围的存储
  • 在 src/mcp-server/server-surface.ts 中注册工具,在 src/index.ts 中注册资源
  • 封装外部 API 调用:校验原始数据 → 规范化为领域类型 → 返回输出架构;绝不编造缺失字段

贡献

欢迎提交问题。提交前请运行检查和测试:

bun run devcheck
bun run test

许可证

Apache-2.0——详情请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。