Skip to main content
Glama
test-interface.ts10.1 kB
#!/usr/bin/env node import { TwitterClient } from './twitter-client.js'; import { AuthConfig } from './types.js'; import { performHealthCheck } from './health.js'; import { logInfo, logError } from './utils/logger.js'; import dotenv from 'dotenv'; import readline from 'readline'; import { TweetTools } from './tools/tweets.js'; import { ProfileTools } from './tools/profiles.js'; import { GrokTools } from './tools/grok.js'; // Load environment variables dotenv.config(); // Create tools instances const tweetTools = new TweetTools(); const profileTools = new ProfileTools(); const grokTools = new GrokTools(); const client = new TwitterClient(); // Configure auth from environment variables function getAuthConfig(): AuthConfig { // Determine auth method const authMethod = process.env.AUTH_METHOD || 'cookies'; switch (authMethod) { case 'cookies': const cookiesStr = process.env.TWITTER_COOKIES; if (!cookiesStr) { throw new Error('TWITTER_COOKIES environment variable is required for cookie auth'); } return { method: 'cookies', data: { cookies: JSON.parse(cookiesStr) } }; case 'credentials': const username = process.env.TWITTER_USERNAME; const password = process.env.TWITTER_PASSWORD; if (!username || !password) { throw new Error('TWITTER_USERNAME and TWITTER_PASSWORD are required for credential auth'); } return { method: 'credentials', data: { username, password, email: process.env.TWITTER_EMAIL, twoFactorSecret: process.env.TWITTER_2FA_SECRET } }; case 'api': const apiKey = process.env.TWITTER_API_KEY; const apiSecretKey = process.env.TWITTER_API_SECRET_KEY; const accessToken = process.env.TWITTER_ACCESS_TOKEN; const accessTokenSecret = process.env.TWITTER_ACCESS_TOKEN_SECRET; if (!apiKey || !apiSecretKey || !accessToken || !accessTokenSecret) { throw new Error('API credentials are required for API auth'); } return { method: 'api', data: { apiKey, apiSecretKey, accessToken, accessTokenSecret } }; default: throw new Error(`Unsupported auth method: ${authMethod}`); } } // Get auth config let authConfig: AuthConfig; try { authConfig = getAuthConfig(); logInfo('Authentication configuration loaded', { method: authConfig.method }); } catch (error) { logError('Failed to load authentication configuration', error); process.exit(1); } // Create readline interface const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Available test commands const commands = { 'health': 'Run a health check', 'profile <username>': 'Get a user profile', 'tweets <username> [count]': 'Get tweets from a user', 'tweet <id>': 'Get a specific tweet by ID', 'search <query> [count]': 'Search for tweets', 'post <text>': 'Post a new tweet', 'like <id>': 'Like a tweet', 'retweet <id>': 'Retweet a tweet', 'quote <id> <text>': 'Quote a tweet', 'follow <username>': 'Follow a user', 'followers <userId> [count]': 'Get a user\'s followers', 'following <userId> [count]': 'Get users a user is following', 'grok <message>': 'Chat with Grok', 'help': 'Show available commands', 'exit': 'Exit the test interface' }; // Show welcome message console.log('\n🐦 Twitter MCP Test Interface 🐦\n'); console.log('Type a command to test the MCP functionality. Type "help" to see available commands.\n'); // Process commands async function processCommand(input: string) { const args = input.trim().split(' '); const command = args[0].toLowerCase(); try { switch (command) { case 'health': console.log('Running health check...'); const healthResult = await performHealthCheck(authConfig); console.log(JSON.stringify(healthResult, null, 2)); break; case 'profile': if (!args[1]) { console.log('Error: Username is required'); break; } console.log(`Getting profile for ${args[1]}...`); const profileResult = await profileTools.getUserProfile(authConfig, { username: args[1] }); console.log(JSON.stringify(profileResult, null, 2)); break; case 'tweets': if (!args[1]) { console.log('Error: Username is required'); break; } const count = args[2] ? parseInt(args[2]) : 10; console.log(`Getting ${count} tweets from ${args[1]}...`); const tweetsResult = await tweetTools.getUserTweets(authConfig, { username: args[1], count, includeReplies: false, includeRetweets: true }); console.log(JSON.stringify(tweetsResult, null, 2)); break; case 'tweet': if (!args[1]) { console.log('Error: Tweet ID is required'); break; } console.log(`Getting tweet ${args[1]}...`); const tweetResult = await tweetTools.getTweetById(authConfig, { id: args[1] }); console.log(JSON.stringify(tweetResult, null, 2)); break; case 'search': if (!args[1]) { console.log('Error: Search query is required'); break; } const searchCount = args[2] ? parseInt(args[2]) : 10; console.log(`Searching for "${args[1]}"...`); const searchResult = await tweetTools.searchTweets(authConfig, { query: args[1], count: searchCount, searchMode: 'Top' }); console.log(JSON.stringify(searchResult, null, 2)); break; case 'post': if (!args[1]) { console.log('Error: Tweet text is required'); break; } const tweetText = args.slice(1).join(' '); console.log(`Posting tweet: "${tweetText}"...`); const postResult = await tweetTools.sendTweet(authConfig, { text: tweetText }); console.log(JSON.stringify(postResult, null, 2)); break; case 'like': if (!args[1]) { console.log('Error: Tweet ID is required'); break; } console.log(`Liking tweet ${args[1]}...`); const likeResult = await tweetTools.likeTweet(authConfig, { id: args[1] }); console.log(JSON.stringify(likeResult, null, 2)); break; case 'retweet': if (!args[1]) { console.log('Error: Tweet ID is required'); break; } console.log(`Retweeting tweet ${args[1]}...`); const retweetResult = await tweetTools.retweet(authConfig, { id: args[1] }); console.log(JSON.stringify(retweetResult, null, 2)); break; case 'quote': if (!args[1] || !args[2]) { console.log('Error: Tweet ID and quote text are required'); break; } const quoteText = args.slice(2).join(' '); console.log(`Quoting tweet ${args[1]} with: "${quoteText}"...`); const quoteResult = await tweetTools.quoteTweet(authConfig, { quotedTweetId: args[1], text: quoteText }); console.log(JSON.stringify(quoteResult, null, 2)); break; case 'follow': if (!args[1]) { console.log('Error: Username is required'); break; } console.log(`Following user ${args[1]}...`); const followResult = await profileTools.followUser(authConfig, { username: args[1] }); console.log(JSON.stringify(followResult, null, 2)); break; case 'followers': if (!args[1]) { console.log('Error: User ID is required'); break; } const followersCount = args[2] ? parseInt(args[2]) : 10; console.log(`Getting ${followersCount} followers for user ${args[1]}...`); const followersResult = await profileTools.getFollowers(authConfig, { userId: args[1], count: followersCount }); console.log(JSON.stringify(followersResult, null, 2)); break; case 'following': if (!args[1]) { console.log('Error: User ID is required'); break; } const followingCount = args[2] ? parseInt(args[2]) : 10; console.log(`Getting ${followingCount} following for user ${args[1]}...`); const followingResult = await profileTools.getFollowing(authConfig, { userId: args[1], count: followingCount }); console.log(JSON.stringify(followingResult, null, 2)); break; case 'grok': if (!args[1]) { console.log('Error: Message is required'); break; } const message = args.slice(1).join(' '); console.log(`Sending message to Grok: "${message}"...`); const grokResult = await grokTools.grokChat(authConfig, { message, returnSearchResults: true, returnCitations: true }); console.log(JSON.stringify(grokResult, null, 2)); break; case 'help': console.log('\nAvailable commands:'); Object.entries(commands).forEach(([cmd, desc]) => { console.log(` ${cmd.padEnd(25)} ${desc}`); }); console.log(); break; case 'exit': console.log('Exiting test interface...'); rl.close(); process.exit(0); break; default: console.log(`Unknown command: ${command}`); console.log('Type "help" to see available commands.'); break; } } catch (error) { logError(`Error executing command ${command}`, error); console.error(`Error: ${error instanceof Error ? error.message : String(error)}`); } // Prompt for next command rl.prompt(); } // Start the command loop rl.setPrompt('agent-twitter-client-mcp> '); rl.prompt(); rl.on('line', async (line) => { await processCommand(line); }).on('close', () => { console.log('Goodbye!'); process.exit(0); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ryanmac/agent-twitter-client-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server