Pre-reboot backup: Feb 13 — SOLVR contract, Buba 3D dashboard, MCP V3 batch 1+2, artist research, daily log
This commit is contained in:
parent
ae3fc2dec3
commit
9a11210151
1335
buba-dashboard/public/index.html
Normal file
1335
buba-dashboard/public/index.html
Normal file
File diff suppressed because it is too large
Load Diff
237
buba-dashboard/server.js
Normal file
237
buba-dashboard/server.js
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const readline = require('readline');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const PORT = 8890;
|
||||||
|
|
||||||
|
const SESSIONS_DIR = '/Users/jakeshore/.clawdbot/agents/main/sessions';
|
||||||
|
const WORKSPACE = '/Users/jakeshore/.clawdbot/workspace';
|
||||||
|
const MEMORY_DIR = path.join(WORKSPACE, 'memory');
|
||||||
|
|
||||||
|
// Serve static files
|
||||||
|
app.use(express.static(path.join(__dirname, 'public')));
|
||||||
|
|
||||||
|
// Parse JSONL file (last N lines for efficiency)
|
||||||
|
async function parseSessionFile(filePath, maxLines = 50) {
|
||||||
|
const messages = [];
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const lines = content.trim().split('\n').slice(-maxLines);
|
||||||
|
for (const line of lines) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(line);
|
||||||
|
messages.push(parsed);
|
||||||
|
} catch (e) { /* skip malformed */ }
|
||||||
|
}
|
||||||
|
} catch (e) { /* file not readable */ }
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all sessions with metadata
|
||||||
|
function getSessionFiles() {
|
||||||
|
try {
|
||||||
|
const files = fs.readdirSync(SESSIONS_DIR)
|
||||||
|
.filter(f => f.endsWith('.jsonl'))
|
||||||
|
.map(f => {
|
||||||
|
const fullPath = path.join(SESSIONS_DIR, f);
|
||||||
|
const stat = fs.statSync(fullPath);
|
||||||
|
return {
|
||||||
|
id: f.replace('.jsonl', ''),
|
||||||
|
file: f,
|
||||||
|
path: fullPath,
|
||||||
|
size: stat.size,
|
||||||
|
modified: stat.mtime,
|
||||||
|
created: stat.ctime,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => b.modified - a.modified);
|
||||||
|
return files;
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract activity from messages
|
||||||
|
function extractActivity(messages, sessionId) {
|
||||||
|
const activities = [];
|
||||||
|
for (const msg of messages) {
|
||||||
|
const ts = msg.timestamp || msg.ts || null;
|
||||||
|
|
||||||
|
if (msg.role === 'user') {
|
||||||
|
const content = typeof msg.content === 'string' ? msg.content :
|
||||||
|
Array.isArray(msg.content) ? msg.content.map(c => c.text || '').join(' ') : '';
|
||||||
|
if (content && !content.startsWith('HEARTBEAT')) {
|
||||||
|
activities.push({
|
||||||
|
type: 'user_message',
|
||||||
|
session: sessionId,
|
||||||
|
content: content.substring(0, 200),
|
||||||
|
timestamp: ts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg.role === 'assistant') {
|
||||||
|
const content = typeof msg.content === 'string' ? msg.content :
|
||||||
|
Array.isArray(msg.content) ? msg.content.map(c => c.text || '').join(' ') : '';
|
||||||
|
|
||||||
|
// Check for tool use
|
||||||
|
if (Array.isArray(msg.content)) {
|
||||||
|
for (const block of msg.content) {
|
||||||
|
if (block.type === 'tool_use') {
|
||||||
|
activities.push({
|
||||||
|
type: 'tool_call',
|
||||||
|
session: sessionId,
|
||||||
|
tool: block.name,
|
||||||
|
content: block.name + (block.input?.command ? ': ' + block.input.command.substring(0, 80) :
|
||||||
|
block.input?.action ? ': ' + block.input.action :
|
||||||
|
block.input?.query ? ': ' + block.input.query.substring(0, 80) : ''),
|
||||||
|
timestamp: ts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content && content !== 'NO_REPLY' && content !== 'HEARTBEAT_OK') {
|
||||||
|
activities.push({
|
||||||
|
type: 'buba_reply',
|
||||||
|
session: sessionId,
|
||||||
|
content: content.substring(0, 200),
|
||||||
|
timestamp: ts,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return activities;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API: Dashboard state
|
||||||
|
app.get('/api/state', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const sessions = getSessionFiles();
|
||||||
|
const now = Date.now();
|
||||||
|
const oneHourAgo = now - (60 * 60 * 1000);
|
||||||
|
const oneDayAgo = now - (24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
// Categorize sessions
|
||||||
|
const activeSessions = sessions.filter(s => s.modified.getTime() > oneHourAgo);
|
||||||
|
const recentSessions = sessions.filter(s => s.modified.getTime() > oneDayAgo);
|
||||||
|
const subagentSessions = sessions.filter(s => s.id.includes('subagent'));
|
||||||
|
const activeSubagents = subagentSessions.filter(s => s.modified.getTime() > oneHourAgo);
|
||||||
|
|
||||||
|
// Parse main session for recent activity
|
||||||
|
const mainSession = sessions.find(s => !s.id.includes('subagent'));
|
||||||
|
let recentActivity = [];
|
||||||
|
|
||||||
|
// Get activity from recent sessions
|
||||||
|
const sessionsToScan = sessions.slice(0, 10);
|
||||||
|
for (const session of sessionsToScan) {
|
||||||
|
const messages = await parseSessionFile(session.path, 20);
|
||||||
|
const activity = extractActivity(messages, session.id);
|
||||||
|
recentActivity.push(...activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by recency and limit
|
||||||
|
recentActivity.sort((a, b) => {
|
||||||
|
const ta = a.timestamp ? new Date(a.timestamp).getTime() : 0;
|
||||||
|
const tb = b.timestamp ? new Date(b.timestamp).getTime() : 0;
|
||||||
|
return tb - ta;
|
||||||
|
});
|
||||||
|
recentActivity = recentActivity.slice(0, 50);
|
||||||
|
|
||||||
|
// Read working state
|
||||||
|
let workingState = '';
|
||||||
|
try {
|
||||||
|
workingState = fs.readFileSync(path.join(MEMORY_DIR, 'working-state.md'), 'utf8');
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
// Read today's log
|
||||||
|
let todayLog = '';
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
try {
|
||||||
|
todayLog = fs.readFileSync(path.join(MEMORY_DIR, `${today}.md`), 'utf8');
|
||||||
|
} catch (e) { }
|
||||||
|
|
||||||
|
// Sub-agent details
|
||||||
|
const subagentDetails = [];
|
||||||
|
for (const sa of subagentSessions.slice(0, 20)) {
|
||||||
|
const messages = await parseSessionFile(sa.path, 5);
|
||||||
|
const firstMsg = messages.find(m => m.role === 'user');
|
||||||
|
const lastMsg = [...messages].reverse().find(m => m.role === 'assistant');
|
||||||
|
const isActive = sa.modified.getTime() > oneHourAgo;
|
||||||
|
|
||||||
|
let task = '';
|
||||||
|
if (firstMsg) {
|
||||||
|
const content = typeof firstMsg.content === 'string' ? firstMsg.content :
|
||||||
|
Array.isArray(firstMsg.content) ? firstMsg.content.map(c => c.text || '').join(' ') : '';
|
||||||
|
task = content.substring(0, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
subagentDetails.push({
|
||||||
|
id: sa.id.split(':').pop().substring(0, 8),
|
||||||
|
fullId: sa.id,
|
||||||
|
task: task,
|
||||||
|
active: isActive,
|
||||||
|
lastModified: sa.modified,
|
||||||
|
size: sa.size,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats
|
||||||
|
const totalSessions = sessions.length;
|
||||||
|
const totalSubagents = subagentSessions.length;
|
||||||
|
const todaysSessions = sessions.filter(s => {
|
||||||
|
const d = s.created.toISOString().split('T')[0];
|
||||||
|
return d === today;
|
||||||
|
}).length;
|
||||||
|
|
||||||
|
// Tools used today
|
||||||
|
const toolCounts = {};
|
||||||
|
for (const act of recentActivity) {
|
||||||
|
if (act.type === 'tool_call') {
|
||||||
|
const tool = act.tool || 'unknown';
|
||||||
|
toolCounts[tool] = (toolCounts[tool] || 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
buba: {
|
||||||
|
status: activeSessions.length > 0 ? 'active' : 'idle',
|
||||||
|
currentTask: workingState.split('\n').slice(0, 5).join('\n'),
|
||||||
|
uptime: '24/7',
|
||||||
|
},
|
||||||
|
stats: {
|
||||||
|
totalSessions,
|
||||||
|
totalSubagents,
|
||||||
|
activeSessions: activeSessions.length,
|
||||||
|
activeSubagents: activeSubagents.length,
|
||||||
|
todaysSessions,
|
||||||
|
toolsUsedRecently: toolCounts,
|
||||||
|
},
|
||||||
|
subagents: subagentDetails,
|
||||||
|
activity: recentActivity,
|
||||||
|
workingState: workingState.substring(0, 2000),
|
||||||
|
todayLog: todayLog.substring(0, 2000),
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
res.status(500).json({ error: e.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// API: Session detail
|
||||||
|
app.get('/api/session/:id', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const sessionFile = path.join(SESSIONS_DIR, req.params.id + '.jsonl');
|
||||||
|
const messages = await parseSessionFile(sessionFile, 100);
|
||||||
|
res.json({ messages });
|
||||||
|
} catch (e) {
|
||||||
|
res.status(500).json({ error: e.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT, '0.0.0.0', () => {
|
||||||
|
console.log(`Buba Dashboard running at http://localhost:${PORT}`);
|
||||||
|
console.log(`Network: http://192.168.0.25:8890`);
|
||||||
|
});
|
||||||
183
good-society-2025-artist-stats.md
Normal file
183
good-society-2025-artist-stats.md
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# Good Society 2025 Artist Statistics
|
||||||
|
|
||||||
|
Research completed: January 2026
|
||||||
|
Total Artists Researched: 67
|
||||||
|
|
||||||
|
## Artist Statistics Table
|
||||||
|
|
||||||
|
| # | Artist | Platform | Monthly Listeners/Followers | Notes |
|
||||||
|
|---|--------|----------|----------------------------|-------|
|
||||||
|
| 1 | A Hundred Drums | Spotify | 58,200 | |
|
||||||
|
| 2 | Aaya | Spotify | 206 | Very small presence, may be emerging artist |
|
||||||
|
| 3 | Abelation | Spotify | 32,100 | |
|
||||||
|
| 4 | AIRGLO | Spotify | 45,400 | |
|
||||||
|
| 5 | Aych | Spotify | 3,200 | |
|
||||||
|
| 6 | Babsy. | Spotify | 455,400 | One of the largest artists |
|
||||||
|
| 7 | Baby Kush | SoundCloud | N/A | Active on SoundCloud, minimal Spotify presence |
|
||||||
|
| 8 | Badlike | Spotify | 5,900 | |
|
||||||
|
| 9 | BEMM | Spotify | 95 | Very emerging artist |
|
||||||
|
| 10 | Blue Blood | Spotify | 24,800 | |
|
||||||
|
| 11 | Buku | Spotify | 140,700 | |
|
||||||
|
| 12 | Bunny G | Spotify | 25 | Very small, emerging artist |
|
||||||
|
| 13 | capshun | Spotify | 25,500 | |
|
||||||
|
| 14 | Combine | SoundCloud | N/A | Couldn't locate Spotify profile |
|
||||||
|
| 15 | Dabow | Spotify | 29,000 | |
|
||||||
|
| 16 | Dehm | Bandcamp/SoundCloud | N/A | Active on Bandcamp via DOMEOFDOOM label |
|
||||||
|
| 17 | Depths | Spotify | 611 | Very small presence |
|
||||||
|
| 18 | Dêtre | SoundCloud/Apple Music | N/A | Active on SoundCloud, minimal Spotify |
|
||||||
|
| 19 | D!llema | N/A | N/A | Could not locate profile |
|
||||||
|
| 20 | Dimond Saints | Spotify | 60,100 | |
|
||||||
|
| 21 | DVNK | N/A | N/A | Could not locate profile |
|
||||||
|
| 22 | EAZYBAKED | Spotify | 136,000 | |
|
||||||
|
| 23 | Effin | Spotify | 333,200 | One of the largest artists |
|
||||||
|
| 24 | Farley. | Spotify | 36,400 | |
|
||||||
|
| 25 | Fly | Spotify | 63 | Very small artist, emerging |
|
||||||
|
| 26 | Gunpoint | Spotify | 36,600 | Dallas-based bass producer |
|
||||||
|
| 27 | Hamdi | Spotify | 1,400,000 | **LARGEST ARTIST** - UK dubstep |
|
||||||
|
| 28 | Handz | N/A | N/A | Could not locate profile |
|
||||||
|
| 29 | Hershe | N/A | N/A | Could not locate profile |
|
||||||
|
| 30 | JiLLi | Spotify | 36,200 | |
|
||||||
|
| 31 | jordnmoody | Spotify | 33,800 | |
|
||||||
|
| 32 | Juush | Spotify | 44,900 | |
|
||||||
|
| 33 | Know Good | Spotify | 389,900 | One of the larger artists |
|
||||||
|
| 34 | Litha | Spotify | 59 | Very small, may not be correct profile |
|
||||||
|
| 35 | Lumasi | Spotify | 80,700 | |
|
||||||
|
| 36 | MadBliss | Spotify | 13,300 | |
|
||||||
|
| 37 | Milano | SoundCloud | N/A | Lost Dogz member, unclear Spotify profile |
|
||||||
|
| 38 | Mindset | Spotify | 9,400 | Bass producer |
|
||||||
|
| 39 | Moceans | Spotify | 10,500 | |
|
||||||
|
| 40 | Nikita, The Wicked | Spotify | 248,500 | Large presence, San Francisco-based |
|
||||||
|
| 41 | Odd Language | Spotify | 30,200 | |
|
||||||
|
| 42 | Ooga | Spotify | 24,600 | Bay Area producer |
|
||||||
|
| 43 | PAV4N (P4van) | Spotify | 77,300 | UK grime/dubstep |
|
||||||
|
| 44 | Pastry. | SoundCloud | N/A | Bass Waffle curator, minimal Spotify |
|
||||||
|
| 45 | Phayla | Beatport/SoundCloud | N/A | Drum & bass producer |
|
||||||
|
| 46 | Phrva | Spotify | 61,400 | Rising dubstep artist |
|
||||||
|
| 47 | Ricky Marano | Spotify | 172,300 | |
|
||||||
|
| 48 | Roto | Spotify | 26,200 | |
|
||||||
|
| 49 | rSUN (Rsun) | Spotify | 154,300 | Virginia trap/bass producer |
|
||||||
|
| 50 | Sayara | Spotify | 93 | Very new artist (producing since Oct 2023) |
|
||||||
|
| 51 | Simula | Spotify | 202,900 | Large following |
|
||||||
|
| 52 | Solotrip | SoundCloud | N/A | Active on SoundCloud |
|
||||||
|
| 53 | Spunky | Spotify | 5,300 | |
|
||||||
|
| 54 | Sully | Spotify | 40,700 | UK dubstep/garage producer |
|
||||||
|
| 55 | Sumthin Sumthin | Spotify | 95,400 | |
|
||||||
|
| 56 | Terminal 6 | SoundCloud | N/A | Collaborates with Know Good |
|
||||||
|
| 57 | The Widdler | Spotify | 127,000 | Classic dubstep artist |
|
||||||
|
| 58 | Tone | N/A | N/A | Could not locate profile |
|
||||||
|
| 59 | Torcha | Spotify | 6,600 | Toronto-based 140 dubstep |
|
||||||
|
| 60 | Untitld | Spotify | 2,500 | |
|
||||||
|
| 61 | Violet | Spotify | 5,000 | Riverside, CA bass producer |
|
||||||
|
| 62 | Vyhara | Spotify | 4,800 | |
|
||||||
|
| 63 | Zen Selekta | Spotify | 34,100 | Atlanta-based ceremonial bass |
|
||||||
|
|
||||||
|
## COLLABORATORS
|
||||||
|
|
||||||
|
| # | Artist/Entity | Platform | Monthly Listeners/Followers | Notes |
|
||||||
|
|---|---------------|----------|----------------------------|-------|
|
||||||
|
| 64 | B Side | Spotify | 1,400 | Multiple profiles exist |
|
||||||
|
| 65 | Pirate Panda | N/A | N/A | Could not locate |
|
||||||
|
| 66 | Same Same But Different | Festival | N/A | This is a music festival, not an artist |
|
||||||
|
| 67 | Yappy Studios | N/A | N/A | Could not locate - may be production/visual studio |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary Statistics
|
||||||
|
|
||||||
|
### By Size Category:
|
||||||
|
|
||||||
|
**Major Artists (100K+ monthly listeners):**
|
||||||
|
- Hamdi: 1,400,000
|
||||||
|
- Babsy.: 455,400
|
||||||
|
- Know Good: 389,900
|
||||||
|
- Effin: 333,200
|
||||||
|
- Nikita, The Wicked: 248,500
|
||||||
|
- Simula: 202,900
|
||||||
|
- Ricky Marano: 172,300
|
||||||
|
- rSUN: 154,300
|
||||||
|
- Buku: 140,700
|
||||||
|
- EAZYBAKED: 136,000
|
||||||
|
- The Widdler: 127,000
|
||||||
|
|
||||||
|
**Mid-Tier Artists (20K-100K monthly listeners):**
|
||||||
|
- Sumthin Sumthin: 95,400
|
||||||
|
- Lumasi: 80,700
|
||||||
|
- PAV4N: 77,300
|
||||||
|
- Phrva: 61,400
|
||||||
|
- Dimond Saints: 60,100
|
||||||
|
- A Hundred Drums: 58,200
|
||||||
|
- AIRGLO: 45,400
|
||||||
|
- Juush: 44,900
|
||||||
|
- Sully: 40,700
|
||||||
|
- Farley.: 36,400
|
||||||
|
- Gunpoint: 36,600
|
||||||
|
- JiLLi: 36,200
|
||||||
|
- Zen Selekta: 34,100
|
||||||
|
- jordnmoody: 33,800
|
||||||
|
- Abelation: 32,100
|
||||||
|
- Odd Language: 30,200
|
||||||
|
- Dabow: 29,000
|
||||||
|
- Roto: 26,200
|
||||||
|
- capshun: 25,500
|
||||||
|
- Blue Blood: 24,800
|
||||||
|
- Ooga: 24,600
|
||||||
|
|
||||||
|
**Emerging Artists (5K-20K monthly listeners):**
|
||||||
|
- MadBliss: 13,300
|
||||||
|
- Moceans: 10,500
|
||||||
|
- Mindset: 9,400
|
||||||
|
- Torcha: 6,600
|
||||||
|
- Badlike: 5,900
|
||||||
|
- Spunky: 5,300
|
||||||
|
- Violet: 5,000
|
||||||
|
- Vyhara: 4,800
|
||||||
|
- Aych: 3,200
|
||||||
|
|
||||||
|
**Very Small/New Artists (Under 5K):**
|
||||||
|
- Untitld: 2,500
|
||||||
|
- B Side: 1,400
|
||||||
|
- Depths: 611
|
||||||
|
- Aaya: 206
|
||||||
|
- BEMM: 95
|
||||||
|
- Sayara: 93
|
||||||
|
- Fly: 63
|
||||||
|
- Litha: 59
|
||||||
|
- Bunny G: 25
|
||||||
|
|
||||||
|
**Artists Not Found on Spotify:**
|
||||||
|
- Baby Kush (SoundCloud only)
|
||||||
|
- Combine
|
||||||
|
- Dehm (Bandcamp/DOMEOFDOOM)
|
||||||
|
- Dêtre (SoundCloud/Apple Music)
|
||||||
|
- D!llema
|
||||||
|
- DVNK
|
||||||
|
- Handz
|
||||||
|
- Hershe
|
||||||
|
- Milano (Lost Dogz - unclear profile)
|
||||||
|
- Pastry. (SoundCloud primarily)
|
||||||
|
- Phayla (Beatport/SoundCloud)
|
||||||
|
- Solotrip (SoundCloud)
|
||||||
|
- Terminal 6 (Collaborator)
|
||||||
|
- Tone
|
||||||
|
- Pirate Panda
|
||||||
|
- Yappy Studios
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- **Hamdi** stands out as the festival's biggest booking by far with 1.4M monthly listeners
|
||||||
|
- Strong representation of mid-tier experimental bass artists (20K-100K range)
|
||||||
|
- Several very emerging artists with under 1,000 monthly listeners, indicating Good Society's commitment to new talent
|
||||||
|
- Many artists are primarily active on SoundCloud, Bandcamp, or other platforms rather than Spotify
|
||||||
|
- "Same Same But Different" is actually a music festival, not an artist
|
||||||
|
- "Yappy Studios" appears to be a production/visual studio rather than a music artist
|
||||||
|
- The lineup represents a strong mix of established bass music names and underground/emerging talent
|
||||||
|
- Geographic diversity: Artists from UK (Hamdi, Sully, PAV4N), California (Bay Area, LA, Riverside), Toronto, Atlanta, Dallas, Virginia, and more
|
||||||
|
- Genre span: Dubstep, drum & bass, experimental bass, trap, UK garage, 140, grime, and more
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Research Method:** Web searches for Spotify monthly listeners were conducted for each artist. When Spotify data was unavailable, alternative platforms (SoundCloud, Apple Music, Bandcamp, Instagram, TikTok) were checked. Some artists could not be located on any major platform, which may indicate they are local DJs, visual artists, or have minimal online presence.
|
||||||
|
|
||||||
|
**Data Current As Of:** January 2026
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"lastUpdated": "2026-02-12T22:02:00-05:00",
|
"lastUpdated": "2026-02-13T02:00:00-05:00",
|
||||||
"updatedBy": "Buba (heartbeat: no advances — dec-004 still awaiting reaction 29h+, all else gated on API credentials)",
|
"updatedBy": "Buba (heartbeat 2AM: no advances possible — dec-004 at 31h+ no reaction, 23 MCPs gated on Stage 7 design approval, 2 on API credentials)",
|
||||||
"phases": [
|
"phases": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
|
|||||||
90
mcp-factory-v3/FACTORY-SPEC.md
Normal file
90
mcp-factory-v3/FACTORY-SPEC.md
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# MCP Factory V3 — Quality-First Build System
|
||||||
|
|
||||||
|
## Quality Standards (Feb 2026)
|
||||||
|
|
||||||
|
Every MCP server MUST include these features:
|
||||||
|
|
||||||
|
### Server Architecture
|
||||||
|
- **Lazy-loaded tool modules** — tools loaded on-demand, not all at startup
|
||||||
|
- **Dual transport** — HTTP (SSE) + stdio support
|
||||||
|
- **Graceful shutdown** — SIGINT/SIGTERM handlers, connection cleanup
|
||||||
|
- **Health endpoint** — `/health` for monitoring
|
||||||
|
- **Structured logging** — JSON logs with levels, request IDs
|
||||||
|
- **Environment validation** — fail fast on missing required env vars
|
||||||
|
|
||||||
|
### API Client
|
||||||
|
- **Retry with exponential backoff** — 3 retries, 1s/2s/4s delays
|
||||||
|
- **Rate limit awareness** — respect 429 headers, auto-throttle
|
||||||
|
- **Automatic pagination** — cursor/offset pagination abstracted away
|
||||||
|
- **Request/response interceptors** — logging, error normalization
|
||||||
|
- **Timeout handling** — 30s default, configurable per-request
|
||||||
|
- **Auth refresh** — auto-refresh OAuth tokens before expiry
|
||||||
|
|
||||||
|
### Tool Quality
|
||||||
|
- **Strict inputSchema** — Zod validation on all inputs
|
||||||
|
- **Typed outputs** — consistent response shapes
|
||||||
|
- **Error categorization** — user errors vs system errors vs auth errors
|
||||||
|
- **Pagination support** — limit/offset/cursor params where applicable
|
||||||
|
- **Bulk operations** — batch create/update/delete where API supports it
|
||||||
|
- **Search/filter** — rich query params, not just list-all
|
||||||
|
|
||||||
|
### React MCP Apps (UI Resources)
|
||||||
|
- **React 18+ with Suspense** — lazy loading components
|
||||||
|
- **Code splitting** — dynamic imports for heavy components
|
||||||
|
- **Error boundaries** — graceful error UI, not white screens
|
||||||
|
- **Loading skeletons** — shimmer/skeleton UI during data fetch
|
||||||
|
- **Dark theme** — CSS custom properties, #0f172a/#1e293b base
|
||||||
|
- **Responsive** — mobile-first, works on all screen sizes
|
||||||
|
- **Accessible** — ARIA labels, keyboard navigation, focus management
|
||||||
|
- **Optimistic UI** — instant feedback on user actions
|
||||||
|
- **Virtual scrolling** — for large lists (100+ items)
|
||||||
|
- **Toast notifications** — success/error feedback
|
||||||
|
- **Empty states** — helpful messaging when no data
|
||||||
|
- **Client-side search/filter** — instant filtering without API calls
|
||||||
|
- **Debounced inputs** — search inputs don't fire on every keystroke
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
- **Strict mode** — `"strict": true` in tsconfig
|
||||||
|
- **No `any` types** — everything typed, use `unknown` if needed
|
||||||
|
- **Discriminated unions** — for API response variants
|
||||||
|
- **Branded types** — for IDs (CustomerId, OrderId, etc.)
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- **README.md** — setup, env vars, examples, API reference
|
||||||
|
- **Tool catalog** — table of all tools with descriptions
|
||||||
|
- **App catalog** — table of all apps with screenshots descriptions
|
||||||
|
|
||||||
|
## Factory Pipeline
|
||||||
|
|
||||||
|
### Phase 1: Manifest Creation (Opus, 1 agent)
|
||||||
|
- Research API docs for each platform
|
||||||
|
- Create manifest.json with categories, endpoints, auth pattern
|
||||||
|
- Human review before proceeding
|
||||||
|
|
||||||
|
### Phase 2: Foundation Build (Sonnet, 1 agent per server)
|
||||||
|
- API client + types + server shell
|
||||||
|
- Scope: ~15 min per server
|
||||||
|
- Verify: TSC compiles, server starts
|
||||||
|
|
||||||
|
### Phase 3: Tool Build (Sonnet, 1 agent per server)
|
||||||
|
- All tool files based on manifest categories
|
||||||
|
- Scope: ~15 min per server
|
||||||
|
- Verify: TSC compiles, tool count matches manifest
|
||||||
|
|
||||||
|
### Phase 4: App Build (Sonnet, 1 agent per server)
|
||||||
|
- All React apps
|
||||||
|
- Scope: ~15 min per server
|
||||||
|
- Verify: file count, each app has required files
|
||||||
|
|
||||||
|
### Phase 5: Quality Pass (Sonnet, 1 agent per batch)
|
||||||
|
- TSC strict mode check
|
||||||
|
- Verify lazy loading patterns
|
||||||
|
- Check error boundaries exist
|
||||||
|
- Verify loading skeletons
|
||||||
|
- Fix any issues
|
||||||
|
|
||||||
|
### Phase 6: Git + Deploy
|
||||||
|
- Commit each server individually
|
||||||
|
- Push to monorepo
|
||||||
|
- Sync to individual repos
|
||||||
|
- All done via bash script (zero tokens)
|
||||||
47
mcp-factory-v3/manifests/batch-1.json
Normal file
47
mcp-factory-v3/manifests/batch-1.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "shopify",
|
||||||
|
"displayName": "Shopify",
|
||||||
|
"repo": "shopify-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{store}.myshopify.com/admin/api/2024-01",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["products", "orders", "customers", "inventory", "collections", "discounts", "shipping", "fulfillments", "themes", "pages", "blogs", "analytics", "webhooks"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stripe",
|
||||||
|
"displayName": "Stripe",
|
||||||
|
"repo": "stripe-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.stripe.com/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["charges", "customers", "subscriptions", "invoices", "products", "prices", "payment-intents", "payment-methods", "refunds", "disputes", "payouts", "balance", "events", "webhooks"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quickbooks",
|
||||||
|
"displayName": "QuickBooks Online",
|
||||||
|
"repo": "quickbooks-mcp-2026-complete",
|
||||||
|
"apiBase": "https://quickbooks.api.intuit.com/v3/company/{realmId}",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["invoices", "customers", "payments", "estimates", "bills", "vendors", "items", "accounts", "reports", "employees", "time-activities", "taxes", "purchases", "journal-entries"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hubspot",
|
||||||
|
"displayName": "HubSpot",
|
||||||
|
"repo": "hubspot-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.hubapi.com",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["contacts", "companies", "deals", "tickets", "emails", "engagements", "pipelines", "lists", "forms", "campaigns", "blog", "analytics", "workflows", "webhooks"],
|
||||||
|
"appCount": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "salesforce",
|
||||||
|
"displayName": "Salesforce",
|
||||||
|
"repo": "salesforce-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{instance}.salesforce.com/services/data/v59.0",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["accounts", "contacts", "leads", "opportunities", "cases", "tasks", "events", "campaigns", "reports", "dashboards", "users", "custom-objects", "soql", "bulk-api"],
|
||||||
|
"appCount": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
47
mcp-factory-v3/manifests/batch-2.json
Normal file
47
mcp-factory-v3/manifests/batch-2.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "notion",
|
||||||
|
"displayName": "Notion",
|
||||||
|
"repo": "notion-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.notion.com/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["pages", "databases", "blocks", "users", "comments", "search"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "airtable",
|
||||||
|
"displayName": "Airtable",
|
||||||
|
"repo": "airtable-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.airtable.com/v0",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["bases", "tables", "records", "fields", "views", "webhooks", "automations"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "intercom",
|
||||||
|
"displayName": "Intercom",
|
||||||
|
"repo": "intercom-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.intercom.io",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["contacts", "conversations", "companies", "articles", "help-center", "tickets", "tags", "segments", "events", "messages", "teams", "admins"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "monday",
|
||||||
|
"displayName": "Monday.com",
|
||||||
|
"repo": "monday-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.monday.com/v2",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["boards", "items", "columns", "groups", "updates", "users", "teams", "workspaces", "folders", "webhooks", "automations"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "xero",
|
||||||
|
"displayName": "Xero",
|
||||||
|
"repo": "xero-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.xero.com/api.xro/2.0",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["invoices", "contacts", "accounts", "bank-transactions", "payments", "bills", "credit-notes", "purchase-orders", "quotes", "reports", "employees", "payroll", "tax-rates"],
|
||||||
|
"appCount": 18
|
||||||
|
}
|
||||||
|
]
|
||||||
47
mcp-factory-v3/manifests/batch-3.json
Normal file
47
mcp-factory-v3/manifests/batch-3.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "jira",
|
||||||
|
"displayName": "Jira/Atlassian",
|
||||||
|
"repo": "jira-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{domain}.atlassian.net/rest/api/3",
|
||||||
|
"auth": "basic_or_oauth2",
|
||||||
|
"toolCategories": ["issues", "projects", "boards", "sprints", "users", "comments", "attachments", "transitions", "fields", "filters", "dashboards", "webhooks"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linear",
|
||||||
|
"displayName": "Linear",
|
||||||
|
"repo": "linear-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.linear.app/graphql",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["issues", "projects", "teams", "cycles", "labels", "milestones", "users", "comments", "workflows", "webhooks"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "asana",
|
||||||
|
"displayName": "Asana",
|
||||||
|
"repo": "asana-mcp-2026-complete",
|
||||||
|
"apiBase": "https://app.asana.com/api/1.0",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["tasks", "projects", "workspaces", "teams", "users", "sections", "tags", "goals", "portfolios", "custom-fields", "status-updates", "webhooks"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "docusign",
|
||||||
|
"displayName": "DocuSign",
|
||||||
|
"repo": "docusign-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{account}.docusign.net/restapi/v2.1",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["envelopes", "templates", "recipients", "documents", "signing", "folders", "users", "accounts", "reports", "bulk-send"],
|
||||||
|
"appCount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "square",
|
||||||
|
"displayName": "Square",
|
||||||
|
"repo": "square-mcp-2026-complete",
|
||||||
|
"apiBase": "https://connect.squareup.com/v2",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["payments", "orders", "customers", "catalog", "inventory", "locations", "team", "invoices", "subscriptions", "loyalty", "bookings", "disputes", "refunds"],
|
||||||
|
"appCount": 18
|
||||||
|
}
|
||||||
|
]
|
||||||
47
mcp-factory-v3/manifests/batch-4.json
Normal file
47
mcp-factory-v3/manifests/batch-4.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "klaviyo",
|
||||||
|
"displayName": "Klaviyo",
|
||||||
|
"repo": "klaviyo-mcp-2026-complete",
|
||||||
|
"apiBase": "https://a.klaviyo.com/api",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["profiles", "lists", "segments", "campaigns", "flows", "templates", "metrics", "events", "catalogs", "forms", "tags", "reporting"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "activecampaign",
|
||||||
|
"displayName": "ActiveCampaign",
|
||||||
|
"repo": "activecampaign-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{account}.api-us1.com/api/3",
|
||||||
|
"auth": "api_key",
|
||||||
|
"toolCategories": ["contacts", "deals", "lists", "campaigns", "automations", "forms", "tags", "tasks", "notes", "pipelines", "accounts", "webhooks"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "salesloft",
|
||||||
|
"displayName": "Salesloft",
|
||||||
|
"repo": "salesloft-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.salesloft.com/v2",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["people", "cadences", "emails", "calls", "accounts", "steps", "users", "teams", "imports", "activities", "notes"],
|
||||||
|
"appCount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zoho-crm",
|
||||||
|
"displayName": "Zoho CRM",
|
||||||
|
"repo": "zoho-crm-mcp-2026-complete",
|
||||||
|
"apiBase": "https://www.zohoapis.com/crm/v6",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["leads", "contacts", "accounts", "deals", "tasks", "events", "calls", "notes", "products", "quotes", "invoices", "campaigns", "blueprints", "workflows"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sendgrid",
|
||||||
|
"displayName": "SendGrid",
|
||||||
|
"repo": "sendgrid-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.sendgrid.com/v3",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["mail", "contacts", "lists", "segments", "templates", "campaigns", "senders", "stats", "suppressions", "webhooks", "api-keys"],
|
||||||
|
"appCount": 14
|
||||||
|
}
|
||||||
|
]
|
||||||
47
mcp-factory-v3/manifests/batch-5.json
Normal file
47
mcp-factory-v3/manifests/batch-5.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "greenhouse",
|
||||||
|
"displayName": "Greenhouse",
|
||||||
|
"repo": "greenhouse-mcp-2026-complete",
|
||||||
|
"apiBase": "https://harvest.greenhouse.io/v1",
|
||||||
|
"auth": "basic",
|
||||||
|
"toolCategories": ["candidates", "applications", "jobs", "offers", "scorecards", "interviews", "users", "departments", "offices", "custom-fields", "activity-feed"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "datadog",
|
||||||
|
"displayName": "Datadog",
|
||||||
|
"repo": "datadog-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.datadoghq.com/api/v2",
|
||||||
|
"auth": "api_key_app_key",
|
||||||
|
"toolCategories": ["monitors", "dashboards", "events", "metrics", "logs", "incidents", "service-checks", "hosts", "downtimes", "synthetics", "apm"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "supabase",
|
||||||
|
"displayName": "Supabase",
|
||||||
|
"repo": "supabase-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{project}.supabase.co",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["database", "auth", "storage", "edge-functions", "realtime", "rpc", "migrations", "policies"],
|
||||||
|
"appCount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "typeform",
|
||||||
|
"displayName": "Typeform",
|
||||||
|
"repo": "typeform-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.typeform.com",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["forms", "responses", "workspaces", "themes", "images", "insights", "webhooks"],
|
||||||
|
"appCount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "chargebee",
|
||||||
|
"displayName": "Chargebee",
|
||||||
|
"repo": "chargebee-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{site}.chargebee.com/api/v2",
|
||||||
|
"auth": "basic",
|
||||||
|
"toolCategories": ["subscriptions", "customers", "invoices", "plans", "addons", "coupons", "payments", "credit-notes", "events", "quotes", "exports"],
|
||||||
|
"appCount": 15
|
||||||
|
}
|
||||||
|
]
|
||||||
47
mcp-factory-v3/manifests/batch-6.json
Normal file
47
mcp-factory-v3/manifests/batch-6.json
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "pandadoc",
|
||||||
|
"displayName": "PandaDoc",
|
||||||
|
"repo": "pandadoc-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.pandadoc.com/public/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["documents", "templates", "contacts", "content-library", "forms", "webhooks", "workspaces", "members"],
|
||||||
|
"appCount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loom",
|
||||||
|
"displayName": "Loom",
|
||||||
|
"repo": "loom-mcp-2026-complete",
|
||||||
|
"apiBase": "https://www.loom.com/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["videos", "folders", "workspaces", "members", "comments", "transcripts", "analytics", "embeds"],
|
||||||
|
"appCount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "webflow",
|
||||||
|
"displayName": "Webflow",
|
||||||
|
"repo": "webflow-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.webflow.com/v2",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["sites", "pages", "collections", "items", "orders", "products", "inventory", "users", "forms", "webhooks", "assets"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apollo",
|
||||||
|
"displayName": "Apollo.io",
|
||||||
|
"repo": "apollo-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.apollo.io/v1",
|
||||||
|
"auth": "api_key",
|
||||||
|
"toolCategories": ["people", "organizations", "contacts", "accounts", "sequences", "tasks", "emails", "opportunities", "labels", "lists", "enrichment"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lever",
|
||||||
|
"displayName": "Lever",
|
||||||
|
"repo": "lever-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.lever.co/v1",
|
||||||
|
"auth": "basic_or_oauth2",
|
||||||
|
"toolCategories": ["opportunities", "candidates", "postings", "interviews", "offers", "stages", "users", "archive-reasons", "sources", "tags", "feedback-forms"],
|
||||||
|
"appCount": 14
|
||||||
|
}
|
||||||
|
]
|
||||||
309
mcp-factory-v3/scripts/build-manifest.sh
Executable file
309
mcp-factory-v3/scripts/build-manifest.sh
Executable file
@ -0,0 +1,309 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# MCP Factory V3 — Manifest Builder
|
||||||
|
# Creates the manifest file for all 30 servers
|
||||||
|
|
||||||
|
MANIFEST_DIR="$(dirname "$0")/../manifests"
|
||||||
|
mkdir -p "$MANIFEST_DIR"
|
||||||
|
|
||||||
|
cat > "$MANIFEST_DIR/batch-1.json" << 'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "shopify",
|
||||||
|
"displayName": "Shopify",
|
||||||
|
"repo": "shopify-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{store}.myshopify.com/admin/api/2024-01",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["products", "orders", "customers", "inventory", "collections", "discounts", "shipping", "fulfillments", "themes", "pages", "blogs", "analytics", "webhooks"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stripe",
|
||||||
|
"displayName": "Stripe",
|
||||||
|
"repo": "stripe-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.stripe.com/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["charges", "customers", "subscriptions", "invoices", "products", "prices", "payment-intents", "payment-methods", "refunds", "disputes", "payouts", "balance", "events", "webhooks"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "quickbooks",
|
||||||
|
"displayName": "QuickBooks Online",
|
||||||
|
"repo": "quickbooks-mcp-2026-complete",
|
||||||
|
"apiBase": "https://quickbooks.api.intuit.com/v3/company/{realmId}",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["invoices", "customers", "payments", "estimates", "bills", "vendors", "items", "accounts", "reports", "employees", "time-activities", "taxes", "purchases", "journal-entries"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hubspot",
|
||||||
|
"displayName": "HubSpot",
|
||||||
|
"repo": "hubspot-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.hubapi.com",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["contacts", "companies", "deals", "tickets", "emails", "engagements", "pipelines", "lists", "forms", "campaigns", "blog", "analytics", "workflows", "webhooks"],
|
||||||
|
"appCount": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "salesforce",
|
||||||
|
"displayName": "Salesforce",
|
||||||
|
"repo": "salesforce-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{instance}.salesforce.com/services/data/v59.0",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["accounts", "contacts", "leads", "opportunities", "cases", "tasks", "events", "campaigns", "reports", "dashboards", "users", "custom-objects", "soql", "bulk-api"],
|
||||||
|
"appCount": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$MANIFEST_DIR/batch-2.json" << 'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "notion",
|
||||||
|
"displayName": "Notion",
|
||||||
|
"repo": "notion-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.notion.com/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["pages", "databases", "blocks", "users", "comments", "search"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "airtable",
|
||||||
|
"displayName": "Airtable",
|
||||||
|
"repo": "airtable-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.airtable.com/v0",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["bases", "tables", "records", "fields", "views", "webhooks", "automations"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "intercom",
|
||||||
|
"displayName": "Intercom",
|
||||||
|
"repo": "intercom-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.intercom.io",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["contacts", "conversations", "companies", "articles", "help-center", "tickets", "tags", "segments", "events", "messages", "teams", "admins"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "monday",
|
||||||
|
"displayName": "Monday.com",
|
||||||
|
"repo": "monday-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.monday.com/v2",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["boards", "items", "columns", "groups", "updates", "users", "teams", "workspaces", "folders", "webhooks", "automations"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "xero",
|
||||||
|
"displayName": "Xero",
|
||||||
|
"repo": "xero-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.xero.com/api.xro/2.0",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["invoices", "contacts", "accounts", "bank-transactions", "payments", "bills", "credit-notes", "purchase-orders", "quotes", "reports", "employees", "payroll", "tax-rates"],
|
||||||
|
"appCount": 18
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$MANIFEST_DIR/batch-3.json" << 'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "jira",
|
||||||
|
"displayName": "Jira/Atlassian",
|
||||||
|
"repo": "jira-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{domain}.atlassian.net/rest/api/3",
|
||||||
|
"auth": "basic_or_oauth2",
|
||||||
|
"toolCategories": ["issues", "projects", "boards", "sprints", "users", "comments", "attachments", "transitions", "fields", "filters", "dashboards", "webhooks"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linear",
|
||||||
|
"displayName": "Linear",
|
||||||
|
"repo": "linear-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.linear.app/graphql",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["issues", "projects", "teams", "cycles", "labels", "milestones", "users", "comments", "workflows", "webhooks"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "asana",
|
||||||
|
"displayName": "Asana",
|
||||||
|
"repo": "asana-mcp-2026-complete",
|
||||||
|
"apiBase": "https://app.asana.com/api/1.0",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["tasks", "projects", "workspaces", "teams", "users", "sections", "tags", "goals", "portfolios", "custom-fields", "status-updates", "webhooks"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "docusign",
|
||||||
|
"displayName": "DocuSign",
|
||||||
|
"repo": "docusign-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{account}.docusign.net/restapi/v2.1",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["envelopes", "templates", "recipients", "documents", "signing", "folders", "users", "accounts", "reports", "bulk-send"],
|
||||||
|
"appCount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "square",
|
||||||
|
"displayName": "Square",
|
||||||
|
"repo": "square-mcp-2026-complete",
|
||||||
|
"apiBase": "https://connect.squareup.com/v2",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["payments", "orders", "customers", "catalog", "inventory", "locations", "team", "invoices", "subscriptions", "loyalty", "bookings", "disputes", "refunds"],
|
||||||
|
"appCount": 18
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$MANIFEST_DIR/batch-4.json" << 'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "klaviyo",
|
||||||
|
"displayName": "Klaviyo",
|
||||||
|
"repo": "klaviyo-mcp-2026-complete",
|
||||||
|
"apiBase": "https://a.klaviyo.com/api",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["profiles", "lists", "segments", "campaigns", "flows", "templates", "metrics", "events", "catalogs", "forms", "tags", "reporting"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "activecampaign",
|
||||||
|
"displayName": "ActiveCampaign",
|
||||||
|
"repo": "activecampaign-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{account}.api-us1.com/api/3",
|
||||||
|
"auth": "api_key",
|
||||||
|
"toolCategories": ["contacts", "deals", "lists", "campaigns", "automations", "forms", "tags", "tasks", "notes", "pipelines", "accounts", "webhooks"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "salesloft",
|
||||||
|
"displayName": "Salesloft",
|
||||||
|
"repo": "salesloft-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.salesloft.com/v2",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["people", "cadences", "emails", "calls", "accounts", "steps", "users", "teams", "imports", "activities", "notes"],
|
||||||
|
"appCount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zoho-crm",
|
||||||
|
"displayName": "Zoho CRM",
|
||||||
|
"repo": "zoho-crm-mcp-2026-complete",
|
||||||
|
"apiBase": "https://www.zohoapis.com/crm/v6",
|
||||||
|
"auth": "oauth2",
|
||||||
|
"toolCategories": ["leads", "contacts", "accounts", "deals", "tasks", "events", "calls", "notes", "products", "quotes", "invoices", "campaigns", "blueprints", "workflows"],
|
||||||
|
"appCount": 18
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sendgrid",
|
||||||
|
"displayName": "SendGrid",
|
||||||
|
"repo": "sendgrid-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.sendgrid.com/v3",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["mail", "contacts", "lists", "segments", "templates", "campaigns", "senders", "stats", "suppressions", "webhooks", "api-keys"],
|
||||||
|
"appCount": 14
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$MANIFEST_DIR/batch-5.json" << 'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "greenhouse",
|
||||||
|
"displayName": "Greenhouse",
|
||||||
|
"repo": "greenhouse-mcp-2026-complete",
|
||||||
|
"apiBase": "https://harvest.greenhouse.io/v1",
|
||||||
|
"auth": "basic",
|
||||||
|
"toolCategories": ["candidates", "applications", "jobs", "offers", "scorecards", "interviews", "users", "departments", "offices", "custom-fields", "activity-feed"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "datadog",
|
||||||
|
"displayName": "Datadog",
|
||||||
|
"repo": "datadog-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.datadoghq.com/api/v2",
|
||||||
|
"auth": "api_key_app_key",
|
||||||
|
"toolCategories": ["monitors", "dashboards", "events", "metrics", "logs", "incidents", "service-checks", "hosts", "downtimes", "synthetics", "apm"],
|
||||||
|
"appCount": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "supabase",
|
||||||
|
"displayName": "Supabase",
|
||||||
|
"repo": "supabase-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{project}.supabase.co",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["database", "auth", "storage", "edge-functions", "realtime", "rpc", "migrations", "policies"],
|
||||||
|
"appCount": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "typeform",
|
||||||
|
"displayName": "Typeform",
|
||||||
|
"repo": "typeform-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.typeform.com",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["forms", "responses", "workspaces", "themes", "images", "insights", "webhooks"],
|
||||||
|
"appCount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "chargebee",
|
||||||
|
"displayName": "Chargebee",
|
||||||
|
"repo": "chargebee-mcp-2026-complete",
|
||||||
|
"apiBase": "https://{site}.chargebee.com/api/v2",
|
||||||
|
"auth": "basic",
|
||||||
|
"toolCategories": ["subscriptions", "customers", "invoices", "plans", "addons", "coupons", "payments", "credit-notes", "events", "quotes", "exports"],
|
||||||
|
"appCount": 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > "$MANIFEST_DIR/batch-6.json" << 'EOF'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "pandadoc",
|
||||||
|
"displayName": "PandaDoc",
|
||||||
|
"repo": "pandadoc-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.pandadoc.com/public/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["documents", "templates", "contacts", "content-library", "forms", "webhooks", "workspaces", "members"],
|
||||||
|
"appCount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "loom",
|
||||||
|
"displayName": "Loom",
|
||||||
|
"repo": "loom-mcp-2026-complete",
|
||||||
|
"apiBase": "https://www.loom.com/v1",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["videos", "folders", "workspaces", "members", "comments", "transcripts", "analytics", "embeds"],
|
||||||
|
"appCount": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "webflow",
|
||||||
|
"displayName": "Webflow",
|
||||||
|
"repo": "webflow-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.webflow.com/v2",
|
||||||
|
"auth": "bearer",
|
||||||
|
"toolCategories": ["sites", "pages", "collections", "items", "orders", "products", "inventory", "users", "forms", "webhooks", "assets"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apollo",
|
||||||
|
"displayName": "Apollo.io",
|
||||||
|
"repo": "apollo-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.apollo.io/v1",
|
||||||
|
"auth": "api_key",
|
||||||
|
"toolCategories": ["people", "organizations", "contacts", "accounts", "sequences", "tasks", "emails", "opportunities", "labels", "lists", "enrichment"],
|
||||||
|
"appCount": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lever",
|
||||||
|
"displayName": "Lever",
|
||||||
|
"repo": "lever-mcp-2026-complete",
|
||||||
|
"apiBase": "https://api.lever.co/v1",
|
||||||
|
"auth": "basic_or_oauth2",
|
||||||
|
"toolCategories": ["opportunities", "candidates", "postings", "interviews", "offers", "stages", "users", "archive-reasons", "sources", "tags", "feedback-forms"],
|
||||||
|
"appCount": 14
|
||||||
|
}
|
||||||
|
]
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "All 6 batch manifests created (30 servers total)"
|
||||||
|
ls -la "$MANIFEST_DIR"
|
||||||
272
mcp-factory-v3/templates/AGENT-PROMPT-APPS.md
Normal file
272
mcp-factory-v3/templates/AGENT-PROMPT-APPS.md
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
# App Build Agent Prompt
|
||||||
|
|
||||||
|
Build ALL React MCP Apps for the {{NAME}} MCP server at {{DIR}}.
|
||||||
|
|
||||||
|
## Foundation + Tools Already Exist
|
||||||
|
DO NOT modify any existing files. Only ADD app files under `src/ui/react-app/`.
|
||||||
|
|
||||||
|
## Apps to Build
|
||||||
|
|
||||||
|
{{APP_LIST}}
|
||||||
|
|
||||||
|
## Quality Requirements — 2026 Standards
|
||||||
|
|
||||||
|
### Each App Directory Structure
|
||||||
|
```
|
||||||
|
src/ui/react-app/{app-name}/
|
||||||
|
├── App.tsx # Main component
|
||||||
|
├── index.html # Entry point
|
||||||
|
├── main.tsx # React mount with ErrorBoundary
|
||||||
|
├── styles.css # Dark theme styles
|
||||||
|
└── vite.config.ts # Build config
|
||||||
|
```
|
||||||
|
|
||||||
|
### main.tsx — With Error Boundary + Suspense
|
||||||
|
```tsx
|
||||||
|
import React, { Suspense } from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import './styles.css';
|
||||||
|
|
||||||
|
// Lazy load the main app component
|
||||||
|
const App = React.lazy(() => import('./App'));
|
||||||
|
|
||||||
|
// Error Boundary
|
||||||
|
class ErrorBoundary extends React.Component<
|
||||||
|
{ children: React.ReactNode },
|
||||||
|
{ hasError: boolean; error?: Error }
|
||||||
|
> {
|
||||||
|
constructor(props: { children: React.ReactNode }) {
|
||||||
|
super(props);
|
||||||
|
this.state = { hasError: false };
|
||||||
|
}
|
||||||
|
static getDerivedStateFromError(error: Error) {
|
||||||
|
return { hasError: true, error };
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
if (this.state.hasError) {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: 40, color: '#f87171', background: '#0f172a', minHeight: '100vh' }}>
|
||||||
|
<h2>Something went wrong</h2>
|
||||||
|
<pre style={{ color: '#94a3b8' }}>{this.state.error?.message}</pre>
|
||||||
|
<button onClick={() => this.setState({ hasError: false })}
|
||||||
|
style={{ marginTop: 16, padding: '8px 16px', background: '#3b82f6', color: '#fff', border: 'none', borderRadius: 6, cursor: 'pointer' }}>
|
||||||
|
Retry
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.props.children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loading skeleton
|
||||||
|
function LoadingSkeleton() {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: 40, background: '#0f172a', minHeight: '100vh' }}>
|
||||||
|
<div className="skeleton" style={{ height: 32, width: '40%', marginBottom: 24 }} />
|
||||||
|
<div className="skeleton" style={{ height: 200, width: '100%', marginBottom: 16 }} />
|
||||||
|
<div className="skeleton" style={{ height: 200, width: '100%' }} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<ErrorBoundary>
|
||||||
|
<Suspense fallback={<LoadingSkeleton />}>
|
||||||
|
<App />
|
||||||
|
</Suspense>
|
||||||
|
</ErrorBoundary>
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
### App.tsx — Modern React Patterns
|
||||||
|
```tsx
|
||||||
|
import React, { useState, useMemo, useCallback, useTransition } from 'react';
|
||||||
|
|
||||||
|
// Debounce hook for search
|
||||||
|
function useDebounce<T>(value: T, delay: number): T {
|
||||||
|
const [debounced, setDebounced] = React.useState(value);
|
||||||
|
React.useEffect(() => {
|
||||||
|
const t = setTimeout(() => setDebounced(value), delay);
|
||||||
|
return () => clearTimeout(t);
|
||||||
|
}, [value, delay]);
|
||||||
|
return debounced;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toast notification system
|
||||||
|
function useToast() {
|
||||||
|
const [toasts, setToasts] = useState<Array<{ id: number; message: string; type: 'success' | 'error' }>>([]);
|
||||||
|
const show = useCallback((message: string, type: 'success' | 'error' = 'success') => {
|
||||||
|
const id = Date.now();
|
||||||
|
setToasts(prev => [...prev, { id, message, type }]);
|
||||||
|
setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), 3000);
|
||||||
|
}, []);
|
||||||
|
return { toasts, show };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function App() {
|
||||||
|
const [search, setSearch] = useState('');
|
||||||
|
const [isPending, startTransition] = useTransition();
|
||||||
|
const debouncedSearch = useDebounce(search, 300);
|
||||||
|
const { toasts, show: showToast } = useToast();
|
||||||
|
|
||||||
|
// Mock data — replace with MCP tool calls
|
||||||
|
const [data] = useState(MOCK_DATA);
|
||||||
|
|
||||||
|
// Client-side filtering with useMemo
|
||||||
|
const filtered = useMemo(() =>
|
||||||
|
data.filter(item =>
|
||||||
|
item.name.toLowerCase().includes(debouncedSearch.toLowerCase())
|
||||||
|
), [data, debouncedSearch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="app">
|
||||||
|
{/* Header with search */}
|
||||||
|
<header className="header">
|
||||||
|
<h1>{{App Title}}</h1>
|
||||||
|
<div className="search-wrapper">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search..."
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => startTransition(() => setSearch(e.target.value))}
|
||||||
|
className="search-input"
|
||||||
|
/>
|
||||||
|
{isPending && <span className="spinner" />}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{/* Stats cards */}
|
||||||
|
<div className="stats-grid">
|
||||||
|
{/* Stat cards with numbers */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Data grid or dashboard content */}
|
||||||
|
<div className="content">
|
||||||
|
{filtered.length === 0 ? (
|
||||||
|
<div className="empty-state">
|
||||||
|
<p>No results found</p>
|
||||||
|
<span className="empty-hint">Try adjusting your search</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="data-grid">
|
||||||
|
{filtered.map(item => (
|
||||||
|
<div key={item.id} className="card">
|
||||||
|
{/* Card content */}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Toast notifications */}
|
||||||
|
<div className="toast-container">
|
||||||
|
{toasts.map(t => (
|
||||||
|
<div key={t.id} className={`toast toast-${t.type}`}>{t.message}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### styles.css — Dark Theme with CSS Variables + Skeleton Animation
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--bg-primary: #0f172a;
|
||||||
|
--bg-secondary: #1e293b;
|
||||||
|
--bg-tertiary: #334155;
|
||||||
|
--text-primary: #f1f5f9;
|
||||||
|
--text-secondary: #94a3b8;
|
||||||
|
--text-muted: #64748b;
|
||||||
|
--accent: #3b82f6;
|
||||||
|
--accent-hover: #2563eb;
|
||||||
|
--success: #22c55e;
|
||||||
|
--warning: #f59e0b;
|
||||||
|
--error: #ef4444;
|
||||||
|
--border: #334155;
|
||||||
|
--radius: 8px;
|
||||||
|
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
background: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skeleton loading animation */
|
||||||
|
.skeleton {
|
||||||
|
background: linear-gradient(90deg, var(--bg-secondary) 25%, var(--bg-tertiary) 50%, var(--bg-secondary) 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: shimmer 1.5s infinite;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
@keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
|
||||||
|
|
||||||
|
/* Search input */
|
||||||
|
.search-input {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
color: var(--text-primary);
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
width: 280px;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.search-input:focus { outline: none; border-color: var(--accent); }
|
||||||
|
.search-input::placeholder { color: var(--text-muted); }
|
||||||
|
|
||||||
|
/* Stats grid */
|
||||||
|
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }
|
||||||
|
|
||||||
|
/* Cards */
|
||||||
|
.card {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 20px;
|
||||||
|
transition: transform 0.15s, box-shadow 0.15s;
|
||||||
|
}
|
||||||
|
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
|
||||||
|
|
||||||
|
/* Empty state */
|
||||||
|
.empty-state { text-align: center; padding: 60px 20px; color: var(--text-secondary); }
|
||||||
|
.empty-hint { font-size: 14px; color: var(--text-muted); }
|
||||||
|
|
||||||
|
/* Toast notifications */
|
||||||
|
.toast-container { position: fixed; bottom: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 1000; }
|
||||||
|
.toast {
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
color: white;
|
||||||
|
font-weight: 500;
|
||||||
|
animation: slideIn 0.3s ease;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
.toast-success { background: var(--success); }
|
||||||
|
.toast-error { background: var(--error); }
|
||||||
|
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
.search-input { width: 100%; }
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.stats-grid { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
- Each app MUST have: ErrorBoundary, Suspense, loading skeleton, empty state, toast system
|
||||||
|
- Debounced search on all grids/lists
|
||||||
|
- CSS custom properties (not hardcoded colors)
|
||||||
|
- Mobile responsive
|
||||||
|
- DO NOT modify existing files
|
||||||
|
- Commit when done: `git add src/ui/ && git commit -m "{{name}}: Add {{count}} React MCP apps"`
|
||||||
156
mcp-factory-v3/templates/AGENT-PROMPT-FOUNDATION.md
Normal file
156
mcp-factory-v3/templates/AGENT-PROMPT-FOUNDATION.md
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
# Foundation Build Agent Prompt
|
||||||
|
|
||||||
|
Build the foundation for the {{NAME}} MCP server at {{DIR}}.
|
||||||
|
|
||||||
|
## What to Build
|
||||||
|
|
||||||
|
### 1. `package.json`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "@mcpengine/{{NAME}}",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"main": "dist/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"start": "node dist/main.js",
|
||||||
|
"dev": "tsx watch src/main.ts"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||||
|
"axios": "^1.7.0",
|
||||||
|
"zod": "^3.23.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.6.0",
|
||||||
|
"tsx": "^4.19.0",
|
||||||
|
"@types/node": "^22.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. `tsconfig.json`
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleResolution": "Node16",
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"declaration": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. `src/types/index.ts`
|
||||||
|
- Define TypeScript interfaces for ALL API entities
|
||||||
|
- Use branded types for IDs: `type CustomerId = string & { __brand: 'CustomerId' }`
|
||||||
|
- Use discriminated unions for status fields
|
||||||
|
- Export everything
|
||||||
|
|
||||||
|
### 4. `src/clients/{{NAME}}.ts`
|
||||||
|
API client with:
|
||||||
|
- Auth: {{AUTH_TYPE}} (Bearer token / API key / OAuth2)
|
||||||
|
- Base URL: {{API_BASE}}
|
||||||
|
- Retry with exponential backoff (3 retries, 1s/2s/4s)
|
||||||
|
- Rate limit awareness (respect 429 + Retry-After header)
|
||||||
|
- Automatic pagination (abstract cursor/offset)
|
||||||
|
- Request interceptors for logging
|
||||||
|
- Response interceptors for error normalization
|
||||||
|
- Timeout: 30s default
|
||||||
|
- OAuth token auto-refresh if applicable
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import axios, { AxiosInstance, AxiosError } from 'axios';
|
||||||
|
|
||||||
|
export class {{PascalName}}Client {
|
||||||
|
private client: AxiosInstance;
|
||||||
|
private rateLimitRemaining = Infinity;
|
||||||
|
private rateLimitReset = 0;
|
||||||
|
|
||||||
|
constructor(config: { apiKey?: string; accessToken?: string; baseUrl?: string }) {
|
||||||
|
this.client = axios.create({
|
||||||
|
baseURL: config.baseUrl || '{{API_BASE}}',
|
||||||
|
timeout: 30000,
|
||||||
|
headers: { /* auth headers */ }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Response interceptor for rate limiting
|
||||||
|
this.client.interceptors.response.use(
|
||||||
|
(res) => {
|
||||||
|
this.rateLimitRemaining = parseInt(res.headers['x-ratelimit-remaining'] || 'Infinity');
|
||||||
|
this.rateLimitReset = parseInt(res.headers['x-ratelimit-reset'] || '0');
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
async (error: AxiosError) => {
|
||||||
|
if (error.response?.status === 429) {
|
||||||
|
const retryAfter = parseInt(error.response.headers['retry-after'] || '5');
|
||||||
|
await this.sleep(retryAfter * 1000);
|
||||||
|
return this.client.request(error.config!);
|
||||||
|
}
|
||||||
|
throw this.normalizeError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paginated fetch helper
|
||||||
|
async paginate<T>(endpoint: string, params?: Record<string, unknown>): Promise<T[]> { ... }
|
||||||
|
|
||||||
|
// Retry with exponential backoff
|
||||||
|
private async withRetry<T>(fn: () => Promise<T>, retries = 3): Promise<T> { ... }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. `src/server.ts`
|
||||||
|
MCP server with:
|
||||||
|
- Lazy-loaded tool modules (dynamic import)
|
||||||
|
- Resource handlers for UI apps
|
||||||
|
- Structured error responses
|
||||||
|
- Request logging
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||||
|
|
||||||
|
// Lazy load tool modules
|
||||||
|
const toolModules = {
|
||||||
|
'customers': () => import('./tools/customers-tools.js'),
|
||||||
|
'orders': () => import('./tools/orders-tools.js'),
|
||||||
|
// ... etc
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tools loaded on first call
|
||||||
|
const loadedTools = new Map<string, any>();
|
||||||
|
|
||||||
|
async function getToolHandler(category: string) {
|
||||||
|
if (!loadedTools.has(category)) {
|
||||||
|
const mod = await toolModules[category]();
|
||||||
|
loadedTools.set(category, mod);
|
||||||
|
}
|
||||||
|
return loadedTools.get(category);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. `src/main.ts`
|
||||||
|
Entry point with:
|
||||||
|
- Environment validation (fail fast)
|
||||||
|
- Dual transport (stdio + HTTP/SSE)
|
||||||
|
- Graceful shutdown handlers
|
||||||
|
- Health check endpoint
|
||||||
|
|
||||||
|
### 7. `.env.example` + `.gitignore` + `README.md`
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
- DO NOT create tool files or app files — only foundation
|
||||||
|
- TSC must compile clean with `strict: true`
|
||||||
|
- Run `npm install` and `npx tsc --noEmit` to verify
|
||||||
|
- Commit when done
|
||||||
77
mcp-factory-v3/templates/AGENT-PROMPT-TOOLS.md
Normal file
77
mcp-factory-v3/templates/AGENT-PROMPT-TOOLS.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Tool Build Agent Prompt
|
||||||
|
|
||||||
|
Build ALL tool files for the {{NAME}} MCP server at {{DIR}}.
|
||||||
|
|
||||||
|
## Foundation Already Exists
|
||||||
|
- `src/types/index.ts` — TypeScript interfaces
|
||||||
|
- `src/clients/{{NAME}}.ts` — API client with retry, pagination, rate limiting
|
||||||
|
- `src/server.ts` — Server shell with lazy loading
|
||||||
|
- `src/main.ts` — Entry point
|
||||||
|
|
||||||
|
DO NOT modify these files. Only ADD tool files.
|
||||||
|
|
||||||
|
## Tool Categories to Build
|
||||||
|
|
||||||
|
{{TOOL_CATEGORIES}}
|
||||||
|
|
||||||
|
## Quality Requirements for Each Tool File
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
```typescript
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { {{PascalName}}Client } from '../clients/{{NAME}}.js';
|
||||||
|
import type { ToolDefinition } from '../server.js';
|
||||||
|
|
||||||
|
// Input schemas with Zod
|
||||||
|
const ListCustomersInput = z.object({
|
||||||
|
limit: z.number().min(1).max(100).default(25).describe('Results per page'),
|
||||||
|
offset: z.number().min(0).default(0).describe('Pagination offset'),
|
||||||
|
search: z.string().optional().describe('Search by name or email'),
|
||||||
|
sort_by: z.enum(['name', 'created_at', 'updated_at']).default('created_at'),
|
||||||
|
sort_order: z.enum(['asc', 'desc']).default('desc'),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Tool definitions
|
||||||
|
export function getTools(client: {{PascalName}}Client): ToolDefinition[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: '{{name}}_list_customers',
|
||||||
|
description: 'List customers with pagination, search, and sorting',
|
||||||
|
inputSchema: ListCustomersInput,
|
||||||
|
handler: async (input) => {
|
||||||
|
const validated = ListCustomersInput.parse(input);
|
||||||
|
const results = await client.paginate('/customers', validated);
|
||||||
|
return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ... more tools
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Each Tool MUST Have
|
||||||
|
- **Zod input schema** — with `.describe()` on every field
|
||||||
|
- **Pagination params** — limit/offset or cursor for list operations
|
||||||
|
- **Search/filter** — where the API supports it
|
||||||
|
- **Error handling** — catch and return meaningful error messages
|
||||||
|
- **Consistent naming** — `{{name}}_verb_noun` format (e.g., `shopify_list_orders`)
|
||||||
|
|
||||||
|
### Tool Count Targets
|
||||||
|
- Each category: 4-8 tools (CRUD + search + bulk where applicable)
|
||||||
|
- Total per server: 40-60+ tools
|
||||||
|
- Every tool must be useful — no filler
|
||||||
|
|
||||||
|
### Common Patterns Per Category
|
||||||
|
- `list_*` — paginated list with filters
|
||||||
|
- `get_*` — single item by ID
|
||||||
|
- `create_*` — create with validated input
|
||||||
|
- `update_*` — partial update by ID
|
||||||
|
- `delete_*` — delete by ID
|
||||||
|
- `search_*` — full-text or field search
|
||||||
|
- `bulk_*` — batch operations where API supports
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
- DO NOT modify existing files
|
||||||
|
- DO NOT create app files
|
||||||
|
- Run `npx tsc --noEmit` to verify everything compiles
|
||||||
|
- Commit when done
|
||||||
@ -1 +1 @@
|
|||||||
Subproject commit 2c41d0fb3b0c4a00c4b114551dc5efe835dc8bb7
|
Subproject commit 7afa3208ac3d8e870855a6da2729a0b7d89a3e37
|
||||||
58
memory/2026-02-13.md
Normal file
58
memory/2026-02-13.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# Daily Log — Feb 13, 2026
|
||||||
|
|
||||||
|
## Session Summary
|
||||||
|
|
||||||
|
### SOLVR Contract (COMPLETE)
|
||||||
|
- Created full SOW (QU-026-20) — $20K, 6-week timeline, 50/25/25 payment split
|
||||||
|
- v2: Added § 5 Scope Flexibility (3 free software swaps, $300/hr capped at $900 for extra work)
|
||||||
|
- v2: Added § 4.5 Early Completion clause (full $10K due if finished before Week 3)
|
||||||
|
- v3: Added § 4.6 Gross Negligence definition (14-day missed deadline + 7-day no communication)
|
||||||
|
- Updated to Team Shore Services LLC dba MCPEngage
|
||||||
|
- Created Invoice INV-026-01 for $10K deposit (Wise payment)
|
||||||
|
- Files: `proposals/solvr-contract-sow.{html,md,pdf}`, `proposals/solvr-invoice-001.{html,pdf}`
|
||||||
|
|
||||||
|
### Good Society 2025 Artist Research (COMPLETE)
|
||||||
|
- Researched all 67 artists from the lineup image
|
||||||
|
- Top artists: Hamdi (1.4M), Babsy (455K), Know Good (390K), Effin (333K)
|
||||||
|
- 53 found on Spotify, 14 SoundCloud/Bandcamp only
|
||||||
|
- Results saved: `good-society-2025-artist-stats.md`
|
||||||
|
|
||||||
|
### Buba 3D Neural Dashboard (3 ITERATIONS)
|
||||||
|
- v1: Dark cyberpunk Three.js 3D city — Jake said too scary/liminal/angular
|
||||||
|
- v2: Added chibi character + bloom post-processing — still too dark
|
||||||
|
- v3: Complete pastel makeover — floating island, rounded buildings, Animal Crossing aesthetic
|
||||||
|
- Buildings: MCP Factory, SOLVR, CannaBri, TheNicheQuiz, CREdispo, OpenClaw, OSKV Coaching
|
||||||
|
- Trees, flowers, clouds, pond, sparkles, pastel gradient sky
|
||||||
|
- Server: `buba-dashboard/server.js` on port 8890
|
||||||
|
- Frontend: `buba-dashboard/public/index.html` (54.5KB Three.js)
|
||||||
|
- **NOTE:** Server needs manual restart after reboot — `cd buba-dashboard && nohup node server.js &`
|
||||||
|
|
||||||
|
### Atlanta Airport Chibi Image (COMPLETE)
|
||||||
|
- Generated kawaii chibi family running through ATL airport
|
||||||
|
- Learned Jake's preferred style = chibi/kawaii (NOT comic book)
|
||||||
|
|
||||||
|
### Mac Mini Mouse Fix (REBOOT NEEDED)
|
||||||
|
- Mouse freezing issue — even wired mouse doesn't work
|
||||||
|
- Killed LM Studio Helper (99.8% CPU for 17 days!)
|
||||||
|
- Killed old puppeteer Chrome zombies
|
||||||
|
- Tried: Bluetooth reset, HID driver restart, input stack restart
|
||||||
|
- Resolution: Hard reboot needed (can't sudo reboot remotely)
|
||||||
|
|
||||||
|
### MCP Factory V3 — Batch 1+2 Progress
|
||||||
|
- All 5 foundations complete: Xero, Monday, Intercom, Airtable, Notion
|
||||||
|
- All 5 tools phases complete: Xero (84), Monday (60), Intercom (71), Airtable (34), Notion (43)
|
||||||
|
- HubSpot apps complete (20 apps)
|
||||||
|
- 5 apps sub-agents queued but not started: Xero, Monday, Intercom, Airtable, Notion
|
||||||
|
- **Re-spawn these after reboot**
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
- Jake's image style = chibi kawaii anime (ALWAYS default to this)
|
||||||
|
- Company name: Team Shore Services LLC dba MCPEngage
|
||||||
|
- SOLVR gross negligence = 14-day deadline miss + 7-day no communication
|
||||||
|
- Dashboard aesthetic: PASTEL, not cyberpunk (rounded, whimsical, bright)
|
||||||
|
|
||||||
|
## Pending After Reboot
|
||||||
|
1. Re-spawn 5 MCP apps sub-agents (xero, monday, intercom, airtable, notion)
|
||||||
|
2. Restart buba-dashboard server on port 8890
|
||||||
|
3. Verify mouse works after reboot
|
||||||
|
4. Jake may want to continue iterating on 3D dashboard visuals
|
||||||
@ -195,8 +195,79 @@
|
|||||||
- **What happened:** Some use subdirectories, some use .tsx files, some use .ts files, some use .html files, some use src/apps/ instead of src/ui/react-app/
|
- **What happened:** Some use subdirectories, some use .tsx files, some use .ts files, some use .html files, some use src/apps/ instead of src/ui/react-app/
|
||||||
- **Rule:** Check ALL patterns: subdirs in react-app/, .tsx files, .ts files, .html files, AND src/apps/*.ts. Take the max. Use a consistent counting script.
|
- **Rule:** Check ALL patterns: subdirs in react-app/, .tsx files, .ts files, .html files, AND src/apps/*.ts. Take the max. Use a consistent counting script.
|
||||||
|
|
||||||
*Last updated: 2026-02-12 22:20 EST*
|
## MCP Factory Quality Standards (2026-02-13)
|
||||||
*Total lessons: 25*
|
|
||||||
|
### 26. ALWAYS start from the actual API spec — never hand-pick tools from vibes
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Mistake:** For the 30 SMB MCP servers, I read API docs casually and hand-picked 7-8 "obvious" tools per server
|
||||||
|
- **What happened:** Ended up with surface-level CRUD (list/get/create/update) covering maybe 10-15% of each API, missing the tools people actually need
|
||||||
|
- **Rule:** ALWAYS pull the official OpenAPI/Swagger spec (or systematically crawl every endpoint). Build a complete endpoint inventory BEFORE deciding what becomes a tool. If Mailchimp has 127 endpoints, I need to know all 127 before picking which 50 become tools.
|
||||||
|
|
||||||
|
### 27. Prioritize tools by real user workflows, not alphabetical CRUD
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Mistake:** Mechanically created `list_X / get_X / create_X / update_X` for each resource — zero workflow awareness
|
||||||
|
- **What happened:** A CRM MCP that can `list_leads` but can't `log_a_call` or `add_note_to_lead` — the things salespeople do 50x/day
|
||||||
|
- **Rule:** Research the platform's top use cases. Map workflow chains (create contact → add to list → send campaign → check results). Tier the tools:
|
||||||
|
- **Tier 1 (daily):** 10-15 things every user does daily
|
||||||
|
- **Tier 2 (power user):** 15-30 things power users need
|
||||||
|
- **Tier 3 (complete):** Everything else for full API coverage
|
||||||
|
- Ship Tier 1+2 minimum. Tier 3 = "best on market" differentiator.
|
||||||
|
|
||||||
|
### 28. Rich tool descriptions are NOT optional — they drive agent behavior
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Mistake:** Wrote basic descriptions like "Lists contacts" with minimal parameter docs
|
||||||
|
- **What happened:** AI agents make tool selection decisions based on descriptions. Vague = wrong tool chosen = bad UX
|
||||||
|
- **Rule:** Every tool description must tell an AI agent WHEN to use it:
|
||||||
|
- BAD: "Lists contacts"
|
||||||
|
- GOOD: "Lists contacts with optional filtering by email, name, tag, or date range. Use when the user wants to find, search, or browse their contact database. Returns paginated results up to 100 per page."
|
||||||
|
- Every param needs: description, type+format constraints, defaults, required/optional, example values
|
||||||
|
- `_meta` labels from day one: category, access (read/write/destructive), complexity, rateLimit
|
||||||
|
|
||||||
|
### 29. Maintain a coverage manifest for every MCP server
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Mistake:** No tracking of which endpoints were covered vs skipped. No way to measure quality.
|
||||||
|
- **Rule:** Every server gets a coverage manifest in its README:
|
||||||
|
```
|
||||||
|
Total API endpoints: 127
|
||||||
|
Tools implemented: 45
|
||||||
|
Intentionally skipped: 12 (deprecated/admin-only)
|
||||||
|
Not yet covered: 70 (backlog)
|
||||||
|
Coverage: 35% → target 80%+
|
||||||
|
```
|
||||||
|
Every skipped endpoint needs a REASON (deprecated, admin-only, OAuth-only, redundant). Set 80%+ as "production quality" threshold.
|
||||||
|
|
||||||
|
### 30. 7-8 tools per server is a demo, not a product
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Mistake:** Treated 7-8 tools as "enough" for the initial 30 servers
|
||||||
|
- **What it actually is:** A toy. Nobody can do their real job with 7 tools for a platform that has 100+ API endpoints.
|
||||||
|
- **Rule:** Minimum viable tool count depends on API size:
|
||||||
|
- Small API (<30 endpoints): 15-20 tools
|
||||||
|
- Medium API (30-100 endpoints): 30-50 tools
|
||||||
|
- Large API (100+ endpoints): 50-80+ tools
|
||||||
|
- If customers install it and can't do their #1 use case, it's not a product.
|
||||||
|
|
||||||
|
### 31. Consistent naming conventions across ALL servers — no exceptions
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Rule:** Factory-wide naming standard:
|
||||||
|
- `list_*` for paginated collections
|
||||||
|
- `get_*` for single resource by ID
|
||||||
|
- `create_*`, `update_*`, `delete_*` for mutations
|
||||||
|
- `search_*` for query-based lookups
|
||||||
|
- Domain verbs: `send_email`, `cancel_event`, `archive_card`, `assign_task`
|
||||||
|
- NEVER mix `fetch_*` / `get_*` / `retrieve_*` — pick ONE
|
||||||
|
- All snake_case, all lowercase
|
||||||
|
|
||||||
|
### 32. Handle pagination and rate limits properly in every server
|
||||||
|
- **Date:** 2026-02-13
|
||||||
|
- **Rule:** Every `list_*` tool must:
|
||||||
|
- Support cursor/page tokens
|
||||||
|
- Use reasonable default page sizes (25-100, never "all")
|
||||||
|
- Return `has_more` / `next_page` indicators
|
||||||
|
- Handle API rate limits (429) with retry + exponential backoff
|
||||||
|
- Document known rate limits in tool `_meta`
|
||||||
|
|
||||||
|
*Last updated: 2026-02-13 02:46 EST*
|
||||||
|
*Total lessons: 32*
|
||||||
|
|
||||||
### 17. Jake's Preferred Image Style
|
### 17. Jake's Preferred Image Style
|
||||||
- **Mistake:** Used comic book/vibrant cartoon style when Jake asked for "the style I like"
|
- **Mistake:** Used comic book/vibrant cartoon style when Jake asked for "the style I like"
|
||||||
|
|||||||
@ -1,26 +1,28 @@
|
|||||||
# Working State — Last Updated Feb 12, 11:00 PM ET
|
# Working State — Last Updated Feb 13, 3:35 AM ET
|
||||||
|
|
||||||
## Right Now
|
## Right Now
|
||||||
End-of-day memory checkpoint. All major work done for today. Sub-agents for batch 5+6 may have completed or failed (rate limits hit tonight).
|
About to reboot Mac mini to fix mouse/input freeze. All work saved.
|
||||||
|
|
||||||
|
## Pending After Reboot
|
||||||
|
1. Re-spawn 5 MCP V3 apps sub-agents (xero, monday, intercom, airtable, notion)
|
||||||
|
2. Restart buba-dashboard server: `cd buba-dashboard && nohup node server.js > /tmp/buba-dashboard.log 2>&1 &`
|
||||||
|
3. Verify mouse works
|
||||||
|
4. Continue MCP Factory V3 pipeline
|
||||||
|
|
||||||
## Today's Done List
|
## Today's Done List
|
||||||
- TheNicheQuiz.com: fully deployed (domain + Worker + Flask + Postgres)
|
- [x] SOLVR contract v1/v2/v3 + invoice INV-026-01
|
||||||
- CannaBri site: built + deployed to GitHub Pages
|
- [x] Good Society 2025 artist research (67 artists)
|
||||||
- Veo 3.1 video generation: first successful test
|
- [x] Buba 3D Dashboard v1/v2/v3 (pastel floating island)
|
||||||
- MCP Factory V2 batches 1-4: 20 servers complete, committed, pushed
|
- [x] Atlanta airport chibi image
|
||||||
- Batch 5+6: 6 fixer sub-agents spawned for remaining 10 servers
|
- [x] MCP V3 Batch 1 foundations (5 servers)
|
||||||
- dec-003 resolved (approved 2, killed HR People Ops)
|
- [x] MCP V3 Batch 1 tools (5 servers: 292 tools total)
|
||||||
- dec-004 reminder posted (still pending after 29h)
|
- [x] MCP V3 HubSpot apps (20 apps)
|
||||||
- Burton Method competitor scan #6 posted
|
- [x] Killed LM Studio (99.8% CPU for 17 days)
|
||||||
- OpenClaw contract SOW updated with LLC name
|
- [x] Fixed Xbox Controller Manager issue
|
||||||
- All repos pushed (mcpengine, GHL, workspace)
|
- [x] Mouse troubleshooting (reboot needed)
|
||||||
- .gitignore fixed to exclude .next/ dirs
|
|
||||||
- Discord TLDR summaries generated
|
|
||||||
|
|
||||||
## Pending
|
## MCP Factory V3 Status
|
||||||
- dec-004: Registry listing approval (29h+ pending)
|
- **Foundations done:** Xero, Monday, Intercom, Airtable, Notion
|
||||||
- Jake's coaching decision for Oliver/Kevin (paused at Day 7)
|
- **Tools done:** Xero (84), Monday (60), Intercom (71), Airtable (34), Notion (43)
|
||||||
- CREdispo domain purchase
|
- **Apps done:** HubSpot (20)
|
||||||
- Verify batch 5+6 sub-agent results
|
- **Apps queued (re-spawn after reboot):** Xero, Monday, Intercom, Airtable, Notion
|
||||||
- Complete all 30 servers → research 5 new high-money MCPs
|
|
||||||
- fatgordo's CannaBri original imagery request (needs Jake approval)
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user