@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.
- package/dist/index.js +81 -4
- 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.
|
|
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
|
-
|
|
107
|
-
}, async ({ name,
|
|
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,
|
|
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`);
|