@opentweet/mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +99 -0
  2. package/dist/api-client.d.ts +102 -0
  3. package/dist/api-client.d.ts.map +1 -0
  4. package/dist/api-client.js +125 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +44 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/prompts/index.d.ts +3 -0
  11. package/dist/prompts/index.d.ts.map +1 -0
  12. package/dist/prompts/index.js +93 -0
  13. package/dist/prompts/index.js.map +1 -0
  14. package/dist/resources/index.d.ts +4 -0
  15. package/dist/resources/index.d.ts.map +1 -0
  16. package/dist/resources/index.js +55 -0
  17. package/dist/resources/index.js.map +1 -0
  18. package/dist/tools/account.d.ts +4 -0
  19. package/dist/tools/account.d.ts.map +1 -0
  20. package/dist/tools/account.js +38 -0
  21. package/dist/tools/account.js.map +1 -0
  22. package/dist/tools/analytics.d.ts +4 -0
  23. package/dist/tools/analytics.d.ts.map +1 -0
  24. package/dist/tools/analytics.js +100 -0
  25. package/dist/tools/analytics.js.map +1 -0
  26. package/dist/tools/media.d.ts +4 -0
  27. package/dist/tools/media.d.ts.map +1 -0
  28. package/dist/tools/media.js +47 -0
  29. package/dist/tools/media.js.map +1 -0
  30. package/dist/tools/posts.d.ts +4 -0
  31. package/dist/tools/posts.d.ts.map +1 -0
  32. package/dist/tools/posts.js +194 -0
  33. package/dist/tools/posts.js.map +1 -0
  34. package/dist/tools/scheduling.d.ts +4 -0
  35. package/dist/tools/scheduling.d.ts.map +1 -0
  36. package/dist/tools/scheduling.js +52 -0
  37. package/dist/tools/scheduling.js.map +1 -0
  38. package/dist/types.d.ts +104 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +2 -0
  41. package/dist/types.js.map +1 -0
  42. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # @opentweet/mcp-server
