@samanhappy/mcphub 0.0.5 → 0.0.6

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.
Files changed (97) hide show
  1. package/.env.example +2 -0
  2. package/.eslintrc.json +25 -0
  3. package/.github/workflows/build.yml +51 -0
  4. package/.github/workflows/release.yml +19 -0
  5. package/.prettierrc +7 -0
  6. package/Dockerfile +51 -0
  7. package/assets/amap-edit.png +0 -0
  8. package/assets/amap-result.png +0 -0
  9. package/assets/cherry-mcp.png +0 -0
  10. package/assets/cursor-mcp.png +0 -0
  11. package/assets/cursor-query.png +0 -0
  12. package/assets/cursor-tools.png +0 -0
  13. package/assets/dashboard.png +0 -0
  14. package/assets/dashboard.zh.png +0 -0
  15. package/assets/group.png +0 -0
  16. package/assets/group.zh.png +0 -0
  17. package/assets/market.zh.png +0 -0
  18. package/assets/wegroup.jpg +0 -0
  19. package/assets/wegroup.png +0 -0
  20. package/assets/wexin.png +0 -0
  21. package/doc/intro.md +73 -0
  22. package/doc/intro2.md +232 -0
  23. package/entrypoint.sh +10 -0
  24. package/frontend/favicon.ico +0 -0
  25. package/frontend/index.html +13 -0
  26. package/frontend/postcss.config.js +6 -0
  27. package/frontend/src/App.tsx +44 -0
  28. package/frontend/src/components/AddGroupForm.tsx +132 -0
  29. package/frontend/src/components/AddServerForm.tsx +90 -0
  30. package/frontend/src/components/ChangePasswordForm.tsx +158 -0
  31. package/frontend/src/components/EditGroupForm.tsx +149 -0
  32. package/frontend/src/components/EditServerForm.tsx +76 -0
  33. package/frontend/src/components/GroupCard.tsx +143 -0
  34. package/frontend/src/components/MarketServerCard.tsx +153 -0
  35. package/frontend/src/components/MarketServerDetail.tsx +297 -0
  36. package/frontend/src/components/ProtectedRoute.tsx +27 -0
  37. package/frontend/src/components/ServerCard.tsx +230 -0
  38. package/frontend/src/components/ServerForm.tsx +276 -0
  39. package/frontend/src/components/icons/LucideIcons.tsx +14 -0
  40. package/frontend/src/components/layout/Content.tsx +17 -0
  41. package/frontend/src/components/layout/Header.tsx +61 -0
  42. package/frontend/src/components/layout/Sidebar.tsx +98 -0
  43. package/frontend/src/components/ui/Badge.tsx +33 -0
  44. package/frontend/src/components/ui/Button.tsx +0 -0
  45. package/frontend/src/components/ui/DeleteDialog.tsx +48 -0
  46. package/frontend/src/components/ui/Pagination.tsx +128 -0
  47. package/frontend/src/components/ui/Toast.tsx +96 -0
  48. package/frontend/src/components/ui/ToggleGroup.tsx +134 -0
  49. package/frontend/src/components/ui/ToolCard.tsx +38 -0
  50. package/frontend/src/contexts/AuthContext.tsx +159 -0
  51. package/frontend/src/contexts/ToastContext.tsx +60 -0
  52. package/frontend/src/hooks/useGroupData.ts +232 -0
  53. package/frontend/src/hooks/useMarketData.ts +410 -0
  54. package/frontend/src/hooks/useServerData.ts +306 -0
  55. package/frontend/src/hooks/useSettingsData.ts +131 -0
  56. package/frontend/src/i18n.ts +42 -0
  57. package/frontend/src/index.css +20 -0
  58. package/frontend/src/layouts/MainLayout.tsx +33 -0
  59. package/frontend/src/locales/en.json +214 -0
  60. package/frontend/src/locales/zh.json +214 -0
  61. package/frontend/src/main.tsx +12 -0
  62. package/frontend/src/pages/Dashboard.tsx +206 -0
  63. package/frontend/src/pages/GroupsPage.tsx +116 -0
  64. package/frontend/src/pages/LoginPage.tsx +104 -0
  65. package/frontend/src/pages/MarketPage.tsx +356 -0
  66. package/frontend/src/pages/ServersPage.tsx +144 -0
  67. package/frontend/src/pages/SettingsPage.tsx +149 -0
  68. package/frontend/src/services/authService.ts +141 -0
  69. package/frontend/src/types/index.ts +160 -0
  70. package/frontend/src/utils/cn.ts +10 -0
  71. package/frontend/tsconfig.json +31 -0
  72. package/frontend/tsconfig.node.json +10 -0
  73. package/frontend/vite.config.ts +26 -0
  74. package/googled76ca578b6543fbc.html +1 -0
  75. package/jest.config.js +10 -0
  76. package/mcp_settings.json +45 -0
  77. package/package.json +3 -18
  78. package/servers.json +74722 -0
  79. package/src/config/index.ts +46 -0
  80. package/src/controllers/authController.ts +179 -0
  81. package/src/controllers/groupController.ts +341 -0
  82. package/src/controllers/marketController.ts +154 -0
  83. package/src/controllers/serverController.ts +303 -0
  84. package/src/index.ts +17 -0
  85. package/src/middlewares/auth.ts +28 -0
  86. package/src/middlewares/index.ts +43 -0
  87. package/src/models/User.ts +103 -0
  88. package/src/routes/index.ts +96 -0
  89. package/src/server.ts +72 -0
  90. package/src/services/groupService.ts +232 -0
  91. package/src/services/marketService.ts +116 -0
  92. package/src/services/mcpService.ts +385 -0
  93. package/src/services/sseService.ts +119 -0
  94. package/src/types/index.ts +129 -0
  95. package/src/utils/migration.ts +52 -0
  96. package/tsconfig.json +17 -0
  97. package/bin/cli.js +0 -43
@@ -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,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true
8
+ },
9
+ "include": ["vite.config.ts"]
10
+ }
@@ -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,18 +1,9 @@
1
1
  {
2
2
  "name": "@samanhappy/mcphub",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "A hub server for mcp servers",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
- "bin": {
8
- "mcphub": "bin/cli.js"
9
- },
10
- "files": [
11
- "dist",
12
- "bin",
13
- "README.md",
14
- "LICENSE"
15
- ],
16
7
  "scripts": {
17
8
  "build": "tsc",
18
9
  "start": "node dist/index.js",
@@ -23,20 +14,14 @@
23
14
  "frontend:dev": "cd frontend && vite",
24
15
  "frontend:build": "cd frontend && vite build",
25
16
  "frontend:preview": "cd frontend && vite preview",
26
- "dev": "concurrently \"pnpm backend:dev\" \"pnpm frontend:dev\"",
27
- "prepublishOnly": "npm run build && npm run frontend:build"
17
+ "dev": "concurrently \"pnpm backend:dev\" \"pnpm frontend:dev\""
28
18
  },
29
19
  "keywords": [
30
20
  "typescript",
31
- "server",
32
- "mcp",
33
- "model-context-protocol"
21
+ "server"
34
22
  ],
35
23
  "author": "",
36
24
  "license": "ISC",
37
- "publishConfig": {
38
- "access": "public"
39
- },
40
25
  "dependencies": {
41
26
  "@modelcontextprotocol/sdk": "^1.10.2",
42
27
  "@radix-ui/react-accordion": "^1.2.3",