@lucianfialho/build-in-public-mcp 0.3.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 +21 -0
- package/README.md +218 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +425 -0
- package/dist/index.js.map +1 -0
- package/dist/services/git-analyzer.d.ts +22 -0
- package/dist/services/git-analyzer.d.ts.map +1 -0
- package/dist/services/git-analyzer.js +168 -0
- package/dist/services/git-analyzer.js.map +1 -0
- package/dist/services/storage.d.ts +111 -0
- package/dist/services/storage.d.ts.map +1 -0
- package/dist/services/storage.js +260 -0
- package/dist/services/storage.js.map +1 -0
- package/dist/services/suggestion-engine.d.ts +20 -0
- package/dist/services/suggestion-engine.d.ts.map +1 -0
- package/dist/services/suggestion-engine.js +171 -0
- package/dist/services/suggestion-engine.js.map +1 -0
- package/dist/services/twitter.d.ts +36 -0
- package/dist/services/twitter.d.ts.map +1 -0
- package/dist/services/twitter.js +149 -0
- package/dist/services/twitter.js.map +1 -0
- package/dist/utils/oauth.d.ts +15 -0
- package/dist/utils/oauth.d.ts.map +1 -0
- package/dist/utils/oauth.js +150 -0
- package/dist/utils/oauth.js.map +1 -0
- package/package.json +42 -0
- package/server.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lucian Fialho
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Build in Public MCP Server
|
|
2
|
+
|
|
3
|
+
> โ
**v0.3.0 - AI-Powered Tweet Suggestions!**
|
|
4
|
+
|
|
5
|
+
MCP (Model Context Protocol) server for Build in Public - automatically share your dev progress on Twitter directly from Claude Code.
|
|
6
|
+
|
|
7
|
+
## ๐ฏ What is this?
|
|
8
|
+
|
|
9
|
+
**The idea is simple:** If Claude Code is already helping you build, why not use it to document the journey too?
|
|
10
|
+
|
|
11
|
+
This MCP server analyzes your coding sessions and generates intelligent tweet suggestions about what you accomplished. Share your dev journey without breaking flow!
|
|
12
|
+
|
|
13
|
+
**Features:**
|
|
14
|
+
- ๐ค **AI-powered tweet suggestions** - Analyzes your coding session and suggests tweets
|
|
15
|
+
- ๐ **Retrospective mode** (`/bp retro`) - Review entire session and extract achievements
|
|
16
|
+
- ๐ฆ Post tweets immediately with `/bp` command
|
|
17
|
+
- ๐งต Create threads about your dev progress
|
|
18
|
+
- ๐ OAuth authentication (tokens stored locally)
|
|
19
|
+
- ๐ฏ 100% local - no external servers needed
|
|
20
|
+
- โก Fast STDIO transport
|
|
21
|
+
|
|
22
|
+
## ๐ฆ Installation
|
|
23
|
+
|
|
24
|
+
### Method 1: NPX (Recommended)
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
claude mcp add --transport stdio build-in-public npx -y @lucianfialho/build-in-public-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Method 2: Global Install
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install -g @lucianfialho/build-in-public-mcp
|
|
34
|
+
claude mcp add --transport stdio build-in-public build-in-public-mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## ๐ How It Works
|
|
38
|
+
|
|
39
|
+
**The Philosophy:** If Claude Code is already helping you code, why not help you share your journey too?
|
|
40
|
+
|
|
41
|
+
1. **You code** - Claude Code assists you with development
|
|
42
|
+
2. **Context is captured** - Files changed, commands run, achievements unlocked
|
|
43
|
+
3. **AI analyzes** - When you run `/bp retro`, AI extracts meaningful insights
|
|
44
|
+
4. **Suggestions generated** - Get tweet ideas about what you actually accomplished
|
|
45
|
+
5. **One-click post** - Choose a suggestion and post to Twitter instantly
|
|
46
|
+
|
|
47
|
+
## ๐ Quick Start
|
|
48
|
+
|
|
49
|
+
### 1. Setup Twitter Authentication
|
|
50
|
+
|
|
51
|
+
You have **two options** for authentication:
|
|
52
|
+
|
|
53
|
+
#### Option A: Interactive OAuth (Recommended)
|
|
54
|
+
|
|
55
|
+
First time only:
|
|
56
|
+
```
|
|
57
|
+
You: How do I setup build in public?
|
|
58
|
+
Claude: Let me help you setup Twitter authentication
|
|
59
|
+
> Calls: mcp__bip__setup_auth
|
|
60
|
+
> Opens browser for OAuth
|
|
61
|
+
> You authorize the app
|
|
62
|
+
> Copy PIN from Twitter
|
|
63
|
+
> Paste in terminal
|
|
64
|
+
โ
Done! Tokens saved to ~/.build-in-public/auth.json
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### Option B: Environment Variables
|
|
68
|
+
|
|
69
|
+
Set these environment variables before starting Claude Code:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
export TWITTER_API_KEY="your_api_key"
|
|
73
|
+
export TWITTER_API_SECRET="your_api_secret"
|
|
74
|
+
export TWITTER_ACCESS_TOKEN="your_access_token"
|
|
75
|
+
export TWITTER_ACCESS_SECRET="your_access_secret"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Where to get these credentials:**
|
|
79
|
+
1. Go to [Twitter Developer Portal](https://developer.twitter.com/en/portal/dashboard)
|
|
80
|
+
2. Create an app (or use existing)
|
|
81
|
+
3. Go to "Keys and tokens"
|
|
82
|
+
4. Copy API Key & Secret (Consumer Keys)
|
|
83
|
+
5. Generate Access Token & Secret
|
|
84
|
+
|
|
85
|
+
**Priority:** If both methods are configured, environment variables take precedence over `~/.build-in-public/auth.json`.
|
|
86
|
+
|
|
87
|
+
### 2. Start Posting!
|
|
88
|
+
|
|
89
|
+
#### Option 1: Quick Tweet
|
|
90
|
+
Post immediately with a custom message:
|
|
91
|
+
```
|
|
92
|
+
/bp Just launched my new feature! ๐
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Option 2: AI-Powered Retro (Recommended!)
|
|
96
|
+
Let AI analyze your entire coding session and suggest tweets:
|
|
97
|
+
```
|
|
98
|
+
/bp retro
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Claude will:
|
|
102
|
+
- Review everything you did this session
|
|
103
|
+
- Extract achievements, learnings, and challenges
|
|
104
|
+
- Generate multiple tweet suggestions with confidence scores
|
|
105
|
+
- Let you choose or customize before posting
|
|
106
|
+
|
|
107
|
+
**Example output:**
|
|
108
|
+
```
|
|
109
|
+
๐ Session Analysis Complete!
|
|
110
|
+
|
|
111
|
+
Achievements:
|
|
112
|
+
โ
Implemented OAuth authentication system
|
|
113
|
+
โ
Fixed 3 critical bugs
|
|
114
|
+
โ
Shipped v2.0 with new dashboard
|
|
115
|
+
|
|
116
|
+
Based on your session, here are tweet suggestions:
|
|
117
|
+
|
|
118
|
+
1. [85% confidence] "Just shipped v2.0! ๐
|
|
119
|
+
New features: OAuth login, redesigned dashboard, 3 bugs squashed.
|
|
120
|
+
4 hours of flow state โ production ready โจ #BuildInPublic"
|
|
121
|
+
|
|
122
|
+
2. [75% confidence] "๐ก TIL: OAuth token refresh is trickier than I thought..."
|
|
123
|
+
|
|
124
|
+
Which one would you like to post? (1-2, or provide custom message)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Option 3: AI Suggestions from Current Context
|
|
128
|
+
```
|
|
129
|
+
/bp
|
|
130
|
+
```
|
|
131
|
+
Gets suggestions based on what the hooks have captured so far.
|
|
132
|
+
|
|
133
|
+
## ๐ ๏ธ Architecture
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Claude Code โ STDIO โ MCP Server (local) โ HTTPS โ Twitter API
|
|
137
|
+
โ
|
|
138
|
+
~/.build-in-public/
|
|
139
|
+
- auth.json (OAuth tokens)
|
|
140
|
+
- context.json (Session context)
|
|
141
|
+
- history.json (Tweet history)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**100% local, zero external infrastructure!**
|
|
145
|
+
|
|
146
|
+
## ๐ Available Tools
|
|
147
|
+
|
|
148
|
+
### `mcp__bip__tweet`
|
|
149
|
+
Post a tweet immediately.
|
|
150
|
+
|
|
151
|
+
**Input:**
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"message": "Your tweet message here (max 280 chars)"
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Returns:** Tweet URL
|
|
159
|
+
|
|
160
|
+
### `mcp__bip__thread`
|
|
161
|
+
Create a Twitter thread from multiple messages. Posts tweets in reply chain.
|
|
162
|
+
|
|
163
|
+
**Input:**
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"messages": ["Tweet 1", "Tweet 2", "Tweet 3"]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Returns:** Array of tweet URLs
|
|
171
|
+
|
|
172
|
+
### `mcp__bip__setup_auth`
|
|
173
|
+
Setup Twitter OAuth authentication via PIN-based flow.
|
|
174
|
+
|
|
175
|
+
**Input:** None (interactive flow)
|
|
176
|
+
|
|
177
|
+
**Returns:** Auth status and username
|
|
178
|
+
|
|
179
|
+
### `mcp__bip__status`
|
|
180
|
+
Check authentication status and show storage location.
|
|
181
|
+
|
|
182
|
+
**Input:** None
|
|
183
|
+
|
|
184
|
+
**Returns:** Status info including authenticated user
|
|
185
|
+
|
|
186
|
+
## ๐ Privacy & Security
|
|
187
|
+
|
|
188
|
+
- โ
OAuth tokens stored locally in `~/.build-in-public/auth.json`
|
|
189
|
+
- โ
Never sent to external servers (except Twitter API)
|
|
190
|
+
- โ
No analytics, no tracking, no telemetry
|
|
191
|
+
- โ
Open source - inspect the code yourself
|
|
192
|
+
|
|
193
|
+
## ๐บ๏ธ Roadmap
|
|
194
|
+
|
|
195
|
+
- [x] v0.1.0 - Basic MCP server + STDIO transport
|
|
196
|
+
- [x] v0.2.0 - Twitter OAuth + tweet posting + thread creation โ
|
|
197
|
+
- [ ] v0.3.0 - MCP prompts + better error handling
|
|
198
|
+
- [ ] v1.0.0 - Production ready + comprehensive docs
|
|
199
|
+
- [ ] v1.1.0 - Skill for automatic context tracking
|
|
200
|
+
- [ ] v2.0.0 - Optional Apify backend for analytics
|
|
201
|
+
|
|
202
|
+
## ๐ค Contributing
|
|
203
|
+
|
|
204
|
+
This is an early alpha! Contributions, issues, and feedback welcome.
|
|
205
|
+
|
|
206
|
+
**Repository:** [github.com/lucianfialho/build-in-public-mcp](https://github.com/lucianfialho/build-in-public-mcp)
|
|
207
|
+
|
|
208
|
+
## ๐ License
|
|
209
|
+
|
|
210
|
+
MIT License - see LICENSE file for details
|
|
211
|
+
|
|
212
|
+
## ๐ Credits
|
|
213
|
+
|
|
214
|
+
Built with [Claude Code](https://claude.com/code) and inspired by the #BuildInPublic community.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
**Made with โค๏ธ for developers who build in public**
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;GAGG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Build in Public MCP Server
|
|
5
|
+
* Entry point for STDIO transport
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
9
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
10
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
11
|
+
const oauth_js_1 = require("./utils/oauth.js");
|
|
12
|
+
const twitter_js_1 = require("./services/twitter.js");
|
|
13
|
+
const storage_js_1 = require("./services/storage.js");
|
|
14
|
+
const suggestion_engine_js_1 = require("./services/suggestion-engine.js");
|
|
15
|
+
// MCP Server instance
|
|
16
|
+
const server = new index_js_1.Server({
|
|
17
|
+
name: 'build-in-public',
|
|
18
|
+
version: '0.3.0',
|
|
19
|
+
}, {
|
|
20
|
+
capabilities: {
|
|
21
|
+
tools: {},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* List available tools
|
|
26
|
+
*/
|
|
27
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
28
|
+
return {
|
|
29
|
+
tools: [
|
|
30
|
+
{
|
|
31
|
+
name: 'mcp__bip__tweet',
|
|
32
|
+
description: 'Post a tweet immediately for build in public. Requires authentication.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
message: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: 'The tweet message to post (max 280 characters)',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
required: ['message'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'mcp__bip__thread',
|
|
46
|
+
description: 'Create a Twitter thread from multiple messages. Posts tweets in reply chain.',
|
|
47
|
+
inputSchema: {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
messages: {
|
|
51
|
+
type: 'array',
|
|
52
|
+
items: { type: 'string' },
|
|
53
|
+
description: 'Array of tweet messages for the thread',
|
|
54
|
+
},
|
|
55
|
+
replyToTweetId: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Optional: Tweet ID to reply to (creates thread as replies to this tweet)',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
required: ['messages'],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'mcp__bip__setup_auth',
|
|
65
|
+
description: 'Setup Twitter authentication via OAuth 1.0a (PIN-based flow)',
|
|
66
|
+
inputSchema: {
|
|
67
|
+
type: 'object',
|
|
68
|
+
properties: {},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'mcp__bip__status',
|
|
73
|
+
description: 'Check authentication status and storage location',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: {},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'mcp__bip__suggest',
|
|
81
|
+
description: 'Generate intelligent tweet suggestions based on session context',
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
contextId: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
description: 'Optional context ID (uses current session if not provided)',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'mcp__bip__save_context',
|
|
94
|
+
description: 'Save session context for later analysis and suggestions',
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
context: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
description: 'Session context data',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
required: ['context'],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'mcp__bip__get_context',
|
|
108
|
+
description: 'Retrieve current session context',
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
properties: {
|
|
112
|
+
contextId: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'Optional context ID (uses current session if not provided)',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* Handle tool calls
|
|
124
|
+
*/
|
|
125
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
126
|
+
const { name, arguments: args } = request.params;
|
|
127
|
+
try {
|
|
128
|
+
switch (name) {
|
|
129
|
+
case 'mcp__bip__tweet': {
|
|
130
|
+
const { message } = args;
|
|
131
|
+
if (!message) {
|
|
132
|
+
throw new Error('Message is required');
|
|
133
|
+
}
|
|
134
|
+
if (message.length > 280) {
|
|
135
|
+
throw new Error(`Tweet is too long (${message.length} characters, max 280)`);
|
|
136
|
+
}
|
|
137
|
+
// Check authentication
|
|
138
|
+
if (!(0, twitter_js_1.isAuthenticated)()) {
|
|
139
|
+
return {
|
|
140
|
+
content: [
|
|
141
|
+
{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: 'โ Not authenticated\n\n' +
|
|
144
|
+
'Please run mcp__bip__setup_auth first to authenticate with Twitter.',
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
isError: true,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// Post tweet
|
|
151
|
+
const result = await (0, twitter_js_1.postTweet)(message);
|
|
152
|
+
return {
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: 'text',
|
|
156
|
+
text: `โ
Tweet posted successfully!\n\n` +
|
|
157
|
+
`๐ ${result.url}\n\n` +
|
|
158
|
+
`Message: "${message}"`,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
case 'mcp__bip__thread': {
|
|
164
|
+
const { messages, replyToTweetId } = args;
|
|
165
|
+
if (!messages || messages.length === 0) {
|
|
166
|
+
throw new Error('Thread must have at least one message');
|
|
167
|
+
}
|
|
168
|
+
// Validate message lengths
|
|
169
|
+
for (let i = 0; i < messages.length; i++) {
|
|
170
|
+
if (messages[i].length > 280) {
|
|
171
|
+
throw new Error(`Message ${i + 1} is too long (${messages[i].length} characters, max 280)`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Check authentication
|
|
175
|
+
if (!(0, twitter_js_1.isAuthenticated)()) {
|
|
176
|
+
return {
|
|
177
|
+
content: [
|
|
178
|
+
{
|
|
179
|
+
type: 'text',
|
|
180
|
+
text: 'โ Not authenticated\n\n' +
|
|
181
|
+
'Please run mcp__bip__setup_auth first to authenticate with Twitter.',
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
isError: true,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// Post thread
|
|
188
|
+
const result = await (0, twitter_js_1.postThread)(messages, replyToTweetId);
|
|
189
|
+
return {
|
|
190
|
+
content: [
|
|
191
|
+
{
|
|
192
|
+
type: 'text',
|
|
193
|
+
text: `โ
Thread posted successfully!\n\n` +
|
|
194
|
+
`๐งต ${messages.length} tweets in thread\n` +
|
|
195
|
+
`๐ Thread starts at: ${result.urls[0]}\n\n` +
|
|
196
|
+
`All tweet URLs:\n${result.urls.map((url, i) => ` ${i + 1}. ${url}`).join('\n')}`,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
case 'mcp__bip__setup_auth': {
|
|
202
|
+
console.error('\n๐ Starting OAuth setup...\n');
|
|
203
|
+
console.error('โ ๏ธ IMPORTANT: This is an interactive flow.');
|
|
204
|
+
console.error(' Make sure you are running this in a terminal (not via Claude Code UI).\n');
|
|
205
|
+
try {
|
|
206
|
+
const tokens = await (0, oauth_js_1.performOAuthFlow)();
|
|
207
|
+
// Verify credentials
|
|
208
|
+
const user = await (0, twitter_js_1.verifyCredentials)();
|
|
209
|
+
return {
|
|
210
|
+
content: [
|
|
211
|
+
{
|
|
212
|
+
type: 'text',
|
|
213
|
+
text: `โ
Authentication successful!\n\n` +
|
|
214
|
+
`๐ค Authenticated as: @${user.username} (${user.name})\n` +
|
|
215
|
+
`๐พ Tokens saved to: ${(0, storage_js_1.getStorageDir)()}/auth.json\n\n` +
|
|
216
|
+
`You can now use:\n` +
|
|
217
|
+
` - mcp__bip__tweet to post tweets\n` +
|
|
218
|
+
` - mcp__bip__thread to create threads`,
|
|
219
|
+
},
|
|
220
|
+
],
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
225
|
+
return {
|
|
226
|
+
content: [
|
|
227
|
+
{
|
|
228
|
+
type: 'text',
|
|
229
|
+
text: `โ OAuth setup failed\n\n` +
|
|
230
|
+
`Error: ${errorMessage}\n\n` +
|
|
231
|
+
`Make sure you:\n` +
|
|
232
|
+
` 1. Have valid Twitter API credentials\n` +
|
|
233
|
+
` 2. Authorized the app on Twitter\n` +
|
|
234
|
+
` 3. Entered the correct PIN code`,
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
isError: true,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
case 'mcp__bip__status': {
|
|
242
|
+
const authenticated = (0, twitter_js_1.isAuthenticated)();
|
|
243
|
+
let statusText = `๐ Build in Public MCP Server Status\n\n`;
|
|
244
|
+
statusText += `Version: 0.3.0\n`;
|
|
245
|
+
statusText += `Storage: ${(0, storage_js_1.getStorageDir)()}\n\n`;
|
|
246
|
+
// Debug: Show env vars status
|
|
247
|
+
statusText += `๐ Environment Variables:\n`;
|
|
248
|
+
statusText += ` TWITTER_API_KEY: ${process.env.TWITTER_API_KEY ? 'โ
Set' : 'โ Not set'}\n`;
|
|
249
|
+
statusText += ` TWITTER_API_SECRET: ${process.env.TWITTER_API_SECRET ? 'โ
Set' : 'โ Not set'}\n`;
|
|
250
|
+
statusText += ` TWITTER_ACCESS_TOKEN: ${process.env.TWITTER_ACCESS_TOKEN ? 'โ
Set' : 'โ Not set'}\n`;
|
|
251
|
+
statusText += ` TWITTER_ACCESS_SECRET: ${process.env.TWITTER_ACCESS_SECRET ? 'โ
Set' : 'โ Not set'}\n\n`;
|
|
252
|
+
if (authenticated) {
|
|
253
|
+
try {
|
|
254
|
+
const user = await (0, twitter_js_1.verifyCredentials)();
|
|
255
|
+
statusText += `โ
Authenticated as: @${user.username} (${user.name})\n\n`;
|
|
256
|
+
statusText += `Available tools:\n`;
|
|
257
|
+
statusText += ` - mcp__bip__tweet - Post immediate tweets\n`;
|
|
258
|
+
statusText += ` - mcp__bip__thread - Create Twitter threads\n`;
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
statusText += `โ ๏ธ Authentication file exists but credentials are invalid\n`;
|
|
262
|
+
statusText += ` Run mcp__bip__setup_auth to re-authenticate\n`;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
statusText += `โ Not authenticated\n\n`;
|
|
267
|
+
statusText += `Run mcp__bip__setup_auth to authenticate with Twitter\n`;
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
content: [
|
|
271
|
+
{
|
|
272
|
+
type: 'text',
|
|
273
|
+
text: statusText,
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
case 'mcp__bip__suggest': {
|
|
279
|
+
// Load session context
|
|
280
|
+
const context = (0, storage_js_1.loadSessionContext)();
|
|
281
|
+
if (!context) {
|
|
282
|
+
return {
|
|
283
|
+
content: [
|
|
284
|
+
{
|
|
285
|
+
type: 'text',
|
|
286
|
+
text: 'โ ๏ธ No session context found\n\n' +
|
|
287
|
+
'Start coding and the system will automatically track your session. ' +
|
|
288
|
+
'Or save context manually using mcp__bip__save_context.',
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
// Generate suggestions
|
|
294
|
+
const suggestions = (0, suggestion_engine_js_1.generateSuggestions)(context);
|
|
295
|
+
const confidence = (0, suggestion_engine_js_1.scoreConfidence)(context);
|
|
296
|
+
if (suggestions.length === 0) {
|
|
297
|
+
return {
|
|
298
|
+
content: [
|
|
299
|
+
{
|
|
300
|
+
type: 'text',
|
|
301
|
+
text: '๐ก No strong suggestions yet\n\n' +
|
|
302
|
+
`Session confidence: ${(confidence * 100).toFixed(0)}%\n\n` +
|
|
303
|
+
'Keep working! Suggestions will appear when:\n' +
|
|
304
|
+
' - You commit code to git\n' +
|
|
305
|
+
' - You modify multiple files\n' +
|
|
306
|
+
' - You log achievements or learnings',
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
let responseText = `๐ก Tweet Suggestions (${suggestions.length})\n\n`;
|
|
312
|
+
responseText += `Overall confidence: ${(confidence * 100).toFixed(0)}%\n\n`;
|
|
313
|
+
suggestions.forEach((suggestion, index) => {
|
|
314
|
+
responseText += `${index + 1}. [${(suggestion.confidence * 100).toFixed(0)}% confidence] ${suggestion.type}\n`;
|
|
315
|
+
responseText += ` ${suggestion.reason}\n\n`;
|
|
316
|
+
responseText += ` "${suggestion.message}"\n\n`;
|
|
317
|
+
});
|
|
318
|
+
responseText += `\nUse mcp__bip__tweet to post any of these suggestions!`;
|
|
319
|
+
return {
|
|
320
|
+
content: [
|
|
321
|
+
{
|
|
322
|
+
type: 'text',
|
|
323
|
+
text: responseText,
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
case 'mcp__bip__save_context': {
|
|
329
|
+
const { context } = args;
|
|
330
|
+
if (!context) {
|
|
331
|
+
throw new Error('Context is required');
|
|
332
|
+
}
|
|
333
|
+
// Save the context
|
|
334
|
+
(0, storage_js_1.saveSessionContext)(context);
|
|
335
|
+
return {
|
|
336
|
+
content: [
|
|
337
|
+
{
|
|
338
|
+
type: 'text',
|
|
339
|
+
text: '๐พ Session context saved successfully!\n\n' +
|
|
340
|
+
`Files modified: ${context.filesModified?.length || 0}\n` +
|
|
341
|
+
`Commands run: ${context.commandsRun?.length || 0}\n` +
|
|
342
|
+
`Commits: ${context.commits?.length || 0}\n\n` +
|
|
343
|
+
'Use mcp__bip__suggest to generate tweet suggestions based on this context.',
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
case 'mcp__bip__get_context': {
|
|
349
|
+
const context = (0, storage_js_1.loadSessionContext)();
|
|
350
|
+
if (!context) {
|
|
351
|
+
return {
|
|
352
|
+
content: [
|
|
353
|
+
{
|
|
354
|
+
type: 'text',
|
|
355
|
+
text: 'โ ๏ธ No session context found\n\n' +
|
|
356
|
+
'Context will be automatically created as you work, or you can save context manually using mcp__bip__save_context.',
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
let contextText = `๐ Session Context\n\n`;
|
|
362
|
+
contextText += `Session ID: ${context.sessionId}\n`;
|
|
363
|
+
contextText += `Started: ${new Date(context.startTime).toLocaleString()}\n`;
|
|
364
|
+
if (context.lastUpdated) {
|
|
365
|
+
contextText += `Last updated: ${new Date(context.lastUpdated).toLocaleString()}\n`;
|
|
366
|
+
}
|
|
367
|
+
contextText += `\n`;
|
|
368
|
+
contextText += `๐ Files modified: ${context.filesModified?.length || 0}\n`;
|
|
369
|
+
contextText += `โ๏ธ Commands run: ${context.commandsRun?.length || 0}\n`;
|
|
370
|
+
contextText += `๐ง Tools used: ${context.toolsUsed?.length || 0}\n`;
|
|
371
|
+
contextText += `๐ฌ User messages: ${context.userMessages?.length || 0}\n`;
|
|
372
|
+
contextText += `๐ Git commits: ${context.commits?.length || 0}\n`;
|
|
373
|
+
contextText += `โ
Achievements: ${context.achievements?.length || 0}\n`;
|
|
374
|
+
contextText += `๐ฏ Challenges: ${context.challenges?.length || 0}\n`;
|
|
375
|
+
contextText += `๐ก Learnings: ${context.learnings?.length || 0}\n\n`;
|
|
376
|
+
if (context.shouldTweet) {
|
|
377
|
+
contextText += `๐ฆ Ready to tweet: Yes\n`;
|
|
378
|
+
if (context.triggerMessage) {
|
|
379
|
+
contextText += `Trigger: "${context.triggerMessage}"\n`;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
content: [
|
|
384
|
+
{
|
|
385
|
+
type: 'text',
|
|
386
|
+
text: contextText,
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
default:
|
|
392
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
397
|
+
return {
|
|
398
|
+
content: [
|
|
399
|
+
{
|
|
400
|
+
type: 'text',
|
|
401
|
+
text: `โ Error: ${errorMessage}`,
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
isError: true,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
/**
|
|
409
|
+
* Start the server using STDIO transport
|
|
410
|
+
*/
|
|
411
|
+
async function main() {
|
|
412
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
413
|
+
await server.connect(transport);
|
|
414
|
+
// Log to stderr (stdout is used for MCP protocol)
|
|
415
|
+
console.error('๐ Build in Public MCP Server started');
|
|
416
|
+
console.error('๐ Version: 0.2.0');
|
|
417
|
+
console.error('๐ Transport: STDIO');
|
|
418
|
+
console.error('๐พ Storage:', (0, storage_js_1.getStorageDir)());
|
|
419
|
+
console.error('');
|
|
420
|
+
}
|
|
421
|
+
main().catch((error) => {
|
|
422
|
+
console.error('โ Failed to start server:', error);
|
|
423
|
+
process.exit(1);
|
|
424
|
+
});
|
|
425
|
+
//# sourceMappingURL=index.js.map
|