useless-mcp-friday 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +35 -0
- package/dist/tools/bet-progress.d.ts +24 -0
- package/dist/tools/bet-progress.js +111 -0
- package/dist/tools/founder-mood.d.ts +21 -0
- package/dist/tools/founder-mood.js +67 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# useless-mcp-friday ๐คก
|
|
2
|
+
|
|
3
|
+
One useless MCP tool every Friday. Built in public by [@bennetglinder99](https://x.com/bennetglinder99).
|
|
4
|
+
|
|
5
|
+
This MCP server gives your Claude (or any MCP-compatible AI agent) access to a growing set of intentionally useless tools. They don't make your agent more productive. They make you laugh. They make founders go *"oh god, same."*
|
|
6
|
+
|
|
7
|
+
A new useless tool ships every Friday.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
claude mcp add useless-mcp-friday npx -y useless-mcp-friday
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Restart Claude. That's it. You now have access to every useless MCP tool I've ever shipped. New ones auto-add as they're released.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What's available
|
|
22
|
+
|
|
23
|
+
### `founder_mood` (week 1 ยท shipped May 23, 2026)
|
|
24
|
+
|
|
25
|
+
Returns my current mood while building Nous in public. I update it each morning via commit. Ask Claude:
|
|
26
|
+
|
|
27
|
+
> *"what's the founder mood today?"*
|
|
28
|
+
|
|
29
|
+
Example response:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
๐ค founder mood today:
|
|
33
|
+
"still using apple notes for everything"
|
|
34
|
+
|
|
35
|
+
context: writing useless mcp tool #3 โ rate-my-stack
|
|
36
|
+
last updated: Mon 9:32 AM EDT
|
|
37
|
+
day 39 of building nous in public
|
|
38
|
+
|
|
39
|
+
(updated daily by @bennetglinder99 via commit)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Useful for: not much. Resonant for: every founder who has ever shipped to prod on a Friday at 6pm.
|
|
43
|
+
|
|
44
|
+
### `bet_progress` (week 2 ยท shipped May 30, 2026)
|
|
45
|
+
|
|
46
|
+
Returns live progress toward my open-source bet: **1,000 GitHub stars on Nous by June 30, 2026**. Pulls fresh from the GitHub API on every call. Ask Claude:
|
|
47
|
+
|
|
48
|
+
> *"how is the nous bet going?"*
|
|
49
|
+
|
|
50
|
+
Example response:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
๐ฏ nous bet progress
|
|
54
|
+
|
|
55
|
+
stars: 347
|
|
56
|
+
target: 1,000 by june 30
|
|
57
|
+
days remaining: 25
|
|
58
|
+
pace: 1,089 (ahead of the bet by 89) โ keep shipping.
|
|
59
|
+
|
|
60
|
+
day 11 of 36 in the bet.
|
|
61
|
+
|
|
62
|
+
github.com/bennetglinder1/nous
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Genuinely useful for: tracking the bet. Useless for: anyone who isn't me or rooting for me.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Why this exists
|
|
70
|
+
|
|
71
|
+
I made a bet with my friends: 1,000 GitHub stars on Nous by June 30. Because I believe open source is the new distribution channel for shipping products.
|
|
72
|
+
|
|
73
|
+
This repo is the *useless* side project. Nous is the real one: an open-source project that gives Claude agents structured summary and full account context.
|
|
74
|
+
|
|
75
|
+
โ Main repo: [github.com/bennetglinder1/nous](https://github.com/bennetglinder1/nous)
|
|
76
|
+
โ The bet: [why I'm doing this](https://x.com/bennetglinder99)
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Contributing useless MCP tools
|
|
81
|
+
|
|
82
|
+
PRs welcome **after week 4**. If your useless MCP tool actually works and makes me laugh, I'll merge it.
|
|
83
|
+
|
|
84
|
+
Rules:
|
|
85
|
+
1. It must work. A broken useless tool is worse than no tool.
|
|
86
|
+
2. It must be useless. If it's actually useful, ship it as its own project.
|
|
87
|
+
3. It must fit the format: returns something funny / sarcastic / resonant when called.
|
|
88
|
+
4. Open a PR with one new file in `src/tools/` + registry update.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT. Fork it, remix it, ship your own. (Just don't call it "useless-mcp-friday" โ that's the brand.)
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
*Day 31 of building Nous in public. cheers โ๏ธ*
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* useless-mcp-friday โ one useless MCP tool every Friday.
|
|
4
|
+
* Built in public by @bennetglinder99.
|
|
5
|
+
* github.com/bennetglinder1/useless-mcp-friday
|
|
6
|
+
*/
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { founderMoodTool, founderMoodHandler } from "./tools/founder-mood.js";
|
|
11
|
+
import { betProgressTool, betProgressHandler } from "./tools/bet-progress.js";
|
|
12
|
+
// Add new tools here as you ship each Friday.
|
|
13
|
+
const tools = [founderMoodTool, betProgressTool];
|
|
14
|
+
const handlers = {
|
|
15
|
+
founder_mood: founderMoodHandler,
|
|
16
|
+
bet_progress: betProgressHandler,
|
|
17
|
+
};
|
|
18
|
+
const server = new Server({ name: "useless-mcp-friday", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
19
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
20
|
+
tools,
|
|
21
|
+
}));
|
|
22
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
23
|
+
const handler = handlers[request.params.name];
|
|
24
|
+
if (!handler) {
|
|
25
|
+
throw new Error(`Unknown tool: ${request.params.name}`);
|
|
26
|
+
}
|
|
27
|
+
const result = await handler(request.params.arguments || {});
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: result.text }],
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
const transport = new StdioServerTransport();
|
|
33
|
+
await server.connect(transport);
|
|
34
|
+
// keep process alive
|
|
35
|
+
process.stdin.resume();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bet_progress โ week 2 useless MCP tool.
|
|
3
|
+
*
|
|
4
|
+
* Returns live progress toward Bennet's open-source bet:
|
|
5
|
+
* 1,000 GitHub stars on Nous by June 30, 2026.
|
|
6
|
+
*
|
|
7
|
+
* Fetches live star count from GitHub API on every call.
|
|
8
|
+
* Calculates pace projection vs bet target.
|
|
9
|
+
*
|
|
10
|
+
* Genuinely useful for: tracking the bet (the meta-tool that bridges to Nous proper).
|
|
11
|
+
* Useless for: anyone who isn't Bennet or rooting for him.
|
|
12
|
+
*/
|
|
13
|
+
export declare const betProgressTool: {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: string;
|
|
18
|
+
properties: {};
|
|
19
|
+
required: never[];
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export declare function betProgressHandler(_args: any): Promise<{
|
|
23
|
+
text: string;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bet_progress โ week 2 useless MCP tool.
|
|
3
|
+
*
|
|
4
|
+
* Returns live progress toward Bennet's open-source bet:
|
|
5
|
+
* 1,000 GitHub stars on Nous by June 30, 2026.
|
|
6
|
+
*
|
|
7
|
+
* Fetches live star count from GitHub API on every call.
|
|
8
|
+
* Calculates pace projection vs bet target.
|
|
9
|
+
*
|
|
10
|
+
* Genuinely useful for: tracking the bet (the meta-tool that bridges to Nous proper).
|
|
11
|
+
* Useless for: anyone who isn't Bennet or rooting for him.
|
|
12
|
+
*/
|
|
13
|
+
const REPO = "bennetglinder1/nous";
|
|
14
|
+
const TARGET_STARS = 1000;
|
|
15
|
+
const BET_START = new Date("2026-05-25T00:00:00Z"); // OS launch day
|
|
16
|
+
const BET_END = new Date("2026-06-30T23:59:59Z");
|
|
17
|
+
export const betProgressTool = {
|
|
18
|
+
name: "bet_progress",
|
|
19
|
+
description: "Returns live progress toward Bennet's open-source bet: 1,000 GitHub stars on Nous by June 30, 2026. Live stars + days remaining + pace projection. Calls the GitHub API fresh on every invocation.",
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {},
|
|
23
|
+
required: [],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
export async function betProgressHandler(_args) {
|
|
27
|
+
try {
|
|
28
|
+
const stars = await fetchStars();
|
|
29
|
+
const now = new Date();
|
|
30
|
+
return { text: formatBet(stars, now) };
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
return {
|
|
34
|
+
text: "github api is rate-limited or down. the bet continues regardless. try again in ~1h.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function fetchStars() {
|
|
39
|
+
const res = await fetch(`https://api.github.com/repos/${REPO}`, {
|
|
40
|
+
headers: { "User-Agent": "useless-mcp-friday" },
|
|
41
|
+
cache: "no-store",
|
|
42
|
+
});
|
|
43
|
+
if (!res.ok)
|
|
44
|
+
throw new Error(`GitHub API: ${res.status}`);
|
|
45
|
+
const data = await res.json();
|
|
46
|
+
return data.stargazers_count ?? 0;
|
|
47
|
+
}
|
|
48
|
+
function formatBet(stars, now) {
|
|
49
|
+
const totalBetDays = Math.ceil((BET_END.getTime() - BET_START.getTime()) / 86400000);
|
|
50
|
+
const elapsedDays = Math.floor((now.getTime() - BET_START.getTime()) / 86400000);
|
|
51
|
+
const remainingDays = Math.max(0, Math.ceil((BET_END.getTime() - now.getTime()) / 86400000));
|
|
52
|
+
// Pre-bet (before May 25 launch)
|
|
53
|
+
if (now < BET_START) {
|
|
54
|
+
const untilStart = Math.ceil((BET_START.getTime() - now.getTime()) / 86400000);
|
|
55
|
+
return [
|
|
56
|
+
"๐ฏ nous bet progress",
|
|
57
|
+
"",
|
|
58
|
+
`stars: ${stars}`,
|
|
59
|
+
`target: ${TARGET_STARS.toLocaleString()} by june 30`,
|
|
60
|
+
"",
|
|
61
|
+
`bet doesn't start yet โ OS launch is in ${untilStart} day${untilStart === 1 ? "" : "s"} (may 25).`,
|
|
62
|
+
"",
|
|
63
|
+
"github.com/bennetglinder1/nous",
|
|
64
|
+
].join("\n");
|
|
65
|
+
}
|
|
66
|
+
// Post-bet (after June 30)
|
|
67
|
+
if (now > BET_END) {
|
|
68
|
+
const hit = stars >= TARGET_STARS;
|
|
69
|
+
return [
|
|
70
|
+
"๐ฏ nous bet result",
|
|
71
|
+
"",
|
|
72
|
+
`final stars: ${stars.toLocaleString()}`,
|
|
73
|
+
`target: ${TARGET_STARS.toLocaleString()}`,
|
|
74
|
+
`result: ${hit ? "โ
won the bet" : "โ missed by " + (TARGET_STARS - stars).toLocaleString()}`,
|
|
75
|
+
"",
|
|
76
|
+
hit
|
|
77
|
+
? "open source IS the new distribution channel for shipping products. proven."
|
|
78
|
+
: "open source might still be the distribution channel. just need more reps.",
|
|
79
|
+
"",
|
|
80
|
+
"github.com/bennetglinder1/nous",
|
|
81
|
+
].join("\n");
|
|
82
|
+
}
|
|
83
|
+
// Mid-bet (May 25 โ June 30)
|
|
84
|
+
const safeElapsed = Math.max(1, elapsedDays);
|
|
85
|
+
const dailyPace = stars / safeElapsed;
|
|
86
|
+
const projected = Math.round(dailyPace * totalBetDays);
|
|
87
|
+
const aheadBy = projected - TARGET_STARS;
|
|
88
|
+
let paceLine;
|
|
89
|
+
if (aheadBy > 50) {
|
|
90
|
+
paceLine = `pace: ${projected.toLocaleString()} (ahead of the bet by ${aheadBy.toLocaleString()}) โ keep shipping.`;
|
|
91
|
+
}
|
|
92
|
+
else if (aheadBy >= 0) {
|
|
93
|
+
paceLine = `pace: ${projected.toLocaleString()} (right on the bet) โ don't slow down.`;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const need = Math.ceil((TARGET_STARS - stars) / Math.max(1, remainingDays));
|
|
97
|
+
paceLine = `pace: ${projected.toLocaleString()} (behind by ${Math.abs(aheadBy).toLocaleString()}) โ need ${need} stars/day to catch up.`;
|
|
98
|
+
}
|
|
99
|
+
return [
|
|
100
|
+
"๐ฏ nous bet progress",
|
|
101
|
+
"",
|
|
102
|
+
`stars: ${stars.toLocaleString()}`,
|
|
103
|
+
`target: ${TARGET_STARS.toLocaleString()} by june 30`,
|
|
104
|
+
`days remaining: ${remainingDays}`,
|
|
105
|
+
paceLine,
|
|
106
|
+
"",
|
|
107
|
+
`day ${safeElapsed} of ${totalBetDays} in the bet.`,
|
|
108
|
+
"",
|
|
109
|
+
"github.com/bennetglinder1/nous",
|
|
110
|
+
].join("\n");
|
|
111
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* founder_mood โ week 1 useless MCP tool.
|
|
3
|
+
*
|
|
4
|
+
* Returns Bennet's current mood while building Nous in public.
|
|
5
|
+
* Updated each morning by Bennet via `npm run mood "<mood>" "<context>"`.
|
|
6
|
+
*
|
|
7
|
+
* The mood data is fetched live from the GitHub raw URL on every call,
|
|
8
|
+
* so users always get the latest without reinstalling.
|
|
9
|
+
*/
|
|
10
|
+
export declare const founderMoodTool: {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: string;
|
|
15
|
+
properties: {};
|
|
16
|
+
required: never[];
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export declare function founderMoodHandler(_args: any): Promise<{
|
|
20
|
+
text: string;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* founder_mood โ week 1 useless MCP tool.
|
|
3
|
+
*
|
|
4
|
+
* Returns Bennet's current mood while building Nous in public.
|
|
5
|
+
* Updated each morning by Bennet via `npm run mood "<mood>" "<context>"`.
|
|
6
|
+
*
|
|
7
|
+
* The mood data is fetched live from the GitHub raw URL on every call,
|
|
8
|
+
* so users always get the latest without reinstalling.
|
|
9
|
+
*/
|
|
10
|
+
const MOOD_URL = "https://raw.githubusercontent.com/bennetglinder1/useless-mcp-friday/main/data/current-mood.json";
|
|
11
|
+
export const founderMoodTool = {
|
|
12
|
+
name: "founder_mood",
|
|
13
|
+
description: "Returns the current mood of a founder building Nous in public. Updated daily. The mood is whatever Bennet (@bennetglinder99) is feeling while shipping today. Useful for: not much. Resonant for: every founder who has ever been 'still using apple notes for everything'.",
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {},
|
|
17
|
+
required: [],
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
export async function founderMoodHandler(_args) {
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(MOOD_URL, { cache: "no-store" });
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
return offlineFallback();
|
|
25
|
+
}
|
|
26
|
+
const data = await res.json();
|
|
27
|
+
const text = formatMood(data);
|
|
28
|
+
return { text };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return offlineFallback();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function formatMood(data) {
|
|
35
|
+
const lines = [];
|
|
36
|
+
lines.push("๐ค founder mood today:");
|
|
37
|
+
lines.push(`"${data.mood}"`);
|
|
38
|
+
lines.push("");
|
|
39
|
+
if (data.context)
|
|
40
|
+
lines.push(`context: ${data.context}`);
|
|
41
|
+
if (data.updated_at)
|
|
42
|
+
lines.push(`last updated: ${formatTime(data.updated_at)}`);
|
|
43
|
+
if (data.day_count)
|
|
44
|
+
lines.push(`day ${data.day_count} of building nous in public`);
|
|
45
|
+
lines.push("");
|
|
46
|
+
lines.push("(updated daily by @bennetglinder99 via commit)");
|
|
47
|
+
return lines.join("\n");
|
|
48
|
+
}
|
|
49
|
+
function formatTime(iso) {
|
|
50
|
+
try {
|
|
51
|
+
const d = new Date(iso);
|
|
52
|
+
return d.toLocaleString("en-US", {
|
|
53
|
+
weekday: "short",
|
|
54
|
+
hour: "numeric",
|
|
55
|
+
minute: "2-digit",
|
|
56
|
+
timeZoneName: "short",
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return iso;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function offlineFallback() {
|
|
64
|
+
return {
|
|
65
|
+
text: "the founder is offline. probably sleeping. or shipping. or in a sales call he shouldn't be in.",
|
|
66
|
+
};
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "useless-mcp-friday",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "One useless MCP tool every Friday. Built in public by @bennetglinder99. github.com/bennetglinder1/useless-mcp-friday",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"useless-mcp-friday": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"mood": "tsx scripts/update-mood.ts",
|
|
18
|
+
"dev": "tsx src/index.ts"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"tsx": "^4.0.0",
|
|
25
|
+
"typescript": "^5.5.0",
|
|
26
|
+
"@types/node": "^22.0.0"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"mcp",
|
|
30
|
+
"claude",
|
|
31
|
+
"useless",
|
|
32
|
+
"absurd",
|
|
33
|
+
"build-in-public",
|
|
34
|
+
"open-source"
|
|
35
|
+
],
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"homepage": "https://github.com/bennetglinder1/useless-mcp-friday",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/bennetglinder1/useless-mcp-friday.git"
|
|
41
|
+
},
|
|
42
|
+
"author": "Bennet <@bennetglinder99>"
|
|
43
|
+
}
|