@chirpie/mcp 1.0.12 → 1.0.14

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 (3) hide show
  1. package/README.md +139 -0
  2. package/dist/index.js +162 -240
  3. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # @chirpie/mcp
2
+
3
+ **Give your AI agent a voice on social media.** Chirpie is one API for X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile and Snapchat — posting, threads, scheduling, deletion and analytics. This MCP server puts all of it in front of Claude, Cursor, ChatGPT or any other MCP-capable agent, so "post this to X and LinkedIn, and schedule the follow-up for 9am" is a single sentence rather than a pile of platform SDKs, OAuth dances and rate-limit handling.
4
+
5
+ ## Hosted server (recommended)
6
+
7
+ You don't need to install anything. Point your client at:
8
+
9
+ ```
10
+ https://chirpie.ai/mcp
11
+ ```
12
+
13
+ Sign in when prompted and you're connected — no API key to copy, nothing to keep up to date.
14
+
15
+ **Claude Code**
16
+
17
+ ```bash
18
+ claude mcp add --transport http chirpie https://chirpie.ai/mcp
19
+ ```
20
+
21
+ **Claude** — Settings → Connectors → Add custom connector → `https://chirpie.ai/mcp`
22
+
23
+ **Cursor** — add to `.cursor/mcp.json`:
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "chirpie": {
29
+ "url": "https://chirpie.ai/mcp"
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ **ChatGPT** — Settings → Connectors → Create → MCP server → `https://chirpie.ai/mcp`
36
+
37
+ Prefer a key over OAuth (CI, scripts, clients without an OAuth flow)? Send it as a header:
38
+
39
+ ```json
40
+ {
41
+ "mcpServers": {
42
+ "chirpie": {
43
+ "type": "http",
44
+ "url": "https://chirpie.ai/mcp",
45
+ "headers": { "Authorization": "Bearer chirpie_sk_your_key_here" }
46
+ }
47
+ }
48
+ }
49
+ ```
50
+
51
+ ## Local server (this package)
52
+
53
+ Run the same tool set locally over stdio.
54
+
55
+ ```bash
56
+ npm install -g chirpie
57
+ chirpie login
58
+ ```
59
+
60
+ **Claude Code**
61
+
62
+ ```bash
63
+ claude mcp add chirpie -- npx @chirpie/mcp
64
+ ```
65
+
66
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json`:
67
+
68
+ ```json
69
+ {
70
+ "mcpServers": {
71
+ "chirpie": {
72
+ "command": "npx",
73
+ "args": ["@chirpie/mcp"]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ **Cursor** — add to your MCP settings:
80
+
81
+ ```json
82
+ {
83
+ "mcpServers": {
84
+ "chirpie": {
85
+ "command": "npx",
86
+ "args": ["@chirpie/mcp"]
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ The local server resolves credentials in this order:
93
+
94
+ 1. `CHIRPIE_API_KEY` environment variable
95
+ 2. `~/.chirpie/config.json` (written by `chirpie login`)
96
+
97
+ The CLI and this server share that config, so one `chirpie login` covers both.
98
+
99
+ ## Tools
100
+
101
+ | Tool | What it does |
102
+ |------|--------------|
103
+ | `chirpie_post` | Post to any connected account, now or scheduled |
104
+ | `chirpie_thread` | Post a 2–25 part thread |
105
+ | `chirpie_list_posts` | List posts, filtered by status or account |
106
+ | `chirpie_get_post` | Fetch one post |
107
+ | `chirpie_delete_post` | Delete a post (and remove it from the platform) |
108
+ | `chirpie_list_accounts` | List connected social accounts |
109
+ | `chirpie_analytics` | Engagement metrics for a published post |
110
+ | `chirpie_create_key` | Create an API key |
111
+ | `chirpie_list_keys` | List API keys |
112
+ | `chirpie_revoke_key` | Revoke an API key |
113
+ | `chirpie_connect_x` | Connect X/Twitter (returns an authorization link) |
114
+ | `chirpie_connect_linkedin` | Connect LinkedIn |
115
+ | `chirpie_connect_threads` | Connect Threads |
116
+ | `chirpie_connect_instagram` | Connect Instagram |
117
+ | `chirpie_connect_facebook` | Connect a Facebook Page |
118
+ | `chirpie_connect_bluesky` | Connect Bluesky with an app password |
119
+ | `chirpie_connect_mastodon` | Connect Mastodon on any instance |
120
+ | `chirpie_connect_telegram` | Connect a Telegram bot |
121
+
122
+ The hosted and local servers expose exactly the same tools.
123
+
124
+ ## Try it
125
+
126
+ Once connected, ask your agent:
127
+
128
+ - "Post to X and LinkedIn: we just shipped v2."
129
+ - "Draft a 5-post thread about why we moved off cron, and schedule it for 9am tomorrow."
130
+ - "How did my last Bluesky post do?"
131
+ - "Connect my X account."
132
+
133
+ ## Links
134
+
135
+ - Docs — https://chirpie.ai/docs/mcp
136
+ - API reference — https://chirpie.ai/docs
137
+ - Dashboard — https://chirpie.ai/dashboard
138
+
139
+ MIT © Fireflo LLC
package/dist/index.js CHANGED
@@ -3,191 +3,23 @@
3
3
  // src/index.ts
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
- import { ChirpieClient, ChirpieApiError, getConfig } from "@chirpie/sdk";
6
+ import { ChirpieClient, getConfig } from "@chirpie/sdk";
7
+
8
+ // ../mcp-core/src/tools.ts
7
9
  import { z } from "zod";
8
- var config = getConfig();
9
- var client = config ? new ChirpieClient({ apiKey: config.api_key, baseUrl: config.base_url }) : null;
10
- function requireClient() {
11
- if (!client) {
12
- throw new Error(
13
- "Not authenticated. Run `chirpie login` or set CHIRPIE_API_KEY environment variable."
14
- );
15
- }
16
- return client;
17
- }
18
10
  function formatResult(data) {
19
11
  return {
20
12
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
21
13
  };
22
14
  }
23
15
  function formatError(err) {
24
- const message = err instanceof ChirpieApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : "Unknown error";
16
+ const apiErr = err;
17
+ const message = apiErr && typeof apiErr.code === "string" && typeof apiErr.message === "string" ? `${apiErr.code}: ${apiErr.message}` : err instanceof Error ? err.message : "Unknown error";
25
18
  return {
26
19
  content: [{ type: "text", text: message }],
27
20
  isError: true
28
21
  };
29
22
  }
30
- var SERVER_VERSION = true ? "1.0.12" : "dev";
31
- var server = new McpServer({
32
- name: "chirpie",
33
- version: SERVER_VERSION
34
- });
35
- server.tool(
36
- "chirpie_post",
37
- "Create a post on X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat with optional media. Posts immediately or at a scheduled time. Note: Instagram, Pinterest, TikTok, YouTube, and Snapchat REQUIRE media.",
38
- {
39
- account_id: z.string().describe("Account ID to post from (X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat)"),
40
- text: z.string().max(63206).describe("Post text (max 280 chars for standard X, 25,000 for X Premium, 300 for Bluesky, 3,000 for LinkedIn, 500 for Threads, 500 for Mastodon, 2,200 for Instagram, 63,206 for Facebook, 4,096 for Telegram, 40,000 for Reddit, 500 for Pinterest, 2,200 for TikTok, 5,000 for YouTube, 1,500 for Google Business Profile, 160 for Snapchat)"),
41
- media_urls: z.array(z.string()).max(10).optional().describe("Public image URLs. X supports images + video (max 4); Bluesky supports images only (~1MB each, max 4); LinkedIn supports images (JPEG, PNG, GIF up to 8MB each, max 4). Threads supports one image per post. Mastodon supports images + video (max 4). Instagram REQUIRES at least 1 image (max 10 for carousel). Facebook supports images (max 4). Telegram supports images + video. Reddit supports images (max 1). Pinterest REQUIRES 1 image. TikTok REQUIRES video or photo. YouTube REQUIRES video. Google Business Profile supports images (max 1). Snapchat REQUIRES media (image or video)."),
42
- schedule_at: z.string().optional().describe("ISO 8601 datetime (UTC) to schedule the post. Scheduled posts publish within ~5 minutes of this time.")
43
- },
44
- async ({ account_id, text, media_urls, schedule_at }) => {
45
- try {
46
- const result = await requireClient().createPost({ account_id, text, media_urls, schedule_at });
47
- return formatResult(result);
48
- } catch (err) {
49
- return formatError(err);
50
- }
51
- }
52
- );
53
- server.tool(
54
- "chirpie_thread",
55
- "Create a thread (multiple posts) on X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat. X, Bluesky, Threads, Mastodon, and Telegram support native reply threading. Reddit threads via comments. Others degrade gracefully to standalone posts.",
56
- {
57
- account_id: z.string().describe("Account ID to post from (X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat). Some platforms degrade to standalone posts."),
58
- posts: z.array(z.object({
59
- text: z.string().max(63206).describe("Post text (max 280 chars for standard X, 25,000 for X Premium, 300 for Bluesky, 3,000 for LinkedIn, 500 for Threads, 500 for Mastodon, 2,200 for Instagram, 63,206 for Facebook, 4,096 for Telegram, 40,000 for Reddit, 500 for Pinterest, 2,200 for TikTok, 5,000 for YouTube, 1,500 for Google Business Profile, 160 for Snapchat)"),
60
- media_urls: z.array(z.string()).max(10).optional().describe("Public image URLs (Bluesky: images only, ~1MB each, max 4; X: images + video, max 4; LinkedIn: images up to 8MB each, max 4; Threads: 1 image per post; Mastodon: images + video, max 4; Instagram: requires images, max 10; Facebook: images, max 4; Telegram: images + video; Reddit: 1 image; Pinterest: requires 1 image; TikTok: requires video/photo; YouTube: requires video; Google Business Profile: 1 image; Snapchat: requires media)")
61
- })).min(2).max(25).describe("Array of posts in the thread"),
62
- schedule_at: z.string().optional().describe("ISO 8601 datetime (UTC) to schedule the thread. Scheduled threads publish within ~5 minutes of this time.")
63
- },
64
- async ({ account_id, posts, schedule_at }) => {
65
- try {
66
- const result = await requireClient().createThread({ account_id, posts, schedule_at });
67
- return formatResult(result);
68
- } catch (err) {
69
- return formatError(err);
70
- }
71
- }
72
- );
73
- server.tool(
74
- "chirpie_list_posts",
75
- "List recent posts. Filter by status or account.",
76
- {
77
- status: z.string().optional().describe("Filter: draft, scheduled, published, failed"),
78
- account_id: z.string().optional().describe("Filter by account ID"),
79
- limit: z.number().optional().describe("Max results (default 20)")
80
- },
81
- async ({ status, account_id, limit }) => {
82
- try {
83
- const result = await requireClient().listPosts({ status, account_id, limit });
84
- return formatResult(result);
85
- } catch (err) {
86
- return formatError(err);
87
- }
88
- }
89
- );
90
- server.tool(
91
- "chirpie_get_post",
92
- "Get a single post by ID.",
93
- {
94
- id: z.string().describe("Post ID")
95
- },
96
- async ({ id }) => {
97
- try {
98
- const result = await requireClient().getPost(id);
99
- return formatResult(result);
100
- } catch (err) {
101
- return formatError(err);
102
- }
103
- }
104
- );
105
- server.tool(
106
- "chirpie_delete_post",
107
- "Delete a post. Also deletes from the platform (X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, YouTube, Google Business Profile, or Snapchat) if published. Note: TikTok does not support deletion via API.",
108
- {
109
- id: z.string().describe("Post ID to delete")
110
- },
111
- async ({ id }) => {
112
- try {
113
- const result = await requireClient().deletePost(id);
114
- return formatResult(result);
115
- } catch (err) {
116
- return formatError(err);
117
- }
118
- }
119
- );
120
- server.tool(
121
- "chirpie_list_accounts",
122
- "List connected social accounts (X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, and Snapchat).",
123
- {},
124
- async () => {
125
- try {
126
- const result = await requireClient().listAccounts();
127
- return formatResult(result);
128
- } catch (err) {
129
- return formatError(err);
130
- }
131
- }
132
- );
133
- server.tool(
134
- "chirpie_analytics",
135
- "Get analytics (likes, reposts, replies, etc.) for a published post on X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Reddit, Pinterest, TikTok, YouTube, or Google Business Profile. Note: Telegram and Snapchat do not expose analytics.",
136
- {
137
- post_id: z.string().describe("Post ID to get analytics for")
138
- },
139
- async ({ post_id }) => {
140
- try {
141
- const result = await requireClient().getPostAnalytics(post_id);
142
- return formatResult(result);
143
- } catch (err) {
144
- return formatError(err);
145
- }
146
- }
147
- );
148
- server.tool(
149
- "chirpie_create_key",
150
- "Create a new Chirpie API key. Returns the full key once \u2014 store it securely. Keys are prefixed `chirpie_sk_` and never re-shown by the API.",
151
- {
152
- name: z.string().optional().describe("Friendly name for the key (default: 'Default')")
153
- },
154
- async ({ name }) => {
155
- try {
156
- const result = await requireClient().createKey(name);
157
- return formatResult(result);
158
- } catch (err) {
159
- return formatError(err);
160
- }
161
- }
162
- );
163
- server.tool(
164
- "chirpie_list_keys",
165
- "List the user's Chirpie API keys (prefix + metadata; the full key is only shown on creation).",
166
- {},
167
- async () => {
168
- try {
169
- const result = await requireClient().listKeys();
170
- return formatResult(result);
171
- } catch (err) {
172
- return formatError(err);
173
- }
174
- }
175
- );
176
- server.tool(
177
- "chirpie_revoke_key",
178
- "Revoke a Chirpie API key by its ID. Revocation is permanent and immediate.",
179
- {
180
- id: z.string().describe("API key ID to revoke")
181
- },
182
- async ({ id }) => {
183
- try {
184
- const result = await requireClient().revokeKey(id);
185
- return formatResult(result);
186
- } catch (err) {
187
- return formatError(err);
188
- }
189
- }
190
- );
191
23
  var oauthConnectTools = [
192
24
  { name: "chirpie_connect_x", label: "X/Twitter", method: "connectXAccount" },
193
25
  { name: "chirpie_connect_linkedin", label: "LinkedIn", method: "connectLinkedInAccount" },
@@ -201,80 +33,170 @@ var oauthConnectTools = [
201
33
  // { name: "chirpie_connect_google_business", label: "Google Business Profile", method: "connectGBPAccount" },
202
34
  // { name: "chirpie_connect_snapchat", label: "Snapchat", method: "connectSnapchatAccount" },
203
35
  ];
204
- for (const { name, label, method } of oauthConnectTools) {
205
- server.tool(
206
- name,
207
- `Start the OAuth flow for a ${label} account. Returns an authorization_url the user must open in a browser to complete the connection.`,
208
- {},
209
- async () => {
210
- try {
211
- const fn = requireClient()[method];
212
- const result = await fn.call(requireClient());
213
- return formatResult(result);
214
- } catch (err) {
215
- return formatError(err);
216
- }
217
- }
218
- );
219
- }
220
- server.tool(
221
- "chirpie_connect_bluesky",
222
- "Connect a Bluesky account using an app password (create one at https://bsky.app/settings/app-passwords).",
223
- {
224
- identifier: z.string().describe("Bluesky handle (e.g. user.bsky.social)"),
225
- app_password: z.string().describe("Bluesky app password")
226
- },
227
- async ({ identifier, app_password }) => {
36
+ function registerChirpieTools(server2, resolveClient) {
37
+ const run = async (fn) => {
228
38
  try {
229
- const result = await requireClient().connectBlueskyAccount({
230
- platform: "bluesky",
231
- identifier,
232
- app_password
233
- });
234
- return formatResult(result);
39
+ const client2 = await resolveClient();
40
+ return formatResult(await fn(client2));
235
41
  } catch (err) {
236
42
  return formatError(err);
237
43
  }
44
+ };
45
+ server2.tool(
46
+ "chirpie_post",
47
+ "Create a post on X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat with optional media. Posts immediately or at a scheduled time. Note: Instagram, Pinterest, TikTok, YouTube, and Snapchat REQUIRE media.",
48
+ {
49
+ account_id: z.string().describe("Account ID to post from (X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat)"),
50
+ text: z.string().max(63206).describe("Post text (max 280 chars for standard X, 25,000 for X Premium, 300 for Bluesky, 3,000 for LinkedIn, 500 for Threads, 500 for Mastodon, 2,200 for Instagram, 63,206 for Facebook, 4,096 for Telegram, 40,000 for Reddit, 500 for Pinterest, 2,200 for TikTok, 5,000 for YouTube, 1,500 for Google Business Profile, 160 for Snapchat)"),
51
+ media_urls: z.array(z.string()).max(10).optional().describe("Public image URLs. X supports images + video (max 4); Bluesky supports images only (~1MB each, max 4); LinkedIn supports images (JPEG, PNG, GIF up to 8MB each, max 4). Threads supports one image per post. Mastodon supports images + video (max 4). Instagram REQUIRES at least 1 image (max 10 for carousel). Facebook supports images (max 4). Telegram supports images + video. Reddit supports images (max 1). Pinterest REQUIRES 1 image. TikTok REQUIRES video or photo. YouTube REQUIRES video. Google Business Profile supports images (max 1). Snapchat REQUIRES media (image or video)."),
52
+ schedule_at: z.string().optional().describe("ISO 8601 datetime (UTC) to schedule the post. Scheduled posts publish within ~5 minutes of this time.")
53
+ },
54
+ async ({ account_id, text, media_urls, schedule_at }) => run((c) => c.createPost({ account_id, text, media_urls, schedule_at }))
55
+ );
56
+ server2.tool(
57
+ "chirpie_thread",
58
+ "Create a thread (multiple posts) on X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat. X, Bluesky, Threads, Mastodon, and Telegram support native reply threading. Reddit threads via comments. Others degrade gracefully to standalone posts.",
59
+ {
60
+ account_id: z.string().describe("Account ID to post from (X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, or Snapchat). Some platforms degrade to standalone posts."),
61
+ posts: z.array(z.object({
62
+ text: z.string().max(63206).describe("Post text (max 280 chars for standard X, 25,000 for X Premium, 300 for Bluesky, 3,000 for LinkedIn, 500 for Threads, 500 for Mastodon, 2,200 for Instagram, 63,206 for Facebook, 4,096 for Telegram, 40,000 for Reddit, 500 for Pinterest, 2,200 for TikTok, 5,000 for YouTube, 1,500 for Google Business Profile, 160 for Snapchat)"),
63
+ media_urls: z.array(z.string()).max(10).optional().describe("Public image URLs (Bluesky: images only, ~1MB each, max 4; X: images + video, max 4; LinkedIn: images up to 8MB each, max 4; Threads: 1 image per post; Mastodon: images + video, max 4; Instagram: requires images, max 10; Facebook: images, max 4; Telegram: images + video; Reddit: 1 image; Pinterest: requires 1 image; TikTok: requires video/photo; YouTube: requires video; Google Business Profile: 1 image; Snapchat: requires media)")
64
+ })).min(2).max(25).describe("Array of posts in the thread"),
65
+ schedule_at: z.string().optional().describe("ISO 8601 datetime (UTC) to schedule the thread. Scheduled threads publish within ~5 minutes of this time.")
66
+ },
67
+ async ({ account_id, posts, schedule_at }) => run((c) => c.createThread({ account_id, posts, schedule_at }))
68
+ );
69
+ server2.tool(
70
+ "chirpie_list_posts",
71
+ "List recent posts. Filter by status or account.",
72
+ {
73
+ status: z.string().optional().describe("Filter: draft, scheduled, published, failed"),
74
+ account_id: z.string().optional().describe("Filter by account ID"),
75
+ limit: z.number().optional().describe("Max results (default 20)")
76
+ },
77
+ async ({ status, account_id, limit }) => run((c) => c.listPosts({ status, account_id, limit }))
78
+ );
79
+ server2.tool(
80
+ "chirpie_get_post",
81
+ "Get a single post by ID.",
82
+ {
83
+ id: z.string().describe("Post ID")
84
+ },
85
+ async ({ id }) => run((c) => c.getPost(id))
86
+ );
87
+ server2.tool(
88
+ "chirpie_delete_post",
89
+ "Delete a post. Also deletes from the platform (X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, YouTube, Google Business Profile, or Snapchat) if published. Note: TikTok does not support deletion via API.",
90
+ {
91
+ id: z.string().describe("Post ID to delete")
92
+ },
93
+ async ({ id }) => run((c) => c.deletePost(id))
94
+ );
95
+ server2.tool(
96
+ "chirpie_list_accounts",
97
+ "List connected social accounts (X/Twitter, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Telegram, Reddit, Pinterest, TikTok, YouTube, Google Business Profile, and Snapchat).",
98
+ {},
99
+ async () => run((c) => c.listAccounts())
100
+ );
101
+ server2.tool(
102
+ "chirpie_analytics",
103
+ "Get analytics (likes, reposts, replies, etc.) for a published post on X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook, Reddit, Pinterest, TikTok, YouTube, or Google Business Profile. Note: Telegram and Snapchat do not expose analytics.",
104
+ {
105
+ post_id: z.string().describe("Post ID to get analytics for")
106
+ },
107
+ async ({ post_id }) => run((c) => c.getPostAnalytics(post_id))
108
+ );
109
+ server2.tool(
110
+ "chirpie_create_key",
111
+ "Create a new Chirpie API key. Returns the full key once \u2014 store it securely. Keys are prefixed `chirpie_sk_` and never re-shown by the API.",
112
+ {
113
+ name: z.string().optional().describe("Friendly name for the key (default: 'Default')")
114
+ },
115
+ async ({ name }) => run((c) => c.createKey(name))
116
+ );
117
+ server2.tool(
118
+ "chirpie_list_keys",
119
+ "List the user's Chirpie API keys (prefix + metadata; the full key is only shown on creation).",
120
+ {},
121
+ async () => run((c) => c.listKeys())
122
+ );
123
+ server2.tool(
124
+ "chirpie_revoke_key",
125
+ "Revoke a Chirpie API key by its ID. Revocation is permanent and immediate.",
126
+ {
127
+ id: z.string().describe("API key ID to revoke")
128
+ },
129
+ async ({ id }) => run((c) => c.revokeKey(id))
130
+ );
131
+ for (const { name, label, method } of oauthConnectTools) {
132
+ server2.tool(
133
+ name,
134
+ `Start the OAuth flow for a ${label} account. Returns an authorization_url the user must open in a browser to complete the connection.`,
135
+ {},
136
+ async () => run((c) => c[method].call(c))
137
+ );
238
138
  }
239
- );
240
- server.tool(
139
+ server2.tool(
140
+ "chirpie_connect_bluesky",
141
+ "Connect a Bluesky account using an app password (create one at https://bsky.app/settings/app-passwords).",
142
+ {
143
+ identifier: z.string().describe("Bluesky handle (e.g. user.bsky.social)"),
144
+ app_password: z.string().describe("Bluesky app password")
145
+ },
146
+ async ({ identifier, app_password }) => run((c) => c.connectBlueskyAccount({ platform: "bluesky", identifier, app_password }))
147
+ );
148
+ server2.tool(
149
+ "chirpie_connect_mastodon",
150
+ "Start the OAuth flow for a Mastodon account on a specific instance.",
151
+ {
152
+ instance_url: z.string().describe("Mastodon instance URL (e.g. https://mastodon.social)")
153
+ },
154
+ async ({ instance_url }) => run((c) => c.connectMastodonAccount({ platform: "mastodon", instance_url }))
155
+ );
156
+ server2.tool(
157
+ "chirpie_connect_telegram",
158
+ "Connect a Telegram bot. Create a bot with @BotFather on Telegram, then pass the bot token and the chat ID (user, group, or channel).",
159
+ {
160
+ bot_token: z.string().describe("Bot token from @BotFather"),
161
+ chat_id: z.string().describe("Target chat ID (user, group, or channel)")
162
+ },
163
+ async ({ bot_token, chat_id }) => run((c) => c.connectTelegramAccount({ platform: "telegram", bot_token, chat_id }))
164
+ );
165
+ }
166
+ var CHIRPIE_TOOL_NAMES = [
167
+ "chirpie_post",
168
+ "chirpie_thread",
169
+ "chirpie_list_posts",
170
+ "chirpie_get_post",
171
+ "chirpie_delete_post",
172
+ "chirpie_list_accounts",
173
+ "chirpie_analytics",
174
+ "chirpie_create_key",
175
+ "chirpie_list_keys",
176
+ "chirpie_revoke_key",
177
+ ...oauthConnectTools.map((t) => t.name),
178
+ "chirpie_connect_bluesky",
241
179
  "chirpie_connect_mastodon",
242
- "Start the OAuth flow for a Mastodon account on a specific instance.",
243
- {
244
- instance_url: z.string().describe("Mastodon instance URL (e.g. https://mastodon.social)")
245
- },
246
- async ({ instance_url }) => {
247
- try {
248
- const result = await requireClient().connectMastodonAccount({
249
- platform: "mastodon",
250
- instance_url
251
- });
252
- return formatResult(result);
253
- } catch (err) {
254
- return formatError(err);
255
- }
256
- }
257
- );
258
- server.tool(
259
- "chirpie_connect_telegram",
260
- "Connect a Telegram bot. Create a bot with @BotFather on Telegram, then pass the bot token and the chat ID (user, group, or channel).",
261
- {
262
- bot_token: z.string().describe("Bot token from @BotFather"),
263
- chat_id: z.string().describe("Target chat ID (user, group, or channel)")
264
- },
265
- async ({ bot_token, chat_id }) => {
266
- try {
267
- const result = await requireClient().connectTelegramAccount({
268
- platform: "telegram",
269
- bot_token,
270
- chat_id
271
- });
272
- return formatResult(result);
273
- } catch (err) {
274
- return formatError(err);
275
- }
180
+ "chirpie_connect_telegram"
181
+ ];
182
+
183
+ // src/index.ts
184
+ var config = getConfig();
185
+ var client = config ? new ChirpieClient({ apiKey: config.api_key, baseUrl: config.base_url }) : null;
186
+ function requireClient() {
187
+ if (!client) {
188
+ throw new Error(
189
+ "Not authenticated. Run `chirpie login` or set CHIRPIE_API_KEY environment variable."
190
+ );
276
191
  }
277
- );
192
+ return client;
193
+ }
194
+ var SERVER_VERSION = true ? "1.0.14" : "dev";
195
+ var server = new McpServer({
196
+ name: "chirpie",
197
+ version: SERVER_VERSION
198
+ });
199
+ registerChirpieTools(server, requireClient);
278
200
  var transport = new StdioServerTransport();
279
201
  server.connect(transport).catch((err) => {
280
202
  console.error("Failed to start Chirpie MCP server:", err);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chirpie/mcp",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "mcpName": "io.github.firefloco/chirpie",
5
5
  "description": "Chirpie MCP server — social media tools for AI agents",
6
6
  "repository": {
@@ -52,7 +52,7 @@
52
52
  "dependencies": {
53
53
  "@chirpie/sdk": "^1.0.11",
54
54
  "@modelcontextprotocol/sdk": "^1",
55
- "zod": "^3.24.4"
55
+ "zod": "^4.3.6"
56
56
  },
57
57
  "devDependencies": {
58
58
  "tsup": "^8",