@mseep/mcp-agent-social 1.1.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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -0
  3. package/bin/mcp-agent-social +30 -0
  4. package/dist/api-client.d.ts +31 -0
  5. package/dist/api-client.d.ts.map +1 -0
  6. package/dist/api-client.js +212 -0
  7. package/dist/api-client.js.map +1 -0
  8. package/dist/config.d.ts +19 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +79 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/hooks/index.d.ts +38 -0
  13. package/dist/hooks/index.d.ts.map +1 -0
  14. package/dist/hooks/index.js +253 -0
  15. package/dist/hooks/index.js.map +1 -0
  16. package/dist/hooks/types.d.ts +35 -0
  17. package/dist/hooks/types.d.ts.map +1 -0
  18. package/dist/hooks/types.js +4 -0
  19. package/dist/hooks/types.js.map +1 -0
  20. package/dist/http-server.d.ts +38 -0
  21. package/dist/http-server.d.ts.map +1 -0
  22. package/dist/http-server.js +210 -0
  23. package/dist/http-server.js.map +1 -0
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +186 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/logger.d.ts +44 -0
  29. package/dist/logger.d.ts.map +1 -0
  30. package/dist/logger.js +281 -0
  31. package/dist/logger.js.map +1 -0
  32. package/dist/metrics.d.ts +47 -0
  33. package/dist/metrics.d.ts.map +1 -0
  34. package/dist/metrics.js +178 -0
  35. package/dist/metrics.js.map +1 -0
  36. package/dist/middleware/error-handler.d.ts +74 -0
  37. package/dist/middleware/error-handler.d.ts.map +1 -0
  38. package/dist/middleware/error-handler.js +218 -0
  39. package/dist/middleware/error-handler.js.map +1 -0
  40. package/dist/middleware/index.d.ts +55 -0
  41. package/dist/middleware/index.d.ts.map +1 -0
  42. package/dist/middleware/index.js +91 -0
  43. package/dist/middleware/index.js.map +1 -0
  44. package/dist/middleware/timeout.d.ts +52 -0
  45. package/dist/middleware/timeout.d.ts.map +1 -0
  46. package/dist/middleware/timeout.js +189 -0
  47. package/dist/middleware/timeout.js.map +1 -0
  48. package/dist/middleware/validator.d.ts +25 -0
  49. package/dist/middleware/validator.d.ts.map +1 -0
  50. package/dist/middleware/validator.js +186 -0
  51. package/dist/middleware/validator.js.map +1 -0
  52. package/dist/prompts/analyze.d.ts +46 -0
  53. package/dist/prompts/analyze.d.ts.map +1 -0
  54. package/dist/prompts/analyze.js +351 -0
  55. package/dist/prompts/analyze.js.map +1 -0
  56. package/dist/prompts/generate.d.ts +48 -0
  57. package/dist/prompts/generate.d.ts.map +1 -0
  58. package/dist/prompts/generate.js +177 -0
  59. package/dist/prompts/generate.js.map +1 -0
  60. package/dist/prompts/index.d.ts +23 -0
  61. package/dist/prompts/index.d.ts.map +1 -0
  62. package/dist/prompts/index.js +69 -0
  63. package/dist/prompts/index.js.map +1 -0
  64. package/dist/prompts/summarize.d.ts +32 -0
  65. package/dist/prompts/summarize.d.ts.map +1 -0
  66. package/dist/prompts/summarize.js +182 -0
  67. package/dist/prompts/summarize.js.map +1 -0
  68. package/dist/prompts/types.d.ts +34 -0
  69. package/dist/prompts/types.d.ts.map +1 -0
  70. package/dist/prompts/types.js +24 -0
  71. package/dist/prompts/types.js.map +1 -0
  72. package/dist/resources/agents.d.ts +17 -0
  73. package/dist/resources/agents.d.ts.map +1 -0
  74. package/dist/resources/agents.js +139 -0
  75. package/dist/resources/agents.js.map +1 -0
  76. package/dist/resources/feed.d.ts +19 -0
  77. package/dist/resources/feed.d.ts.map +1 -0
  78. package/dist/resources/feed.js +138 -0
  79. package/dist/resources/feed.js.map +1 -0
  80. package/dist/resources/index.d.ts +19 -0
  81. package/dist/resources/index.d.ts.map +1 -0
  82. package/dist/resources/index.js +146 -0
  83. package/dist/resources/index.js.map +1 -0
  84. package/dist/resources/posts.d.ts +17 -0
  85. package/dist/resources/posts.d.ts.map +1 -0
  86. package/dist/resources/posts.js +151 -0
  87. package/dist/resources/posts.js.map +1 -0
  88. package/dist/resources/types.d.ts +91 -0
  89. package/dist/resources/types.d.ts.map +1 -0
  90. package/dist/resources/types.js +12 -0
  91. package/dist/resources/types.js.map +1 -0
  92. package/dist/roots/index.d.ts +43 -0
  93. package/dist/roots/index.d.ts.map +1 -0
  94. package/dist/roots/index.js +131 -0
  95. package/dist/roots/index.js.map +1 -0
  96. package/dist/roots/types.d.ts +31 -0
  97. package/dist/roots/types.d.ts.map +1 -0
  98. package/dist/roots/types.js +4 -0
  99. package/dist/roots/types.js.map +1 -0
  100. package/dist/session-manager.d.ts +50 -0
  101. package/dist/session-manager.d.ts.map +1 -0
  102. package/dist/session-manager.js +127 -0
  103. package/dist/session-manager.js.map +1 -0
  104. package/dist/tools/create-post.d.ts +45 -0
  105. package/dist/tools/create-post.d.ts.map +1 -0
  106. package/dist/tools/create-post.js +119 -0
  107. package/dist/tools/create-post.js.map +1 -0
  108. package/dist/tools/index.d.ts +13 -0
  109. package/dist/tools/index.d.ts.map +1 -0
  110. package/dist/tools/index.js +44 -0
  111. package/dist/tools/index.js.map +1 -0
  112. package/dist/tools/login.d.ts +35 -0
  113. package/dist/tools/login.d.ts.map +1 -0
  114. package/dist/tools/login.js +132 -0
  115. package/dist/tools/login.js.map +1 -0
  116. package/dist/tools/read-posts.d.ts +48 -0
  117. package/dist/tools/read-posts.d.ts.map +1 -0
  118. package/dist/tools/read-posts.js +93 -0
  119. package/dist/tools/read-posts.js.map +1 -0
  120. package/dist/types.d.ts +88 -0
  121. package/dist/types.d.ts.map +1 -0
  122. package/dist/types.js +4 -0
  123. package/dist/types.js.map +1 -0
  124. package/dist/utils/json.d.ts +13 -0
  125. package/dist/utils/json.d.ts.map +1 -0
  126. package/dist/utils/json.js +48 -0
  127. package/dist/utils/json.js.map +1 -0
  128. package/dist/validation.d.ts +58 -0
  129. package/dist/validation.d.ts.map +1 -0
  130. package/dist/validation.js +223 -0
  131. package/dist/validation.js.map +1 -0
  132. package/package.json +70 -0
  133. package/src/api-client.ts +292 -0
  134. package/src/config.ts +92 -0
  135. package/src/hooks/index.ts +304 -0
  136. package/src/hooks/types.ts +44 -0
  137. package/src/http-server.ts +243 -0
  138. package/src/index.ts +213 -0
  139. package/src/logger.ts +326 -0
  140. package/src/metrics.ts +235 -0
  141. package/src/middleware/error-handler.ts +252 -0
  142. package/src/middleware/index.ts +112 -0
  143. package/src/middleware/timeout.ts +216 -0
  144. package/src/middleware/validator.ts +216 -0
  145. package/src/prompts/analyze.ts +404 -0
  146. package/src/prompts/generate.ts +217 -0
  147. package/src/prompts/index.ts +121 -0
  148. package/src/prompts/summarize.ts +217 -0
  149. package/src/prompts/types.ts +44 -0
  150. package/src/resources/agents.ts +165 -0
  151. package/src/resources/feed.ts +169 -0
  152. package/src/resources/index.ts +210 -0
  153. package/src/resources/posts.ts +179 -0
  154. package/src/resources/types.ts +104 -0
  155. package/src/roots/index.ts +166 -0
  156. package/src/roots/types.ts +36 -0
  157. package/src/session-manager.ts +149 -0
  158. package/src/tools/create-post.ts +154 -0
  159. package/src/tools/index.ts +70 -0
  160. package/src/tools/login.ts +169 -0
  161. package/src/tools/read-posts.ts +120 -0
  162. package/src/types.ts +107 -0
  163. package/src/utils/json.ts +46 -0
  164. package/src/validation.ts +322 -0
  165. package/tsconfig.json +22 -0
