@hasna/microservices 0.0.3 → 0.0.5

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 (68) hide show
  1. package/bin/index.js +63 -0
  2. package/bin/mcp.js +63 -0
  3. package/dist/index.js +63 -0
  4. package/microservices/microservice-ads/package.json +27 -0
  5. package/microservices/microservice-ads/src/cli/index.ts +605 -0
  6. package/microservices/microservice-ads/src/db/campaigns.ts +797 -0
  7. package/microservices/microservice-ads/src/db/database.ts +93 -0
  8. package/microservices/microservice-ads/src/db/migrations.ts +60 -0
  9. package/microservices/microservice-ads/src/index.ts +39 -0
  10. package/microservices/microservice-ads/src/mcp/index.ts +480 -0
  11. package/microservices/microservice-contracts/package.json +27 -0
  12. package/microservices/microservice-contracts/src/cli/index.ts +770 -0
  13. package/microservices/microservice-contracts/src/db/contracts.ts +925 -0
  14. package/microservices/microservice-contracts/src/db/database.ts +93 -0
  15. package/microservices/microservice-contracts/src/db/migrations.ts +141 -0
  16. package/microservices/microservice-contracts/src/index.ts +43 -0
  17. package/microservices/microservice-contracts/src/mcp/index.ts +617 -0
  18. package/microservices/microservice-domains/package.json +27 -0
  19. package/microservices/microservice-domains/src/cli/index.ts +691 -0
  20. package/microservices/microservice-domains/src/db/database.ts +93 -0
  21. package/microservices/microservice-domains/src/db/domains.ts +1164 -0
  22. package/microservices/microservice-domains/src/db/migrations.ts +60 -0
  23. package/microservices/microservice-domains/src/index.ts +65 -0
  24. package/microservices/microservice-domains/src/mcp/index.ts +536 -0
  25. package/microservices/microservice-hiring/package.json +27 -0
  26. package/microservices/microservice-hiring/src/cli/index.ts +741 -0
  27. package/microservices/microservice-hiring/src/db/database.ts +93 -0
  28. package/microservices/microservice-hiring/src/db/hiring.ts +1085 -0
  29. package/microservices/microservice-hiring/src/db/migrations.ts +89 -0
  30. package/microservices/microservice-hiring/src/index.ts +80 -0
  31. package/microservices/microservice-hiring/src/lib/scoring.ts +206 -0
  32. package/microservices/microservice-hiring/src/mcp/index.ts +709 -0
  33. package/microservices/microservice-payments/package.json +27 -0
  34. package/microservices/microservice-payments/src/cli/index.ts +609 -0
  35. package/microservices/microservice-payments/src/db/database.ts +93 -0
  36. package/microservices/microservice-payments/src/db/migrations.ts +81 -0
  37. package/microservices/microservice-payments/src/db/payments.ts +1204 -0
  38. package/microservices/microservice-payments/src/index.ts +51 -0
  39. package/microservices/microservice-payments/src/mcp/index.ts +683 -0
  40. package/microservices/microservice-payroll/package.json +27 -0
  41. package/microservices/microservice-payroll/src/cli/index.ts +643 -0
  42. package/microservices/microservice-payroll/src/db/database.ts +93 -0
  43. package/microservices/microservice-payroll/src/db/migrations.ts +95 -0
  44. package/microservices/microservice-payroll/src/db/payroll.ts +1377 -0
  45. package/microservices/microservice-payroll/src/index.ts +48 -0
  46. package/microservices/microservice-payroll/src/mcp/index.ts +666 -0
  47. package/microservices/microservice-shipping/package.json +27 -0
  48. package/microservices/microservice-shipping/src/cli/index.ts +606 -0
  49. package/microservices/microservice-shipping/src/db/database.ts +93 -0
  50. package/microservices/microservice-shipping/src/db/migrations.ts +69 -0
  51. package/microservices/microservice-shipping/src/db/shipping.ts +1093 -0
  52. package/microservices/microservice-shipping/src/index.ts +53 -0
  53. package/microservices/microservice-shipping/src/mcp/index.ts +533 -0
  54. package/microservices/microservice-social/package.json +27 -0
  55. package/microservices/microservice-social/src/cli/index.ts +689 -0
  56. package/microservices/microservice-social/src/db/database.ts +93 -0
  57. package/microservices/microservice-social/src/db/migrations.ts +88 -0
  58. package/microservices/microservice-social/src/db/social.ts +1046 -0
  59. package/microservices/microservice-social/src/index.ts +46 -0
  60. package/microservices/microservice-social/src/mcp/index.ts +655 -0
  61. package/microservices/microservice-subscriptions/package.json +27 -0
  62. package/microservices/microservice-subscriptions/src/cli/index.ts +715 -0
  63. package/microservices/microservice-subscriptions/src/db/database.ts +93 -0
  64. package/microservices/microservice-subscriptions/src/db/migrations.ts +125 -0
  65. package/microservices/microservice-subscriptions/src/db/subscriptions.ts +1256 -0
  66. package/microservices/microservice-subscriptions/src/index.ts +41 -0
  67. package/microservices/microservice-subscriptions/src/mcp/index.ts +631 -0
  68. package/package.json +1 -1
