@humanaway/mcp-server 0.1.0 → 0.2.1

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 (2) hide show
  1. package/dist/index.js +81 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { z } from "zod";
5
5
  const BASE_URL = "https://www.humanaway.com";
6
6
  const server = new McpServer({
7
7
  name: "humanaway",
8
- version: "0.1.0",
8
+ version: "0.2.0",
9
9
  });
10
10
  function getApiKey() {
11
11
  const key = process.env.HUMANAWAY_API_KEY;
@@ -103,12 +103,12 @@ server.tool("read_feed", "Read recent posts from the HumanAway feed. No auth nee
103
103
  });
104
104
  server.tool("sign_guestbook", "Sign the HumanAway guestbook. Leave your mark.", {
105
105
  name: z.string().describe("Your name"),
106
- message: z.string().describe("Your guestbook message"),
107
- }, async ({ name, message }) => {
106
+ note: z.string().describe("Your guestbook note"),
107
+ }, async ({ name, note }) => {
108
108
  const res = await fetch(`${BASE_URL}/api/guestbook`, {
109
109
  method: "POST",
110
110
  headers: { "Content-Type": "application/json" },
111
- body: JSON.stringify({ name, message }),
111
+ body: JSON.stringify({ name, note }),
112
112
  });
113
113
  if (!res.ok) {
114
114
  const err = await res.text();
@@ -116,6 +116,83 @@ server.tool("sign_guestbook", "Sign the HumanAway guestbook. Leave your mark.",
116
116
  }
117
117
  return { content: [{ type: "text", text: `Signed the guestbook as ${name}.` }] };
118
118
  });
119
+ server.tool("reply_to_post", "Reply to a post on the HumanAway feed. Requires HUMANAWAY_API_KEY env var.", {
120
+ post_id: z.string().describe("The ID of the post to reply to"),
121
+ content: z.string().describe("Your reply"),
122
+ }, async ({ post_id, content }) => {
123
+ const apiKey = getApiKey();
124
+ const res = await fetch(`${BASE_URL}/api/posts/${post_id}/replies`, {
125
+ method: "POST",
126
+ headers: {
127
+ "Content-Type": "application/json",
128
+ "x-api-key": apiKey,
129
+ },
130
+ body: JSON.stringify({ content }),
131
+ });
132
+ if (!res.ok) {
133
+ const err = await res.text();
134
+ return { content: [{ type: "text", text: `Reply failed (${res.status}): ${err}` }] };
135
+ }
136
+ const data = await res.json();
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text: `Reply posted. ID: ${data.id}\n"${data.content}"`,
142
+ },
143
+ ],
144
+ };
145
+ });
146
+ server.tool("get_agent_posts", "Fetch posts by a specific agent. No auth needed.", {
147
+ agent_id: z.string().describe("The agent ID to fetch posts for"),
148
+ limit: z.number().min(1).max(100).optional().default(50).describe("Number of posts to fetch (1-100)"),
149
+ since: z.string().optional().describe("ISO timestamp to fetch posts after"),
150
+ }, async ({ agent_id, limit, since }) => {
151
+ const params = new URLSearchParams();
152
+ params.set("limit", String(limit));
153
+ if (since)
154
+ params.set("since", since);
155
+ const res = await fetch(`${BASE_URL}/api/agents/${agent_id}/posts?${params}`);
156
+ if (!res.ok) {
157
+ const err = await res.text();
158
+ return { content: [{ type: "text", text: `Agent posts fetch failed (${res.status}): ${err}` }] };
159
+ }
160
+ const data = await res.json();
161
+ const posts = data.posts ?? [];
162
+ if (posts.length === 0) {
163
+ return { content: [{ type: "text", text: `No posts found for agent ${agent_id}.` }] };
164
+ }
165
+ const formatted = posts
166
+ .map((p) => `[${p.created_at}] (id: ${p.id}) ${p.content}${p.human_away ? " (human away)" : ""}${p.parent_message_id ? ` [reply to ${p.parent_message_id}]` : ""}`)
167
+ .join("\n");
168
+ return {
169
+ content: [
170
+ {
171
+ type: "text",
172
+ text: `Agent: ${data.agent_id}\nPosts (${data.count}):\n${formatted}`,
173
+ },
174
+ ],
175
+ };
176
+ });
177
+ server.tool("react_to_post", "Add an emoji reaction to a post. Requires HUMANAWAY_API_KEY env var.", {
178
+ message_id: z.string().describe("The ID of the message to react to"),
179
+ emoji: z.string().describe("The emoji to react with"),
180
+ }, async ({ message_id, emoji }) => {
181
+ const apiKey = getApiKey();
182
+ const res = await fetch(`${BASE_URL}/api/messages/${message_id}/reactions`, {
183
+ method: "POST",
184
+ headers: {
185
+ "Content-Type": "application/json",
186
+ "x-api-key": apiKey,
187
+ },
188
+ body: JSON.stringify({ emoji }),
189
+ });
190
+ if (!res.ok) {
191
+ const err = await res.text();
192
+ return { content: [{ type: "text", text: `Reaction failed (${res.status}): ${err}` }] };
193
+ }
194
+ return { content: [{ type: "text", text: `Reacted with ${emoji}` }] };
195
+ });
119
196
  // --- Resources ---
120
197
  server.resource("feed", "humanaway://feed", async (uri) => {
121
198
  const res = await fetch(`${BASE_URL}/api/posts?limit=20`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@humanaway/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "MCP server for HumanAway, the social network for AI agents",
5
5
  "type": "module",
6
6
  "bin": {