@@ -0,0 +1,169 @@
1
+ // ABOUTME: Login tool implementation for agent authentication
2
+ // ABOUTME: Handles session creation and validation for agents
3
+
4
+ import { z } from 'zod';
5
+ import { config } from '../config.js';
6
+ import { logger } from '../logger.js';
7
+ import { withMetrics } from '../metrics.js';
8
+ import type { SessionManager } from '../session-manager.js';
9
+ import type { LoginToolResponse } from '../types.js';
10
+ import { safeJsonStringify } from '../utils/json.js';
11
+ import { validateLoginInput } from '../validation.js';
12
+
13
+ export const loginInputSchema = z.object({
14
+ agent_name: z
15
+ .string()
16
+ .min(1)
17
+ .describe(
18
+ 'Your unique social media handle/username. Choose a memorable name that represents your agent identity.',
19
+ ),
20
+ });
21
+
22
+ export const loginToolSchema = {
23
+ description: 'Authenticate and set your unique agent identity for the social media session.',
24
+ inputSchema: {
25
+ agent_name: z
26
+ .string()
27
+ .min(1)
28
+ .describe(
29
+ 'Your unique social media handle/username. Be creative! Examples: "code_wizard", "research_maven", "data_explorer", "creative_spark". Make it memorable and fun!',
30
+ ),
31
+ },
32
+ annotations: {
33
+ title: 'Social Media Login',
34
+ readOnlyHint: false,
35
+ destructiveHint: false,
36
+ idempotentHint: true,
37
+ openWorldHint: false,
38
+ },
39
+ };
40
+
41
+ export interface LoginToolContext {
42
+ sessionManager: SessionManager;
43
+ getSessionId: () => string;
44
+ }
45
+
46
+ // Infer the input type from Zod schema
47
+ type LoginInput = z.infer<typeof loginInputSchema>;
48
+
49
+ export async function loginToolHandler(
50
+ input: LoginInput,
51
+ context: LoginToolContext,
52
+ ): Promise<{ content: Array<{ type: 'text'; text: string }> }> {
53
+ const startTime = Date.now();
54
+ const sessionId = context.getSessionId();
55
+
56
+ logger.toolStart('login', input, { sessionId });
57
+
58
+ return withMetrics('login', async () => {
59
+ try {
60
+ // Validate input
61
+ const validation = validateLoginInput(input);
62
+ if (!validation.isValid) {
63
+ const response: LoginToolResponse = {
64
+ success: false,
65
+ error: 'Invalid input',
66
+ details: validation.errors
67
+ .map((e) => `${e.field || 'unknown'}: ${e.message || 'unknown error'}`)
68
+ .join(', '),
69
+ };
70
+
71
+ logger.warn('Login failed - invalid input', { sessionId, errors: validation.errors });
72
+
73
+ return {
74
+ content: [
75
+ {
76
+ type: 'text',
77
+ text: safeJsonStringify(response),
78
+ },
79
+ ],
80
+ };
81
+ }
82
+
83
+ if (!validation.data) {
84
+ throw new Error('Validation succeeded but data is missing');
85
+ }
86
+ const { agent_name } = validation.data;
87
+
88
+ // Check if session already exists (re-login scenario)
89
+ const existingSession = context.sessionManager.getSession(sessionId);
90
+
91
+ if (existingSession) {
92
+ // Update existing session
93
+ await context.sessionManager.createSession(sessionId, agent_name);
94
+
95
+ const response: LoginToolResponse = {
96
+ success: true,
97
+ agent_name: agent_name,
98
+ team_name: config.teamName,
99
+ session_id: sessionId,
100
+ message: `Welcome back, @${agent_name}! Your session has been updated. Ready to continue the conversation! 🎉`,
101
+ };
102
+
103
+ logger.info('Re-login successful', {
104
+ sessionId,
105
+ agentName: agent_name,
106
+ previousAgent: existingSession.agentName,
107
+ });
108
+
109
+ logger.toolSuccess('login', Date.now() - startTime, {
110
+ sessionId,
111
+ agentName: agent_name,
112
+ });
113
+
114
+ return {
115
+ content: [
116
+ {
117
+ type: 'text',
118
+ text: safeJsonStringify(response),
119
+ },
120
+ ],
121
+ };
122
+ }
123
+
124
+ // Create new session
125
+ const session = await context.sessionManager.createSession(sessionId, agent_name);
126
+
127
+ logger.sessionCreated(sessionId, agent_name);
128
+
129
+ const response: LoginToolResponse = {
130
+ success: true,
131
+ agent_name: session.agentName,
132
+ team_name: config.teamName,
133
+ session_id: session.sessionId,
134
+ message: `Welcome to the social platform, @${session.agentName}! Great choice of handle - you're now ready to connect and collaborate! 🚀`,
135
+ };
136
+
137
+ logger.toolSuccess('login', Date.now() - startTime, {
138
+ sessionId,
139
+ agentName: session.agentName,
140
+ });
141
+
142
+ return {
143
+ content: [
144
+ {
145
+ type: 'text',
146
+ text: safeJsonStringify(response),
147
+ },
148
+ ],
149
+ };
150
+ } catch (error) {
151
+ const response: LoginToolResponse = {
152
+ success: false,
153
+ error: 'Failed to create session',
154
+ details: error instanceof Error ? error.message : 'Unknown error',
155
+ };
156
+
157
+ logger.toolError('login', error as Error, Date.now() - startTime, { sessionId });
158
+
159
+ return {
160
+ content: [
161
+ {
162
+ type: 'text',
163
+ text: safeJsonStringify(response),
164
+ },
165
+ ],
166
+ };
167
+ }
168
+ });
169
+ }
@@ -0,0 +1,120 @@
1
+ // ABOUTME: Read posts tool implementation for retrieving social media posts
2
+ // ABOUTME: Handles basic pagination and error handling for post retrieval
3
+
4
+ import { z } from 'zod';
5
+ import type { IApiClient } from '../api-client.js';
6
+ import { config } from '../config.js';
7
+ import type { ReadPostsToolResponse } from '../types.js';
8
+ import { safeJsonStringify } from '../utils/json.js';
9
+ import { validateReadPostsInput } from '../validation.js';
10
+
11
+ export const readPostsInputSchema = z.object({
12
+ limit: z.number().min(1).max(100).default(10).describe('Maximum number of posts to retrieve'),
13
+ offset: z.number().min(0).default(0).describe('Number of posts to skip'),
14
+ agent_filter: z.string().optional().describe('Filter posts by author name'),
15
+ tag_filter: z.string().optional().describe('Filter posts by tag'),
16
+ thread_id: z.string().optional().describe('Get posts in a specific thread'),
17
+ });
18
+
19
+ export const readPostsToolSchema = {
20
+ description: "Retrieve posts from the team's social feed with optional filtering",
21
+ inputSchema: {
22
+ limit: z.number().min(1).max(100).default(10).describe('Maximum number of posts to retrieve'),
23
+ offset: z.number().min(0).default(0).describe('Number of posts to skip'),
24
+ agent_filter: z.string().optional().describe('Filter posts by author name'),
25
+ tag_filter: z.string().optional().describe('Filter posts by tag'),
26
+ thread_id: z.string().optional().describe('Get posts in a specific thread'),
27
+ },
28
+ annotations: {
29
+ title: 'Read Social Media Posts',
30
+ readOnlyHint: true,
31
+ openWorldHint: true,
32
+ },
33
+ };
34
+
35
+ export interface ReadPostsToolContext {
36
+ apiClient: IApiClient;
37
+ }
38
+
39
+ // Infer the input type from Zod schema
40
+ type ReadPostsInput = z.infer<typeof readPostsInputSchema>;
41
+
42
+ export async function readPostsToolHandler(
43
+ input: ReadPostsInput,
44
+ context: ReadPostsToolContext,
45
+ ): Promise<{ content: Array<{ type: 'text'; text: string }> }> {
46
+ try {
47
+ // Validate input
48
+ const validation = validateReadPostsInput(input);
49
+ if (!validation.isValid) {
50
+ const response: ReadPostsToolResponse = {
51
+ success: false,
52
+ error: `Invalid input: ${validation.errors.map((e) => `${e.field || 'unknown'}: ${e.message || 'unknown error'}`).join(', ')}`,
53
+ };
54
+
55
+ return {
56
+ content: [
57
+ {
58
+ type: 'text',
59
+ text: safeJsonStringify(response),
60
+ },
61
+ ],
62
+ };
63
+ }
64
+
65
+ if (!validation.data) {
66
+ throw new Error('Validation succeeded but data is missing');
67
+ }
68
+
69
+ const {
70
+ limit: actualLimit,
71
+ offset: actualOffset,
72
+ agent_filter,
73
+ tag_filter,
74
+ thread_id,
75
+ } = validation.data;
76
+
77
+ // Fetch posts from the API with filters
78
+ const response = await context.apiClient.fetchPosts(config.teamName, {
79
+ limit: actualLimit,
80
+ offset: actualOffset,
81
+ agent_filter: agent_filter,
82
+ tag_filter: tag_filter,
83
+ thread_id: thread_id,
84
+ });
85
+
86
+ // Format successful response
87
+ const toolResponse: ReadPostsToolResponse = {
88
+ success: true,
89
+ posts: response.posts,
90
+ limit: actualLimit,
91
+ offset: actualOffset,
92
+ total: response.total,
93
+ has_more: response.has_more,
94
+ };
95
+
96
+ return {
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ text: safeJsonStringify(toolResponse),
101
+ },
102
+ ],
103
+ };
104
+ } catch (error) {
105
+ // Handle API errors
106
+ const errorResponse: ReadPostsToolResponse = {
107
+ success: false,
108
+ error: error instanceof Error ? error.message : 'Failed to fetch posts',
109
+ };
110
+
111
+ return {
112
+ content: [
113
+ {
114
+ type: 'text',
115
+ text: safeJsonStringify(errorResponse),
116
+ },
117
+ ],
118
+ };
119
+ }
120
+ }
package/src/types.ts ADDED
@@ -0,0 +1,107 @@
1
+ // ABOUTME: Type definitions for the MCP Agent Social Media Server
2
+ // ABOUTME: Contains interfaces and types used throughout the application
3
+
4
+ export interface ServerConfig {
5
+ socialApiBaseUrl: string;
6
+ socialApiKey: string;
7
+ teamName: string;
8
+ port: number;
9
+ logLevel: string;
10
+ apiTimeout: number;
11
+ }
12
+
13
+ export interface MCPError {
14
+ code: string;
15
+ message: string;
16
+ data?: unknown;
17
+ }
18
+
19
+ export interface Session {
20
+ sessionId: string;
21
+ agentName: string;
22
+ loginTimestamp: Date;
23
+ lastActivity: Date;
24
+ expiresAt: Date;
25
+ isValid: boolean;
26
+ }
27
+
28
+ export interface Post {
29
+ id: string;
30
+ team_name: string;
31
+ author_name: string;
32
+ content: string;
33
+ tags: string[];
34
+ timestamp: string;
35
+ parent_post_id?: string;
36
+ }
37
+
38
+ export interface PostData {
39
+ author_name: string;
40
+ content: string;
41
+ tags?: string[];
42
+ parent_post_id?: string;
43
+ }
44
+
45
+ export interface PostResponse {
46
+ post: Post;
47
+ }
48
+
49
+ export interface PostsResponse {
50
+ posts: Post[];
51
+ total: number;
52
+ has_more: boolean;
53
+ }
54
+
55
+ export interface PostQueryOptions {
56
+ limit?: number;
57
+ offset?: number;
58
+ agent_filter?: string;
59
+ tag_filter?: string;
60
+ thread_id?: string;
61
+ }
62
+
63
+ export interface ApiError {
64
+ status: number;
65
+ message: string;
66
+ code?: string;
67
+ }
68
+
69
+ export type LoginToolResponse =
70
+ | {
71
+ success: true;
72
+ agent_name: string;
73
+ team_name: string;
74
+ session_id: string;
75
+ message: string;
76
+ }
77
+ | {
78
+ success: false;
79
+ error: string;
80
+ details?: string;
81
+ };
82
+
83
+ export type ReadPostsToolResponse =
84
+ | {
85
+ success: true;
86
+ posts: Post[];
87
+ limit: number;
88
+ offset: number;
89
+ total: number;
90
+ has_more: boolean;
91
+ }
92
+ | {
93
+ success: false;
94
+ error: string;
95
+ details?: string;
96
+ };
97
+
98
+ export type CreatePostToolResponse =
99
+ | {
100
+ success: true;
101
+ post: Post;
102
+ }
103
+ | {
104
+ success: false;
105
+ error: string;
106
+ details?: string;
107
+ };
@@ -0,0 +1,46 @@
1
+ // ABOUTME: Safe JSON utilities to prevent malformed JSON in MCP responses
2
+ // ABOUTME: Handles circular references and serialization errors gracefully
3
+
4
+ /**
5
+ * Safely stringify an object to JSON, handling circular references and errors
6
+ */
7
+ export function safeJsonStringify(obj: any, replacer?: (key: string, value: any) => any): string {
8
+ try {
9
+ return JSON.stringify(obj, replacer);
10
+ } catch (error) {
11
+ // Handle circular references or other serialization errors
12
+ try {
13
+ return JSON.stringify({
14
+ _error: 'JSON_SERIALIZATION_ERROR',
15
+ _originalError: error instanceof Error ? error.message : String(error),
16
+ _fallback: String(obj),
17
+ });
18
+ } catch {
19
+ // Last resort - return a simple error object
20
+ return '{"_error":"JSON_SERIALIZATION_FAILED","_type":"' + typeof obj + '"}';
21
+ }
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Safely parse JSON, returning a default value on error
27
+ */
28
+ export function safeJsonParse<T>(jsonString: string, defaultValue: T): T {
29
+ try {
30
+ return JSON.parse(jsonString) as T;
31
+ } catch {
32
+ return defaultValue;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Validate that a string is valid JSON
38
+ */
39
+ export function isValidJson(str: string): boolean {
40
+ try {
41
+ JSON.parse(str);
42
+ return true;
43
+ } catch {
44
+ return false;
45
+ }
46
+ }