Skip to content

Add AT Protocol (lexicon/XRPC) support and one-command install#8

Merged
gabrielbauman merged 1 commit into
mainfrom
gbauman/atproto-support
Jun 6, 2026
Merged

Add AT Protocol (lexicon/XRPC) support and one-command install#8
gabrielbauman merged 1 commit into
mainfrom
gbauman/atproto-support

Conversation

@gabrielbauman

Copy link
Copy Markdown
Owner

Summary

Adds an atproto adapter kind (AT Protocol / lexicon / XRPC — e.g. Bluesky) and streamlines install so one command sets everything up.

atproto kind

  • New kind: "atproto": search/execute against any AT Protocol service via a thin, typed XRPC client (client.query(nsid, params) / client.procedure(nsid, input)).
  • Reuses official types, generates none of its own. The harness does a type-only import * as Lex from "npm:@atproto/api@…", so nothing from the SDK runs in the sandbox. writeTypes emits only an XrpcMethods map (NSID → {type, params, input, output}) pointing at the per-method namespaces, so calls infer params + result from the NSID string literal.
  • The operation index is built from the package's runtime schemas; NSID → namespace names come from its ids export (never derived), so a Lex.* reference can't drift and break the whole-program type-check execute runs. OutputSchema is referenced only when the lexicon declares one (else unknown).

