# ActivityPub MCP Server - Complete Documentation

> A comprehensive Model Context Protocol (MCP) server that enables LLMs like Claude to explore and interact with the existing Fediverse through standardized MCP tools, resources, and prompts. Built with TypeScript and designed specifically for LLM integration patterns.

## Table of Contents

1. [Overview](#overview)
2. [Quick Start](#quick-start)
3. [Installation](#installation)
4. [Configuration](#configuration)
5. [API Reference](#api-reference)
6. [Usage Guide](#usage-guide)
7. [Examples](#examples)
8. [Development](#development)
9. [Specifications](#specifications)
10. [Troubleshooting](#troubleshooting)

---

## Overview

The ActivityPub MCP Server is a Fediverse client that allows AI assistants to discover actors, fetch timelines, explore instances, and search content across the decentralized social web. It implements the complete MCP specification with resources for data access, tools for interaction, and prompts for guided exploration.

### Key Features

- **Read-only by default**: discovery and timeline tools need no credentials; every write/mutation tool is opt-in behind `ACTIVITYPUB_ENABLE_WRITES` and is not even registered unless that flag is set
- **Fediverse Integration**: Mastodon, Pleroma, Misskey, Foundkey, and compatible servers; Misskey-family reads are routed per instance by NodeInfo software detection and normalized into the same Mastodon-shaped results
- **WebFinger Discovery**: Find and resolve actors across the network (same-origin self link enforced)
- **37 MCP Tools**: 9 read-only discovery/timeline + 28 authenticated (post, follow, boost, polls, media, schedule)
- **10 MCP Resources, 5 MCP Prompts**: `server-info` dynamic from live capability registry
- **Multi-Account Support**: `activitypub-mcp login` (Mastodon OAuth2 / Misskey MiAuth) or pipe-delimited `ACTIVITYPUB_ACCOUNTS`; per-call account selection
- **Dual Transport**: stdio (default, for Claude Desktop / Cursor) and HTTP (Bearer-authenticated `/mcp`)
- **TypeScript Implementation**: Modern, strict TypeScript with ESM, topic-organized source tree
- **Cross-Platform Support**: Works on Windows, macOS, and Linux (Node 20+ required)
- **Security-Hardened**: SSRF guard on every outbound call (full IPv4 + IPv6 private-range blocking), streaming response-size caps (default 10MB), HTTPS-only outbound, credential stripping on cross-origin redirects, instance blocklist, thread cross-origin gating, `upload-media` content-type validation, audit logging on every write tool
- **Testing**: 830+ unit tests plus a daily integration workflow against the live Fediverse

### Architecture

The server acts as a bridge between LLMs and the Fediverse:
- **MCP Server**: Implements the Model Context Protocol specification
- **ActivityPub Client**: Connects to existing Fediverse instances
- **WebFinger Resolver**: Discovers actors across federated servers
- **Resource Manager**: Provides read-only access to remote data
- **Tool System**: Interactive operations for discovery and exploration
- **Prompt Templates**: Guided workflows for common tasks

---

## Quick Start

### Prerequisites

- Node.js 20.0.0 or higher (Node 18 reached EOL on April 30, 2025)
- npm or yarn package manager
- Internet connectivity for federation

### Installation

```bash
# Install via npm
npm install -g activitypub-mcp

# Or install locally
npm install activitypub-mcp

# Verify installation
activitypub-mcp --version
```

### Basic Usage

```bash
# Start the MCP server
npx activitypub-mcp

# Or if installed globally
activitypub-mcp
```

### Claude Desktop Integration

Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "activitypub": {
      "command": "npx",
      "args": ["-y", "activitypub-mcp"]
    }
  }
}
```

---

## Installation

### Platform-Specific Installation

#### macOS / Linux

```bash
# Using npm
npm install -g activitypub-mcp

# Using the installation script
curl -fsSL https://raw.githubusercontent.com/cameronrye/activitypub-mcp/main/scripts/install.sh | bash

# Or clone and build from source
git clone https://github.com/cameronrye/activitypub-mcp.git
cd activitypub-mcp
npm install
npm run build
```

#### Windows

```powershell
# Using npm
npm install -g activitypub-mcp

# Using the installation script
iwr -useb https://raw.githubusercontent.com/cameronrye/activitypub-mcp/main/scripts/install.ps1 | iex

# Or clone and build from source
git clone https://github.com/cameronrye/activitypub-mcp.git
cd activitypub-mcp
npm install
npm run build
```

### Development Installation

```bash
# Clone the repository
git clone https://github.com/cameronrye/activitypub-mcp.git
cd activitypub-mcp

# Install dependencies
npm install

# Run setup script
npm run setup

# Build the project
npm run build

# Run tests
npm run test:all
```

---

## Configuration

### Environment Variables

Create a `.env` file in your project root or set these environment variables. Authoritative reference: `.env.example` and `.env.production.example` in the repo.

```bash
# ---- Core ----
LOG_LEVEL=info                                  # debug | info | warning | error | fatal
REQUEST_TIMEOUT=15000                           # production default: 10000
CACHE_TTL=300                                   # seconds
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MAX=100
RATE_LIMIT_WINDOW=900000

# ---- Writes (off by default) ----
ACTIVITYPUB_ENABLE_WRITES=false                 # master switch. While false, NO mutation tool
                                                # (post/follow/boost/media/...) is registered, so
                                                # prompt-injected content cannot name a tool that
                                                # does not exist. Set true to opt in.

# ---- HTTP transport (only when MCP_TRANSPORT_MODE=http) ----
MCP_TRANSPORT_MODE=stdio                        # stdio | http
MCP_HTTP_PORT=3000
MCP_HTTP_HOST=127.0.0.1
MCP_HTTP_SECRET=                                # REQUIRED for http. 32+ random chars.
                                                # All /mcp requests must include
                                                # `Authorization: Bearer <secret>`. /health stays open.
MCP_HTTP_CORS_ORIGINS=                          # default empty (no origins).
MCP_HTTP_ALLOWED_HOSTS=                         # DNS-rebinding allowlist; required for non-localhost binds.

# ---- Authenticated write tools ----
# Preferred: `activitypub-mcp login` (Mastodon OAuth2 / Misskey MiAuth), which stores
# credentials under ~/.config/activitypub-mcp/accounts.json. Or supply them inline:
# PIPE (|) delimiter; legacy colon format is rejected at startup.
ACTIVITYPUB_ACCOUNTS=id|instance|token|user|label,id2|instance|token|user|label

# ---- Thread traversal caps ----
MCP_THREAD_MAX_DEPTH=5
MCP_THREAD_MAX_REPLIES=50
MCP_THREAD_CROSS_ORIGIN_FETCH=false             # set true to fetch cross-origin replies
```

### Configuration Files

The server uses the following configuration files:

- `.env` - Environment variables
- `package.json` - Project metadata and dependencies
- `tsconfig.json` - TypeScript compiler options
- `biome.json` - Code formatting and linting rules

### MCP Server Configuration

When integrating with MCP clients like Claude Desktop, configure the server in the client's configuration file:

**Claude Desktop (macOS):**
`~/Library/Application Support/Claude/claude_desktop_config.json`

**Claude Desktop (Windows):**
`%APPDATA%\Claude\claude_desktop_config.json`

**Configuration Example:**
```json
{
  "mcpServers": {
    "activitypub": {
      "command": "npx",
      "args": ["-y", "activitypub-mcp"],
      "env": {
        "LOG_LEVEL": "info",
        "CACHE_TTL": "3600"
      }
    }
  }
}
```

---

## API Reference

### MCP Resources (10 total)

Resources provide read-only access to remote ActivityPub data via `activitypub://` URIs. The full reference is at <https://cameronrye.github.io/activitypub-mcp/docs/api/resources/>.

| URI template | Purpose |
|---|---|
| `activitypub://server-info` | Dynamic server capabilities (tools/resources/prompts/feature flags, live from registry) |
| `activitypub://remote-actor/{identifier}` | ActivityPub Actor object |
| `activitypub://remote-timeline/{identifier}` | Actor outbox / public timeline |
| `activitypub://remote-followers/{identifier}` | Followers collection |
| `activitypub://remote-following/{identifier}` | Following collection |
| `activitypub://instance-info/{domain}` | Instance metadata and stats |
| `activitypub://trending/{domain}` | Trending hashtags and posts |
| `activitypub://local-timeline/{domain}` | Local public timeline |
| `activitypub://federated-timeline/{domain}` | Federated public timeline |
| `activitypub://post-thread/{domain}/{statusId}` | Post with ancestors and replies (Mastodon URL form, v2). Legacy `activitypub://post-thread/{postUrl}` form still accepted with a deprecation warning; removed in 2.1.0. |

**Identifier formats**: `@user@domain.com`, `user@domain.com`, or a full Actor URL.

**Example:**
```
activitypub://remote-actor/@gargron@mastodon.social
```

### MCP Tools (37 total)

Tools fall into two groups. Full schemas and examples at <https://cameronrye.github.io/activitypub-mcp/docs/api/tools/>.

**Read-only (9):** `discover-actor`, `discover-instances`, `get-instance-info`, `fetch-timeline`, `get-post-thread`, `get-public-timeline`, `get-trending-hashtags`, `get-trending-posts`, `search`.

**Authenticated write (28):** `list-accounts`, `switch-account`, `verify-account`, `post-status`, `reply-to-post`, `delete-post`, `boost-post`, `unboost-post`, `favourite-post`, `unfavourite-post`, `bookmark-post`, `unbookmark-post`, `follow-account`, `unfollow-account`, `mute-account`, `unmute-account`, `block-account`, `unblock-account`, `get-relationship`, `get-home-timeline`, `get-notifications`, `get-bookmarks`, `get-favourites`, `vote-on-poll`, `upload-media`, `get-scheduled-posts`, `update-scheduled-post`, `cancel-scheduled-post`.

**Behavior notes:**
- `post-status` accepts `mediaIds` and `scheduledAt` for media attachments and scheduled posts.
- `cancel-scheduled-post` / `update-scheduled-post` use `scheduledPostId` (not v1's `scheduledId`).
- `get-relationship` takes `acct: string` (not v1's `accountIds: string[]`).
- `get-post-thread` caps at depth 5 / 50 replies; cross-origin replies are stubbed unless `MCP_THREAD_CROSS_ORIGIN_FETCH=true`.

**Example tool call:**
```json
{
  "name": "discover-actor",
  "arguments": { "identifier": "@gargron@mastodon.social" }
}
```

### MCP Prompts (5 total)

Guided workflows. Full reference at <https://cameronrye.github.io/activitypub-mcp/docs/api/prompts/>.

| Prompt | Purpose |
|---|---|
| `explore-fediverse` | Open-ended fediverse exploration |
| `compare-accounts` | Compare two fediverse accounts |
| `analyze-user-activity` | Detailed activity analysis |
| `find-experts` | Discover experts on a topic |
| `summarize-trending` | Summarize trending posts and hashtags |

---

## Usage Guide

### Basic Operations

#### Discovering Actors

Use the `discover-actor` tool to find actors across the Fediverse:

```typescript
// Using MCP client
const result = await client.callTool("discover-actor", {
  identifier: "@username@instance.com"
});
```

#### Fetching Timelines

Retrieve an actor's public posts:

```typescript
const timeline = await client.callTool("fetch-timeline", {
  identifier: "@username@instance.com",
  limit: 20
});
```

#### Searching Content

Search for posts, accounts, or hashtags:

```typescript
const results = await client.callTool("search", {
  query: "activitypub",
  type: "posts",
  limit: 10
});
```

### Advanced Usage

#### Error Handling

All MCP operations return structured error responses:

```typescript
try {
  const result = await client.callTool("discover-actor", {
    identifier: "@invalid@nonexistent.com"
  });
} catch (error) {
  if (error.code === "InvalidParams") {
    console.error("Invalid parameters:", error.message);
  } else if (error.code === "InternalError") {
    console.error("Server error:", error.message);
  }
}
```

**Common Error Codes:**
- `InvalidParams` - Invalid input parameters
- `InternalError` - Server-side errors (rate limits, network issues)
- `NotFound` - Resource not found
- `Timeout` - Request timeout

#### Caching

The server implements intelligent caching to reduce network requests:

- Actor profiles: 1 hour TTL
- Timelines: 5 minutes TTL
- Instance info: 24 hours TTL
- WebFinger results: 1 hour TTL

Configure cache behavior via environment variables:

```bash
CACHE_TTL=3600          # Default TTL in seconds
CACHE_MAX_SIZE=100      # Maximum cache entries
```

#### Rate Limiting

The server respects instance rate limits and implements exponential backoff:

- Initial retry delay: 1 second
- Maximum retry delay: 30 seconds
- Maximum retries: 3 attempts

---

## Examples

### Example 1: Discover and Analyze an Actor

```typescript
// Step 1: Discover the actor
const discovery = await client.callTool("discover-actor", {
  identifier: "@gargron@mastodon.social"
});

// Step 2: Fetch actor profile
const actor = await client.readResource(
  "activitypub://remote-actor/@gargron@mastodon.social"
);

// Step 3: Fetch recent posts
const timeline = await client.callTool("fetch-timeline", {
  identifier: "@gargron@mastodon.social",
  limit: 10
});

console.log(`Actor: ${actor.name}`);
console.log(`Posts: ${timeline.orderedItems.length}`);
```

### Example 2: Search for Content

```typescript
// Search for posts about a topic
const posts = await client.callTool("search", {
  query: "activitypub protocol",
  type: "posts",
  limit: 20
});

// Search for accounts
const accounts = await client.callTool("search", {
  query: "developer",
  type: "accounts",
  limit: 10
});

// Search for hashtags
const hashtags = await client.callTool("search", {
  query: "opensource",
  type: "hashtags",
  limit: 5
});
```

### Example 3: Explore an Instance

```typescript
// Get instance information
const instance = await client.readResource(
  "activitypub://instance-info/mastodon.social"
);

console.log(`Instance: ${instance.title}`);
console.log(`Users: ${instance.stats.user_count}`);
console.log(`Posts: ${instance.stats.status_count}`);

// Get instance details using a tool
const exploration = await client.callTool("get-instance-info", {
  domain: "mastodon.social"
});
```

### Example 4: Using Prompts

```typescript
// Use the explore-fediverse prompt
const discovery = await client.getPrompt("explore-fediverse", {
  interests: "open source software",
  instanceType: "mastodon"
});

// Use the analyze-user-activity prompt
const analysis = await client.getPrompt("analyze-user-activity", {
  identifier: "@gargron@mastodon.social"
});
```

### Example 5: Real-World Scenario

Find popular open source projects on the Fediverse:

```typescript
// 1. Search for open source content
const results = await client.callTool("search", {
  query: "open source",
  type: "posts",
  limit: 50
});

// 2. Extract unique actors
const actors = new Set(
  results.statuses.map(status => status.account.acct)
);

// 3. Analyze each actor
for (const handle of actors) {
  const actor = await client.readResource(
    `activitypub://remote-actor/@${handle}`
  );

  const timeline = await client.callTool("fetch-timeline", {
    identifier: `@${handle}`,
    limit: 10
  });

  console.log(`${actor.name}: ${timeline.orderedItems.length} posts`);
}
```

---

## Development

### Project Structure (topic-organized)

```
activitypub-mcp/
├── src/
│   ├── mcp-main.ts                   # MCP server entry point (bin)
│   ├── mcp-server.ts                 # Server bootstrap
│   ├── config.ts                     # Configuration loader (Zod-validated)
│   ├── mcp/                          # MCP protocol surface
│   │   ├── tools.ts                  # 9 read-only tools
│   │   ├── tools-write.ts            # 28 authenticated tools
│   │   ├── resources.ts              # 10 resources
│   │   ├── prompts.ts                # 5 prompts
│   │   └── capabilities.ts           # Dynamic capability registry
│   ├── discovery/                    # WebFinger, NodeInfo, instance discovery
│   │   ├── webfinger.ts
│   │   ├── nodeinfo.ts               # software detection (Mastodon vs Misskey)
│   │   ├── software-kind.ts
│   │   └── dynamic-instance-discovery.ts
│   ├── activitypub/                  # ActivityPub client + read adapter
│   │   ├── remote-client.ts
│   │   └── read-adapter.ts           # per-instance read routing (Misskey reads)
│   ├── auth/                         # Login (OAuth2/MiAuth), accounts, write adapters
│   ├── policy/                       # Instance blocklist
│   │   └── instance-blocklist.ts
│   ├── audit/                        # Audit logging
│   │   └── logger.ts
│   ├── telemetry/                    # Structured logging
│   │   └── logging.ts
│   ├── transport/                    # HTTP transport + Bearer auth middleware
│   │   ├── http.ts
│   │   └── auth-middleware.ts
│   ├── resilience/                   # Rate limiting, retry
│   │   └── rate-limiter.ts
│   ├── validation/                   # URL, schemas, validators
│   │   ├── url.ts                    # SSRF guard, scheme allowlist
│   │   └── validators.ts
│   └── utils/                        # Errors, HTML stripping
│       ├── errors.ts
│       └── html.ts
├── tests/                            # 830+ unit tests + integration suite
├── docs/specifications/              # Protocol reference guides
├── scripts/
│   ├── install.sh / install.ps1      # Installer
│   └── setup.sh                      # Setup
└── public/
    ├── llms.txt                      # LLM-friendly summary
    └── llms-full.txt                 # This file
```

### Running Tests

```bash
# Unit tests (default)
npm run test
npm run test:coverage

# Integration tests against live Fediverse (runs daily in CI)
npm run test:integration

# Both
npm run test:all

# Type check
npm run typecheck
```

### Development Mode

```bash
# Start MCP server with auto-reload
npm run mcp:dev

# Run in development mode
npm run dev

# Run in production mode
npm run prod
```

### Code Quality

```bash
# Lint code
npm run lint

# Fix linting issues
npm run lint:fix

# Format code
npm run format

# Check formatting
npm run format:check

# Validate Biome configuration
npm run validate:biome
```

### Building

```bash
# Clean build directory
npm run clean

# Build TypeScript
npm run build

# Build documentation site
npm run build:site

# Preview documentation site
npm run preview:site
```

### Logging

The server uses structured logging via LogTape. Set the level with `LOG_LEVEL`
(`debug | info | warning | error | fatal`). On stdio, logs go to stderr so they
never corrupt the MCP protocol stream on stdout. Audit logging records every
write-tool invocation (tool name, parameters, success/failure, duration).

```bash
LOG_LEVEL=debug   # verbose; surfaces every outbound request and cache hit/miss
```

### Security

Security best practices:

1. **Dependency Auditing**: Run `npm audit` regularly
2. **Input Validation**: All inputs are validated using Zod schemas
3. **Rate Limiting**: Respects instance rate limits
4. **Error Handling**: Comprehensive error handling and logging
5. **HTTPS**: All external requests use HTTPS (non-https schemes are rejected)
6. **Read-only by default**: write/mutation tools are not registered unless `ACTIVITYPUB_ENABLE_WRITES=true`

### Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests and linting
5. Submit a pull request

**Development Guidelines:**
- Follow TypeScript best practices
- Add tests for new features
- Update documentation
- Use conventional commits
- Ensure all tests pass

---

## Specifications

### ActivityPub Protocol

ActivityPub is a decentralized social networking protocol based on ActivityStreams 2.0.

**Key Concepts:**
- **Actors**: Users, bots, or services (Person, Service, Application)
- **Activities**: Actions performed by actors (Create, Update, Delete, Follow, Like)
- **Objects**: Content items (Note, Article, Image, Video)
- **Collections**: Ordered or unordered sets of objects (inbox, outbox, followers, following)

**Core Endpoints:**
- `GET /users/{username}` - Actor profile
- `GET /users/{username}/outbox` - Actor's posts
- `GET /users/{username}/followers` - Actor's followers
- `GET /users/{username}/following` - Accounts actor follows
- `POST /users/{username}/inbox` - Receive activities (server-to-server)

**Example Actor Object:**
```json
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Person",
  "id": "https://mastodon.social/users/gargron",
  "preferredUsername": "gargron",
  "name": "Eugen Rochko",
  "summary": "Founder and CEO of Mastodon",
  "inbox": "https://mastodon.social/users/gargron/inbox",
  "outbox": "https://mastodon.social/users/gargron/outbox",
  "followers": "https://mastodon.social/users/gargron/followers",
  "following": "https://mastodon.social/users/gargron/following"
}
```

### WebFinger Protocol

WebFinger (RFC 7033) enables discovery of information about people and resources identified by URIs.

**Endpoint:** `GET /.well-known/webfinger?resource={uri}`

**Example Request:**
```
GET /.well-known/webfinger?resource=acct:gargron@mastodon.social
```

**Example Response:**
```json
{
  "subject": "acct:gargron@mastodon.social",
  "aliases": [
    "https://mastodon.social/@gargron",
    "https://mastodon.social/users/gargron"
  ],
  "links": [
    {
      "rel": "self",
      "type": "application/activity+json",
      "href": "https://mastodon.social/users/gargron"
    },
    {
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html",
      "href": "https://mastodon.social/@gargron"
    }
  ]
}
```

### ActivityStreams Vocabulary

ActivityStreams 2.0 defines the vocabulary for social activities.

**Core Types:**
- **Actor Types**: Person, Service, Application, Group, Organization
- **Activity Types**: Create, Update, Delete, Follow, Like, Announce, Undo
- **Object Types**: Note, Article, Image, Video, Document, Page

**Example Activity:**
```json
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Create",
  "actor": "https://mastodon.social/users/gargron",
  "object": {
    "type": "Note",
    "content": "Hello Fediverse!",
    "published": "2024-01-15T12:00:00Z",
    "to": ["https://www.w3.org/ns/activitystreams#Public"]
  }
}
```

### Model Context Protocol (MCP)

MCP is a protocol for integrating context providers with LLM applications.

**Core Components:**
- **Resources**: Read-only data sources (URI-based)
- **Tools**: Interactive operations (function calls)
- **Prompts**: Templated workflows (guided interactions)

**Resource URI Format:**
```
{protocol}://{resource-type}/{identifier}
```

**Tool Call Format:**
```json
{
  "name": "tool-name",
  "arguments": {
    "param1": "value1",
    "param2": "value2"
  }
}
```

**Prompt Format:**
```json
{
  "name": "prompt-name",
  "arguments": {
    "variable1": "value1",
    "variable2": "value2"
  }
}
```

---

## Troubleshooting

### Common Issues

#### Server Won't Start

**Problem:** Server fails to start or crashes immediately.

**Solutions:**
1. Check Node.js version: `node --version` (must be 20.0.0+)
2. Reinstall dependencies: `npm install`
3. Clear cache: `npm cache clean --force`
4. Check for port conflicts
5. Review error logs

#### Actor Discovery Fails

**Problem:** Cannot discover actors using WebFinger.

**Solutions:**
1. Verify handle format: `@username@domain.com`
2. Check instance is online and accessible
3. Verify instance supports WebFinger (`.well-known/webfinger`)
4. Check network connectivity
5. Review rate limiting

#### Timeline Fetch Errors

**Problem:** Cannot fetch actor timelines.

**Solutions:**
1. Verify actor exists and is public
2. Check instance API is accessible
3. Verify actor has public posts
4. Check rate limits
5. Review cache settings

#### Performance Issues

**Problem:** Slow response times or high memory usage.

**Solutions:**
1. Adjust cache settings (increase TTL)
2. Reduce concurrent requests
3. Enable performance monitoring
4. Check network latency
5. Review instance load

#### Integration Issues

**Problem:** MCP client cannot connect to server.

**Solutions:**
1. Verify server is running
2. Check client configuration
3. Review server logs
4. Verify command path
5. Check environment variables

### Debug Mode

Enable debug logging for detailed troubleshooting:

```bash
# Set environment variables
export LOG_LEVEL=debug
export DEBUG=true

# Run server
npm run mcp
```

### Logging

Logs are written to:
- Console (stdout/stderr)
- Log files (if configured)

Log levels:
- `debug`: Detailed debugging information
- `info`: General informational messages
- `warn`: Warning messages
- `error`: Error messages

### Getting Help

- **Documentation**: https://cameronrye.github.io/activitypub-mcp/
- **GitHub Issues**: https://github.com/cameronrye/activitypub-mcp/issues
- **npm Package**: https://www.npmjs.com/package/activitypub-mcp

---

## Additional Resources

### Official Specifications

- **ActivityPub**: https://www.w3.org/TR/activitypub/
- **ActivityStreams 2.0**: https://www.w3.org/TR/activitystreams-core/
- **WebFinger**: https://tools.ietf.org/html/rfc7033
- **Model Context Protocol**: https://modelcontextprotocol.io/

### Fediverse Resources

- **Fediverse Info**: https://fediverse.info/
- **Mastodon Documentation**: https://docs.joinmastodon.org/
- **Fedify Framework**: https://fedify.dev/
- **ActivityPub Rocks**: https://activitypub.rocks/

### Development Tools

- **MCP Inspector**: https://github.com/modelcontextprotocol/inspector
- **ActivityPub Validator**: https://activitypub.rocks/
- **WebFinger Tester**: https://webfinger.net/

### Community

- **Fediverse Developer Network**: https://fediverse.party/
- **ActivityPub Community**: https://socialhub.activitypub.rocks/
- **Mastodon Development**: https://github.com/mastodon/mastodon

---

## Changelog

The canonical changelog lives in [CHANGELOG.md](https://github.com/cameronrye/activitypub-mcp/blob/main/CHANGELOG.md). Highlights:

### Version 3.1.1 (Current)

Correctness and distribution patch.

**Fixed:**
- Misskey relationship results: `users/relation` returns the relation wrapped in an array for a single user id, which the adapter read as a bare object — so follow / mute / block relationship fields silently came back `false`. Both shapes are now handled.
- Outbox pagination no longer reports `hasMore: true` without a cursor to follow (a full final page with no `next` link previously looked like there was more).

**Security:**
- `upload-media` validates that the file content is an actual image/video/audio file (by magic bytes, not extension) before sending. A prompt-injected model can no longer name an arbitrary path (a key, the credential store, a `.env`) and exfiltrate it to a public media URL.

**Distribution:**
- The Claude Desktop Extension (`.mcpb`) is now built and attached to every GitHub Release, so the README's one-click install always resolves on the latest release.

### Version 3.1.0 — 2026-06-04

**Added:**
- Misskey / Foundkey read support: `search`, `get-trending-hashtags`, `get-trending-posts`, and `get-public-timeline` now work on Misskey-family instances, routed per instance by NodeInfo software detection and normalized into Mastodon-shaped results.
- Authentication guide on the docs site covering the `activitypub-mcp login` (Mastodon OAuth2 / Misskey MiAuth) flow, credential storage, and multi-account usage.

**Fixed:**
- Corrected the site's "Quick install" command and added a one-line stderr hint so an interactive stdio start no longer looks hung.
- Reconciled getting-started docs with the code (removed phantom env vars; a drift test now fails CI on documentation of an env var the code never reads).

**Security:**
- Full IPv6 private-range SSRF blocking (`fc00::/7`, `fe80::/10`, `fec0::/10`) via leading-hextet masks, replacing literal-prefix regexes that matched only canonical addresses.
- All GitHub Actions pinned to commit SHAs.

**Changed:**
- Releases publish automatically: `release.yml` and `publish-mcp.yml` are reusable workflows called inline after tagging.

### Version 3.0.1 — 2026-06-02

Correctness and distribution release.

**Security:**
- Strip `Authorization`, `Cookie`, and the request body when an outbound fetch follows a cross-origin redirect, preventing credential leakage to a redirected host.

**Added:**
- Official MCP Registry manifest (`server.json` + a `mcpName` marker) — the server is now publishable to registry.modelcontextprotocol.io (npm, stdio, read-only by default).

**Fixed:**
- Misskey `get-home-timeline` maps `minId` to the correct API parameter.
- Remote fetches honor `Retry-After`, retry transient (5xx / network) failures with backoff, and tolerate ActivityStreams `to`/`cc` delivered as a single string.

### Version 3.0.0 — 2026-05-27

Major release. Security, correctness, and ergonomics overhaul.

**Breaking changes:**
- Node 20+ required (Node 18 EOL April 30, 2025)
- HTTP transport requires `MCP_HTTP_SECRET` (32+ random chars). All requests to `/mcp` and `/metrics` must include `Authorization: Bearer <secret>`. `/health` stays unauthenticated. Stdio is unaffected.
- `MCP_HTTP_CORS_ORIGINS` no longer defaults to `"*"` — defaults to empty.
- `ACTIVITYPUB_ACCOUNTS` uses pipe `|` delimiter (legacy colon format rejected at startup).
- `scheduledId` → `scheduledPostId` on `cancel-scheduled-post` and `update-scheduled-post`.
- `get-relationship` takes `acct: string` (rejects legacy `accountIds: string[]`).
- `HEALTH_CHECK_ENABLED` removed; use `HEALTH_CHECK_EXTERNAL_PROBE` for the outbound mastodon.social probe.
- Outbound URL scheme allow-list: `validateExternalUrl` now rejects non-https schemes.

**Added:**
- `post-status` supports `mediaIds` and `scheduledAt` (round-trip with `upload-media`).
- Unified `search` tool with `type: "all" | "accounts" | "posts" | "hashtags"` (consolidates the former `search-instance` / `search-accounts` / `search-hashtags` / `search-posts`), returning prose output.
- `fetch-timeline` renders all posts (was capped at 10) with 500-char per-post truncation.
- Dynamic `server-info` capabilities — list comes from the live registry.
- Thread traversal caps: `MCP_THREAD_MAX_DEPTH=5`, `MCP_THREAD_MAX_REPLIES=50`, with `MCP_THREAD_CROSS_ORIGIN_FETCH=false` cross-origin gate.
- Audit logging wired into every write tool.
- New `post-thread` resource URI template: `activitypub://post-thread/{domain}/{statusId}` (Mastodon-style URL constructor). Legacy `{postUrl}` form still accepted with a deprecation warning; removed in 2.1.0.
- `npm run typecheck` script and CI step.
- Daily integration test workflow against the live Fediverse.

**Security:**
- Streaming response-size enforcement (default 10 MB) — aborts even when Content-Length is missing.
- `verifyAccount` routes through SSRF guard; instance-discovery raw fetches gated by `DomainSchema` + `validateExternalUrl`.
- `DomainSchema` rejects IP literals.
- WebFinger same-origin actor check closes a spoofing path.
- Redirects re-run SSRF + blocklist checks on each hop (up to 3).
- Instance blocklist now enforced on WebFinger, actor fetches, all write operations, media uploads, and credential verification.

**Internal:**
- Source tree reorganized into 11 topic directories (see Project Structure above).
- 624 unit tests (up from 533 at v2 start).
- `files` whitelist in `package.json` controls npm publish contents.
- See `MIGRATION-v2.md` for the full upgrade guide.

### Version 1.1.0 — 2026-02-02

Added authenticated write operations (multi-account, posting, interactions, polls, scheduling, exports), HTTP transport support, instance blocklist, dynamic instance discovery, audit logging. 13 new read-only tools, 4 new resources, 4 new prompts.

### Version 1.0.0

Initial release: complete MCP read-only server, ActivityPub client, WebFinger discovery, cross-platform support, full documentation.

---

## License

MIT License - See LICENSE file for details

Copyright (c) 2025 ActivityPub MCP Server Contributors

---

## Credits

**Maintainer:** Cameron Rye (https://rye.dev/)

**Built With:**
- TypeScript
- Model Context Protocol SDK (`@modelcontextprotocol/sdk`)
- undici (HTTP client)
- LogTape (Logging)
- Zod (Validation)

**Special Thanks:**
- Mastodon community
- Fediverse developers
- MCP specification authors
- All contributors

---

## Contact

- **Website**: https://cameronrye.github.io/activitypub-mcp/
- **GitHub**: https://github.com/cameronrye/activitypub-mcp
- **npm**: https://www.npmjs.com/package/activitypub-mcp
- **Issues**: https://github.com/cameronrye/activitypub-mcp/issues

---

*This documentation is maintained as part of the ActivityPub MCP Server project. For the latest updates, visit the GitHub repository.*
```

