@tokcalc/mcp-server 0.1.2 → 0.1.4
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 +86 -406
- package/dist/index.js +21285 -0
- package/package.json +34 -91
- package/.zscripts/build.sh +0 -175
- package/.zscripts/database-runtime-build.sh +0 -33
- package/.zscripts/dev.pid +0 -1
- package/.zscripts/dev.sh +0 -154
- package/.zscripts/mini-services-build.sh +0 -78
- package/.zscripts/mini-services-install.sh +0 -65
- package/.zscripts/mini-services-start.sh +0 -123
- package/.zscripts/python-runtime-build.sh +0 -120
- package/.zscripts/start.sh +0 -145
- package/CAPACITY_STUDY.md +0 -283
- package/CODE_OF_CONDUCT.md +0 -55
- package/CONTRIBUTING.md +0 -177
- package/Caddyfile +0 -23
- package/LICENSE +0 -204
- package/bun.lock +0 -1965
- package/components.json +0 -21
- package/db/custom.db +0 -0
- package/download/README.md +0 -1
- package/download/tokcalc-dark-calculator.png +0 -0
- package/download/tokcalc-dark-default.png +0 -0
- package/download/tokcalc-demo.webm +0 -0
- package/download/tokcalc-github-link.png +0 -0
- package/download/tokcalc-hydration-fixed.png +0 -0
- package/download/tokcalc-issue-resolved.png +0 -0
- package/download/tokcalc-light-mode.png +0 -0
- package/download/tokcalc-light-reference.png +0 -0
- package/download/tokcalc-long-context-qwen.png +0 -0
- package/download/tokcalc-long-context.png +0 -0
- package/download/tokcalc-og-image-preview.png +0 -0
- package/download/tokcalc-phase2-3.png +0 -0
- package/download/tokcalc-plain-english.png +0 -0
- package/download/tokcalc-preview.png +0 -0
- package/download/tokcalc-share-bvb.png +0 -0
- package/download/tokcalc-share-feature.png +0 -0
- package/download/tokcalc-tab-build-vs-buy.png +0 -0
- package/download/tokcalc-tab-calculator.png +0 -0
- package/download/tokcalc-tab-reference.png +0 -0
- package/eslint.config.mjs +0 -50
- package/examples/websocket/frontend.tsx +0 -196
- package/examples/websocket/server.ts +0 -138
- package/mini-services/.gitkeep +0 -0
- package/mini-services/mcp-server/README.md +0 -86
- package/mini-services/mcp-server/bun.lock +0 -202
- package/mini-services/mcp-server/index.ts +0 -504
- package/mini-services/mcp-server/package.json +0 -40
- package/next.config.ts +0 -12
- package/postcss.config.mjs +0 -5
- package/prisma/schema.prisma +0 -32
- package/public/google6f58ca6be85fa903.html +0 -1
- package/public/logo.svg +0 -29
- package/public/manifest.json +0 -51
- package/public/og-icon-256.png +0 -0
- package/public/og.png +0 -0
- package/public/robots.txt +0 -25
- package/public/sitemap.xml +0 -23
- package/public/tokcalc-demo.gif +0 -0
- package/scripts/og-template.html +0 -120
- package/scripts/render-og.mjs +0 -43
- package/server.json +0 -21
- package/src/app/api/pricing/aws/route.ts +0 -186
- package/src/app/api/pricing/azure/route.ts +0 -168
- package/src/app/api/pricing/gcp/route.ts +0 -230
- package/src/app/api/pricing/vast-ai/route.ts +0 -164
- package/src/app/api/route.ts +0 -5
- package/src/app/compare/h100-vs-h200/layout.tsx +0 -30
- package/src/app/compare/h100-vs-h200/page.tsx +0 -328
- package/src/app/globals.css +0 -122
- package/src/app/layout.tsx +0 -276
- package/src/app/page.tsx +0 -2670
- package/src/components/azure-live-pricing.tsx +0 -185
- package/src/components/benchmark-import.tsx +0 -340
- package/src/components/confidence-badge.tsx +0 -116
- package/src/components/live-pricing-comparison.tsx +0 -241
- package/src/components/theme-provider.tsx +0 -11
- package/src/components/theme-toggle.tsx +0 -55
- package/src/components/ui/accordion.tsx +0 -66
- package/src/components/ui/alert-dialog.tsx +0 -157
- package/src/components/ui/alert.tsx +0 -66
- package/src/components/ui/aspect-ratio.tsx +0 -11
- package/src/components/ui/avatar.tsx +0 -53
- package/src/components/ui/badge.tsx +0 -46
- package/src/components/ui/breadcrumb.tsx +0 -109
- package/src/components/ui/button.tsx +0 -59
- package/src/components/ui/calendar.tsx +0 -213
- package/src/components/ui/card.tsx +0 -92
- package/src/components/ui/carousel.tsx +0 -241
- package/src/components/ui/chart.tsx +0 -353
- package/src/components/ui/checkbox.tsx +0 -32
- package/src/components/ui/collapsible.tsx +0 -33
- package/src/components/ui/command.tsx +0 -184
- package/src/components/ui/context-menu.tsx +0 -252
- package/src/components/ui/dialog.tsx +0 -143
- package/src/components/ui/drawer.tsx +0 -135
- package/src/components/ui/dropdown-menu.tsx +0 -257
- package/src/components/ui/form.tsx +0 -167
- package/src/components/ui/hover-card.tsx +0 -44
- package/src/components/ui/input-otp.tsx +0 -77
- package/src/components/ui/input.tsx +0 -21
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/menubar.tsx +0 -276
- package/src/components/ui/navigation-menu.tsx +0 -168
- package/src/components/ui/pagination.tsx +0 -127
- package/src/components/ui/popover.tsx +0 -48
- package/src/components/ui/progress.tsx +0 -31
- package/src/components/ui/radio-group.tsx +0 -45
- package/src/components/ui/resizable.tsx +0 -56
- package/src/components/ui/scroll-area.tsx +0 -58
- package/src/components/ui/select.tsx +0 -185
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/sidebar.tsx +0 -726
- package/src/components/ui/skeleton.tsx +0 -13
- package/src/components/ui/slider.tsx +0 -63
- package/src/components/ui/sonner.tsx +0 -25
- package/src/components/ui/switch.tsx +0 -31
- package/src/components/ui/table.tsx +0 -116
- package/src/components/ui/tabs.tsx +0 -66
- package/src/components/ui/textarea.tsx +0 -18
- package/src/components/ui/toast.tsx +0 -129
- package/src/components/ui/toaster.tsx +0 -35
- package/src/components/ui/toggle-group.tsx +0 -73
- package/src/components/ui/toggle.tsx +0 -47
- package/src/components/ui/tooltip.tsx +0 -61
- package/src/components/vast-ai-live-pricing.tsx +0 -176
- package/src/hooks/use-mobile.ts +0 -19
- package/src/hooks/use-toast.ts +0 -194
- package/src/lib/benchmark-parser-sglang.ts +0 -150
- package/src/lib/benchmark-parser-tokcalc.ts +0 -247
- package/src/lib/benchmark-parser-trtllm.ts +0 -152
- package/src/lib/benchmark-parser-vllm.ts +0 -198
- package/src/lib/benchmark-schema.ts +0 -263
- package/src/lib/db.ts +0 -13
- package/src/lib/engine-presets.ts +0 -183
- package/src/lib/price-schema.ts +0 -141
- package/src/lib/token-calc.ts +0 -808
- package/src/lib/track.ts +0 -31
- package/src/lib/url-state.ts +0 -256
- package/src/lib/utils.ts +0 -6
- package/tailwind.config.ts +0 -64
- package/tests/database-runtime-build.sh +0 -75
- package/tests/python-runtime-build.sh +0 -64
- package/tests/python-runtime-container.sh +0 -31
- package/tool-results/bash_1789888171144_2c5381860539.txt +0 -161
- package/tool-results/bash_1789888175925_49c53ba3c61b.txt +0 -191
- package/tool-results/bash_1789888181202_49c53ba3c61b.txt +0 -191
- package/tool-results/bash_1789888195219_4a86a5c91411.txt +0 -200
- package/tool-results/bash_1789888203128_6cca13c71b47.txt +0 -199
- package/tool-results/bash_1789929256963_2a52aff0d0a8.txt +0 -160
- package/tool-results/read_1789888151021_69f58eec6a5b.txt +0 -653
- package/tool-results/read_1789888153837_1d3a8bfc2a94.txt +0 -653
- package/tool-results/read_1789888163087_ccc406d47505.txt +0 -122
- package/tool-results/read_1789888167347_67d1d7c9830a.txt +0 -122
- package/tool-results/read_1789929252529_d90e8f383a25.txt +0 -285
- package/tsconfig.json +0 -42
- package/upload/Pasted Content_1789887800864.txt +0 -652
- package/upload/Pasted Content_1789887909561.txt +0 -652
- package/upload/Pasted Content_1789887918428.txt +0 -652
- package/upload/Pasted Content_1789887959420.txt +0 -652
- package/upload/Pasted Content_1789888020485.txt +0 -652
- package/upload/Pasted Content_1789888058079.txt +0 -652
- package/upload/Pasted Content_1789888885033.txt +0 -686
- package/upload/Pasted Content_1789928912741.txt +0 -285
- package/upload/Pasted Content_1789928938402.txt +0 -285
- package/upload/Pasted Content_1789929160389.txt +0 -285
- package/upload/Pasted Content_1789929176660.txt +0 -285
- package/upload/issue_vision.json +0 -28
- package/upload/pasted_image_1789883175209.png +0 -0
- package/upload/pasted_image_1789899056690.png +0 -0
- package/upload/pasted_image_1789900371483.png +0 -0
- package/upload/pasted_image_1789900472823.png +0 -0
- package/upload/pasted_image_1789900490374.png +0 -0
- package/upload/pasted_image_1789900585552.png +0 -0
- package/upload/pasted_image_1789900606519.png +0 -0
- package/upload/pasted_image_1789901598705.png +0 -0
- package/upload/pasted_image_1789901613545.png +0 -0
- package/upload/pasted_image_1789978382674.png +0 -0
- package/upload/pasted_image_1789978392749.png +0 -0
- package/upload/pasted_image_1789978474879.png +0 -0
- package/upload/pasted_image_1789978523652.png +0 -0
- package/upload/pasted_image_1789984219089.png +0 -0
- package/upload/pasted_image_1789984491896.png +0 -0
- package/upload/pasted_image_1789985017950.png +0 -0
- package/upload/pasted_image_1789985036765.png +0 -0
- package/upload/pasted_image_1789985049848.png +0 -0
- package/upload/pasted_image_1790002427833.png +0 -0
- package/upload/pasted_image_1790002659944.png +0 -0
- package/upload/pasted_image_1790037038476.png +0 -0
- package/upload/screenshot_analysis.json +0 -28
- package/upload/vision_output.json +0 -28
package/components.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
3
|
-
"style": "new-york",
|
|
4
|
-
"rsc": true,
|
|
5
|
-
"tsx": true,
|
|
6
|
-
"tailwind": {
|
|
7
|
-
"config": "",
|
|
8
|
-
"css": "src/app/globals.css",
|
|
9
|
-
"baseColor": "neutral",
|
|
10
|
-
"cssVariables": true,
|
|
11
|
-
"prefix": ""
|
|
12
|
-
},
|
|
13
|
-
"aliases": {
|
|
14
|
-
"components": "@/components",
|
|
15
|
-
"utils": "@/lib/utils",
|
|
16
|
-
"ui": "@/components/ui",
|
|
17
|
-
"lib": "@/lib",
|
|
18
|
-
"hooks": "@/hooks"
|
|
19
|
-
},
|
|
20
|
-
"iconLibrary": "lucide"
|
|
21
|
-
}
|
package/db/custom.db
DELETED
|
Binary file
|
package/download/README.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Here are all the generated files.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/eslint.config.mjs
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import nextCoreWebVitals from "eslint-config-next/core-web-vitals";
|
|
2
|
-
import nextTypescript from "eslint-config-next/typescript";
|
|
3
|
-
import { dirname } from "path";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = dirname(__filename);
|
|
8
|
-
|
|
9
|
-
const eslintConfig = [...nextCoreWebVitals, ...nextTypescript, {
|
|
10
|
-
rules: {
|
|
11
|
-
// TypeScript rules
|
|
12
|
-
"@typescript-eslint/no-explicit-any": "off",
|
|
13
|
-
"@typescript-eslint/no-unused-vars": "off",
|
|
14
|
-
"@typescript-eslint/no-non-null-assertion": "off",
|
|
15
|
-
"@typescript-eslint/ban-ts-comment": "off",
|
|
16
|
-
"@typescript-eslint/prefer-as-const": "off",
|
|
17
|
-
"@typescript-eslint/no-unused-disable-directive": "off",
|
|
18
|
-
|
|
19
|
-
// React rules
|
|
20
|
-
"react-hooks/exhaustive-deps": "off",
|
|
21
|
-
"react-hooks/purity": "off",
|
|
22
|
-
"react/no-unescaped-entities": "off",
|
|
23
|
-
"react/display-name": "off",
|
|
24
|
-
"react/prop-types": "off",
|
|
25
|
-
"react-compiler/react-compiler": "off",
|
|
26
|
-
|
|
27
|
-
// Next.js rules
|
|
28
|
-
"@next/next/no-img-element": "off",
|
|
29
|
-
"@next/next/no-html-link-for-pages": "off",
|
|
30
|
-
|
|
31
|
-
// General JavaScript rules
|
|
32
|
-
"prefer-const": "off",
|
|
33
|
-
"no-unused-vars": "off",
|
|
34
|
-
"no-console": "off",
|
|
35
|
-
"no-debugger": "off",
|
|
36
|
-
"no-empty": "off",
|
|
37
|
-
"no-irregular-whitespace": "off",
|
|
38
|
-
"no-case-declarations": "off",
|
|
39
|
-
"no-fallthrough": "off",
|
|
40
|
-
"no-mixed-spaces-and-tabs": "off",
|
|
41
|
-
"no-redeclare": "off",
|
|
42
|
-
"no-undef": "off",
|
|
43
|
-
"no-unreachable": "off",
|
|
44
|
-
"no-useless-escape": "off",
|
|
45
|
-
},
|
|
46
|
-
}, {
|
|
47
|
-
ignores: ["node_modules/**", ".next/**", "out/**", "build/**", "next-env.d.ts", "examples/**", "skills", "mini-services/mcp-server/dist/**"]
|
|
48
|
-
}];
|
|
49
|
-
|
|
50
|
-
export default eslintConfig;
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
import { io } from 'socket.io-client';
|
|
5
|
-
import { Button } from '@/components/ui/button';
|
|
6
|
-
import { Input } from '@/components/ui/input';
|
|
7
|
-
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
8
|
-
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
9
|
-
|
|
10
|
-
type User = {
|
|
11
|
-
id: string;
|
|
12
|
-
username: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type Message = {
|
|
16
|
-
id: string;
|
|
17
|
-
username: string;
|
|
18
|
-
content: string;
|
|
19
|
-
timestamp: Date | string;
|
|
20
|
-
type: 'user' | 'system';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default function SocketDemo() {
|
|
24
|
-
const [messages, setMessages] = useState<Message[]>([]);
|
|
25
|
-
const [inputMessage, setInputMessage] = useState('');
|
|
26
|
-
const [username, setUsername] = useState('');
|
|
27
|
-
const [isUsernameSet, setIsUsernameSet] = useState(false);
|
|
28
|
-
const [socket, setSocket] = useState<any>(null);
|
|
29
|
-
const [isConnected, setIsConnected] = useState(false);
|
|
30
|
-
const [users, setUsers] = useState<User[]>([]);
|
|
31
|
-
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
// Connect to websocket server
|
|
34
|
-
// Never use PORT in the URL, alyways use XTransformPort
|
|
35
|
-
// DO NOT change the path, it is used by Caddy to forward the request to the correct port
|
|
36
|
-
const socketInstance = io('/?XTransformPort=3003', {
|
|
37
|
-
transports: ['websocket', 'polling'],
|
|
38
|
-
forceNew: true,
|
|
39
|
-
reconnection: true,
|
|
40
|
-
reconnectionAttempts: 5,
|
|
41
|
-
reconnectionDelay: 1000,
|
|
42
|
-
timeout: 10000
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
setSocket(socketInstance);
|
|
46
|
-
|
|
47
|
-
socketInstance.on('connect', () => {
|
|
48
|
-
setIsConnected(true);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
socketInstance.on('disconnect', () => {
|
|
52
|
-
setIsConnected(false);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
socketInstance.on('message', (msg: Message) => {
|
|
56
|
-
setMessages(prev => [...prev, msg]);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
socketInstance.on('user-joined', (data: { user: User; message: Message }) => {
|
|
60
|
-
setMessages(prev => [...prev, data.message]);
|
|
61
|
-
setUsers(prev => {
|
|
62
|
-
if (!prev.find(u => u.id === data.user.id)) {
|
|
63
|
-
return [...prev, data.user];
|
|
64
|
-
}
|
|
65
|
-
return prev;
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
socketInstance.on('user-left', (data: { user: User; message: Message }) => {
|
|
70
|
-
setMessages(prev => [...prev, data.message]);
|
|
71
|
-
setUsers(prev => prev.filter(u => u.id !== data.user.id));
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
socketInstance.on('users-list', (data: { users: User[] }) => {
|
|
75
|
-
setUsers(data.users);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return () => {
|
|
79
|
-
socketInstance.disconnect();
|
|
80
|
-
};
|
|
81
|
-
}, []);
|
|
82
|
-
|
|
83
|
-
const handleJoin = () => {
|
|
84
|
-
if (socket && username.trim() && isConnected) {
|
|
85
|
-
socket.emit('join', { username: username.trim() });
|
|
86
|
-
setIsUsernameSet(true);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const sendMessage = () => {
|
|
91
|
-
if (socket && inputMessage.trim() && username.trim()) {
|
|
92
|
-
socket.emit('message', {
|
|
93
|
-
content: inputMessage.trim(),
|
|
94
|
-
username: username.trim()
|
|
95
|
-
});
|
|
96
|
-
setInputMessage('');
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
const handleKeyPress = (e: React.KeyboardEvent) => {
|
|
101
|
-
if (e.key === 'Enter') {
|
|
102
|
-
sendMessage();
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<div className="container mx-auto p-4 max-w-2xl">
|
|
108
|
-
<Card>
|
|
109
|
-
<CardHeader>
|
|
110
|
-
<CardTitle className="flex items-center justify-between">
|
|
111
|
-
WebSocket Demo
|
|
112
|
-
<span className={`text-sm px-2 py-1 rounded ${isConnected ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`}>
|
|
113
|
-
{isConnected ? 'Connected' : 'Disconnected'}
|
|
114
|
-
</span>
|
|
115
|
-
</CardTitle>
|
|
116
|
-
</CardHeader>
|
|
117
|
-
<CardContent className="space-y-4">
|
|
118
|
-
{!isUsernameSet ? (
|
|
119
|
-
<div className="space-y-2">
|
|
120
|
-
<Input
|
|
121
|
-
value={username}
|
|
122
|
-
onChange={(e) => setUsername(e.target.value)}
|
|
123
|
-
onKeyPress={(e) => {
|
|
124
|
-
if (e.key === 'Enter') {
|
|
125
|
-
handleJoin();
|
|
126
|
-
}
|
|
127
|
-
}}
|
|
128
|
-
placeholder="Enter your username..."
|
|
129
|
-
disabled={!isConnected}
|
|
130
|
-
className="flex-1"
|
|
131
|
-
/>
|
|
132
|
-
<Button
|
|
133
|
-
onClick={handleJoin}
|
|
134
|
-
disabled={!isConnected || !username.trim()}
|
|
135
|
-
className="w-full"
|
|
136
|
-
>
|
|
137
|
-
Join Chat
|
|
138
|
-
</Button>
|
|
139
|
-
</div>
|
|
140
|
-
) : (
|
|
141
|
-
<>
|
|
142
|
-
<ScrollArea className="h-80 w-full border rounded-md p-4">
|
|
143
|
-
<div className="space-y-2">
|
|
144
|
-
{messages.length === 0 ? (
|
|
145
|
-
<p className="text-gray-500 text-center">No messages yet</p>
|
|
146
|
-
) : (
|
|
147
|
-
messages.map((msg) => (
|
|
148
|
-
<div key={msg.id} className="border-b pb-2 last:border-b-0">
|
|
149
|
-
<div className="flex justify-between items-start">
|
|
150
|
-
<div className="flex-1">
|
|
151
|
-
<p className={`text-sm font-medium ${msg.type === 'system'
|
|
152
|
-
? 'text-blue-600 italic'
|
|
153
|
-
: 'text-gray-700'
|
|
154
|
-
}`}>
|
|
155
|
-
{msg.username}
|
|
156
|
-
</p>
|
|
157
|
-
<p className={`${msg.type === 'system'
|
|
158
|
-
? 'text-blue-500 italic'
|
|
159
|
-
: 'text-gray-900'
|
|
160
|
-
}`}>
|
|
161
|
-
{msg.content}
|
|
162
|
-
</p>
|
|
163
|
-
</div>
|
|
164
|
-
<span className="text-xs text-gray-500">
|
|
165
|
-
{new Date(msg.timestamp).toLocaleTimeString()}
|
|
166
|
-
</span>
|
|
167
|
-
</div>
|
|
168
|
-
</div>
|
|
169
|
-
))
|
|
170
|
-
)}
|
|
171
|
-
</div>
|
|
172
|
-
</ScrollArea>
|
|
173
|
-
|
|
174
|
-
<div className="flex space-x-2">
|
|
175
|
-
<Input
|
|
176
|
-
value={inputMessage}
|
|
177
|
-
onChange={(e) => setInputMessage(e.target.value)}
|
|
178
|
-
onKeyPress={handleKeyPress}
|
|
179
|
-
placeholder="Type a message..."
|
|
180
|
-
disabled={!isConnected}
|
|
181
|
-
className="flex-1"
|
|
182
|
-
/>
|
|
183
|
-
<Button
|
|
184
|
-
onClick={sendMessage}
|
|
185
|
-
disabled={!isConnected || !inputMessage.trim()}
|
|
186
|
-
>
|
|
187
|
-
Send
|
|
188
|
-
</Button>
|
|
189
|
-
</div>
|
|
190
|
-
</>
|
|
191
|
-
)}
|
|
192
|
-
</CardContent>
|
|
193
|
-
</Card>
|
|
194
|
-
</div>
|
|
195
|
-
);
|
|
196
|
-
}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { createServer } from 'http'
|
|
2
|
-
import { Server } from 'socket.io'
|
|
3
|
-
|
|
4
|
-
const httpServer = createServer()
|
|
5
|
-
const io = new Server(httpServer, {
|
|
6
|
-
// DO NOT change the path, it is used by Caddy to forward the request to the correct port
|
|
7
|
-
path: '/',
|
|
8
|
-
cors: {
|
|
9
|
-
origin: "*",
|
|
10
|
-
methods: ["GET", "POST"]
|
|
11
|
-
},
|
|
12
|
-
pingTimeout: 60000,
|
|
13
|
-
pingInterval: 25000,
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
interface User {
|
|
17
|
-
id: string
|
|
18
|
-
username: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface Message {
|
|
22
|
-
id: string
|
|
23
|
-
username: string
|
|
24
|
-
content: string
|
|
25
|
-
timestamp: Date
|
|
26
|
-
type: 'user' | 'system'
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const users = new Map<string, User>()
|
|
30
|
-
|
|
31
|
-
const generateMessageId = () => Math.random().toString(36).substr(2, 9)
|
|
32
|
-
|
|
33
|
-
const createSystemMessage = (content: string): Message => ({
|
|
34
|
-
id: generateMessageId(),
|
|
35
|
-
username: 'System',
|
|
36
|
-
content,
|
|
37
|
-
timestamp: new Date(),
|
|
38
|
-
type: 'system'
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const createUserMessage = (username: string, content: string): Message => ({
|
|
42
|
-
id: generateMessageId(),
|
|
43
|
-
username,
|
|
44
|
-
content,
|
|
45
|
-
timestamp: new Date(),
|
|
46
|
-
type: 'user'
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
io.on('connection', (socket) => {
|
|
50
|
-
console.log(`User connected: ${socket.id}`)
|
|
51
|
-
|
|
52
|
-
// Add test event handler
|
|
53
|
-
socket.on('test', (data) => {
|
|
54
|
-
console.log('Received test message:', data)
|
|
55
|
-
socket.emit('test-response', {
|
|
56
|
-
message: 'Server received test message',
|
|
57
|
-
data: data,
|
|
58
|
-
timestamp: new Date().toISOString()
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
socket.on('join', (data: { username: string }) => {
|
|
63
|
-
const { username } = data
|
|
64
|
-
|
|
65
|
-
// Create user object
|
|
66
|
-
const user: User = {
|
|
67
|
-
id: socket.id,
|
|
68
|
-
username
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Add to user list
|
|
72
|
-
users.set(socket.id, user)
|
|
73
|
-
|
|
74
|
-
// Send join message to all users
|
|
75
|
-
const joinMessage = createSystemMessage(`${username} joined the chat room`)
|
|
76
|
-
io.emit('user-joined', { user, message: joinMessage })
|
|
77
|
-
|
|
78
|
-
// Send current user list to new user
|
|
79
|
-
const usersList = Array.from(users.values())
|
|
80
|
-
socket.emit('users-list', { users: usersList })
|
|
81
|
-
|
|
82
|
-
console.log(`${username} joined the chat room, current online users: ${users.size}`)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
socket.on('message', (data: { content: string; username: string }) => {
|
|
86
|
-
const { content, username } = data
|
|
87
|
-
const user = users.get(socket.id)
|
|
88
|
-
|
|
89
|
-
if (user && user.username === username) {
|
|
90
|
-
const message = createUserMessage(username, content)
|
|
91
|
-
io.emit('message', message)
|
|
92
|
-
console.log(`${username}: ${content}`)
|
|
93
|
-
}
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
socket.on('disconnect', () => {
|
|
97
|
-
const user = users.get(socket.id)
|
|
98
|
-
|
|
99
|
-
if (user) {
|
|
100
|
-
// Remove from user list
|
|
101
|
-
users.delete(socket.id)
|
|
102
|
-
|
|
103
|
-
// Send leave message to all users
|
|
104
|
-
const leaveMessage = createSystemMessage(`${user.username} left the chat room`)
|
|
105
|
-
io.emit('user-left', { user: { id: socket.id, username: user.username }, message: leaveMessage })
|
|
106
|
-
|
|
107
|
-
console.log(`${user.username} left the chat room, current online users: ${users.size}`)
|
|
108
|
-
} else {
|
|
109
|
-
console.log(`User disconnected: ${socket.id}`)
|
|
110
|
-
}
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
socket.on('error', (error) => {
|
|
114
|
-
console.error(`Socket error (${socket.id}):`, error)
|
|
115
|
-
})
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
const PORT = 3003
|
|
119
|
-
httpServer.listen(PORT, () => {
|
|
120
|
-
console.log(`WebSocket server running on port ${PORT}`)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
// Graceful shutdown
|
|
124
|
-
process.on('SIGTERM', () => {
|
|
125
|
-
console.log('Received SIGTERM signal, shutting down server...')
|
|
126
|
-
httpServer.close(() => {
|
|
127
|
-
console.log('WebSocket server closed')
|
|
128
|
-
process.exit(0)
|
|
129
|
-
})
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
process.on('SIGINT', () => {
|
|
133
|
-
console.log('Received SIGINT signal, shutting down server...')
|
|
134
|
-
httpServer.close(() => {
|
|
135
|
-
console.log('WebSocket server closed')
|
|
136
|
-
process.exit(0)
|
|
137
|
-
})
|
|
138
|
-
})
|
package/mini-services/.gitkeep
DELETED
|
File without changes
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# @tokcalc/mcp-server
|
|
2
|
-
|
|
3
|
-
**LLM serving capacity planner for AI agents.**
|
|
4
|
-
|
|
5
|
-
Open-source MCP (Model Context Protocol) server that lets AI agents (Cursor, Claude Desktop, Cline) estimate LLM serving capacity — model fit, KV cache, throughput, latency, multi-GPU topology, and cost.
|
|
6
|
-
|
|
7
|
-
## Tools
|
|
8
|
-
|
|
9
|
-
| Tool | What it does |
|
|
10
|
-
|---|---|
|
|
11
|
-
| `estimate_capacity` | VRAM/KV/throughput/latency/cost for one config |
|
|
12
|
-
| `compare_gpus` | Ranked GPU comparison for one workload |
|
|
13
|
-
| `recommend_topology` | TP/CP topology recommendation |
|
|
14
|
-
| `estimate_api_vs_self_host` | Break-even analysis |
|
|
15
|
-
| `list_models` | Discover supported model IDs (35 models) |
|
|
16
|
-
| `list_gpus` | Discover supported GPU IDs (30 GPUs) |
|
|
17
|
-
|
|
18
|
-
All tools are **read-only** — no side effects, no cloud credentials, no deployments.
|
|
19
|
-
|
|
20
|
-
## Install
|
|
21
|
-
|
|
22
|
-
### Claude Desktop
|
|
23
|
-
|
|
24
|
-
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
25
|
-
|
|
26
|
-
```json
|
|
27
|
-
{
|
|
28
|
-
"mcpServers": {
|
|
29
|
-
"tokcalc": {
|
|
30
|
-
"command": "npx",
|
|
31
|
-
"args": ["-y", "@tokcalc/mcp-server"]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Restart Claude Desktop. The `tokcalc` server will be available as an MCP tool source.
|
|
38
|
-
|
|
39
|
-
### Cursor
|
|
40
|
-
|
|
41
|
-
Add to `.cursor/mcp.json` in your project:
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{
|
|
45
|
-
"mcpServers": {
|
|
46
|
-
"tokcalc": {
|
|
47
|
-
"command": "npx",
|
|
48
|
-
"args": ["-y", "@tokcalc/mcp-server"]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Cline (VS Code)
|
|
55
|
-
|
|
56
|
-
Add the same config to Cline's MCP settings.
|
|
57
|
-
|
|
58
|
-
## Example prompts
|
|
59
|
-
|
|
60
|
-
Ask your AI agent:
|
|
61
|
-
|
|
62
|
-
> "I need to serve Llama 3.3 70B at 32K context for 50 concurrent users. What GPU topology do you recommend, and how much will it cost per month?"
|
|
63
|
-
|
|
64
|
-
> "Compare H100 vs H200 for serving Qwen 2.5 72B in FP8 with continuous batching."
|
|
65
|
-
|
|
66
|
-
> "At what daily request volume does self-hosting Llama 70B on H200 beat the GPT-4o API?"
|
|
67
|
-
|
|
68
|
-
The agent calls `list_models` → `list_gpus` → `recommend_topology` → `estimate_capacity` and returns a structured plan with throughput ranges, latency, VRAM, cost, and confidence levels.
|
|
69
|
-
|
|
70
|
-
## Supported models (35)
|
|
71
|
-
|
|
72
|
-
Llama 3/3.1/3.3, Llama 4 Scout/Maverick, Mistral 7B, Mixtral 8x7B/8x22B, Mistral Large 3, Pixtral 12B, Codestral, Qwen 2/2.5/3 (incl. MoE + VL), DeepSeek V3/R1/Coder V2, Gemma 2, Phi-3/4, SmolLM2, Falcon 3, OLMo 2, BGE-M3, E5, GTE.
|
|
73
|
-
|
|
74
|
-
## Supported GPUs (30)
|
|
75
|
-
|
|
76
|
-
NVIDIA H100/H200/B200/B300, A100, L40S, L4, T4, V100, RTX 4090/3090/5090, RTX PRO 6000 Blackwell, AMD MI300X/MI325X, Intel Gaudi 3, Google TPU v5p/Trillium, Groq LPU, Cerebras CS-3, Apple M2/M3/M4 Ultra/Max.
|
|
77
|
-
|
|
78
|
-
## License
|
|
79
|
-
|
|
80
|
-
Apache 2.0 — same as the main tokcalc project.
|
|
81
|
-
|
|
82
|
-
## Links
|
|
83
|
-
|
|
84
|
-
- [Live calculator](https://tokcalc.vercel.app)
|
|
85
|
-
- [GitHub](https://github.com/stevecrates489-commits/tokcalc)
|
|
86
|
-
- [CONTRIBUTING](https://github.com/stevecrates489-commits/tokcalc/blob/main/CONTRIBUTING.md)
|