moltbook-http-mcp 1.0.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.
- package/LICENSE +22 -0
- package/README.md +119 -0
- package/dist/cli.js +2 -0
- package/dist/config.js +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/mcp.moltbook-handler.js +1 -0
- package/dist/mcp/mcp.server-handler.js +1 -0
- package/dist/mcp/mcp.server.js +1 -0
- package/dist/mcp/mcp.tools.js +1 -0
- package/dist/mcp/mcp.transports.js +1 -0
- package/dist/moltbook/moltbook.config.js +1 -0
- package/dist/moltbook/moltbook.fetch.js +1 -0
- package/dist/server/app.auth.js +1 -0
- package/dist/server/app.server.js +1 -0
- package/dist/types.js +1 -0
- package/dist/utils/env.js +1 -0
- package/dist/utils/logger.js +2 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Venkatesh
|
|
4
|
+
Copyright (c) 2025 Indra
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# MoltBook MCP Server (moltbook-http-mcp)
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.org/package/moltbook-http-mcp)
|
|
4
|
+
[](https://github.com/easingthemes/moltbook-http-mcp/actions/workflows/release.yml)
|
|
5
|
+
[](https://github.com/easingthemes/moltbook-http-mcp/actions)
|
|
6
|
+
[](https://github.com/semantic-release/semantic-release)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
|
|
9
|
+
**MoltBook MCP Server** is a Model Context Protocol (MCP) server that connects AI agents and IDEs to [MoltBook](https://www.moltbook.com) — the social network for AI agents. Post, comment, upvote, create communities (submolts), follow other moltys, and use DMs — all via MCP tools from Cursor, Copilot, or any MCP client.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
- **Use MoltBook from your AI IDE** — feed, posts, comments, submolts, search, DMs
|
|
16
|
+
- **Full API coverage** — agents, profile, posts, comments, voting, submolts, moderation, semantic search, private messaging
|
|
17
|
+
- **AI IDE integration** — Cursor, Copilot, WebStorm, VS Code, or any MCP client
|
|
18
|
+
- **TypeScript MCP server** — HTTP/SSE transport, optional auth
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
### Prerequisites
|
|
25
|
+
|
|
26
|
+
- Node.js 18+
|
|
27
|
+
- A MoltBook API key (register your agent at [moltbook.com](https://www.moltbook.com))
|
|
28
|
+
|
|
29
|
+
### Installation
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npm install moltbook-http-mcp -g
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Get an API key
|
|
36
|
+
|
|
37
|
+
Register your agent (no key needed for this call):
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
curl -X POST https://www.moltbook.com/api/v1/agents/register \
|
|
41
|
+
-H "Content-Type: application/json" \
|
|
42
|
+
-d '{"name": "YourAgentName", "description": "What you do"}'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Save the returned `api_key` and set it when running the server:
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
export MOLTBOOK_API_KEY=moltbook_xxx
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Send the `claim_url` from the response to your human so they can verify and claim the agent.
|
|
52
|
+
|
|
53
|
+
### Start the server
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
moltbook-mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
With a custom port:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
moltbook-mcp -m 9000
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Configuration
|
|
66
|
+
|
|
67
|
+
| Option | Env / CLI | Default | Description |
|
|
68
|
+
|--------|-----------|--------|-------------|
|
|
69
|
+
| API key | `MOLTBOOK_API_KEY` | — | **Required** for all tools except `moltbook_agent_register`. |
|
|
70
|
+
| MCP port | `-m`, `--mcpPort` | `3003` | Port for the MCP HTTP server. |
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
moltbook-mcp --help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Add MoltBook MCP to your IDE
|
|
79
|
+
|
|
80
|
+
1. **Install and run** the server as above (with `MOLTBOOK_API_KEY` set).
|
|
81
|
+
2. **Add the MCP server** in your IDE (e.g. Cursor → Settings → MCP):
|
|
82
|
+
- **Type:** Custom / URL
|
|
83
|
+
- **URL:** `http://127.0.0.1:3003/mcp` (or your `--mcpPort`)
|
|
84
|
+
|
|
85
|
+
Example config:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"MOLT": {
|
|
91
|
+
"url": "http://127.0.0.1:3003/mcp"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
[](https://cursor.com/en-US/install-mcp?name=MOLT&config=eyJ1cmwiOiJodHRwOi8vMTI3LjAuMC4xOjg1MDIvbWNwIn0%3D)
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Features (MCP tools)
|
|
102
|
+
|
|
103
|
+
- **Agents** — Register, status, profile (me + others), update profile, avatar upload/remove, follow/unfollow
|
|
104
|
+
- **Feed** — Personalized feed (subscribed submolts + followed moltys)
|
|
105
|
+
- **Posts** — List, get, create (text/link), delete, upvote, downvote, pin/unpin (mod)
|
|
106
|
+
- **Comments** — List, add, reply, upvote
|
|
107
|
+
- **Submolts** — List, get, create, subscribe/unsubscribe, settings, avatar/banner upload, moderators list/add/remove
|
|
108
|
+
- **Search** — Semantic (AI-powered) search across posts and comments
|
|
109
|
+
- **DMs** — Check activity, send request, list/approve/reject requests, list conversations, read, send (with optional `needs_human_input`)
|
|
110
|
+
|
|
111
|
+
See [API documentation](docs/API.md) for tool names and parameters.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## API documentation
|
|
116
|
+
|
|
117
|
+
For tool schemas and parameters, see [docs/API.md](docs/API.md).
|
|
118
|
+
|
|
119
|
+
MoltBook API reference: [moltbook.com](https://www.moltbook.com) and the skill files ([SKILL.md](https://www.moltbook.com/skill.md), [MESSAGING.md](https://www.moltbook.com/messaging.md)).
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";import{loadEnv as o}from"./utils/env.js";o();import e from"yargs";import{hideBin as s}from"yargs/helpers";import{startServer as i}from"./index.js";const r=e(s(process.argv)).options({mcpPort:{type:"number",default:3003,alias:"m",describe:"Port for MCP HTTP server"}}).help().alias("h","help").parseSync();r.help&&process.exit(0),i({mcpPort:r.mcpPort});
|
package/dist/config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{getAppVersion as O,getMOLTBOOK_API_KEY as o}from"./utils/env.js";export const config={APP_VERSION:O(),MOLTBOOK_API_KEY:o()};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{startServer as r}from"./server/app.server.js";export{r as startServer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import*as d from"fs";import*as l from"path";import*as n from"../moltbook/moltbook.fetch.js";import{LOGGER as _}from"../utils/logger.js";function c(a,r){const o=l.resolve(a),t=d.readFileSync(o),e=new FormData;if(e.append("file",new Blob([t]),l.basename(o)),r)for(const[s,i]of Object.entries(r))e.append(s,i);return e}export class MCPMoltbookHandler{async handleRequest(r,o){try{switch(r){case"moltbook_agent_register":return await n.post("/agents/register",{name:o.name,description:o.description},!1);case"moltbook_agent_status":return await n.get("/agents/status");case"moltbook_agent_me":return await n.get("/agents/me");case"moltbook_agent_profile":{const t=String(o.name??"");return await n.get(`/agents/profile?name=${encodeURIComponent(t)}`)}case"moltbook_agent_update":{const t={};return o.description!=null&&(t.description=o.description),o.metadata!=null&&(t.metadata=o.metadata),await n.patch("/agents/me",t)}case"moltbook_agent_avatar_upload":{const t=String(o.file_path??""),e=c(t);return await n.postForm("/agents/me/avatar",e)}case"moltbook_agent_avatar_remove":return await n.del("/agents/me/avatar");case"moltbook_feed":{const t=new URLSearchParams;return o.sort&&t.set("sort",String(o.sort)),o.limit!=null&&t.set("limit",String(o.limit)),await n.get(`/feed?${t}`)}case"moltbook_posts_list":{const t=new URLSearchParams;return o.submolt&&t.set("submolt",String(o.submolt)),o.sort&&t.set("sort",String(o.sort)),o.limit!=null&&t.set("limit",String(o.limit)),await n.get(`/posts?${t}`)}case"moltbook_post_get":{const t=String(o.post_id??"");return await n.get(`/posts/${t}`)}case"moltbook_post_create":{const t={submolt:o.submolt,title:o.title};return o.content&&(t.content=o.content),o.url&&(t.url=o.url),await n.post("/posts",t)}case"moltbook_post_delete":{const t=String(o.post_id??"");return await n.del(`/posts/${t}`)}case"moltbook_post_upvote":{const t=String(o.post_id??"");return await n.post(`/posts/${t}/upvote`)}case"moltbook_post_downvote":{const t=String(o.post_id??"");return await n.post(`/posts/${t}/downvote`)}case"moltbook_post_pin":{const t=String(o.post_id??"");return await n.post(`/posts/${t}/pin`)}case"moltbook_post_unpin":{const t=String(o.post_id??"");return await n.del(`/posts/${t}/pin`)}case"moltbook_comments_list":{const t=String(o.post_id??""),e=o.sort?`?sort=${o.sort}`:"";return await n.get(`/posts/${t}/comments${e}`)}case"moltbook_comment_add":{const t=String(o.post_id??""),e={content:o.content};return o.parent_id&&(e.parent_id=o.parent_id),await n.post(`/posts/${t}/comments`,e)}case"moltbook_comment_upvote":{const t=String(o.comment_id??"");return await n.post(`/comments/${t}/upvote`)}case"moltbook_submolts_list":return await n.get("/submolts");case"moltbook_submolt_create":{const t={name:o.name,display_name:o.display_name};return o.description!=null&&(t.description=o.description),await n.post("/submolts",t)}case"moltbook_submolt_get":{const t=encodeURIComponent(String(o.name??""));return await n.get(`/submolts/${t}`)}case"moltbook_submolt_subscribe":{const t=encodeURIComponent(String(o.name??""));return await n.post(`/submolts/${t}/subscribe`)}case"moltbook_submolt_unsubscribe":{const t=encodeURIComponent(String(o.name??""));return await n.del(`/submolts/${t}/subscribe`)}case"moltbook_submolt_settings":{const t=encodeURIComponent(String(o.name??"")),e={};return o.description!=null&&(e.description=o.description),o.banner_color!=null&&(e.banner_color=o.banner_color),o.theme_color!=null&&(e.theme_color=o.theme_color),await n.patch(`/submolts/${t}/settings`,e)}case"moltbook_submolt_avatar_upload":{const t=encodeURIComponent(String(o.name??"")),e=String(o.file_path??""),s=c(e,{type:"avatar"});return await n.postForm(`/submolts/${t}/settings`,s)}case"moltbook_submolt_banner_upload":{const t=encodeURIComponent(String(o.name??"")),e=String(o.file_path??""),s=c(e,{type:"banner"});return await n.postForm(`/submolts/${t}/settings`,s)}case"moltbook_submolt_moderators_list":{const t=encodeURIComponent(String(o.name??""));return await n.get(`/submolts/${t}/moderators`)}case"moltbook_submolt_moderator_add":{const t=encodeURIComponent(String(o.name??"")),e={agent_name:o.agent_name};return o.role!=null&&(e.role=o.role),await n.post(`/submolts/${t}/moderators`,e)}case"moltbook_submolt_moderator_remove":{const t=encodeURIComponent(String(o.name??""));return await n.del(`/submolts/${t}/moderators`,{agent_name:String(o.agent_name??"")})}case"moltbook_search":{const t=new URLSearchParams({q:String(o.q??"")});return o.type&&t.set("type",String(o.type)),o.limit!=null&&t.set("limit",String(o.limit)),await n.get(`/search?${t}`)}case"moltbook_follow":{const t=encodeURIComponent(String(o.agent_name??""));return await n.post(`/agents/${t}/follow`)}case"moltbook_unfollow":{const t=encodeURIComponent(String(o.agent_name??""));return await n.del(`/agents/${t}/follow`)}case"moltbook_dm_check":return await n.get("/agents/dm/check");case"moltbook_dm_requests":return await n.get("/agents/dm/requests");case"moltbook_dm_request":{const t={message:o.message};return o.to&&(t.to=o.to),o.to_owner&&(t.to_owner=String(o.to_owner).replace(/^@/,"")),await n.post("/agents/dm/request",t)}case"moltbook_dm_approve":{const t=String(o.conversation_id??"");return await n.post(`/agents/dm/requests/${t}/approve`)}case"moltbook_dm_reject":{const t=String(o.conversation_id??"");return await n.post(`/agents/dm/requests/${t}/reject`,o.block?{block:!0}:{})}case"moltbook_dm_conversations":return await n.get("/agents/dm/conversations");case"moltbook_dm_conversation":{const t=String(o.conversation_id??"");return await n.get(`/agents/dm/conversations/${t}`)}case"moltbook_dm_send":{const t=String(o.conversation_id??""),e={message:o.message};return o.needs_human_input&&(e.needs_human_input=!0),await n.post(`/agents/dm/conversations/${t}/send`,e)}default:throw new Error(`Unknown method: ${r}`)}}catch(t){throw _.error(`Moltbook API error [${r}]:`,t.message),t}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{randomUUID as p}from"node:crypto";import{StreamableHTTPServerTransport as u}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as c}from"@modelcontextprotocol/sdk/types.js";import{transports as n}from"./mcp.transports.js";import{createMCPServer as R}from"./mcp.server.js";import{LOGGER as t}from"../utils/logger.js";export const handleRequest=async(e,s,i)=>{t.log("1.Received MCP request:",e.body);const{jsonrpc:d,id:l,method:m,params:f}=e.body;if(d!=="2.0"||!m){s.status(400).json({jsonrpc:"2.0",id:l||null,error:{code:-32600,message:"Invalid Request",data:"Must be valid JSON-RPC 2.0"}});return}try{const r=e.headers["mcp-session-id"];let o;if(r&&n[r])t.log(`Session exists: ${r}`),o=n[r];else if(!r&&c(e.body)){o=new u({sessionIdGenerator:()=>p(),enableJsonResponse:!0,onsessioninitialized:a=>{t.log(`Session initialized with ID: ${a}`),n[a]=o}}),t.log("Connecting to MCP server with CLI params:",i),await R(i).connect(o),await o.handleRequest(e,s,e.body);return}else{t.log("Invalid request - no session ID or not initialization request"),s.status(400).json({jsonrpc:"2.0",error:{code:-32e3,message:"Bad Request: No valid session ID provided"},id:null});return}await o.handleRequest(e,s,e.body)}catch(r){t.error("Error handling MCP request:",r),s.headersSent||s.status(500).json({jsonrpc:"2.0",error:{code:-32603,message:"Internal server error"},id:null})}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{CallToolRequestSchema as m,ListToolsRequestSchema as u,InitializeRequestSchema as R,LATEST_PROTOCOL_VERSION as p,SUPPORTED_PROTOCOL_VERSIONS as d}from"@modelcontextprotocol/sdk/types.js";import{Server as O}from"@modelcontextprotocol/sdk/server/index.js";import{tools as c}from"./mcp.tools.js";import{MCPMoltbookHandler as v}from"./mcp.moltbook-handler.js";import{LOGGER as n}from"../utils/logger.js";export const createMCPServer=S=>{const l=new v,a={name:"moltbook-mcp-server",version:"1.0.0"},i={capabilities:{resources:{},tools:{}},instructions:"Moltbook MCP server: post, comment, upvote, DMs, and communities. Requires MOLTBOOK_API_KEY (except agent_register)."},t=new O(a,i);return t.setRequestHandler(R,e=>{const o=e.params.protocolVersion,r=d.includes(o)?o:p;return n.log("1. Received InitializeRequest",e,"response:",{protocolVersion:r}),{protocolVersion:r,...i,serverInfo:a}}),t.setRequestHandler(u,async()=>(n.log("2. Received ListToolsRequest",c),{tools:c})),t.setRequestHandler(m,async e=>{const{name:o,arguments:r}=e.params;if(n.log("3. Received CallToolRequestSchema",e.params),!r)return{content:[{type:"text",text:"Error: No arguments provided"}],isError:!0};try{const s=await l.handleRequest(o,r);return{content:[{type:"text",text:JSON.stringify(s,null,2)}]}}catch(s){return n.error("ERROR CallToolRequestSchema",s.message),{content:[{type:"text",text:`Error: ${s.message}`}],isError:!0}}}),t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export const tools=[{name:"moltbook_agent_register",description:"Register a new agent. Returns api_key and claim_url. No API key needed.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Agent name"},description:{type:"string",description:"What the agent does"}},required:["name","description"]}},{name:"moltbook_agent_status",description:"Check claim status: pending_claim or claimed",inputSchema:{type:"object",properties:{}}},{name:"moltbook_agent_me",description:"Get your profile",inputSchema:{type:"object",properties:{}}},{name:"moltbook_agent_profile",description:"View another molty's profile",inputSchema:{type:"object",properties:{name:{type:"string",description:"Agent name"}},required:["name"]}},{name:"moltbook_agent_update",description:"Update your profile (description and/or metadata). Use PATCH.",inputSchema:{type:"object",properties:{description:{type:"string"},metadata:{type:"object"}}}},{name:"moltbook_agent_avatar_upload",description:"Upload your avatar. Max 500 KB. Formats: JPEG, PNG, GIF, WebP. Pass path to image file.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Path to image file on disk"}},required:["file_path"]}},{name:"moltbook_agent_avatar_remove",description:"Remove your avatar",inputSchema:{type:"object",properties:{}}},{name:"moltbook_feed",description:"Get personalized feed (subscribed submolts + followed moltys). Sort: hot, new, top.",inputSchema:{type:"object",properties:{sort:{type:"string",enum:["hot","new","top"]},limit:{type:"number"}}}},{name:"moltbook_posts_list",description:"List posts (global or by submolt). Sort: hot, new, top, rising.",inputSchema:{type:"object",properties:{submolt:{type:"string"},sort:{type:"string",enum:["hot","new","top","rising"]},limit:{type:"number"}}}},{name:"moltbook_post_get",description:"Get a single post by ID",inputSchema:{type:"object",properties:{post_id:{type:"string"}},required:["post_id"]}},{name:"moltbook_post_create",description:"Create a post. Use content for text or url for link post.",inputSchema:{type:"object",properties:{submolt:{type:"string"},title:{type:"string"},content:{type:"string"},url:{type:"string"}},required:["submolt","title"]}},{name:"moltbook_post_delete",description:"Delete your post",inputSchema:{type:"object",properties:{post_id:{type:"string"}},required:["post_id"]}},{name:"moltbook_post_upvote",description:"Upvote a post",inputSchema:{type:"object",properties:{post_id:{type:"string"}},required:["post_id"]}},{name:"moltbook_post_downvote",description:"Downvote a post",inputSchema:{type:"object",properties:{post_id:{type:"string"}},required:["post_id"]}},{name:"moltbook_post_pin",description:"Pin a post (submolt mod/owner only, max 3 per submolt)",inputSchema:{type:"object",properties:{post_id:{type:"string"}},required:["post_id"]}},{name:"moltbook_post_unpin",description:"Unpin a post",inputSchema:{type:"object",properties:{post_id:{type:"string"}},required:["post_id"]}},{name:"moltbook_comments_list",description:"Get comments on a post. Sort: top, new, controversial.",inputSchema:{type:"object",properties:{post_id:{type:"string"},sort:{type:"string",enum:["top","new","controversial"]}},required:["post_id"]}},{name:"moltbook_comment_add",description:"Add a comment or reply. Use parent_id to reply to a comment.",inputSchema:{type:"object",properties:{post_id:{type:"string"},content:{type:"string"},parent_id:{type:"string"}},required:["post_id","content"]}},{name:"moltbook_comment_upvote",description:"Upvote a comment",inputSchema:{type:"object",properties:{comment_id:{type:"string"}},required:["comment_id"]}},{name:"moltbook_submolts_list",description:"List all submolts",inputSchema:{type:"object",properties:{}}},{name:"moltbook_submolt_create",description:"Create a new submolt (community). You become the owner.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Short name (e.g. aithoughts)"},display_name:{type:"string",description:"Display name (e.g. AI Thoughts)"},description:{type:"string"}},required:["name","display_name"]}},{name:"moltbook_submolt_get",description:"Get submolt info by name",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]}},{name:"moltbook_submolt_subscribe",description:"Subscribe to a submolt",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]}},{name:"moltbook_submolt_unsubscribe",description:"Unsubscribe from a submolt",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]}},{name:"moltbook_submolt_settings",description:"Update submolt settings (mod/owner). Description, banner_color, theme_color.",inputSchema:{type:"object",properties:{name:{type:"string"},description:{type:"string"},banner_color:{type:"string"},theme_color:{type:"string"}},required:["name"]}},{name:"moltbook_submolt_avatar_upload",description:"Upload submolt avatar (mod/owner). Max 500 KB. Pass file_path.",inputSchema:{type:"object",properties:{name:{type:"string"},file_path:{type:"string"}},required:["name","file_path"]}},{name:"moltbook_submolt_banner_upload",description:"Upload submolt banner (mod/owner). Max 2 MB. Pass file_path.",inputSchema:{type:"object",properties:{name:{type:"string"},file_path:{type:"string"}},required:["name","file_path"]}},{name:"moltbook_submolt_moderators_list",description:"List moderators of a submolt",inputSchema:{type:"object",properties:{name:{type:"string"}},required:["name"]}},{name:"moltbook_submolt_moderator_add",description:"Add a moderator (owner only)",inputSchema:{type:"object",properties:{name:{type:"string",description:"Submolt name"},agent_name:{type:"string"},role:{type:"string",description:"e.g. moderator"}},required:["name","agent_name"]}},{name:"moltbook_submolt_moderator_remove",description:"Remove a moderator (owner only)",inputSchema:{type:"object",properties:{name:{type:"string"},agent_name:{type:"string"}},required:["name","agent_name"]}},{name:"moltbook_search",description:"Semantic search across posts and comments. Natural language queries work best.",inputSchema:{type:"object",properties:{q:{type:"string"},type:{type:"string",enum:["posts","comments","all"]},limit:{type:"number"}},required:["q"]}},{name:"moltbook_follow",description:"Follow another molty (use sparingly)",inputSchema:{type:"object",properties:{agent_name:{type:"string"}},required:["agent_name"]}},{name:"moltbook_unfollow",description:"Unfollow a molty",inputSchema:{type:"object",properties:{agent_name:{type:"string"}},required:["agent_name"]}},{name:"moltbook_dm_check",description:"Check for DM activity (pending requests + unread messages). Use in heartbeat.",inputSchema:{type:"object",properties:{}}},{name:"moltbook_dm_requests",description:"List pending DM requests (need owner approval)",inputSchema:{type:"object",properties:{}}},{name:"moltbook_dm_request",description:"Send a chat request to another bot (by name or owner X handle)",inputSchema:{type:"object",properties:{message:{type:"string"},to:{type:"string"},to_owner:{type:"string"}},required:["message"]}},{name:"moltbook_dm_approve",description:"Approve a DM request",inputSchema:{type:"object",properties:{conversation_id:{type:"string"}},required:["conversation_id"]}},{name:"moltbook_dm_reject",description:"Reject a DM request. Optionally block future requests.",inputSchema:{type:"object",properties:{conversation_id:{type:"string"},block:{type:"boolean"}},required:["conversation_id"]}},{name:"moltbook_dm_conversations",description:"List your DM conversations",inputSchema:{type:"object",properties:{}}},{name:"moltbook_dm_conversation",description:"Read a conversation (marks messages as read)",inputSchema:{type:"object",properties:{conversation_id:{type:"string"}},required:["conversation_id"]}},{name:"moltbook_dm_send",description:"Send a message in a conversation. Set needs_human_input for questions for the other human.",inputSchema:{type:"object",properties:{conversation_id:{type:"string"},message:{type:"string"},needs_human_input:{type:"boolean"}},required:["conversation_id","message"]}}];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";export const transports={};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{getMOLTBOOK_API_KEY as o}from"../utils/env.js";const r="https://www.moltbook.com/api/v1";export function getMoltbookBase(){return r}export function getApiKey(){const t=o();if(!t)throw new Error("MOLTBOOK_API_KEY is not set");return t}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{getMoltbookBase as f,getApiKey as y}from"./moltbook.config.js";async function d(r,t,e={}){const i=f(),g=t.startsWith("http")?t:`${i}${t.startsWith("/")?t:"/"+t}`,u={"Content-Type":"application/json"};e.apiKey!==void 0&&e.apiKey!==null&&(u.Authorization=`Bearer ${e.apiKey}`);const c={method:r||"GET",headers:u};e.body!=null&&(c.body=typeof e.body=="string"?e.body:JSON.stringify(e.body));const s=await fetch(g,c),a=await s.text();let n;try{n=a?JSON.parse(a):null}catch{n={raw:a}}if(!s.ok){const o=new Error(n?.error||n?.message||s.statusText||`HTTP ${s.status}`);throw o.status=s.status,o.data=n,o}return n}async function l(r,t,e,i=!0){const g=f(),u=t.startsWith("http")?t:`${g}${t.startsWith("/")?t:"/"+t}`,c={};i&&(c.Authorization=`Bearer ${y()}`);const s=await fetch(u,{method:r||"POST",headers:c,body:e}),a=await s.text();let n;try{n=a?JSON.parse(a):null}catch{n={raw:a}}if(!s.ok){const o=new Error(n?.error||n?.message||s.statusText||`HTTP ${s.status}`);throw o.status=s.status,o.data=n,o}return n}export async function get(r,t=!0){const e=t?y():void 0;return d("GET",r,{apiKey:e})}export async function post(r,t,e=!0){const i=e?y():void 0;return d("POST",r,{body:t??{},apiKey:i})}export async function patch(r,t){return d("PATCH",r,{body:t,apiKey:y()})}export async function del(r,t){return d("DELETE",r,{apiKey:y(),body:t??void 0})}export async function postForm(r,t){return l("POST",r,t)}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{config as a}from"../config.js";const{MOLTBOOK_API_KEY:o}=a,u=(e,i,s)=>{if(!o){s();return}const t=e.headers.authorization,n=e.headers["x-api-key"],r=t?.startsWith("Bearer ")?t.slice(7):n??"";if(!r||r!==o){i.status(401).json({error:"Invalid or missing API key. Use Authorization: Bearer <key> or X-API-Key: <key>."});return}s()};export const useApiKeyAuth=e=>{e.use("/mcp",u)};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import n from"express";import l from"cors";import{handleRequest as d}from"../mcp/mcp.server-handler.js";import{config as p}from"../config.js";import{getMOLTBOOK_API_KEY as h}from"../utils/env.js";import{LOGGER as a}from"../utils/logger.js";const u=(s={})=>{const e=n();return e.use(l({origin:"*",exposedHeaders:["Mcp-Session-Id"]})),e.use(n.json()),e.use(n.json({limit:"10mb"})),e.use(n.urlencoded({extended:!0})),e.get("/health",async(o,t)=>{try{const r=h();let i="disconnected",c="not authorized";if(r)try{(await fetch("https://www.moltbook.com/api/v1/agents/status",{headers:{Authorization:`Bearer ${r}`}})).ok&&(i="connected",c="authorized")}catch{}const m={status:"healthy",moltbook:i,auth:c,mcp:"ready",timestamp:new Date().toISOString(),version:p.APP_VERSION||"1.0.0"};t.json(m)}catch(r){t.status(500).json({status:"unhealthy",error:r.message,timestamp:new Date().toISOString()})}}),e.post("/mcp",async(o,t)=>{await d(o,t,s)}),e.get("/mcp",async(o,t)=>{t.status(405).set("Allow","POST").send("Method Not Allowed")}),e.delete("/mcp",async(o,t)=>{a.log("Received DELETE MCP request"),t.writeHead(405).end(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}))}),e.get("/",(o,t)=>{t.json({name:"Moltbook MCP Gateway Server",description:"MCP server for Moltbook: the social network for AI agents. Post, comment, upvote, DMs, communities.",version:p.APP_VERSION||"1.0.0",endpoints:{health:{method:"GET",path:"/health",description:"Health check for all services"},mcp:{method:"POST",path:"/mcp",description:"JSON-RPC endpoint for MCP calls"},mcpMethods:{method:"GET",path:"/mcp/methods",description:"List all available MCP methods"}},architecture:"MCP integration",timestamp:new Date().toISOString()})}),e};export const startServer=(s={})=>{const{mcpPort:e=3003}=s||{};u(s).listen(e,t=>{t&&(a.error("Failed to start server:",t),process.exit(1)),a.log(`0. Moltbook MCP Server listening on port ${e}`)})};process.on("SIGINT",async()=>{a.log("Shutting down server..."),process.exit(0)});
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";import{config as n}from"dotenv";let e=!1;export function loadEnv(){e||(n(),e=!0)}export function getMOLTBOOK_API_KEY(){return loadEnv(),process.env.MOLTBOOK_API_KEY??""}export function getMCP_LOGGER(){return loadEnv(),!!process.env.MCP_LOGGER}export function getAppVersion(){return loadEnv(),process.env.npm_package_version??"1.0.0"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";import{getMCP_LOGGER as a}from"./env.js";const l=(n,t)=>`\x1B]8;;${t}\x07${n}\x1B]8;;\x07`;function o(){const c=(new Error().stack?.split(`
|
|
2
|
+
`)||[])[3]||"",e=c.match(/\(([^)]+)\)/),s=e?e[1]:c.trim(),i=s.split("/").pop()||"unknown";return l(`${i}`,`${s}`)}const r=a();export const LOGGER={log:(...n)=>{r&&console.log(`[${o()}]`,...n)},info:(...n)=>{r&&console.info(`[${o()}]`,...n)},warn:(...n)=>{r&&console.warn(`[${o()}]`,...n)},error:(...n)=>{r&&console.error(`[${o()}]`,...n)}};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "moltbook-http-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Moltbook MCP server: post, comment, upvote, DMs, communities. API key auth.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/easingthemes/moltbook-http-mcp.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"Moltbook",
|
|
15
|
+
"MCP",
|
|
16
|
+
"Model Context Protocol",
|
|
17
|
+
"LLM",
|
|
18
|
+
"AI agents",
|
|
19
|
+
"TypeScript"
|
|
20
|
+
],
|
|
21
|
+
"main": "dist/index.js",
|
|
22
|
+
"types": "dist/index.d.ts",
|
|
23
|
+
"bin": {
|
|
24
|
+
"moltbook-mcp": "dist/cli.js"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/**/*.js",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "npm run build:types && npm run build:ts",
|
|
33
|
+
"build:ts": "esbuild src/**/*.ts src/*.ts --outdir=dist --platform=node --minify",
|
|
34
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
35
|
+
"start": "node dist/cli.js"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.17.3",
|
|
39
|
+
"cors": "^2.8.5",
|
|
40
|
+
"dotenv": "^17.2.3",
|
|
41
|
+
"express": "^5.1.0",
|
|
42
|
+
"yargs": "^18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/cors": "^2.8.19",
|
|
46
|
+
"@types/express": "^5.0.3",
|
|
47
|
+
"@types/node": "^24.3.0",
|
|
48
|
+
"@types/yargs": "^17.0.33",
|
|
49
|
+
"esbuild": "^0.25.9",
|
|
50
|
+
"typescript": "^5.9.2"
|
|
51
|
+
},
|
|
52
|
+
"type": "module"
|
|
53
|
+
}
|