@@ -0,0 +1,46 @@
1
+ /**
2
+ * microservice-social — Social media management microservice
3
+ */
4
+
5
+ export {
6
+ createAccount,
7
+ getAccount,
8
+ listAccounts,
9
+ updateAccount,
10
+ deleteAccount,
11
+ countAccounts,
12
+ createPost,
13
+ getPost,
14
+ listPosts,
15
+ updatePost,
16
+ deletePost,
17
+ countPosts,
18
+ schedulePost,
19
+ publishPost,
20
+ createTemplate,
21
+ getTemplate,
22
+ listTemplates,
23
+ deleteTemplate,
24
+ useTemplate,
25
+ getEngagementStats,
26
+ getStatsByPlatform,
27
+ getCalendar,
28
+ getOverallStats,
29
+ type Platform,
30
+ type PostStatus,
31
+ type Account,
32
+ type Post,
33
+ type Template,
34
+ type Engagement,
35
+ type EngagementStats,
36
+ type PlatformStats,
37
+ type CreateAccountInput,
38
+ type UpdateAccountInput,
39
+ type ListAccountsOptions,
40
+ type CreatePostInput,
41
+ type UpdatePostInput,
42
+ type ListPostsOptions,
43
+ type CreateTemplateInput,
44
+ } from "./db/social.js";
45
+
46
+ export { getDatabase, closeDatabase } from "./db/database.js";
@@ -0,0 +1,655 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+ import {
7
+ createAccount,
8
+ getAccount,
9
+ listAccounts,
10
+ updateAccount,
11
+ deleteAccount,
12
+ createPost,
13
+ getPost,
14
+ listPosts,
15
+ updatePost,
16
+ deletePost,
17
+ schedulePost,
18
+ publishPost,
19
+ createTemplate,
20
+ getTemplate,
21
+ listTemplates,
22
+ deleteTemplate,
23
+ useTemplate,
24
+ getEngagementStats,
25
+ getStatsByPlatform,
26
+ getCalendar,
27
+ getOverallStats,
28
+ batchSchedule,
29
+ crossPost,
30
+ getBestTimeToPost,
31
+ reschedulePost,
32
+ submitPostForReview,
33
+ approvePost,
34
+ createRecurringPost,
35
+ getHashtagStats,
36
+ PLATFORM_LIMITS,
37
+ } from "../db/social.js";
38
+
39
+ const PlatformEnum = z.enum(["x", "linkedin", "instagram", "threads", "bluesky"]);
40
+ const PostStatusEnum = z.enum(["draft", "scheduled", "published", "failed", "pending_review"]);
41
+ const RecurrenceEnum = z.enum(["daily", "weekly", "biweekly", "monthly"]);
42
+
43
+ const server = new McpServer({
44
+ name: "microservice-social",
45
+ version: "0.0.1",
46
+ });
47
+
48
+ // --- Accounts ---
49
+
50
+ server.registerTool(
51
+ "create_account",
52
+ {
53
+ title: "Create Social Account",
54
+ description: "Add a social media account.",
55
+ inputSchema: {
56
+ platform: PlatformEnum,
57
+ handle: z.string(),
58
+ display_name: z.string().optional(),
59
+ connected: z.boolean().optional(),
60
+ access_token_env: z.string().optional(),
61
+ },
62
+ },
63
+ async (params) => {
64
+ const account = createAccount(params);
65
+ return { content: [{ type: "text", text: JSON.stringify(account, null, 2) }] };
66
+ }
67
+ );
68
+
69
+ server.registerTool(
70
+ "get_account",
71
+ {
72
+ title: "Get Social Account",
73
+ description: "Get a social media account by ID.",
74
+ inputSchema: { id: z.string() },
75
+ },
76
+ async ({ id }) => {
77
+ const account = getAccount(id);
78
+ if (!account) {
79
+ return { content: [{ type: "text", text: `Account '${id}' not found.` }], isError: true };
80
+ }
81
+ return { content: [{ type: "text", text: JSON.stringify(account, null, 2) }] };
82
+ }
83
+ );
84
+
85
+ server.registerTool(
86
+ "list_accounts",
87
+ {
88
+ title: "List Social Accounts",
89
+ description: "List social media accounts with optional filters.",
90
+ inputSchema: {
91
+ platform: PlatformEnum.optional(),
92
+ connected: z.boolean().optional(),
93
+ limit: z.number().optional(),
94
+ },
95
+ },
96
+ async (params) => {
97
+ const accounts = listAccounts(params);
98
+ return {
99
+ content: [
100
+ { type: "text", text: JSON.stringify({ accounts, count: accounts.length }, null, 2) },
101
+ ],
102
+ };
103
+ }
104
+ );
105
+
106
+ server.registerTool(
107
+ "update_account",
108
+ {
109
+ title: "Update Social Account",
110
+ description: "Update a social media account.",
111
+ inputSchema: {
112
+ id: z.string(),
113
+ platform: PlatformEnum.optional(),
114
+ handle: z.string().optional(),
115
+ display_name: z.string().optional(),
116
+ connected: z.boolean().optional(),
117
+ access_token_env: z.string().optional(),
118
+ },
119
+ },
120
+ async ({ id, ...input }) => {
121
+ const account = updateAccount(id, input);
122
+ if (!account) {
123
+ return { content: [{ type: "text", text: `Account '${id}' not found.` }], isError: true };
124
+ }
125
+ return { content: [{ type: "text", text: JSON.stringify(account, null, 2) }] };
126
+ }
127
+ );
128
+
129
+ server.registerTool(
130
+ "delete_account",
131
+ {
132
+ title: "Delete Social Account",
133
+ description: "Delete a social media account by ID.",
134
+ inputSchema: { id: z.string() },
135
+ },
136
+ async ({ id }) => {
137
+ const deleted = deleteAccount(id);
138
+ return { content: [{ type: "text", text: JSON.stringify({ id, deleted }) }] };
139
+ }
140
+ );
141
+
142
+ // --- Posts ---
143
+
144
+ server.registerTool(
145
+ "create_post",
146
+ {
147
+ title: "Create Post",
148
+ description: "Create a new social media post.",
149
+ inputSchema: {
150
+ account_id: z.string(),
151
+ content: z.string(),
152
+ media_urls: z.array(z.string()).optional(),
153
+ status: PostStatusEnum.optional(),
154
+ scheduled_at: z.string().optional(),
155
+ tags: z.array(z.string()).optional(),
156
+ },
157
+ },
158
+ async (params) => {
159
+ const post = createPost(params);
160
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
161
+ }
162
+ );
163
+
164
+ server.registerTool(
165
+ "get_post",
166
+ {
167
+ title: "Get Post",
168
+ description: "Get a post by ID.",
169
+ inputSchema: { id: z.string() },
170
+ },
171
+ async ({ id }) => {
172
+ const post = getPost(id);
173
+ if (!post) {
174
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
175
+ }
176
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
177
+ }
178
+ );
179
+
180
+ server.registerTool(
181
+ "list_posts",
182
+ {
183
+ title: "List Posts",
184
+ description: "List posts with optional filters.",
185
+ inputSchema: {
186
+ account_id: z.string().optional(),
187
+ status: PostStatusEnum.optional(),
188
+ tag: z.string().optional(),
189
+ search: z.string().optional(),
190
+ limit: z.number().optional(),
191
+ },
192
+ },
193
+ async (params) => {
194
+ const posts = listPosts(params);
195
+ return {
196
+ content: [
197
+ { type: "text", text: JSON.stringify({ posts, count: posts.length }, null, 2) },
198
+ ],
199
+ };
200
+ }
201
+ );
202
+
203
+ server.registerTool(
204
+ "update_post",
205
+ {
206
+ title: "Update Post",
207
+ description: "Update an existing post.",
208
+ inputSchema: {
209
+ id: z.string(),
210
+ content: z.string().optional(),
211
+ media_urls: z.array(z.string()).optional(),
212
+ status: PostStatusEnum.optional(),
213
+ scheduled_at: z.string().optional(),
214
+ published_at: z.string().optional(),
215
+ platform_post_id: z.string().optional(),
216
+ engagement: z.object({
217
+ likes: z.number().optional(),
218
+ shares: z.number().optional(),
219
+ comments: z.number().optional(),
220
+ impressions: z.number().optional(),
221
+ clicks: z.number().optional(),
222
+ }).optional(),
223
+ tags: z.array(z.string()).optional(),
224
+ },
225
+ },
226
+ async ({ id, ...input }) => {
227
+ const post = updatePost(id, input);
228
+ if (!post) {
229
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
230
+ }
231
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
232
+ }
233
+ );
234
+
235
+ server.registerTool(
236
+ "delete_post",
237
+ {
238
+ title: "Delete Post",
239
+ description: "Delete a post by ID.",
240
+ inputSchema: { id: z.string() },
241
+ },
242
+ async ({ id }) => {
243
+ const deleted = deletePost(id);
244
+ return { content: [{ type: "text", text: JSON.stringify({ id, deleted }) }] };
245
+ }
246
+ );
247
+
248
+ server.registerTool(
249
+ "schedule_post",
250
+ {
251
+ title: "Schedule Post",
252
+ description: "Schedule a post for a specific date/time.",
253
+ inputSchema: {
254
+ id: z.string(),
255
+ scheduled_at: z.string(),
256
+ },
257
+ },
258
+ async ({ id, scheduled_at }) => {
259
+ const post = schedulePost(id, scheduled_at);
260
+ if (!post) {
261
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
262
+ }
263
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
264
+ }
265
+ );
266
+
267
+ server.registerTool(
268
+ "publish_post",
269
+ {
270
+ title: "Publish Post",
271
+ description: "Mark a post as published.",
272
+ inputSchema: {
273
+ id: z.string(),
274
+ platform_post_id: z.string().optional(),
275
+ },
276
+ },
277
+ async ({ id, platform_post_id }) => {
278
+ const post = publishPost(id, platform_post_id);
279
+ if (!post) {
280
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
281
+ }
282
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
283
+ }
284
+ );
285
+
286
+ // --- Templates ---
287
+
288
+ server.registerTool(
289
+ "create_template",
290
+ {
291
+ title: "Create Template",
292
+ description: "Create a post template with variables.",
293
+ inputSchema: {
294
+ name: z.string(),
295
+ content: z.string(),
296
+ variables: z.array(z.string()).optional(),
297
+ },
298
+ },
299
+ async (params) => {
300
+ const template = createTemplate(params);
301
+ return { content: [{ type: "text", text: JSON.stringify(template, null, 2) }] };
302
+ }
303
+ );
304
+
305
+ server.registerTool(
306
+ "list_templates",
307
+ {
308
+ title: "List Templates",
309
+ description: "List all post templates.",
310
+ inputSchema: {},
311
+ },
312
+ async () => {
313
+ const templates = listTemplates();
314
+ return {
315
+ content: [
316
+ { type: "text", text: JSON.stringify({ templates, count: templates.length }, null, 2) },
317
+ ],
318
+ };
319
+ }
320
+ );
321
+
322
+ server.registerTool(
323
+ "get_template",
324
+ {
325
+ title: "Get Template",
326
+ description: "Get a template by ID.",
327
+ inputSchema: { id: z.string() },
328
+ },
329
+ async ({ id }) => {
330
+ const template = getTemplate(id);
331
+ if (!template) {
332
+ return { content: [{ type: "text", text: `Template '${id}' not found.` }], isError: true };
333
+ }
334
+ return { content: [{ type: "text", text: JSON.stringify(template, null, 2) }] };
335
+ }
336
+ );
337
+
338
+ server.registerTool(
339
+ "delete_template",
340
+ {
341
+ title: "Delete Template",
342
+ description: "Delete a template by ID.",
343
+ inputSchema: { id: z.string() },
344
+ },
345
+ async ({ id }) => {
346
+ const deleted = deleteTemplate(id);
347
+ return { content: [{ type: "text", text: JSON.stringify({ id, deleted }) }] };
348
+ }
349
+ );
350
+
351
+ server.registerTool(
352
+ "use_template",
353
+ {
354
+ title: "Use Template",
355
+ description: "Create a post from a template by replacing variables.",
356
+ inputSchema: {
357
+ template_id: z.string(),
358
+ account_id: z.string(),
359
+ values: z.record(z.string()).optional(),
360
+ tags: z.array(z.string()).optional(),
361
+ },
362
+ },
363
+ async ({ template_id, account_id, values, tags }) => {
364
+ try {
365
+ const post = useTemplate(template_id, account_id, values || {}, tags);
366
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
367
+ } catch (error) {
368
+ return {
369
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
370
+ isError: true,
371
+ };
372
+ }
373
+ }
374
+ );
375
+
376
+ // --- Analytics ---
377
+
378
+ server.registerTool(
379
+ "get_engagement_stats",
380
+ {
381
+ title: "Get Engagement Stats",
382
+ description: "Get engagement analytics for published posts.",
383
+ inputSchema: {
384
+ account_id: z.string().optional(),
385
+ },
386
+ },
387
+ async ({ account_id }) => {
388
+ const stats = getEngagementStats(account_id);
389
+ return { content: [{ type: "text", text: JSON.stringify(stats, null, 2) }] };
390
+ }
391
+ );
392
+
393
+ server.registerTool(
394
+ "get_stats_by_platform",
395
+ {
396
+ title: "Get Stats By Platform",
397
+ description: "Get analytics grouped by social media platform.",
398
+ inputSchema: {},
399
+ },
400
+ async () => {
401
+ const stats = getStatsByPlatform();
402
+ return { content: [{ type: "text", text: JSON.stringify(stats, null, 2) }] };
403
+ }
404
+ );
405
+
406
+ server.registerTool(
407
+ "get_calendar",
408
+ {
409
+ title: "Get Calendar",
410
+ description: "View scheduled posts grouped by date.",
411
+ inputSchema: {
412
+ start_date: z.string().optional(),
413
+ end_date: z.string().optional(),
414
+ },
415
+ },
416
+ async ({ start_date, end_date }) => {
417
+ const calendar = getCalendar(start_date, end_date);
418
+ return { content: [{ type: "text", text: JSON.stringify(calendar, null, 2) }] };
419
+ }
420
+ );
421
+
422
+ server.registerTool(
423
+ "get_overall_stats",
424
+ {
425
+ title: "Get Overall Stats",
426
+ description: "Get overall social media management statistics.",
427
+ inputSchema: {},
428
+ },
429
+ async () => {
430
+ const stats = getOverallStats();
431
+ return { content: [{ type: "text", text: JSON.stringify(stats, null, 2) }] };
432
+ }
433
+ );
434
+
435
+ // --- Batch Schedule ---
436
+
437
+ server.registerTool(
438
+ "batch_schedule_posts",
439
+ {
440
+ title: "Batch Schedule Posts",
441
+ description: "Schedule multiple posts at once from an array of post definitions.",
442
+ inputSchema: {
443
+ posts: z.array(z.object({
444
+ account_id: z.string(),
445
+ content: z.string(),
446
+ scheduled_at: z.string(),
447
+ media_urls: z.array(z.string()).optional(),
448
+ tags: z.array(z.string()).optional(),
449
+ recurrence: RecurrenceEnum.optional(),
450
+ })),
451
+ },
452
+ },
453
+ async ({ posts }) => {
454
+ const result = batchSchedule(posts);
455
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
456
+ }
457
+ );
458
+
459
+ // --- Cross-Post ---
460
+
461
+ server.registerTool(
462
+ "crosspost",
463
+ {
464
+ title: "Cross-Post",
465
+ description: "Create identical post on multiple platform accounts.",
466
+ inputSchema: {
467
+ content: z.string(),
468
+ platforms: z.array(PlatformEnum),
469
+ media_urls: z.array(z.string()).optional(),
470
+ tags: z.array(z.string()).optional(),
471
+ scheduled_at: z.string().optional(),
472
+ },
473
+ },
474
+ async ({ content, platforms, ...options }) => {
475
+ try {
476
+ const result = crossPost(content, platforms, options);
477
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
478
+ } catch (error) {
479
+ return {
480
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
481
+ isError: true,
482
+ };
483
+ }
484
+ }
485
+ );
486
+
487
+ // --- Best Time to Post ---
488
+
489
+ server.registerTool(
490
+ "best_time_to_post",
491
+ {
492
+ title: "Best Time to Post",
493
+ description: "Analyze historical engagement to find the best hours and days to post.",
494
+ inputSchema: {
495
+ account_id: z.string(),
496
+ },
497
+ },
498
+ async ({ account_id }) => {
499
+ const result = getBestTimeToPost(account_id);
500
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
501
+ }
502
+ );
503
+
504
+ // --- Reschedule Post ---
505
+
506
+ server.registerTool(
507
+ "reschedule_post",
508
+ {
509
+ title: "Reschedule Post",
510
+ description: "Update the scheduled date/time of a post without delete/recreate.",
511
+ inputSchema: {
512
+ id: z.string(),
513
+ new_date: z.string(),
514
+ },
515
+ },
516
+ async ({ id, new_date }) => {
517
+ try {
518
+ const post = reschedulePost(id, new_date);
519
+ if (!post) {
520
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
521
+ }
522
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
523
+ } catch (error) {
524
+ return {
525
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
526
+ isError: true,
527
+ };
528
+ }
529
+ }
530
+ );
531
+
532
+ // --- Approval Workflow ---
533
+
534
+ server.registerTool(
535
+ "submit_post_for_review",
536
+ {
537
+ title: "Submit Post for Review",
538
+ description: "Submit a draft post for review (draft → pending_review).",
539
+ inputSchema: {
540
+ id: z.string(),
541
+ },
542
+ },
543
+ async ({ id }) => {
544
+ try {
545
+ const post = submitPostForReview(id);
546
+ if (!post) {
547
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
548
+ }
549
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
550
+ } catch (error) {
551
+ return {
552
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
553
+ isError: true,
554
+ };
555
+ }
556
+ }
557
+ );
558
+
559
+ server.registerTool(
560
+ "approve_post",
561
+ {
562
+ title: "Approve Post",
563
+ description: "Approve a post pending review (pending_review → scheduled).",
564
+ inputSchema: {
565
+ id: z.string(),
566
+ scheduled_at: z.string().optional(),
567
+ },
568
+ },
569
+ async ({ id, scheduled_at }) => {
570
+ try {
571
+ const post = approvePost(id, scheduled_at);
572
+ if (!post) {
573
+ return { content: [{ type: "text", text: `Post '${id}' not found.` }], isError: true };
574
+ }
575
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
576
+ } catch (error) {
577
+ return {
578
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
579
+ isError: true,
580
+ };
581
+ }
582
+ }
583
+ );
584
+
585
+ // --- Platform Limits ---
586
+
587
+ server.registerTool(
588
+ "get_platform_limits",
589
+ {
590
+ title: "Get Platform Limits",
591
+ description: "Get character limits for all supported platforms.",
592
+ inputSchema: {},
593
+ },
594
+ async () => {
595
+ return { content: [{ type: "text", text: JSON.stringify(PLATFORM_LIMITS, null, 2) }] };
596
+ }
597
+ );
598
+
599
+ // --- Recurring Posts ---
600
+
601
+ server.registerTool(
602
+ "create_recurring_post",
603
+ {
604
+ title: "Create Recurring Post",
605
+ description: "Create a post that recurs on a schedule (daily, weekly, biweekly, monthly).",
606
+ inputSchema: {
607
+ account_id: z.string(),
608
+ content: z.string(),
609
+ scheduled_at: z.string(),
610
+ recurrence: RecurrenceEnum,
611
+ media_urls: z.array(z.string()).optional(),
612
+ tags: z.array(z.string()).optional(),
613
+ },
614
+ },
615
+ async (params) => {
616
+ try {
617
+ const post = createRecurringPost(params);
618
+ return { content: [{ type: "text", text: JSON.stringify(post, null, 2) }] };
619
+ } catch (error) {
620
+ return {
621
+ content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }],
622
+ isError: true,
623
+ };
624
+ }
625
+ }
626
+ );
627
+
628
+ // --- Hashtag Analytics ---
629
+
630
+ server.registerTool(
631
+ "hashtag_analytics",
632
+ {
633
+ title: "Hashtag Analytics",
634
+ description: "Extract hashtags from published posts and correlate with engagement metrics.",
635
+ inputSchema: {
636
+ account_id: z.string(),
637
+ },
638
+ },
639
+ async ({ account_id }) => {
640
+ const stats = getHashtagStats(account_id);
641
+ return { content: [{ type: "text", text: JSON.stringify(stats, null, 2) }] };
642
+ }
643
+ );
644
+
645
+ // --- Start ---
646
+ async function main() {
647
+ const transport = new StdioServerTransport();
648
+ await server.connect(transport);
649
+ console.error("microservice-social MCP server running on stdio");
650
+ }
651
+
652
+ main().catch((error) => {
653
+ console.error("Fatal error:", error);
654
+ process.exit(1);
655
+ });