Auth (parent-side, like OAuth)

  • App-password sessions: com.atproto.server.createSession/refreshSession run in the parent; only the short-lived access JWT reaches the sandbox (never the app password or refresh JWT). Self-heals from the stored app password — no browser.
  • identifier is the intent signal: none → anonymous (public reads, no token — replaces pointing an OpenAPI entry at the public AppView); set → authenticated, minting/refreshing a session and guiding to anyapi-mcp login when needed.
  • App passwords are CLI-only (anyapi-mcp login, or add --app-password); no MCP tool accepts secrets. New Auth variant atproto; keystore accounts …:apppass / …:session.
  • Deferred: atproto OAuth (DPoP-bound tokens can't be replayed as a bearer through the sandbox).

Install

  • install.sh now runs anyapi-mcp install after building (best-effort under set -e; opt out with ANYAPI_MCP_NO_INSTALL).
  • anyapi-mcp install adds OpenCode alongside Claude Code/Desktop, by merging an mcp entry into ~/.config/opencode/opencode.json (its opencode mcp add is an interactive wizard with no flags). Same safe read-modify-write as the Claude Desktop path: preserves other servers/keys, refuses to clobber an unparseable .jsonc.

Docs & site

  • README and CLAUDE.md updated; landing page reworked to emphasize one server / many APIs / ask-your-model.

Testing

  • deno task check / lint / fmt clean; deno test 16 passing (incl. new src/atproto_test.ts covering index/map generation).
  • Verified live: the generated 306-method map type-checks against the real @atproto/api types; an anonymous public read (app.bsky.actor.getProfile via public.api.bsky.app) runs through the sandbox.
  • OpenCode install paths (fresh / merge / jsonc-refusal / not-installed / dry-run) verified against throwaway config dirs.

Copilot AI review requested due to automatic review settings June 6, 2026 20:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new atproto protocol adapter (AT Protocol / lexicon / XRPC) so search/execute can interact with AT Protocol services (e.g. Bluesky) via a typed XRPC client, and streamlines setup by expanding anyapi-mcp install plus making the website/installer emphasize “one-command” onboarding.

Changes:

  • Introduces kind: "atproto": builds an operation index and a typed NSID→types map from @atproto/api lexicons; adds parent-side session mint/refresh via app passwords.
  • Extends CLI/MCP server flows (add, add_api, list, login, logout, serve) to support atproto registration, status reporting, and session handling.
  • Expands installation automation to also register with OpenCode; updates docs/site messaging accordingly.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/registry.ts Adds AtprotoAuth and extends ApiKind/Auth unions to include atproto.
src/register.ts Adds atproto registration logic, keystore key management, and unregister secret cleanup.
src/commands/serve.ts Extends MCP server tool descriptions, add_api schema/flow, execute auth handling, and list_apis auth status for atproto.
src/commands/logout.ts Adds atproto session/app-password logout behavior (reusing --forget-client).
src/commands/login.ts Adds atproto app-password login path alongside existing OAuth browser login.
src/commands/list.ts Reports atproto auth status in CLI list.
src/commands/install.ts Adds OpenCode config merge/install support; expands --client options.
src/commands/add.ts Adds atproto flags (--identifier, --app-password) and validation; passes through new register options.
src/atproto.ts New atproto adapter: builds ops index + generates NSID→official type map; provides XRPC execute harness.
src/atproto-auth.ts New parent-side atproto auth module: app-password storage + session mint/refresh/self-heal.
src/atproto_test.ts New tests covering lexicon indexing and method-map generation behavior.
src/adapters.ts Registers the new atprotoAdapter.
site/install.sh Installer now runs anyapi-mcp install by default (best-effort) with opt-out env var.
site/index.html Landing page copy updated to emphasize multi-API support and one-server messaging (incl. atproto).
README.md Documents atproto adapter usage and updated install flow including OpenCode registration.
deno.lock Adds pinned npm:@atproto/api@0.20.9 and transitive dependencies.
CLAUDE.md Updates repo architecture/docs to include atproto adapter/auth and OpenCode install behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/register.ts
Comment on lines +246 to +255
if (kind === "atproto") {
const passwordKey = `anyapi-mcp:${id}:apppass`;
const sessionKey = `anyapi-mcp:${id}:session`;
if (opts.appPassword) await setSecret(passwordKey, opts.appPassword);
auth = {
kind: "atproto",
identifier: opts.identifier ?? "",
passwordKey,
sessionKey,
};
Comment thread src/commands/login.ts Outdated
} from "../oauth.ts";
import { loginWithAppPassword } from "../atproto-auth.ts";

const HELP = `anyapi-mcp login - authenticate an OAuth 2.0 API in the browser
Comment thread site/install.sh
Comment on lines +9 to 12
# ANYAPI_MCP_REF git ref (branch or tag) to install (default: main)
# ANYAPI_MCP_BIN_DIR directory to install the binary into (default: ~/.local/bin)
# ANYAPI_MCP_NO_INSTALL set to any value to skip registering with Claude clients
set -eu
Comment thread src/atproto.ts
Comment on lines +295 to +301
const headers: Record<string, string> = {};
if (token) headers["authorization"] = \`Bearer \${token}\`;
let body: string | undefined;
if (method === "POST" && input !== undefined) {
headers["content-type"] = "application/json";
body = JSON.stringify(input);
}
Add an `atproto` adapter kind: search/execute against any AT Protocol service
(e.g. Bluesky) via a thin, typed XRPC client. Types are reused from @atproto/api
with a type-only import, so none of the SDK runs in the execute sandbox;
writeTypes emits only an NSID -> {params,input,output} map, letting
client.query/procedure infer from the NSID string literal. The operation index
is built from the package's runtime `schemas`, and NSID -> namespace names come
from its `ids` export (never derived) so a type reference can't drift and break
the whole-program check.

Auth runs in the parent like OAuth: app-password sessions
(createSession/refreshSession), injecting only a short-lived access JWT into the
sandbox. Registering without an identifier is anonymous (public reads, no
token); with one, the parent mints/refreshes a session and guides to `login`
when needed.

install.sh now runs `anyapi-mcp install` after building (best-effort; opt out
with ANYAPI_MCP_NO_INSTALL), and `install` also registers with OpenCode by
merging an `mcp` entry into its config (its `mcp add` is interactive-only).
Docs and the landing page updated throughout.
@gabrielbauman gabrielbauman force-pushed the gbauman/atproto-support branch from a4f2abd to 2f3de1a Compare June 6, 2026 20:52
@gabrielbauman gabrielbauman merged commit 88a8075 into main Jun 6, 2026
4 checks passed
@gabrielbauman gabrielbauman deleted the gbauman/atproto-support branch June 6, 2026 20:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants