@samanhappy/mcphub 0.0.8 → 0.0.10
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/.env.example +2 -0
- package/.eslintrc.json +25 -0
- package/.github/workflows/build.yml +51 -0
- package/.github/workflows/release.yml +19 -0
- package/.prettierrc +7 -0
- package/Dockerfile +51 -0
- package/assets/amap-edit.png +0 -0
- package/assets/amap-result.png +0 -0
- package/assets/cherry-mcp.png +0 -0
- package/assets/cursor-mcp.png +0 -0
- package/assets/cursor-query.png +0 -0
- package/assets/cursor-tools.png +0 -0
- package/assets/dashboard.png +0 -0
- package/assets/dashboard.zh.png +0 -0
- package/assets/group.png +0 -0
- package/assets/group.zh.png +0 -0
- package/assets/market.zh.png +0 -0
- package/assets/wegroup.jpg +0 -0
- package/assets/wegroup.png +0 -0
- package/assets/wexin.png +0 -0
- package/bin/mcphub.js +3 -0
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/doc/intro.md +73 -0
- package/doc/intro2.md +232 -0
- package/entrypoint.sh +10 -0
- package/frontend/favicon.ico +0 -0
- package/frontend/index.html +13 -0
- package/frontend/postcss.config.js +6 -0
- package/frontend/src/App.tsx +44 -0
- package/frontend/src/components/AddGroupForm.tsx +132 -0
- package/frontend/src/components/AddServerForm.tsx +90 -0
- package/frontend/src/components/ChangePasswordForm.tsx +158 -0
- package/frontend/src/components/EditGroupForm.tsx +149 -0
- package/frontend/src/components/EditServerForm.tsx +76 -0
- package/frontend/src/components/GroupCard.tsx +143 -0
- package/frontend/src/components/MarketServerCard.tsx +153 -0
- package/frontend/src/components/MarketServerDetail.tsx +297 -0
- package/frontend/src/components/ProtectedRoute.tsx +27 -0
- package/frontend/src/components/ServerCard.tsx +230 -0
- package/frontend/src/components/ServerForm.tsx +276 -0
- package/frontend/src/components/icons/LucideIcons.tsx +14 -0
- package/frontend/src/components/layout/Content.tsx +17 -0
- package/frontend/src/components/layout/Header.tsx +61 -0
- package/frontend/src/components/layout/Sidebar.tsx +98 -0
- package/frontend/src/components/ui/Badge.tsx +33 -0
- package/frontend/src/components/ui/Button.tsx +0 -0
- package/frontend/src/components/ui/DeleteDialog.tsx +48 -0
- package/frontend/src/components/ui/Pagination.tsx +128 -0
- package/frontend/src/components/ui/Toast.tsx +96 -0
- package/frontend/src/components/ui/ToggleGroup.tsx +134 -0
- package/frontend/src/components/ui/ToolCard.tsx +38 -0
- package/frontend/src/contexts/AuthContext.tsx +159 -0
- package/frontend/src/contexts/ToastContext.tsx +60 -0
- package/frontend/src/hooks/useGroupData.ts +232 -0
- package/frontend/src/hooks/useMarketData.ts +410 -0
- package/frontend/src/hooks/useServerData.ts +306 -0
- package/frontend/src/hooks/useSettingsData.ts +131 -0
- package/frontend/src/i18n.ts +42 -0
- package/frontend/src/index.css +20 -0
- package/frontend/src/layouts/MainLayout.tsx +33 -0
- package/frontend/src/locales/en.json +214 -0
- package/frontend/src/locales/zh.json +214 -0
- package/frontend/src/main.tsx +12 -0
- package/frontend/src/pages/Dashboard.tsx +206 -0
- package/frontend/src/pages/GroupsPage.tsx +116 -0
- package/frontend/src/pages/LoginPage.tsx +104 -0
- package/frontend/src/pages/MarketPage.tsx +356 -0
- package/frontend/src/pages/ServersPage.tsx +144 -0
- package/frontend/src/pages/SettingsPage.tsx +149 -0
- package/frontend/src/services/authService.ts +141 -0
- package/frontend/src/types/index.ts +160 -0
- package/frontend/src/utils/cn.ts +10 -0
- package/frontend/tsconfig.json +31 -0
- package/frontend/tsconfig.node.json +10 -0
- package/frontend/vite.config.ts +26 -0
- package/googled76ca578b6543fbc.html +1 -0
- package/jest.config.js +10 -0
- package/mcp_settings.json +45 -0
- package/package.json +4 -7
- package/servers.json +74722 -0
- package/src/config/index.ts +46 -0
- package/src/controllers/authController.ts +179 -0
- package/src/controllers/groupController.ts +341 -0
- package/src/controllers/marketController.ts +154 -0
- package/src/controllers/serverController.ts +303 -0
- package/src/index.ts +17 -0
- package/src/middlewares/auth.ts +28 -0
- package/src/middlewares/index.ts +43 -0
- package/src/models/User.ts +103 -0
- package/src/routes/index.ts +96 -0
- package/src/server.ts +72 -0
- package/src/services/groupService.ts +232 -0
- package/src/services/marketService.ts +116 -0
- package/src/services/mcpService.ts +385 -0
- package/src/services/sseService.ts +119 -0
- package/src/types/index.ts +129 -0
- package/src/utils/migration.ts +52 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { AuthResponse, LoginCredentials, RegisterCredentials, ChangePasswordCredentials } from '../types';
|
|
2
|
+
|
|
3
|
+
// Base URL for API requests
|
|
4
|
+
const API_URL = '';
|
|
5
|
+
|
|
6
|
+
// Token key in localStorage
|
|
7
|
+
const TOKEN_KEY = 'mcphub_token';
|
|
8
|
+
|
|
9
|
+
// Get token from localStorage
|
|
10
|
+
export const getToken = (): string | null => {
|
|
11
|
+
return localStorage.getItem(TOKEN_KEY);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Set token in localStorage
|
|
15
|
+
export const setToken = (token: string): void => {
|
|
16
|
+
localStorage.setItem(TOKEN_KEY, token);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Remove token from localStorage
|
|
20
|
+
export const removeToken = (): void => {
|
|
21
|
+
localStorage.removeItem(TOKEN_KEY);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Login user
|
|
25
|
+
export const login = async (credentials: LoginCredentials): Promise<AuthResponse> => {
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch(`${API_URL}/auth/login`, {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
},
|
|
32
|
+
body: JSON.stringify(credentials),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const data: AuthResponse = await response.json();
|
|
36
|
+
|
|
37
|
+
if (data.success && data.token) {
|
|
38
|
+
setToken(data.token);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return data;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Login error:', error);
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
message: 'An error occurred during login',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Register user
|
|
52
|
+
export const register = async (credentials: RegisterCredentials): Promise<AuthResponse> => {
|
|
53
|
+
try {
|
|
54
|
+
const response = await fetch(`${API_URL}/auth/register`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: {
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
},
|
|
59
|
+
body: JSON.stringify(credentials),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const data: AuthResponse = await response.json();
|
|
63
|
+
|
|
64
|
+
if (data.success && data.token) {
|
|
65
|
+
setToken(data.token);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return data;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Register error:', error);
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
message: 'An error occurred during registration',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Get current user
|
|
79
|
+
export const getCurrentUser = async (): Promise<AuthResponse> => {
|
|
80
|
+
const token = getToken();
|
|
81
|
+
|
|
82
|
+
if (!token) {
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
message: 'No authentication token',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(`${API_URL}/auth/user`, {
|
|
91
|
+
method: 'GET',
|
|
92
|
+
headers: {
|
|
93
|
+
'x-auth-token': token,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return await response.json();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('Get current user error:', error);
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
message: 'An error occurred while fetching user data',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Change password
|
|
108
|
+
export const changePassword = async (credentials: ChangePasswordCredentials): Promise<AuthResponse> => {
|
|
109
|
+
const token = getToken();
|
|
110
|
+
|
|
111
|
+
if (!token) {
|
|
112
|
+
return {
|
|
113
|
+
success: false,
|
|
114
|
+
message: 'No authentication token',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const response = await fetch(`${API_URL}/auth/change-password`, {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
headers: {
|
|
122
|
+
'Content-Type': 'application/json',
|
|
123
|
+
'x-auth-token': token,
|
|
124
|
+
},
|
|
125
|
+
body: JSON.stringify(credentials),
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return await response.json();
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error('Change password error:', error);
|
|
131
|
+
return {
|
|
132
|
+
success: false,
|
|
133
|
+
message: 'An error occurred while changing password',
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// Logout user
|
|
139
|
+
export const logout = (): void => {
|
|
140
|
+
removeToken();
|
|
141
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Server status types
|
|
2
|
+
export type ServerStatus = 'connecting' | 'connected' | 'disconnected';
|
|
3
|
+
|
|
4
|
+
// Market server types
|
|
5
|
+
export interface MarketServerRepository {
|
|
6
|
+
type: string;
|
|
7
|
+
url: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface MarketServerAuthor {
|
|
11
|
+
name: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MarketServerInstallation {
|
|
15
|
+
type: string;
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
env?: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface MarketServerArgument {
|
|
22
|
+
description: string;
|
|
23
|
+
required: boolean;
|
|
24
|
+
example: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface MarketServerExample {
|
|
28
|
+
title: string;
|
|
29
|
+
description: string;
|
|
30
|
+
prompt: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface MarketServerTool {
|
|
34
|
+
name: string;
|
|
35
|
+
description: string;
|
|
36
|
+
inputSchema: Record<string, any>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface MarketServer {
|
|
40
|
+
name: string;
|
|
41
|
+
display_name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
repository: MarketServerRepository;
|
|
44
|
+
homepage: string;
|
|
45
|
+
author: MarketServerAuthor;
|
|
46
|
+
license: string;
|
|
47
|
+
categories: string[];
|
|
48
|
+
tags: string[];
|
|
49
|
+
examples: MarketServerExample[];
|
|
50
|
+
installations: {
|
|
51
|
+
[key: string]: MarketServerInstallation;
|
|
52
|
+
};
|
|
53
|
+
arguments: Record<string, MarketServerArgument>;
|
|
54
|
+
tools: MarketServerTool[];
|
|
55
|
+
is_official?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Tool input schema types
|
|
59
|
+
export interface ToolInputSchema {
|
|
60
|
+
type: string;
|
|
61
|
+
properties?: Record<string, unknown>;
|
|
62
|
+
required?: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Tool types
|
|
66
|
+
export interface Tool {
|
|
67
|
+
name: string;
|
|
68
|
+
description: string;
|
|
69
|
+
inputSchema: ToolInputSchema;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Server config types
|
|
73
|
+
export interface ServerConfig {
|
|
74
|
+
url?: string;
|
|
75
|
+
command?: string;
|
|
76
|
+
args?: string[];
|
|
77
|
+
env?: Record<string, string>;
|
|
78
|
+
enabled?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Server types
|
|
82
|
+
export interface Server {
|
|
83
|
+
name: string;
|
|
84
|
+
status: ServerStatus;
|
|
85
|
+
error?: string;
|
|
86
|
+
tools?: Tool[];
|
|
87
|
+
config?: ServerConfig;
|
|
88
|
+
enabled?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Group types
|
|
92
|
+
export interface Group {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
description?: string;
|
|
96
|
+
servers: string[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Environment variable types
|
|
100
|
+
export interface EnvVar {
|
|
101
|
+
key: string;
|
|
102
|
+
value: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Form data types
|
|
106
|
+
export interface ServerFormData {
|
|
107
|
+
name: string;
|
|
108
|
+
url: string;
|
|
109
|
+
command: string;
|
|
110
|
+
arguments: string;
|
|
111
|
+
env: EnvVar[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Group form data types
|
|
115
|
+
export interface GroupFormData {
|
|
116
|
+
name: string;
|
|
117
|
+
description: string;
|
|
118
|
+
servers: string[]; // Added servers array to include in form data
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// API response types
|
|
122
|
+
export interface ApiResponse<T = any> {
|
|
123
|
+
success: boolean;
|
|
124
|
+
message?: string;
|
|
125
|
+
data?: T;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Auth types
|
|
129
|
+
export interface IUser {
|
|
130
|
+
username: string;
|
|
131
|
+
isAdmin?: boolean;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export interface AuthState {
|
|
135
|
+
isAuthenticated: boolean;
|
|
136
|
+
user: IUser | null;
|
|
137
|
+
loading: boolean;
|
|
138
|
+
error: string | null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface LoginCredentials {
|
|
142
|
+
username: string;
|
|
143
|
+
password: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface RegisterCredentials extends LoginCredentials {
|
|
147
|
+
isAdmin?: boolean;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface ChangePasswordCredentials {
|
|
151
|
+
currentPassword: string;
|
|
152
|
+
newPassword: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface AuthResponse {
|
|
156
|
+
success: boolean;
|
|
157
|
+
token?: string;
|
|
158
|
+
user?: IUser;
|
|
159
|
+
message?: string;
|
|
160
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ClassValue, clsx } from 'clsx';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Combines multiple class names and deduplicates Tailwind CSS classes
|
|
6
|
+
* This is a utility function for conditionally joining class names together
|
|
7
|
+
*/
|
|
8
|
+
export function cn(...inputs: ClassValue[]) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": false,
|
|
20
|
+
"noUnusedParameters": false,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
|
|
23
|
+
/* Paths */
|
|
24
|
+
"baseUrl": ".",
|
|
25
|
+
"paths": {
|
|
26
|
+
"@/*": ["./src/*"]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"include": ["src"],
|
|
30
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
31
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import react from '@vitejs/plugin-react';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
5
|
+
|
|
6
|
+
// https://vitejs.dev/config/
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
plugins: [react(), tailwindcss()],
|
|
9
|
+
resolve: {
|
|
10
|
+
alias: {
|
|
11
|
+
'@': path.resolve(__dirname, './src'),
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
server: {
|
|
15
|
+
proxy: {
|
|
16
|
+
'/api': {
|
|
17
|
+
target: 'http://localhost:3000',
|
|
18
|
+
changeOrigin: true,
|
|
19
|
+
},
|
|
20
|
+
'/auth': {
|
|
21
|
+
target: 'http://localhost:3000',
|
|
22
|
+
changeOrigin: true,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
google-site-verification: googled76ca578b6543fbc.html
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
preset: 'ts-jest',
|
|
3
|
+
testEnvironment: 'node',
|
|
4
|
+
roots: ['<rootDir>/src'],
|
|
5
|
+
transform: {
|
|
6
|
+
'^.+\\.tsx?$': 'ts-jest',
|
|
7
|
+
},
|
|
8
|
+
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
|
|
9
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
|
|
10
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"amap": {
|
|
4
|
+
"command": "npx",
|
|
5
|
+
"args": [
|
|
6
|
+
"-y",
|
|
7
|
+
"@amap/amap-maps-mcp-server"
|
|
8
|
+
],
|
|
9
|
+
"env": {
|
|
10
|
+
"AMAP_MAPS_API_KEY": "your-api-key"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"playwright": {
|
|
14
|
+
"command": "npx",
|
|
15
|
+
"args": [
|
|
16
|
+
"@playwright/mcp@latest",
|
|
17
|
+
"--headless"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"fetch": {
|
|
21
|
+
"command": "uvx",
|
|
22
|
+
"args": [
|
|
23
|
+
"mcp-server-fetch"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"slack": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": [
|
|
29
|
+
"-y",
|
|
30
|
+
"@modelcontextprotocol/server-slack"
|
|
31
|
+
],
|
|
32
|
+
"env": {
|
|
33
|
+
"SLACK_BOT_TOKEN": "your-bot-token",
|
|
34
|
+
"SLACK_TEAM_ID": "your-team-id"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"users": [
|
|
39
|
+
{
|
|
40
|
+
"username": "admin",
|
|
41
|
+
"password": "$2b$10$Vt7krIvjNgyN67LXqly0uOcTpN0LI55cYRbcKC71pUDAP0nJ7RPa.",
|
|
42
|
+
"isAdmin": true
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samanhappy/mcphub",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "A hub server for mcp servers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mcphub": "./dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist"
|
|
12
|
-
],
|
|
13
7
|
"scripts": {
|
|
14
8
|
"build": "tsc",
|
|
15
9
|
"start": "node dist/index.js",
|
|
@@ -79,5 +73,8 @@
|
|
|
79
73
|
"tsx": "^4.7.0",
|
|
80
74
|
"typescript": "^5.2.2",
|
|
81
75
|
"vite": "^5.4.18"
|
|
76
|
+
},
|
|
77
|
+
"bin": {
|
|
78
|
+
"mcphub": "bin/mcphub.js"
|
|
82
79
|
}
|
|
83
80
|
}
|