@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,121 @@
1
+ // ABOUTME: Main prompt registration and handling for MCP prompts
2
+ // ABOUTME: Coordinates all prompt types and implements list/get endpoints
3
+
4
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
6
+ import type {
7
+ GetPromptResult,
8
+ ListPromptsResult,
9
+ ServerNotification,
10
+ ServerRequest,
11
+ } from '@modelcontextprotocol/sdk/types.js';
12
+ import type { z } from 'zod';
13
+ import type { IApiClient } from '../api-client.js';
14
+ import { logger } from '../logger.js';
15
+ import type { SessionManager } from '../session-manager.js';
16
+ import { analyzePrompts } from './analyze.js';
17
+ import { generatePrompts } from './generate.js';
18
+ import { summarizePrompts } from './summarize.js';
19
+
20
+ export interface PromptContext {
21
+ apiClient: IApiClient;
22
+ sessionManager: SessionManager;
23
+ hooksManager?: any;
24
+ }
25
+
26
+ // Type for prompt handlers - use any for args since prompts have different arg types
27
+ type PromptHandler<T = any> = (
28
+ args: T,
29
+ extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
30
+ context: PromptContext,
31
+ ) => Promise<GetPromptResult>;
32
+
33
+ interface PromptDefinition {
34
+ description: string;
35
+ argsSchema: Record<string, z.ZodString | z.ZodOptional<z.ZodString>>;
36
+ handler: PromptHandler<any>;
37
+ }
38
+
39
+ // Combine all prompts
40
+ const allPrompts: Record<string, PromptDefinition> = {
41
+ // Summarization prompts
42
+ 'summarize-thread': summarizePrompts.summarizeThread,
43
+ 'summarize-agent-activity': summarizePrompts.summarizeAgentActivity,
44
+
45
+ // Generation prompts
46
+ 'draft-reply': generatePrompts.draftReply,
47
+ 'generate-hashtags': generatePrompts.generateHashtags,
48
+ 'create-engagement-post': generatePrompts.createEngagementPost,
49
+
50
+ // Analysis prompts
51
+ 'analyze-sentiment': analyzePrompts.analyzeSentiment,
52
+ 'find-related-discussions': analyzePrompts.findRelatedDiscussions,
53
+ 'generate-engagement-report': analyzePrompts.generateEngagementReport,
54
+ };
55
+
56
+ /**
57
+ * Register all prompts with the MCP server
58
+ */
59
+ export function registerPrompts(server: McpServer, context: PromptContext): void {
60
+ logger.info('Registering MCP prompts');
61
+
62
+ // Register each prompt
63
+ for (const [name, prompt] of Object.entries(allPrompts)) {
64
+ server.prompt(
65
+ name,
66
+ prompt.description,
67
+ prompt.argsSchema,
68
+ async (args: any, extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => {
69
+ logger.debug(`Executing prompt: ${name}`, { args });
70
+ return prompt.handler(args, extra, context);
71
+ },
72
+ );
73
+ }
74
+
75
+ logger.info('Prompts registered', {
76
+ count: Object.keys(allPrompts).length,
77
+ prompts: Object.keys(allPrompts),
78
+ });
79
+ }
80
+
81
+ /**
82
+ * List all available prompts
83
+ */
84
+ export async function listPrompts(): Promise<ListPromptsResult> {
85
+ logger.debug('Listing all prompts');
86
+
87
+ const prompts = Object.entries(allPrompts).map(([name, prompt]) => ({
88
+ name,
89
+ description: prompt.description,
90
+ arguments: Object.entries(prompt.argsSchema).map(([argName, schema]) => ({
91
+ name: argName,
92
+ description: schema._def.description || '',
93
+ required: !schema.isOptional(),
94
+ })),
95
+ }));
96
+
97
+ return { prompts };
98
+ }
99
+
100
+ /**
101
+ * Get a specific prompt by name
102
+ */
103
+ export async function getPrompt(
104
+ name: string,
105
+ args: Record<string, string>,
106
+ context: PromptContext,
107
+ extra?: RequestHandlerExtra<ServerRequest, ServerNotification>,
108
+ ): Promise<GetPromptResult | null> {
109
+ const prompt = allPrompts[name];
110
+ if (!prompt) {
111
+ logger.warn('Prompt not found', { name });
112
+ return null;
113
+ }
114
+
115
+ // If no extra provided, this shouldn't be called directly
116
+ if (!extra) {
117
+ throw new Error('getPrompt requires RequestHandlerExtra parameter');
118
+ }
119
+
120
+ return prompt.handler(args, extra, context);
121
+ }
@@ -0,0 +1,217 @@
1
+ // ABOUTME: Summarization prompts for threads and conversations
2
+ // ABOUTME: Provides templates for summarizing social media content
3
+
4
+ import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
5
+ import type {
6
+ GetPromptResult,
7
+ ServerNotification,
8
+ ServerRequest,
9
+ } from '@modelcontextprotocol/sdk/types.js';
10
+ import { z } from 'zod';
11
+ import type { IApiClient } from '../api-client.js';
12
+ import { config } from '../config.js';
13
+ import { logger } from '../logger.js';
14
+
15
+ export interface SummarizePromptContext {
16
+ apiClient: IApiClient;
17
+ }
18
+
19
+ const summarizeThreadArgsSchema = {
20
+ thread_id: z.string().describe('The ID of the thread to summarize'),
21
+ };
22
+
23
+ export async function summarizeThreadPrompt(
24
+ args: { thread_id: string },
25
+ _extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
26
+ context: SummarizePromptContext,
27
+ ): Promise<GetPromptResult> {
28
+ try {
29
+ logger.debug('Generating thread summary prompt', { threadId: args.thread_id });
30
+
31
+ // Fetch the thread posts
32
+ const response = await context.apiClient.fetchPosts(config.teamName, {
33
+ thread_id: args.thread_id,
34
+ limit: 100,
35
+ offset: 0,
36
+ });
37
+
38
+ if (!response.posts || response.posts.length === 0) {
39
+ return {
40
+ description: 'Thread not found',
41
+ messages: [
42
+ {
43
+ role: 'user',
44
+ content: {
45
+ type: 'text',
46
+ text: `Unable to find thread with ID: ${args.thread_id}`,
47
+ },
48
+ },
49
+ ],
50
+ };
51
+ }
52
+
53
+ // Build the conversation history
54
+ const conversation = response.posts
55
+ .sort((a, b) => a.timestamp.localeCompare(b.timestamp))
56
+ .map((post) => `${post.author_name}: ${post.content}`)
57
+ .join('\n\n');
58
+
59
+ // Count unique participants
60
+ const participants = new Set(response.posts.map((p) => p.author_name));
61
+
62
+ return {
63
+ description: 'Summarize a social media conversation thread',
64
+ messages: [
65
+ {
66
+ role: 'user',
67
+ content: {
68
+ type: 'text',
69
+ text: `Please summarize the following social media conversation thread:
70
+
71
+ Thread ID: ${args.thread_id}
72
+ Participants: ${participants.size} (${Array.from(participants).join(', ')})
73
+ Total Posts: ${response.posts.length}
74
+
75
+ Conversation:
76
+ ${conversation}
77
+
78
+ Please provide:
79
+ 1. A brief summary of the main topic(s) discussed
80
+ 2. Key points or decisions made
81
+ 3. Any action items or follow-ups mentioned
82
+ 4. The overall sentiment/tone of the conversation`,
83
+ },
84
+ },
85
+ ],
86
+ };
87
+ } catch (error) {
88
+ logger.error('Error generating thread summary prompt', { error, threadId: args.thread_id });
89
+ return {
90
+ description: 'Error generating prompt',
91
+ messages: [
92
+ {
93
+ role: 'user',
94
+ content: {
95
+ type: 'text',
96
+ text: `Error fetching thread data: ${error instanceof Error ? error.message : 'Unknown error'}`,
97
+ },
98
+ },
99
+ ],
100
+ };
101
+ }
102
+ }
103
+
104
+ const summarizeAgentArgsSchema = {
105
+ agent_name: z.string().describe('The name of the agent to summarize'),
106
+ limit: z.string().optional().describe('Maximum number of posts to analyze (default: 20)'),
107
+ };
108
+
109
+ export async function summarizeAgentActivityPrompt(
110
+ args: { agent_name: string; limit?: string },
111
+ _extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
112
+ context: SummarizePromptContext,
113
+ ): Promise<GetPromptResult> {
114
+ try {
115
+ const limit = args.limit ? Number.parseInt(args.limit, 10) : 20;
116
+ logger.debug('Generating agent activity summary prompt', { agentName: args.agent_name, limit });
117
+
118
+ // Fetch the agent's posts
119
+ const response = await context.apiClient.fetchPosts(config.teamName, {
120
+ agent_filter: args.agent_name,
121
+ limit,
122
+ offset: 0,
123
+ });
124
+
125
+ if (!response.posts || response.posts.length === 0) {
126
+ return {
127
+ description: 'Agent not found or has no posts',
128
+ messages: [
129
+ {
130
+ role: 'user',
131
+ content: {
132
+ type: 'text',
133
+ text: `No posts found for agent: ${args.agent_name}`,
134
+ },
135
+ },
136
+ ],
137
+ };
138
+ }
139
+
140
+ // Analyze post patterns
141
+ const posts = response.posts.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
142
+ const tags = posts.flatMap((p) => p.tags || []);
143
+ const tagCounts = tags.reduce(
144
+ (acc, tag) => {
145
+ acc[tag] = (acc[tag] || 0) + 1;
146
+ return acc;
147
+ },
148
+ {} as Record<string, number>,
149
+ );
150
+
151
+ const recentPosts = posts
152
+ .slice(0, 5)
153
+ .map((p) => `- ${p.content}${p.tags?.length ? ` [${p.tags.join(', ')}]` : ''}`)
154
+ .join('\n');
155
+
156
+ return {
157
+ description: `Summarize ${args.agent_name}'s social media activity`,
158
+ messages: [
159
+ {
160
+ role: 'user',
161
+ content: {
162
+ type: 'text',
163
+ text: `Please analyze and summarize the social media activity for agent "${args.agent_name}":
164
+
165
+ Total Posts: ${response.total || response.posts.length}
166
+ Posts Analyzed: ${posts.length}
167
+ Time Range: ${posts[posts.length - 1]?.timestamp} to ${posts[0]?.timestamp}
168
+
169
+ Most Used Tags: ${Object.entries(tagCounts)
170
+ .sort(([, a], [, b]) => b - a)
171
+ .slice(0, 5)
172
+ .map(([tag, count]) => `${tag} (${count})`)
173
+ .join(', ')}
174
+
175
+ Recent Posts:
176
+ ${recentPosts}
177
+
178
+ Please provide:
179
+ 1. A summary of this agent's main topics of interest
180
+ 2. Their posting patterns and frequency
181
+ 3. Their communication style and tone
182
+ 4. Key themes or recurring subjects in their posts
183
+ 5. Their level of engagement with others (replies vs original posts)`,
184
+ },
185
+ },
186
+ ],
187
+ };
188
+ } catch (error) {
189
+ logger.error('Error generating agent summary prompt', { error, agentName: args.agent_name });
190
+ return {
191
+ description: 'Error generating prompt',
192
+ messages: [
193
+ {
194
+ role: 'user',
195
+ content: {
196
+ type: 'text',
197
+ text: `Error fetching agent data: ${error instanceof Error ? error.message : 'Unknown error'}`,
198
+ },
199
+ },
200
+ ],
201
+ };
202
+ }
203
+ }
204
+
205
+ // Export schemas for registration
206
+ export const summarizePrompts = {
207
+ summarizeThread: {
208
+ description: 'Generate a summary of a conversation thread',
209
+ argsSchema: summarizeThreadArgsSchema,
210
+ handler: summarizeThreadPrompt,
211
+ },
212
+ summarizeAgentActivity: {
213
+ description: "Summarize an agent's posting patterns and activity",
214
+ argsSchema: summarizeAgentArgsSchema,
215
+ handler: summarizeAgentActivityPrompt,
216
+ },
217
+ };
@@ -0,0 +1,44 @@
1
+ // ABOUTME: Type definitions for MCP prompts in the social media server
2
+ // ABOUTME: Defines prompt structures and interfaces
3
+
4
+ import { z } from 'zod';
5
+
6
+ export interface PromptMessage {
7
+ role: 'user' | 'assistant';
8
+ content: {
9
+ type: 'text';
10
+ text: string;
11
+ };
12
+ }
13
+
14
+ export interface PromptTemplate {
15
+ name: string;
16
+ description?: string;
17
+ arguments?: Record<string, z.ZodString | z.ZodOptional<z.ZodString>>;
18
+ messages: PromptMessage[];
19
+ }
20
+
21
+ // Prompt argument schemas
22
+ export const threadIdSchema = {
23
+ thread_id: z.string().describe('The ID of the thread to analyze'),
24
+ };
25
+
26
+ export const agentNameSchema = {
27
+ agent_name: z.string().describe('The name of the agent to analyze'),
28
+ };
29
+
30
+ export const postContentSchema = {
31
+ post_content: z.string().describe('The content of the post to analyze or reply to'),
32
+ context: z.string().optional().describe('Additional context about the conversation'),
33
+ };
34
+
35
+ export const topicSchema = {
36
+ topic: z.string().describe('The topic or theme to search for'),
37
+ limit: z.string().optional().describe('Maximum number of results to return'),
38
+ };
39
+
40
+ export const timeRangeSchema = {
41
+ start_date: z.string().optional().describe('Start date for the report (ISO format)'),
42
+ end_date: z.string().optional().describe('End date for the report (ISO format)'),
43
+ agent_filter: z.string().optional().describe('Filter by specific agent name'),
44
+ };
@@ -0,0 +1,165 @@
1
+ // ABOUTME: Agent resource handlers for reading agent profiles and posts
2
+ // ABOUTME: Implements resource callbacks for agent-related URIs
3
+
4
+ import type { URL } from 'node:url';
5
+ import type { ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
6
+ import type { IApiClient } from '../api-client.js';
7
+ import { config } from '../config.js';
8
+ import { logger } from '../logger.js';
9
+ import type { AgentPostsResource, AgentProfileResource } from './types.js';
10
+
11
+ export interface AgentResourceContext {
12
+ apiClient: IApiClient;
13
+ }
14
+
15
+ /**
16
+ * Read an agent's profile
17
+ * URI: social://agents/{agentName}/profile
18
+ */
19
+ export async function readAgentProfileResource(
20
+ uri: URL,
21
+ context: AgentResourceContext,
22
+ ): Promise<ReadResourceResult> {
23
+ try {
24
+ // Extract agentName from URI path
25
+ const pathMatch = uri.pathname.match(/^\/\/agents\/([^/]+)\/profile$/);
26
+ const agentName = pathMatch?.[1];
27
+
28
+ if (!agentName) {
29
+ return {
30
+ contents: [
31
+ {
32
+ uri: uri.toString(),
33
+ mimeType: 'application/json',
34
+ text: JSON.stringify({ error: 'Invalid agent profile URI: missing agentName' }),
35
+ },
36
+ ],
37
+ };
38
+ }
39
+
40
+ logger.debug('Reading agent profile resource', { agentName });
41
+
42
+ // Fetch all posts by this agent to build profile
43
+ const response = await context.apiClient.fetchPosts(config.teamName, {
44
+ agent_filter: agentName,
45
+ limit: 100,
46
+ offset: 0,
47
+ });
48
+
49
+ // Calculate profile stats
50
+ let firstSeenAt: string | undefined;
51
+ let lastSeenAt: string | undefined;
52
+
53
+ if (response.posts.length > 0) {
54
+ const timestamps = response.posts.map((p) => p.timestamp);
55
+ timestamps.sort();
56
+ firstSeenAt = timestamps[0];
57
+ lastSeenAt = timestamps[timestamps.length - 1];
58
+ }
59
+
60
+ const resource: AgentProfileResource = {
61
+ profile: {
62
+ agentName,
63
+ postCount: response.total || response.posts.length,
64
+ firstSeenAt,
65
+ lastSeenAt,
66
+ },
67
+ };
68
+
69
+ return {
70
+ contents: [
71
+ {
72
+ uri: uri.toString(),
73
+ mimeType: 'application/json',
74
+ text: JSON.stringify(resource, null, 2),
75
+ },
76
+ ],
77
+ };
78
+ } catch (error) {
79
+ logger.error('Error reading agent profile resource', { error, uri: uri.toString() });
80
+ return {
81
+ contents: [
82
+ {
83
+ uri: uri.toString(),
84
+ mimeType: 'application/json',
85
+ text: JSON.stringify({
86
+ error: 'Failed to read agent profile resource',
87
+ details: error instanceof Error ? error.message : 'Unknown error',
88
+ }),
89
+ },
90
+ ],
91
+ };
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Read an agent's posts
97
+ * URI: social://agents/{agentName}/posts
98
+ */
99
+ export async function readAgentPostsResource(
100
+ uri: URL,
101
+ context: AgentResourceContext,
102
+ ): Promise<ReadResourceResult> {
103
+ try {
104
+ // Extract agentName from URI path
105
+ const pathMatch = uri.pathname.match(/^\/\/agents\/([^/]+)\/posts$/);
106
+ const agentName = pathMatch?.[1];
107
+
108
+ if (!agentName) {
109
+ return {
110
+ contents: [
111
+ {
112
+ uri: uri.toString(),
113
+ mimeType: 'application/json',
114
+ text: JSON.stringify({ error: 'Invalid agent posts URI: missing agentName' }),
115
+ },
116
+ ],
117
+ };
118
+ }
119
+
120
+ logger.debug('Reading agent posts resource', { agentName });
121
+
122
+ // Fetch posts by this agent
123
+ const response = await context.apiClient.fetchPosts(config.teamName, {
124
+ agent_filter: agentName,
125
+ limit: 50, // Reasonable default
126
+ offset: 0,
127
+ });
128
+
129
+ const resource: AgentPostsResource = {
130
+ agentName,
131
+ posts: response.posts.map((p) => ({
132
+ id: p.id,
133
+ content: p.content,
134
+ tags: p.tags,
135
+ timestamp: p.timestamp,
136
+ parent_post_id: p.parent_post_id,
137
+ })),
138
+ total: response.total || response.posts.length,
139
+ };
140
+
141
+ return {
142
+ contents: [
143
+ {
144
+ uri: uri.toString(),
145
+ mimeType: 'application/json',
146
+ text: JSON.stringify(resource, null, 2),
147
+ },
148
+ ],
149
+ };
150
+ } catch (error) {
151
+ logger.error('Error reading agent posts resource', { error, uri: uri.toString() });
152
+ return {
153
+ contents: [
154
+ {
155
+ uri: uri.toString(),
156
+ mimeType: 'application/json',
157
+ text: JSON.stringify({
158
+ error: 'Failed to read agent posts resource',
159
+ details: error instanceof Error ? error.message : 'Unknown error',
160
+ }),
161
+ },
162
+ ],
163
+ };
164
+ }
165
+ }