Warpcast MCP Server
- src
import axios from 'axios';
import * as dotenv from 'dotenv';
dotenv.config();
const API_BASE_URL = 'https://api.warpcast.com';
// Create an axios instance with default configuration
const warpcastApi = axios.create({
baseURL: API_BASE_URL,
headers: {
'Content-Type': 'application/json'
}
});
// Define interfaces for the API responses
export interface Cast {
hash: string;
threadHash?: string;
parentHash?: string;
author: {
fid: number;
username: string;
displayName: string;
pfp: {
url: string;
};
profile: {
bio: string;
};
};
text: string;
timestamp: string;
reactions: {
likes: number;
recasts: number;
replies: number;
};
embeds?: any[];
}
export interface Channel {
id: string;
url: string;
name: string;
description: string;
imageUrl?: string;
headerImageUrl?: string;
leadFid: number;
moderatorFids: number[];
createdAt: number;
followerCount: number;
memberCount: number;
pinnedCastHash?: string;
publicCasting: boolean;
externalLink?: {
title: string;
url: string;
};
}
export interface ApiResponse<T> {
result: {
data: T;
next?: {
cursor: string;
};
};
}
interface PaginationOptions {
cursor?: string;
limit?: number;
}
/**
* Post a new cast to Warpcast
* @param text The content of the cast (max 320 characters)
* @param authToken The authentication token
* @returns The created cast
*/
export async function postCast(text: string, authToken: string): Promise<Cast> {
try {
if (text.length > 320) {
text = text.substring(0, 320); // Truncate to 320 characters
}
const response = await warpcastApi.post('/v2/casts',
{ text },
{
headers: {
'Authorization': `Bearer ${authToken}`
}
}
);
return response.data.result.cast;
} catch (error) {
console.error('Error posting cast:', error);
throw new Error('Failed to post cast to Warpcast');
}
}
/**
* Get recent casts from a specific user
* @param username The username to fetch casts for
* @param options Pagination options
* @returns List of casts
*/
export async function getUserCasts(username: string, options: PaginationOptions = {}): Promise<Cast[]> {
try {
const { cursor, limit = 10 } = options;
let url = `/v2/user-casts?username=${username}&limit=${limit}`;
if (cursor) {
url += `&cursor=${cursor}`;
}
const response = await warpcastApi.get<{result: {casts: Cast[], next?: {cursor: string}}}>(url);
return response.data.result.casts;
} catch (error) {
console.error(`Error fetching casts for user ${username}:`, error);
throw new Error(`Failed to fetch casts for ${username}`);
}
}
/**
* Search for casts by query string
* @param query The search query
* @param options Pagination options
* @returns List of matching casts
*/
export async function searchCasts(query: string, options: PaginationOptions = {}): Promise<Cast[]> {
try {
const { cursor, limit = 10 } = options;
let url = `/v2/search?q=${encodeURIComponent(query)}&limit=${limit}`;
if (cursor) {
url += `&cursor=${cursor}`;
}
const response = await warpcastApi.get<{result: {casts: Cast[], next?: {cursor: string}}}>(url);
return response.data.result.casts;
} catch (error) {
console.error(`Error searching casts for "${query}":`, error);
throw new Error(`Failed to search for casts containing "${query}"`);
}
}
/**
* Get trending casts
* @param options Pagination options
* @returns List of trending casts
*/
export async function getTrendingCasts(options: PaginationOptions = {}): Promise<Cast[]> {
try {
const { cursor, limit = 10 } = options;
let url = `/v2/trending-casts?limit=${limit}`;
if (cursor) {
url += `&cursor=${cursor}`;
}
const response = await warpcastApi.get<{result: {casts: Cast[], next?: {cursor: string}}}>(url);
return response.data.result.casts;
} catch (error) {
console.error('Error fetching trending casts:', error);
throw new Error('Failed to fetch trending casts');
}
}
/**
* Get all channels
* @returns List of all channels
*/
export async function getAllChannels(): Promise<Channel[]> {
try {
const response = await warpcastApi.get<{result: {channels: Channel[]}}>(
'/v2/all-channels'
);
return response.data.result.channels;
} catch (error) {
console.error('Error fetching all channels:', error);
throw new Error('Failed to fetch channels');
}
}
/**
* Get a specific channel by ID
* @param channelId The channel ID
* @returns Channel data
*/
export async function getChannel(channelId: string): Promise<Channel> {
try {
const response = await warpcastApi.get<{result: {channel: Channel}}>(
`/v1/channel?channelId=${channelId}`
);
return response.data.result.channel;
} catch (error) {
console.error(`Error fetching channel ${channelId}:`, error);
throw new Error(`Failed to fetch channel ${channelId}`);
}
}
/**
* Get casts from a specific channel
* @param channelId The channel ID
* @param options Pagination options
* @returns List of channel casts
*/
export async function getChannelCasts(channelId: string, options: PaginationOptions = {}): Promise<Cast[]> {
try {
const { cursor, limit = 10 } = options;
let url = `/v2/channel-casts?channelId=${channelId}&limit=${limit}`;
if (cursor) {
url += `&cursor=${cursor}`;
}
const response = await warpcastApi.get<{result: {casts: Cast[], next?: {cursor: string}}}>(url);
return response.data.result.casts;
} catch (error) {
console.error(`Error fetching casts for channel ${channelId}:`, error);
throw new Error(`Failed to fetch casts for channel ${channelId}`);
}
}
/**
* Follow a channel
* @param channelId The channel ID to follow
* @param authToken The authentication token
* @returns Success status
*/
export async function followChannel(channelId: string, authToken: string): Promise<boolean> {
try {
const response = await warpcastApi.post(
'/fc/channel-follows',
{ channelId },
{
headers: {
'Authorization': `Bearer ${authToken}`
}
}
);
return response.data.success === true;
} catch (error) {
console.error(`Error following channel ${channelId}:`, error);
throw new Error(`Failed to follow channel ${channelId}`);
}
}
/**
* Unfollow a channel
* @param channelId The channel ID to unfollow
* @param authToken The authentication token
* @returns Success status
*/
export async function unfollowChannel(channelId: string, authToken: string): Promise<boolean> {
try {
const response = await warpcastApi.delete(
'/fc/channel-follows',
{
headers: {
'Authorization': `Bearer ${authToken}`
},
data: { channelId }
}
);
return response.data.success === true;
} catch (error) {
console.error(`Error unfollowing channel ${channelId}:`, error);
throw new Error(`Failed to unfollow channel ${channelId}`);
}
}
export default {
postCast,
getUserCasts,
searchCasts,
getTrendingCasts,
getAllChannels,
getChannel,
getChannelCasts,
followChannel,
unfollowChannel
};