2
+
3
+ MCP server for [OpenTweet](https://opentweet.io) — manage your Twitter/X presence from Claude, Cursor, or any AI assistant.
4
+
5
+ ## Quick Start
6
+
7
+ ### 1. Get an API Key
8
+
9
+ Sign up at [opentweet.io](https://opentweet.io) and create an API key from the [Developer Dashboard](https://opentweet.io/developer).
10
+
11
+ ### 2. Configure Your AI Client
12
+
13
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "opentweet": {
19
+ "command": "npx",
20
+ "args": ["-y", "@opentweet/mcp-server"],
21
+ "env": {
22
+ "OPENTWEET_API_KEY": "ot_your_key_here"
23
+ }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ For **Claude Code**:
30
+ ```bash
31
+ claude mcp add opentweet -- npx -y @opentweet/mcp-server
32
+ ```
33
+
34
+ ### 3. Start Using
35
+
36
+ Ask your AI assistant:
37
+ - "Schedule a tweet about React performance for tomorrow at 9am"
38
+ - "Show me my posting streak and analytics"
39
+ - "Create a 5-tweet thread about TypeScript tips"
40
+ - "What are my best posting times?"
41
+
42
+ ## Tools
43
+
44
+ | Tool | Description |
45
+ |------|-------------|
46
+ | `opentweet_create_tweet` | Create a tweet (draft, scheduled, or publish now) |
47
+ | `opentweet_create_thread` | Create a multi-tweet thread (2-25 tweets) |
48
+ | `opentweet_list_tweets` | List tweets with status filters and pagination |
49
+ | `opentweet_get_tweet` | Get full details of a specific tweet |
50
+ | `opentweet_update_tweet` | Edit tweet text, category, schedule, or media |
51
+ | `opentweet_delete_tweet` | Delete a tweet |
52
+ | `opentweet_publish_tweet` | Publish a draft/scheduled tweet immediately to X |
53
+ | `opentweet_batch_schedule` | Schedule up to 50 tweets at once |
54
+ | `opentweet_get_analytics` | Get posting stats, streaks, trends, engagement |
55
+ | `opentweet_get_followers` | Get follower growth data over time |
56
+ | `opentweet_get_account` | Get account status, subscription, and limits |
57
+ | `opentweet_upload_media` | Upload images/videos for use in tweets |
58
+
59
+ ## Resources
60
+
61
+ | URI | Description |
62
+ |-----|-------------|
63
+ | `opentweet://account` | Account status and limits |
64
+ | `opentweet://posts/scheduled` | Currently scheduled tweets |
65
+ | `opentweet://posts/drafts` | Draft tweets |
66
+ | `opentweet://analytics/summary` | Analytics overview |
67
+
68
+ ## Prompts
69
+
70
+ | Name | Description |
71
+ |------|-------------|
72
+ | `weekly_content_plan` | Generate a week of tweet content |
73
+ | `review_and_schedule_drafts` | Review drafts and suggest scheduling |
74
+ | `content_from_url` | Generate tweets from a URL or topic |
75
+ | `performance_review` | Analyze performance and get suggestions |
76
+
77
+ ## Requirements
78
+
79
+ - Node.js 18+
80
+ - OpenTweet account with API key ([get one here](https://opentweet.io/developer))
81
+ - Connected X/Twitter account in OpenTweet
82
+
83
+ ## Environment Variables
84
+
85
+ | Variable | Required | Description |
86
+ |----------|----------|-------------|
87
+ | `OPENTWEET_API_KEY` | Yes | Your OpenTweet API key (starts with `ot_`) |
88
+ | `OPENTWEET_BASE_URL` | No | API base URL (default: `https://opentweet.io`) |
89
+
90
+ ## Links
91
+
92
+ - [OpenTweet](https://opentweet.io)
93
+ - [MCP Server Feature Page](https://opentweet.io/mcp)
94
+ - [Developer Dashboard](https://opentweet.io/developer)
95
+ - [API Documentation](https://opentweet.io/developer)
96
+
97
+ ## License
98
+
99
+ MIT
@@ -0,0 +1,102 @@
1
+ import type { OpenTweetConfig, PaginatedResponse, Post, AccountStatus, AnalyticsOverview, UploadResponse } from './types.js';
2
+ export declare class OpenTweetClient {
3
+ private apiKey;
4
+ private baseUrl;
5
+ constructor(config: OpenTweetConfig);
6
+ private request;
7
+ listPosts(params?: {
8
+ status?: string;
9
+ page?: number;
10
+ limit?: number;
11
+ }): Promise<PaginatedResponse<Post>>;
12
+ getPost(id: string): Promise<Post>;
13
+ createPost(data: {
14
+ text: string;
15
+ category?: string;
16
+ scheduled_date?: string;
17
+ is_thread?: boolean;
18
+ thread_tweets?: string[];
19
+ media_urls?: string[];
20
+ thread_media?: string[][];
21
+ community_id?: string;
22
+ share_with_followers?: boolean;
23
+ publish_now?: boolean;
24
+ }): Promise<{
25
+ success: boolean;
26
+ count: number;
27
+ posts: Post[];
28
+ message?: string;
29
+ }>;
30
+ createBatchPosts(posts: Array<{
31
+ text: string;
32
+ category?: string;
33
+ scheduled_date?: string;
34
+ is_thread?: boolean;
35
+ thread_tweets?: string[];
36
+ media_urls?: string[];
37
+ }>): Promise<{
38
+ success: boolean;
39
+ count: number;
40
+ posts: Post[];
41
+ }>;
42
+ updatePost(id: string, data: {
43
+ text?: string;
44
+ category?: string;
45
+ scheduled_date?: string | null;
46
+ is_thread?: boolean;
47
+ thread_tweets?: string[];
48
+ media_urls?: string[];
49
+ thread_media?: string[][];
50
+ community_id?: string;
51
+ share_with_followers?: boolean;
52
+ }): Promise<Post>;
53
+ deletePost(id: string): Promise<{
54
+ success: boolean;
55
+ message: string;
56
+ }>;
57
+ schedulePost(id: string, scheduledDate: string): Promise<{
58
+ success: boolean;
59
+ id: string;
60
+ text: string;
61
+ scheduled_date: string;
62
+ message: string;
63
+ }>;
64
+ publishPost(id: string): Promise<{
65
+ success: boolean;
66
+ id: string;
67
+ text: string;
68
+ x_post_id: string;
69
+ posted_date: string;
70
+ message: string;
71
+ }>;
72
+ batchSchedule(schedules: Array<{
73
+ post_id: string;
74
+ scheduled_date: string;
75
+ }>, communityId?: string, shareWithFollowers?: boolean): Promise<{
76
+ success: boolean;
77
+ message: string;
78
+ scheduled: Array<{
79
+ id: string;
80
+ text: string;
81
+ scheduled_date: string;
82
+ }>;
83
+ errors?: Array<{
84
+ post_id: string;
85
+ error: string;
86
+ }>;
87
+ }>;
88
+ getAccountStatus(): Promise<AccountStatus>;
89
+ getAnalyticsOverview(): Promise<AnalyticsOverview>;
90
+ getTweetAnalytics(params?: {
91
+ period?: string;
92
+ sort_by?: string;
93
+ limit?: number;
94
+ }): Promise<Record<string, unknown>>;
95
+ getBestTimes(): Promise<Record<string, unknown>>;
96
+ getFollowerGrowth(params?: {
97
+ days?: number;
98
+ }): Promise<Record<string, unknown>>;
99
+ getGrowthSummary(): Promise<Record<string, unknown>>;
100
+ uploadMedia(fileBuffer: Buffer, fileName: string, mimeType: string): Promise<UploadResponse>;
101
+ }
102
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ export class OpenTweetClient {
2
+ apiKey;
3
+ baseUrl;
4
+ constructor(config) {
5
+ this.apiKey = config.apiKey;
6
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
7
+ }
8
+ async request(method, path, body, isFormData) {
9
+ const url = `${this.baseUrl}/api/v1${path}`;
10
+ const headers = {
11
+ 'Authorization': `Bearer ${this.apiKey}`,
12
+ };
13
+ if (!isFormData) {
14
+ headers['Content-Type'] = 'application/json';
15
+ }
16
+ const response = await fetch(url, {
17
+ method,
18
+ headers,
19
+ body: body && !isFormData ? JSON.stringify(body) : body,
20
+ });
21
+ const data = await response.json();
22
+ if (!response.ok) {
23
+ const errorMessage = data.error || `API error: ${response.status}`;
24
+ const details = data.details
25
+ ? Array.isArray(data.details)
26
+ ? data.details.join('; ')
27
+ : data.details
28
+ : '';
29
+ throw new Error(details ? `${errorMessage} — ${details}` : errorMessage);
30
+ }
31
+ return data;
32
+ }
33
+ // Posts
34
+ async listPosts(params = {}) {
35
+ const searchParams = new URLSearchParams();
36
+ if (params.status)
37
+ searchParams.set('status', params.status);
38
+ if (params.page)
39
+ searchParams.set('page', String(params.page));
40
+ if (params.limit)
41
+ searchParams.set('limit', String(params.limit));
42
+ const qs = searchParams.toString();
43
+ return this.request('GET', `/posts${qs ? `?${qs}` : ''}`);
44
+ }
45
+ async getPost(id) {
46
+ return this.request('GET', `/posts/${id}`);
47
+ }
48
+ async createPost(data) {
49
+ return this.request('POST', '/posts', data);
50
+ }
51
+ async createBatchPosts(posts) {
52
+ return this.request('POST', '/posts', { posts });
53
+ }
54
+ async updatePost(id, data) {
55
+ return this.request('PUT', `/posts/${id}`, data);
56
+ }
57
+ async deletePost(id) {
58
+ return this.request('DELETE', `/posts/${id}`);
59
+ }
60
+ async schedulePost(id, scheduledDate) {
61
+ return this.request('POST', `/posts/${id}/schedule`, { scheduled_date: scheduledDate });
62
+ }
63
+ async publishPost(id) {
64
+ return this.request('POST', `/posts/${id}/publish`);
65
+ }
66
+ async batchSchedule(schedules, communityId, shareWithFollowers) {
67
+ return this.request('POST', '/posts/batch-schedule', {
68
+ schedules,
69
+ community_id: communityId,
70
+ share_with_followers: shareWithFollowers,
71
+ });
72
+ }
73
+ // Account
74
+ async getAccountStatus() {
75
+ return this.request('GET', '/me');
76
+ }
77
+ // Analytics
78
+ async getAnalyticsOverview() {
79
+ return this.request('GET', '/analytics/overview');
80
+ }
81
+ async getTweetAnalytics(params = {}) {
82
+ const searchParams = new URLSearchParams();
83
+ if (params.period)
84
+ searchParams.set('period', params.period);
85
+ if (params.sort_by)
86
+ searchParams.set('sort_by', params.sort_by);
87
+ if (params.limit)
88
+ searchParams.set('limit', String(params.limit));
89
+ const qs = searchParams.toString();
90
+ return this.request('GET', `/analytics/tweets${qs ? `?${qs}` : ''}`);
91
+ }
92
+ async getBestTimes() {
93
+ return this.request('GET', '/analytics/best-times');
94
+ }
95
+ async getFollowerGrowth(params = {}) {
96
+ const searchParams = new URLSearchParams();
97
+ if (params.days)
98
+ searchParams.set('days', String(params.days));
99
+ const qs = searchParams.toString();
100
+ return this.request('GET', `/analytics/followers${qs ? `?${qs}` : ''}`);
101
+ }
102
+ async getGrowthSummary() {
103
+ return this.request('GET', '/analytics/growth');
104
+ }
105
+ // Upload
106
+ async uploadMedia(fileBuffer, fileName, mimeType) {
107
+ const formData = new FormData();
108
+ const blob = new Blob([new Uint8Array(fileBuffer)], { type: mimeType });
109
+ formData.append('file', blob, fileName);
110
+ const url = `${this.baseUrl}/api/v1/upload`;
111
+ const response = await fetch(url, {
112
+ method: 'POST',
113
+ headers: {
114
+ 'Authorization': `Bearer ${this.apiKey}`,
115
+ },
116
+ body: formData,
117
+ });
118
+ const data = await response.json();
119
+ if (!response.ok) {
120
+ throw new Error(data.error || `Upload failed: ${response.status}`);
121
+ }
122
+ return data;
123
+ }
124
+ }
125
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { OpenTweetClient } from './api-client.js';
5
+ import { registerPostTools } from './tools/posts.js';
6
+ import { registerSchedulingTools } from './tools/scheduling.js';
7
+ import { registerAnalyticsTools } from './tools/analytics.js';
8
+ import { registerAccountTools } from './tools/account.js';
9
+ import { registerMediaTools } from './tools/media.js';
10
+ import { registerResources } from './resources/index.js';
11
+ import { registerPrompts } from './prompts/index.js';
12
+ const API_KEY = process.env.OPENTWEET_API_KEY;
13
+ const BASE_URL = process.env.OPENTWEET_BASE_URL || 'https://opentweet.io';
14
+ if (!API_KEY) {
15
+ console.error('Error: OPENTWEET_API_KEY environment variable is required.');
16
+ console.error('');
17
+ console.error('Get your API key from: https://opentweet.io/developer');
18
+ console.error('');
19
+ console.error('Set it in your MCP client config:');
20
+ console.error(' "env": { "OPENTWEET_API_KEY": "ot_your_key_here" }');
21
+ process.exit(1);
22
+ }
23
+ const client = new OpenTweetClient({
24
+ apiKey: API_KEY,
25
+ baseUrl: BASE_URL,
26
+ });
27
+ const server = new McpServer({
28
+ name: 'opentweet',
29
+ version: '1.0.0',
30
+ });
31
+ // Register all tools
32
+ registerPostTools(server, client);
33
+ registerSchedulingTools(server, client);
34
+ registerAnalyticsTools(server, client);
35
+ registerAccountTools(server, client);
36
+ registerMediaTools(server, client);
37
+ // Register resources
38
+ registerResources(server, client);
39
+ // Register prompts
40
+ registerPrompts(server);
41
+ // Start server with stdio transport
42
+ const transport = new StdioServerTransport();
43
+ await server.connect(transport);
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,sBAAsB,CAAC;AAE1E,IAAI,CAAC,OAAO,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAC5E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACnD,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;IACjC,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,QAAQ;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACxC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACrC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnC,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElC,mBAAmB;AACnB,eAAe,CAAC,MAAM,CAAC,CAAC;AAExB,oCAAoC;AACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerPrompts(server: McpServer): void;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,QAiHhD"}
@@ -0,0 +1,93 @@
1
+ import { z } from 'zod';
2
+ export function registerPrompts(server) {
3
+ server.prompt('weekly_content_plan', 'Generate a week of tweet content based on topics and preferences', {
4
+ topics: z.string().describe('Comma-separated topics to tweet about (e.g. "AI, startups, product launches")'),
5
+ tone: z.enum(['professional', 'casual', 'humorous', 'inspirational', 'technical']).optional()
6
+ .describe('Desired tone for the tweets'),
7
+ tweets_per_day: z.string().optional().describe('Number of tweets per day (default "2")'),
8
+ }, ({ topics, tone = 'professional', tweets_per_day = '2' }) => ({
9
+ messages: [{
10
+ role: 'user',
11
+ content: {
12
+ type: 'text',
13
+ text: `Create a weekly content plan for X/Twitter.
14
+
15
+ Topics: ${topics}
16
+ Tone: ${tone}
17
+ Tweets per day: ${tweets_per_day}
18
+
19
+ For each day (Monday through Sunday), generate ${tweets_per_day} tweet(s). Each tweet should:
20
+ - Be under 280 characters
21
+ - Be engaging and encourage interaction
22
+ - Include a mix of content types (insights, questions, tips, stories)
23
+ - Be relevant to the topics listed
24
+
25
+ After generating the tweets, use the opentweet_create_tweet tool to save each one as a draft with an appropriate category. Then I can review and schedule them.
26
+
27
+ Format each tweet clearly with the day and tweet number.`,
28
+ },
29
+ }],
30
+ }));
31
+ server.prompt('review_and_schedule_drafts', 'Review your current drafts and suggest optimal scheduling times', {}, () => ({
32
+ messages: [{
33
+ role: 'user',
34
+ content: {
35
+ type: 'text',
36
+ text: `Please help me review and schedule my draft tweets.
37
+
38
+ 1. First, use opentweet_list_tweets with status "draft" to see all my drafts
39
+ 2. Then use opentweet_get_analytics with type "best_times" to find my optimal posting times
40
+ 3. Review each draft for quality - suggest any improvements
41
+ 4. Propose a schedule that spreads the tweets across the next few days at optimal times
42
+ 5. After I approve, use opentweet_batch_schedule to schedule them all
43
+
44
+ Show me the drafts and your recommended schedule before taking action.`,
45
+ },
46
+ }],
47
+ }));
48
+ server.prompt('content_from_url', 'Generate tweets from a URL/article/topic', {
49
+ source: z.string().describe('URL, article title, or topic to generate tweets about'),
50
+ count: z.string().optional().describe('Number of tweets to generate (default "5")'),
51
+ style: z.string().optional().describe('Additional style instructions (e.g. "include statistics", "ask questions")'),
52
+ }, ({ source, count = '5', style }) => ({
53
+ messages: [{
54
+ role: 'user',
55
+ content: {
56
+ type: 'text',
57
+ text: `Generate ${count} engaging tweets about: ${source}
58
+
59
+ ${style ? `Style: ${style}\n` : ''}
60
+ Each tweet should:
61
+ - Be under 280 characters
62
+ - Have a unique angle or perspective
63
+ - Be engaging and shareable
64
+ - Include relevant hashtags where appropriate
65
+
66
+ After generating them, use opentweet_create_tweet to save each as a draft so I can review and schedule them.`,
67
+ },
68
+ }],
69
+ }));
70
+ server.prompt('performance_review', 'Analyze your recent tweet performance and get improvement suggestions', {}, () => ({
71
+ messages: [{
72
+ role: 'user',
73
+ content: {
74
+ type: 'text',
75
+ text: `Analyze my Twitter/X performance and give me actionable suggestions.
76
+
77
+ 1. Use opentweet_get_analytics with type "overview" to get my posting stats and streaks
78
+ 2. Use opentweet_get_analytics with type "best_times" to see optimal posting times
79
+ 3. Use opentweet_get_analytics with type "tweets" to see per-tweet engagement (if available)
80
+ 4. Use opentweet_get_followers to check follower growth trends
81
+
82
+ Based on the data, tell me:
83
+ - How consistent am I with posting?
84
+ - What categories/topics perform best?
85
+ - Am I posting at optimal times?
86
+ - What's my streak status and how can I maintain it?
87
+ - Specific actionable tips to improve engagement
88
+ - Any concerning trends I should address`,
89
+ },
90
+ }],
91
+ }));
92
+ }
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,MAAM,CACX,qBAAqB,EACrB,kEAAkE,EAClE;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+EAA+E,CAAC;QAC5G,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC1F,QAAQ,CAAC,6BAA6B,CAAC;QAC1C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;KACzF,EACD,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,cAAc,EAAE,cAAc,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5D,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;UAEN,MAAM;QACR,IAAI;kBACM,cAAc;;iDAEiB,cAAc;;;;;;;;yDAQN;iBAChD;aACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,4BAA4B,EAC5B,iEAAiE,EACjE,EAAE,EACF,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;uEAQuD;iBAC9D;aACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,kBAAkB,EAClB,0CAA0C,EAC1C;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;QACpF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACnF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;KACpH,EACD,CAAC,EAAE,MAAM,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACnC,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,YAAY,KAAK,2BAA2B,MAAM;;EAEhE,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE;;;;;;;6GAO2E;iBACpG;aACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,oBAAoB,EACpB,uEAAuE,EACvE,EAAE,EACF,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;;;yCAayB;iBAChC;aACF,CAAC;KACH,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { OpenTweetClient } from '../api-client.js';
3
+ export declare function registerResources(server: McpServer, client: OpenTweetClient): void;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,QA4E3E"}
@@ -0,0 +1,55 @@
1
+ export function registerResources(server, client) {
2
+ server.resource('account-status', 'opentweet://account', {
3
+ description: 'Your OpenTweet account status: subscription plan, daily limits, and post counts',
4
+ mimeType: 'application/json',
5
+ }, async () => {
6
+ const data = await client.getAccountStatus();
7
+ return {
8
+ contents: [{
9
+ uri: 'opentweet://account',
10
+ mimeType: 'application/json',
11
+ text: JSON.stringify(data, null, 2),
12
+ }],
13
+ };
14
+ });
15
+ server.resource('scheduled-tweets', 'opentweet://posts/scheduled', {
16
+ description: 'All your currently scheduled tweets (upcoming posts waiting to be published)',
17
+ mimeType: 'application/json',
18
+ }, async () => {
19
+ const data = await client.listPosts({ status: 'scheduled', limit: 100 });
20
+ return {
21
+ contents: [{
22
+ uri: 'opentweet://posts/scheduled',
23
+ mimeType: 'application/json',
24
+ text: JSON.stringify(data, null, 2),
25
+ }],
26
+ };
27
+ });
28
+ server.resource('draft-tweets', 'opentweet://posts/drafts', {
29
+ description: 'All your draft tweets (saved but not yet scheduled)',
30
+ mimeType: 'application/json',
31
+ }, async () => {
32
+ const data = await client.listPosts({ status: 'draft', limit: 100 });
33
+ return {
34
+ contents: [{
35
+ uri: 'opentweet://posts/drafts',
36
+ mimeType: 'application/json',
37
+ text: JSON.stringify(data, null, 2),
38
+ }],
39
+ };
40
+ });
41
+ server.resource('analytics-summary', 'opentweet://analytics/summary', {
42
+ description: 'Your posting analytics: stats, streaks, trends, and category breakdown',
43
+ mimeType: 'application/json',
44
+ }, async () => {
45
+ const data = await client.getAnalyticsOverview();
46
+ return {
47
+ contents: [{
48
+ uri: 'opentweet://analytics/summary',
49
+ mimeType: 'application/json',
50
+ text: JSON.stringify(data, null, 2),
51
+ }],
52
+ };
53
+ });
54
+ }
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAuB;IAC1E,MAAM,CAAC,QAAQ,CACb,gBAAgB,EAChB,qBAAqB,EACrB;QACE,WAAW,EAAE,iFAAiF;QAC9F,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC7C,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,qBAAqB;oBAC1B,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,kBAAkB,EAClB,6BAA6B,EAC7B;QACE,WAAW,EAAE,8EAA8E;QAC3F,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACzE,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,6BAA6B;oBAClC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,0BAA0B,EAC1B;QACE,WAAW,EAAE,qDAAqD;QAClE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACrE,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,0BAA0B;oBAC/B,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,mBAAmB,EACnB,+BAA+B,EAC/B;QACE,WAAW,EAAE,wEAAwE;QACrF,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,oBAAoB,EAAE,CAAC;QACjD,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,+BAA+B;oBACpC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { OpenTweetClient } from '../api-client.js';
3
+ export declare function registerAccountTools(server: McpServer, client: OpenTweetClient): void;
4
+ //# sourceMappingURL=account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/tools/account.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,QA4C9E"}
@@ -0,0 +1,38 @@
1
+ export function registerAccountTools(server, client) {
2
+ server.tool('opentweet_get_account', 'Get your OpenTweet account status including subscription plan, daily posting limits, and post counts.', {}, async () => {
3
+ try {
4
+ const data = await client.getAccountStatus();
5
+ const { subscription: sub, limits, stats } = data;
6
+ let text = `OpenTweet Account Status\n\n`;
7
+ text += `Subscription:\n`;
8
+ text += ` Status: ${sub.status}\n`;
9
+ text += ` Has access: ${sub.has_access ? 'Yes' : 'No'}\n`;
10
+ if (sub.is_trialing) {
11
+ text += ` Trial: Active (ends ${sub.trial_ends_at})\n`;
12
+ }
13
+ if (sub.current_period_ends_at) {
14
+ text += ` Current period ends: ${sub.current_period_ends_at}\n`;
15
+ }
16
+ if (limits) {
17
+ text += `\nDaily Limits:\n`;
18
+ text += ` Can post: ${limits.can_post ? 'Yes' : 'No'}\n`;
19
+ text += ` Posted today: ${limits.posts_published_today}\n`;
20
+ text += ` Remaining today: ${limits.remaining_posts_today}\n`;
21
+ text += ` Daily limit: ${limits.daily_limit}\n`;
22
+ }
23
+ text += `\nPost Counts:\n`;
24
+ text += ` Total: ${stats.total_posts}\n`;
25
+ text += ` Scheduled: ${stats.scheduled_posts}\n`;
26
+ text += ` Posted: ${stats.posted_posts}\n`;
27
+ text += ` Drafts: ${stats.draft_posts}`;
28
+ return { content: [{ type: 'text', text }] };
29
+ }
30
+ catch (error) {
31
+ return {
32
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
33
+ isError: true,
34
+ };
35
+ }
36
+ });
37
+ }
38
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/tools/account.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,MAAuB;IAC7E,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,uGAAuG,EACvG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAC7C,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;YAElD,IAAI,IAAI,GAAG,8BAA8B,CAAC;YAC1C,IAAI,IAAI,iBAAiB,CAAC;YAC1B,IAAI,IAAI,aAAa,GAAG,CAAC,MAAM,IAAI,CAAC;YACpC,IAAI,IAAI,iBAAiB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;YAC3D,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,IAAI,IAAI,yBAAyB,GAAG,CAAC,aAAa,KAAK,CAAC;YAC1D,CAAC;YACD,IAAI,GAAG,CAAC,sBAAsB,EAAE,CAAC;gBAC/B,IAAI,IAAI,0BAA0B,GAAG,CAAC,sBAAsB,IAAI,CAAC;YACnE,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,IAAI,mBAAmB,CAAC;gBAC5B,IAAI,IAAI,eAAe,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBAC1D,IAAI,IAAI,mBAAmB,MAAM,CAAC,qBAAqB,IAAI,CAAC;gBAC5D,IAAI,IAAI,sBAAsB,MAAM,CAAC,qBAAqB,IAAI,CAAC;gBAC/D,IAAI,IAAI,kBAAkB,MAAM,CAAC,WAAW,IAAI,CAAC;YACnD,CAAC;YAED,IAAI,IAAI,kBAAkB,CAAC;YAC3B,IAAI,IAAI,YAAY,KAAK,CAAC,WAAW,IAAI,CAAC;YAC1C,IAAI,IAAI,gBAAgB,KAAK,CAAC,eAAe,IAAI,CAAC;YAClD,IAAI,IAAI,aAAa,KAAK,CAAC,YAAY,IAAI,CAAC;YAC5C,IAAI,IAAI,aAAa,KAAK,CAAC,WAAW,EAAE,CAAC;YAEzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAW,KAAe,CAAC,OAAO,EAAE,EAAE,CAAC;gBAChF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { OpenTweetClient } from '../api-client.js';
3
+ export declare function registerAnalyticsTools(server: McpServer, client: OpenTweetClient): void;
4
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/tools/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,QA+GhF"}