@dxheroes/local-mcp-backend 0.3.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/.swcrc +22 -0
- package/.turbo/turbo-build.log +9 -0
- package/AGENTS.md +360 -0
- package/CHANGELOG.md +60 -0
- package/Dockerfile +71 -0
- package/LICENSE +94 -0
- package/dist/app.module.js +72 -0
- package/dist/app.module.js.map +1 -0
- package/dist/common/decorators/request-id.decorator.js +12 -0
- package/dist/common/decorators/request-id.decorator.js.map +1 -0
- package/dist/common/filters/all-exceptions.filter.js +61 -0
- package/dist/common/filters/all-exceptions.filter.js.map +1 -0
- package/dist/common/interceptors/logging.interceptor.js +46 -0
- package/dist/common/interceptors/logging.interceptor.js.map +1 -0
- package/dist/common/pipes/validation.pipe.js +43 -0
- package/dist/common/pipes/validation.pipe.js.map +1 -0
- package/dist/config/app.config.js +14 -0
- package/dist/config/app.config.js.map +1 -0
- package/dist/config/database.config.js +30 -0
- package/dist/config/database.config.js.map +1 -0
- package/dist/main.js +68 -0
- package/dist/main.js.map +1 -0
- package/dist/modules/database/database.module.js +27 -0
- package/dist/modules/database/database.module.js.map +1 -0
- package/dist/modules/database/prisma.service.js +122 -0
- package/dist/modules/database/prisma.service.js.map +1 -0
- package/dist/modules/debug/debug.controller.js +87 -0
- package/dist/modules/debug/debug.controller.js.map +1 -0
- package/dist/modules/debug/debug.module.js +30 -0
- package/dist/modules/debug/debug.module.js.map +1 -0
- package/dist/modules/debug/debug.service.js +126 -0
- package/dist/modules/debug/debug.service.js.map +1 -0
- package/dist/modules/health/health.controller.js +69 -0
- package/dist/modules/health/health.controller.js.map +1 -0
- package/dist/modules/health/health.module.js +23 -0
- package/dist/modules/health/health.module.js.map +1 -0
- package/dist/modules/mcp/dto/create-mcp-server.dto.js +74 -0
- package/dist/modules/mcp/dto/create-mcp-server.dto.js.map +1 -0
- package/dist/modules/mcp/dto/update-mcp-server.dto.js +74 -0
- package/dist/modules/mcp/dto/update-mcp-server.dto.js.map +1 -0
- package/dist/modules/mcp/mcp-discovery.service.js +176 -0
- package/dist/modules/mcp/mcp-discovery.service.js.map +1 -0
- package/dist/modules/mcp/mcp-registry.js +67 -0
- package/dist/modules/mcp/mcp-registry.js.map +1 -0
- package/dist/modules/mcp/mcp-seed.service.js +122 -0
- package/dist/modules/mcp/mcp-seed.service.js.map +1 -0
- package/dist/modules/mcp/mcp.controller.js +152 -0
- package/dist/modules/mcp/mcp.controller.js.map +1 -0
- package/dist/modules/mcp/mcp.module.js +70 -0
- package/dist/modules/mcp/mcp.module.js.map +1 -0
- package/dist/modules/mcp/mcp.service.js +401 -0
- package/dist/modules/mcp/mcp.service.js.map +1 -0
- package/dist/modules/oauth/oauth.controller.js +116 -0
- package/dist/modules/oauth/oauth.controller.js.map +1 -0
- package/dist/modules/oauth/oauth.module.js +31 -0
- package/dist/modules/oauth/oauth.module.js.map +1 -0
- package/dist/modules/oauth/oauth.service.js +183 -0
- package/dist/modules/oauth/oauth.service.js.map +1 -0
- package/dist/modules/profiles/profiles.controller.js +241 -0
- package/dist/modules/profiles/profiles.controller.js.map +1 -0
- package/dist/modules/profiles/profiles.module.js +34 -0
- package/dist/modules/profiles/profiles.module.js.map +1 -0
- package/dist/modules/profiles/profiles.service.js +390 -0
- package/dist/modules/profiles/profiles.service.js.map +1 -0
- package/dist/modules/proxy/proxy.controller.js +98 -0
- package/dist/modules/proxy/proxy.controller.js.map +1 -0
- package/dist/modules/proxy/proxy.module.js +36 -0
- package/dist/modules/proxy/proxy.module.js.map +1 -0
- package/dist/modules/proxy/proxy.service.js +439 -0
- package/dist/modules/proxy/proxy.service.js.map +1 -0
- package/docker-entrypoint.sh +10 -0
- package/nest-cli.json +10 -0
- package/package.json +51 -0
- package/src/app.module.ts +59 -0
- package/src/common/decorators/request-id.decorator.ts +16 -0
- package/src/common/filters/all-exceptions.filter.ts +77 -0
- package/src/common/interceptors/logging.interceptor.ts +45 -0
- package/src/common/pipes/validation.pipe.ts +31 -0
- package/src/config/app.config.ts +15 -0
- package/src/config/database.config.ts +34 -0
- package/src/main.ts +66 -0
- package/src/modules/database/database.module.ts +15 -0
- package/src/modules/database/prisma.service.ts +110 -0
- package/src/modules/debug/debug.controller.ts +53 -0
- package/src/modules/debug/debug.module.ts +16 -0
- package/src/modules/debug/debug.service.ts +143 -0
- package/src/modules/health/health.controller.ts +48 -0
- package/src/modules/health/health.module.ts +13 -0
- package/src/modules/mcp/dto/create-mcp-server.dto.ts +53 -0
- package/src/modules/mcp/dto/update-mcp-server.dto.ts +53 -0
- package/src/modules/mcp/mcp-discovery.service.ts +205 -0
- package/src/modules/mcp/mcp-registry.ts +73 -0
- package/src/modules/mcp/mcp-seed.service.ts +125 -0
- package/src/modules/mcp/mcp.controller.ts +98 -0
- package/src/modules/mcp/mcp.module.ts +48 -0
- package/src/modules/mcp/mcp.service.ts +427 -0
- package/src/modules/oauth/oauth.controller.ts +89 -0
- package/src/modules/oauth/oauth.module.ts +17 -0
- package/src/modules/oauth/oauth.service.ts +212 -0
- package/src/modules/profiles/profiles.controller.ts +177 -0
- package/src/modules/profiles/profiles.module.ts +18 -0
- package/src/modules/profiles/profiles.service.ts +421 -0
- package/src/modules/proxy/proxy.controller.ts +61 -0
- package/src/modules/proxy/proxy.module.ts +19 -0
- package/src/modules/proxy/proxy.service.ts +595 -0
- package/tsconfig.json +28 -0
package/.swcrc
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/swcrc",
|
|
3
|
+
"sourceMaps": true,
|
|
4
|
+
"jsc": {
|
|
5
|
+
"parser": {
|
|
6
|
+
"syntax": "typescript",
|
|
7
|
+
"decorators": true,
|
|
8
|
+
"dynamicImport": true
|
|
9
|
+
},
|
|
10
|
+
"transform": {
|
|
11
|
+
"legacyDecorator": true,
|
|
12
|
+
"decoratorMetadata": true
|
|
13
|
+
},
|
|
14
|
+
"target": "es2022",
|
|
15
|
+
"keepClassNames": true
|
|
16
|
+
},
|
|
17
|
+
"module": {
|
|
18
|
+
"type": "es6",
|
|
19
|
+
"strict": true,
|
|
20
|
+
"noInterop": false
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
> @dxheroes/local-mcp-backend@0.3.1 build /home/runner/work/local-mcp-gateway/local-mcp-gateway/apps/backend
|
|
3
|
+
> nest build
|
|
4
|
+
|
|
5
|
+
- [46m[1m TSC [22m[49m[36m Initializing type checker...[39m
|
|
6
|
+
✔ [46m[1m TSC [22m[49m[36m Initializing type checker...[39m
|
|
7
|
+
[32m> [39m[42m[1m TSC [22m[49m[32m Found 0 issues.[39m
|
|
8
|
+
[36m> [39m[46m[1m SWC [22m[49m [36mRunning...[39m
|
|
9
|
+
Successfully compiled: 32 files with swc (73.37ms)
|
package/AGENTS.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Backend Application (NestJS)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
NestJS backend that serves as the MCP proxy server. Handles profile management, MCP server management, OAuth flows for MCP servers, API key management, and MCP proxy endpoints per profile.
|
|
6
|
+
|
|
7
|
+
**NOTE:** No user authentication required. All endpoints are public and immediately accessible.
|
|
8
|
+
|
|
9
|
+
## Technology Stack
|
|
10
|
+
|
|
11
|
+
- **Framework**: NestJS 11.x
|
|
12
|
+
- **Language**: TypeScript (ES modules)
|
|
13
|
+
- **Database**: Prisma ORM with SQLite
|
|
14
|
+
- **Validation**: Zod (generated from Prisma schema)
|
|
15
|
+
- **Security**: Helmet, CORS, Rate limiting (@nestjs/throttler)
|
|
16
|
+
|
|
17
|
+
## Structure
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
backend/
|
|
21
|
+
├── src/
|
|
22
|
+
│ ├── main.ts # NestJS bootstrap
|
|
23
|
+
│ ├── app.module.ts # Root module
|
|
24
|
+
│ ├── modules/
|
|
25
|
+
│ │ ├── database/ # Prisma service (global)
|
|
26
|
+
│ │ │ ├── database.module.ts
|
|
27
|
+
│ │ │ └── prisma.service.ts
|
|
28
|
+
│ │ ├── mcp/ # MCP management, discovery, registry
|
|
29
|
+
│ │ │ ├── mcp.module.ts
|
|
30
|
+
│ │ │ ├── mcp.controller.ts
|
|
31
|
+
│ │ │ ├── mcp.service.ts
|
|
32
|
+
│ │ │ ├── mcp-discovery.service.ts
|
|
33
|
+
│ │ │ ├── mcp-seed.service.ts
|
|
34
|
+
│ │ │ └── mcp-registry.ts
|
|
35
|
+
│ │ ├── profiles/ # Profile CRUD
|
|
36
|
+
│ │ │ ├── profiles.module.ts
|
|
37
|
+
│ │ │ ├── profiles.controller.ts
|
|
38
|
+
│ │ │ └── profiles.service.ts
|
|
39
|
+
│ │ ├── oauth/ # OAuth for MCP servers (not user auth)
|
|
40
|
+
│ │ │ ├── oauth.module.ts
|
|
41
|
+
│ │ │ ├── oauth.controller.ts
|
|
42
|
+
│ │ │ └── oauth.service.ts
|
|
43
|
+
│ │ ├── proxy/ # MCP proxy endpoints
|
|
44
|
+
│ │ │ ├── proxy.module.ts
|
|
45
|
+
│ │ │ ├── proxy.controller.ts
|
|
46
|
+
│ │ │ └── proxy.service.ts
|
|
47
|
+
│ │ ├── health/ # Health checks
|
|
48
|
+
│ │ │ ├── health.module.ts
|
|
49
|
+
│ │ │ └── health.controller.ts
|
|
50
|
+
│ │ └── debug/ # Debug logs
|
|
51
|
+
│ │ ├── debug.module.ts
|
|
52
|
+
│ │ ├── debug.controller.ts
|
|
53
|
+
│ │ └── debug.service.ts
|
|
54
|
+
│ ├── common/
|
|
55
|
+
│ │ ├── filters/ # Exception filters
|
|
56
|
+
│ │ │ └── all-exceptions.filter.ts
|
|
57
|
+
│ │ ├── interceptors/ # Logging, timeout
|
|
58
|
+
│ │ │ ├── logging.interceptor.ts
|
|
59
|
+
│ │ │ └── timeout.interceptor.ts
|
|
60
|
+
│ │ └── pipes/ # Validation
|
|
61
|
+
│ │ └── validation.pipe.ts
|
|
62
|
+
│ └── config/ # App configuration
|
|
63
|
+
│ ├── app.config.ts
|
|
64
|
+
│ └── database.config.ts
|
|
65
|
+
├── test/
|
|
66
|
+
│ └── *.e2e-spec.ts # E2E tests
|
|
67
|
+
├── nest-cli.json
|
|
68
|
+
├── tsconfig.json
|
|
69
|
+
├── tsconfig.build.json
|
|
70
|
+
└── package.json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Key Modules
|
|
74
|
+
|
|
75
|
+
### DatabaseModule (Global)
|
|
76
|
+
- **Purpose**: Provides PrismaService globally to all modules
|
|
77
|
+
- **Files**: `database.module.ts`, `prisma.service.ts`
|
|
78
|
+
- **Usage**: Inject `PrismaService` in any service
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
@Injectable()
|
|
82
|
+
export class MyService {
|
|
83
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
84
|
+
|
|
85
|
+
async findAll() {
|
|
86
|
+
return this.prisma.myModel.findMany();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### McpModule
|
|
92
|
+
- **Purpose**: MCP package discovery, seeding, registry, and management
|
|
93
|
+
- **Key Services**:
|
|
94
|
+
- `McpDiscoveryService`: Scans dependencies for `mcpPackage: true`
|
|
95
|
+
- `McpSeedService`: Creates database records for discovered packages
|
|
96
|
+
- `McpRegistry`: In-memory registry of MCP packages
|
|
97
|
+
- `McpService`: CRUD operations for MCP servers
|
|
98
|
+
|
|
99
|
+
### ProfilesModule
|
|
100
|
+
- **Purpose**: Profile CRUD operations
|
|
101
|
+
- **Endpoints**:
|
|
102
|
+
- `GET /api/profiles` - List all profiles
|
|
103
|
+
- `GET /api/profiles/:id` - Get profile by ID
|
|
104
|
+
- `POST /api/profiles` - Create profile
|
|
105
|
+
- `PUT /api/profiles/:id` - Update profile
|
|
106
|
+
- `DELETE /api/profiles/:id` - Delete profile
|
|
107
|
+
- `POST /api/profiles/:id/servers` - Add server to profile
|
|
108
|
+
- `DELETE /api/profiles/:id/servers/:serverId` - Remove server from profile
|
|
109
|
+
|
|
110
|
+
### ProxyModule
|
|
111
|
+
- **Purpose**: MCP proxy endpoints for Claude/AI clients
|
|
112
|
+
- **Endpoints**:
|
|
113
|
+
- `POST /api/mcp/:profileName` - MCP JSON-RPC endpoint for profile
|
|
114
|
+
|
|
115
|
+
### OAuthModule
|
|
116
|
+
- **Purpose**: OAuth 2.1 flows for MCP servers (not user authentication)
|
|
117
|
+
- **Endpoints**:
|
|
118
|
+
- `GET /api/oauth/authorize/:serverId` - Start OAuth flow
|
|
119
|
+
- `GET /api/oauth/callback` - OAuth callback
|
|
120
|
+
|
|
121
|
+
### HealthModule
|
|
122
|
+
- **Purpose**: Health check endpoints
|
|
123
|
+
- **Endpoints**:
|
|
124
|
+
- `GET /api/health` - Health status
|
|
125
|
+
|
|
126
|
+
### DebugModule
|
|
127
|
+
- **Purpose**: Debug logging for MCP traffic
|
|
128
|
+
- **Endpoints**:
|
|
129
|
+
- `GET /api/debug/logs` - Get debug logs
|
|
130
|
+
|
|
131
|
+
## API Endpoints Summary
|
|
132
|
+
|
|
133
|
+
| Method | Endpoint | Description |
|
|
134
|
+
|--------|----------|-------------|
|
|
135
|
+
| GET | `/api/health` | Health check |
|
|
136
|
+
| GET | `/api/profiles` | List profiles |
|
|
137
|
+
| GET | `/api/profiles/:id` | Get profile |
|
|
138
|
+
| POST | `/api/profiles` | Create profile |
|
|
139
|
+
| PUT | `/api/profiles/:id` | Update profile |
|
|
140
|
+
| DELETE | `/api/profiles/:id` | Delete profile |
|
|
141
|
+
| POST | `/api/profiles/:id/servers` | Add server to profile |
|
|
142
|
+
| DELETE | `/api/profiles/:id/servers/:serverId` | Remove server |
|
|
143
|
+
| GET | `/api/mcp-servers` | List MCP servers |
|
|
144
|
+
| GET | `/api/mcp-servers/available` | List available MCP packages |
|
|
145
|
+
| GET | `/api/mcp-servers/:id` | Get MCP server |
|
|
146
|
+
| POST | `/api/mcp-servers` | Create MCP server |
|
|
147
|
+
| PUT | `/api/mcp-servers/:id` | Update MCP server |
|
|
148
|
+
| DELETE | `/api/mcp-servers/:id` | Delete MCP server |
|
|
149
|
+
| GET | `/api/mcp-servers/:id/tools` | Get server tools |
|
|
150
|
+
| GET | `/api/mcp-servers/:id/status` | Get server status |
|
|
151
|
+
| POST | `/api/mcp/:profileName` | MCP proxy endpoint |
|
|
152
|
+
| GET | `/api/oauth/authorize/:serverId` | Start OAuth |
|
|
153
|
+
| GET | `/api/oauth/callback` | OAuth callback |
|
|
154
|
+
| GET | `/api/debug/logs` | Debug logs |
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
### Running
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Development with hot-reload
|
|
162
|
+
pnpm dev:backend
|
|
163
|
+
|
|
164
|
+
# Build
|
|
165
|
+
pnpm --filter backend build
|
|
166
|
+
|
|
167
|
+
# Production
|
|
168
|
+
pnpm --filter backend start:prod
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Adding a New Module
|
|
172
|
+
|
|
173
|
+
1. **Create module folder**:
|
|
174
|
+
```bash
|
|
175
|
+
mkdir -p src/modules/my-feature
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
2. **Create files**:
|
|
179
|
+
```typescript
|
|
180
|
+
// my-feature.module.ts
|
|
181
|
+
import { Module } from '@nestjs/common';
|
|
182
|
+
import { MyFeatureController } from './my-feature.controller';
|
|
183
|
+
import { MyFeatureService } from './my-feature.service';
|
|
184
|
+
|
|
185
|
+
@Module({
|
|
186
|
+
controllers: [MyFeatureController],
|
|
187
|
+
providers: [MyFeatureService],
|
|
188
|
+
exports: [MyFeatureService],
|
|
189
|
+
})
|
|
190
|
+
export class MyFeatureModule {}
|
|
191
|
+
|
|
192
|
+
// my-feature.controller.ts
|
|
193
|
+
import { Controller, Get, Post, Body } from '@nestjs/common';
|
|
194
|
+
import { MyFeatureService } from './my-feature.service';
|
|
195
|
+
|
|
196
|
+
@Controller('my-feature')
|
|
197
|
+
export class MyFeatureController {
|
|
198
|
+
constructor(private readonly service: MyFeatureService) {}
|
|
199
|
+
|
|
200
|
+
@Get()
|
|
201
|
+
findAll() {
|
|
202
|
+
return this.service.findAll();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// my-feature.service.ts
|
|
207
|
+
import { Injectable } from '@nestjs/common';
|
|
208
|
+
import { PrismaService } from '../database/prisma.service';
|
|
209
|
+
|
|
210
|
+
@Injectable()
|
|
211
|
+
export class MyFeatureService {
|
|
212
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
213
|
+
|
|
214
|
+
async findAll() {
|
|
215
|
+
return this.prisma.myModel.findMany();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
3. **Register in app.module.ts**:
|
|
221
|
+
```typescript
|
|
222
|
+
import { MyFeatureModule } from './modules/my-feature/my-feature.module';
|
|
223
|
+
|
|
224
|
+
@Module({
|
|
225
|
+
imports: [
|
|
226
|
+
// ... other modules
|
|
227
|
+
MyFeatureModule,
|
|
228
|
+
],
|
|
229
|
+
})
|
|
230
|
+
export class AppModule {}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Using Prisma
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { Injectable } from '@nestjs/common';
|
|
237
|
+
import { PrismaService } from '../database/prisma.service';
|
|
238
|
+
|
|
239
|
+
@Injectable()
|
|
240
|
+
export class MyService {
|
|
241
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
242
|
+
|
|
243
|
+
// Find all
|
|
244
|
+
async findAll() {
|
|
245
|
+
return this.prisma.profile.findMany({
|
|
246
|
+
include: { mcpServers: true },
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Find one
|
|
251
|
+
async findById(id: string) {
|
|
252
|
+
return this.prisma.profile.findUnique({
|
|
253
|
+
where: { id },
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Create
|
|
258
|
+
async create(data: { name: string; description?: string }) {
|
|
259
|
+
return this.prisma.profile.create({
|
|
260
|
+
data,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Update
|
|
265
|
+
async update(id: string, data: { name?: string; description?: string }) {
|
|
266
|
+
return this.prisma.profile.update({
|
|
267
|
+
where: { id },
|
|
268
|
+
data,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Delete
|
|
273
|
+
async delete(id: string) {
|
|
274
|
+
return this.prisma.profile.delete({
|
|
275
|
+
where: { id },
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Validation with Zod
|
|
282
|
+
|
|
283
|
+
Use generated Zod schemas from Prisma:
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import { ProfileCreateInputSchema } from '@dxheroes/local-mcp-database';
|
|
287
|
+
|
|
288
|
+
// In controller or service
|
|
289
|
+
const validated = ProfileCreateInputSchema.parse(input);
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Dependencies
|
|
293
|
+
|
|
294
|
+
### Core NestJS
|
|
295
|
+
|
|
296
|
+
- `@nestjs/common` - Common utilities
|
|
297
|
+
- `@nestjs/core` - Core framework
|
|
298
|
+
- `@nestjs/platform-express` - Express adapter
|
|
299
|
+
- `@nestjs/config` - Configuration
|
|
300
|
+
- `@nestjs/throttler` - Rate limiting
|
|
301
|
+
|
|
302
|
+
### Database
|
|
303
|
+
|
|
304
|
+
- `@dxheroes/local-mcp-database` - Prisma client and Zod schemas
|
|
305
|
+
|
|
306
|
+
### MCP
|
|
307
|
+
|
|
308
|
+
- `@modelcontextprotocol/sdk` - MCP SDK
|
|
309
|
+
- `@dxheroes/local-mcp-core` - Core types and abstractions
|
|
310
|
+
|
|
311
|
+
### Security
|
|
312
|
+
|
|
313
|
+
- `helmet` - Security headers
|
|
314
|
+
- `compression` - Response compression
|
|
315
|
+
|
|
316
|
+
## Environment Variables
|
|
317
|
+
|
|
318
|
+
| Variable | Default | Description |
|
|
319
|
+
|----------|---------|-------------|
|
|
320
|
+
| `PORT` | `3001` | Server port |
|
|
321
|
+
| `NODE_ENV` | `development` | Environment |
|
|
322
|
+
| `CORS_ORIGINS` | `http://localhost:3000` | Allowed CORS origins |
|
|
323
|
+
| `DATABASE_URL` | `file:~/.local-mcp-gateway-data/...` | Prisma database URL |
|
|
324
|
+
|
|
325
|
+
## MCP Package Discovery
|
|
326
|
+
|
|
327
|
+
On module initialization (`onModuleInit`), the `McpModule`:
|
|
328
|
+
|
|
329
|
+
1. **Discovers packages**: `McpDiscoveryService` scans all dependencies
|
|
330
|
+
2. **Filters MCP packages**: Looks for `"mcpPackage": true` in package.json
|
|
331
|
+
3. **Registers packages**: Loads and registers in `McpRegistry`
|
|
332
|
+
4. **Seeds database**: `McpSeedService` creates records for new packages
|
|
333
|
+
|
|
334
|
+
```
|
|
335
|
+
[McpModule] Initializing MCP Module...
|
|
336
|
+
[McpModule] Discovered 1 MCP packages
|
|
337
|
+
[McpModule] Registered: Gemini Deep Research (gemini-deep-research)
|
|
338
|
+
[McpModule] MCP Module initialization complete
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Testing
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# Run tests
|
|
345
|
+
pnpm --filter backend test
|
|
346
|
+
|
|
347
|
+
# Watch mode
|
|
348
|
+
pnpm --filter backend test:watch
|
|
349
|
+
|
|
350
|
+
# E2E tests
|
|
351
|
+
pnpm --filter backend test:e2e
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Important Notes
|
|
355
|
+
|
|
356
|
+
- **No user authentication**: All endpoints are public
|
|
357
|
+
- **OAuth is for MCP servers**: Not user login
|
|
358
|
+
- **Prisma for database**: Type-safe queries
|
|
359
|
+
- **NestJS modules**: Clean separation of concerns
|
|
360
|
+
- **Auto-discovery**: MCP packages are auto-discovered on startup
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.3.1](https://github.com/DXHeroes/local-mcp-gateway/compare/backend-v0.3.0...backend-v0.3.1) (2026-01-13)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* update package names in Dockerfiles and add apps to npm publish ([1928dba](https://github.com/DXHeroes/local-mcp-gateway/commit/1928dba89a6a9134fdadf5bcacd3a0617cee74dc))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @dxheroes/local-mcp-core bumped to 0.3.1
|
|
16
|
+
* @dxheroes/local-mcp-database bumped to 0.3.1
|
|
17
|
+
* @dxheroes/mcp-gemini-deep-research bumped to 0.3.1
|
|
18
|
+
* devDependencies
|
|
19
|
+
* @dxheroes/local-mcp-config bumped to 0.3.1
|
|
20
|
+
|
|
21
|
+
## [0.3.0](https://github.com/DXHeroes/local-mcp-gateway/compare/backend-v0.2.0...backend-v0.3.0) (2026-01-13)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Miscellaneous
|
|
25
|
+
|
|
26
|
+
* release 0.3.0 ([9d54f73](https://github.com/DXHeroes/local-mcp-gateway/commit/9d54f73a2d4cd49903ad353e131740513915d681))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Dependencies
|
|
30
|
+
|
|
31
|
+
* The following workspace dependencies were updated
|
|
32
|
+
* dependencies
|
|
33
|
+
* @dxheroes/local-mcp-core bumped to 0.3.0
|
|
34
|
+
* @dxheroes/local-mcp-database bumped to 0.3.0
|
|
35
|
+
* @dxheroes/mcp-gemini-deep-research bumped to 0.3.0
|
|
36
|
+
* devDependencies
|
|
37
|
+
* @dxheroes/local-mcp-config bumped to 0.3.0
|
|
38
|
+
|
|
39
|
+
## [0.2.0](https://github.com/DXHeroes/local-mcp-gateway/compare/backend-v0.2.0...backend-v0.2.0) (2026-01-13)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Features
|
|
43
|
+
|
|
44
|
+
* initial release v0.2.0 ([35645f8](https://github.com/DXHeroes/local-mcp-gateway/commit/35645f81a4f291ae4b3e9f68657cd96db41b8a16))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
### Bug Fixes
|
|
48
|
+
|
|
49
|
+
* add GET handler for MCP endpoint to return usage info instead of 404 ([d7273bb](https://github.com/DXHeroes/local-mcp-gateway/commit/d7273bbc66c18f0d30690483b10f41bc6382863c))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Dependencies
|
|
53
|
+
|
|
54
|
+
* The following workspace dependencies were updated
|
|
55
|
+
* dependencies
|
|
56
|
+
* @dxheroes/local-mcp-core bumped to 0.2.1
|
|
57
|
+
* @dxheroes/local-mcp-database bumped to 0.2.1
|
|
58
|
+
* @dxheroes/mcp-gemini-deep-research bumped to 0.2.1
|
|
59
|
+
* devDependencies
|
|
60
|
+
* @dxheroes/local-mcp-config bumped to 0.2.1
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Build stage
|
|
2
|
+
FROM node:22-alpine AS builder
|
|
3
|
+
|
|
4
|
+
WORKDIR /app
|
|
5
|
+
|
|
6
|
+
# Install pnpm
|
|
7
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
8
|
+
|
|
9
|
+
# Copy workspace files
|
|
10
|
+
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json turbo.json tsconfig.json ./
|
|
11
|
+
COPY packages ./packages
|
|
12
|
+
COPY apps/backend ./apps/backend
|
|
13
|
+
COPY mcp-servers ./mcp-servers
|
|
14
|
+
|
|
15
|
+
# Install dependencies
|
|
16
|
+
RUN pnpm install --frozen-lockfile
|
|
17
|
+
|
|
18
|
+
# Generate Prisma client
|
|
19
|
+
RUN pnpm --filter @dxheroes/local-mcp-database prisma:generate
|
|
20
|
+
|
|
21
|
+
# Build all required packages
|
|
22
|
+
RUN pnpm --filter @dxheroes/local-mcp-backend... build
|
|
23
|
+
|
|
24
|
+
# Production stage
|
|
25
|
+
FROM node:22-alpine AS runner
|
|
26
|
+
|
|
27
|
+
WORKDIR /app
|
|
28
|
+
|
|
29
|
+
# Install pnpm for production
|
|
30
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
31
|
+
|
|
32
|
+
# Create data directory
|
|
33
|
+
RUN mkdir -p /data
|
|
34
|
+
|
|
35
|
+
# Copy package files for production install
|
|
36
|
+
COPY --from=builder /app/package.json /app/pnpm-workspace.yaml /app/pnpm-lock.yaml ./
|
|
37
|
+
COPY --from=builder /app/packages/core/package.json ./packages/core/
|
|
38
|
+
COPY --from=builder /app/packages/database/package.json ./packages/database/
|
|
39
|
+
COPY --from=builder /app/apps/backend/package.json ./apps/backend/
|
|
40
|
+
COPY --from=builder /app/mcp-servers ./mcp-servers
|
|
41
|
+
|
|
42
|
+
# Copy built files
|
|
43
|
+
COPY --from=builder /app/packages/core/dist ./packages/core/dist
|
|
44
|
+
COPY --from=builder /app/packages/database/dist ./packages/database/dist
|
|
45
|
+
COPY --from=builder /app/packages/database/src/generated ./packages/database/src/generated
|
|
46
|
+
COPY --from=builder /app/apps/backend/dist ./apps/backend/dist
|
|
47
|
+
|
|
48
|
+
# Copy Prisma schema and migrations (required for migrate deploy)
|
|
49
|
+
COPY --from=builder /app/packages/database/prisma ./packages/database/prisma
|
|
50
|
+
|
|
51
|
+
# Install production dependencies only
|
|
52
|
+
RUN pnpm install --frozen-lockfile --prod
|
|
53
|
+
|
|
54
|
+
# Set environment
|
|
55
|
+
ENV NODE_ENV=production
|
|
56
|
+
ENV PORT=3001
|
|
57
|
+
|
|
58
|
+
# Expose port
|
|
59
|
+
EXPOSE 3001
|
|
60
|
+
|
|
61
|
+
# Health check
|
|
62
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
63
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/api/health || exit 1
|
|
64
|
+
|
|
65
|
+
# Copy and set up entrypoint script
|
|
66
|
+
COPY apps/backend/docker-entrypoint.sh /app/docker-entrypoint.sh
|
|
67
|
+
RUN chmod +x /app/docker-entrypoint.sh
|
|
68
|
+
|
|
69
|
+
# Start the application via entrypoint (runs prisma db push first)
|
|
70
|
+
WORKDIR /app
|
|
71
|
+
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
package/LICENSE
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Elastic License 2.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 DX Heroes CZ s.r.o.
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
+
|
|
9
|
+
## Copyright License
|
|
10
|
+
|
|
11
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
12
|
+
non-sublicensable, non-transferable license to use, copy, distribute,
|
|
13
|
+
make available, and prepare derivative works of the software, in each
|
|
14
|
+
case subject to the limitations and conditions below.
|
|
15
|
+
|
|
16
|
+
## Limitations
|
|
17
|
+
|
|
18
|
+
You may not provide the software to third parties as a hosted or managed
|
|
19
|
+
service, where the service provides users with access to any substantial
|
|
20
|
+
set of the features or functionality of the software.
|
|
21
|
+
|
|
22
|
+
You may not move, change, disable, or circumvent the license key
|
|
23
|
+
functionality in the software, and you may not remove or obscure any
|
|
24
|
+
functionality in the software that is protected by the license key.
|
|
25
|
+
|
|
26
|
+
You may not alter, remove, or obscure any licensing, copyright, or other
|
|
27
|
+
notices of the licensor in the software. Any use of the licensor's
|
|
28
|
+
trademarks is subject to applicable law.
|
|
29
|
+
|
|
30
|
+
## Patents
|
|
31
|
+
|
|
32
|
+
The licensor grants you a license, under any patent claims the licensor
|
|
33
|
+
can license, or becomes able to license, to make, have made, use, sell,
|
|
34
|
+
offer for sale, import and have imported the software, in each case
|
|
35
|
+
subject to the limitations and conditions in this license. This license
|
|
36
|
+
does not cover any patent claims that you cause to be infringed by
|
|
37
|
+
modifications or additions to the software. If you or your company make
|
|
38
|
+
any written claim that the software infringes or contributes to
|
|
39
|
+
infringement of any patent, your patent license for the software granted
|
|
40
|
+
under these terms ends immediately. If your company makes such a claim,
|
|
41
|
+
your patent license ends immediately for work on behalf of your company.
|
|
42
|
+
|
|
43
|
+
## Notices
|
|
44
|
+
|
|
45
|
+
You must ensure that anyone who gets a copy of any part of the software
|
|
46
|
+
from you also gets a copy of these terms.
|
|
47
|
+
|
|
48
|
+
If you modify the software, you must include in any modified copies of
|
|
49
|
+
the software prominent notices stating that you have modified the software.
|
|
50
|
+
|
|
51
|
+
## No Other Rights
|
|
52
|
+
|
|
53
|
+
These terms do not imply any licenses other than those expressly granted
|
|
54
|
+
in these terms.
|
|
55
|
+
|
|
56
|
+
## Termination
|
|
57
|
+
|
|
58
|
+
If you use the software in violation of these terms, such use is not
|
|
59
|
+
licensed, and your licenses will automatically terminate. If the licensor
|
|
60
|
+
provides you with a notice of your violation, and you cease all violation
|
|
61
|
+
of this license no later than 30 days after you receive that notice, your
|
|
62
|
+
licenses will be reinstated retroactively. However, if you violate these
|
|
63
|
+
terms after such reinstatement, any additional violation of these terms
|
|
64
|
+
will cause your licenses to terminate automatically and permanently.
|
|
65
|
+
|
|
66
|
+
## No Liability
|
|
67
|
+
|
|
68
|
+
AS FAR AS THE LAW ALLOWS, THE SOFTWARE COMES AS IS, WITHOUT ANY WARRANTY
|
|
69
|
+
OR CONDITION, AND THE LICENSOR WILL NOT BE LIABLE TO YOU FOR ANY DAMAGES
|
|
70
|
+
ARISING OUT OF THESE TERMS OR THE USE OR NATURE OF THE SOFTWARE, UNDER
|
|
71
|
+
ANY KIND OF LEGAL CLAIM.
|
|
72
|
+
|
|
73
|
+
## Definitions
|
|
74
|
+
|
|
75
|
+
The "licensor" is the entity offering these terms, and the "software" is
|
|
76
|
+
the software the licensor makes available under these terms, including
|
|
77
|
+
any portion of it.
|
|
78
|
+
|
|
79
|
+
"You" refers to the individual or entity agreeing to these terms.
|
|
80
|
+
|
|
81
|
+
"Your company" is any legal entity, sole proprietorship, or other kind of
|
|
82
|
+
organization that you work for, plus all organizations that have control
|
|
83
|
+
over, are under the control of, or are under common control with that
|
|
84
|
+
organization. "Control" means ownership of substantially all the assets
|
|
85
|
+
of an entity, or the power to direct its management and policies by vote,
|
|
86
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
87
|
+
|
|
88
|
+
"Your licenses" are all the licenses granted to you for the software
|
|
89
|
+
under these terms.
|
|
90
|
+
|
|
91
|
+
"Use" means anything you do with the software requiring one of your
|
|
92
|
+
licenses.
|
|
93
|
+
|
|
94
|
+
"Trademark" means trademarks, service marks, and similar rights.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Root Application Module
|
|
9
|
+
*
|
|
10
|
+
* Configures all NestJS modules for the Local MCP Gateway.
|
|
11
|
+
* No authentication module - immediate access to all features.
|
|
12
|
+
*/ import { Module } from "@nestjs/common";
|
|
13
|
+
import { ConfigModule } from "@nestjs/config";
|
|
14
|
+
import { ThrottlerModule } from "@nestjs/throttler";
|
|
15
|
+
import appConfig from "./config/app.config.js";
|
|
16
|
+
import databaseConfig from "./config/database.config.js";
|
|
17
|
+
import { DatabaseModule } from "./modules/database/database.module.js";
|
|
18
|
+
import { DebugModule } from "./modules/debug/debug.module.js";
|
|
19
|
+
import { HealthModule } from "./modules/health/health.module.js";
|
|
20
|
+
import { McpModule } from "./modules/mcp/mcp.module.js";
|
|
21
|
+
import { OAuthModule } from "./modules/oauth/oauth.module.js";
|
|
22
|
+
import { ProfilesModule } from "./modules/profiles/profiles.module.js";
|
|
23
|
+
import { ProxyModule } from "./modules/proxy/proxy.module.js";
|
|
24
|
+
export class AppModule {
|
|
25
|
+
}
|
|
26
|
+
AppModule = _ts_decorate([
|
|
27
|
+
Module({
|
|
28
|
+
imports: [
|
|
29
|
+
// Configuration
|
|
30
|
+
ConfigModule.forRoot({
|
|
31
|
+
isGlobal: true,
|
|
32
|
+
load: [
|
|
33
|
+
appConfig,
|
|
34
|
+
databaseConfig
|
|
35
|
+
],
|
|
36
|
+
envFilePath: [
|
|
37
|
+
'../../.env',
|
|
38
|
+
'.env.local',
|
|
39
|
+
'.env'
|
|
40
|
+
]
|
|
41
|
+
}),
|
|
42
|
+
// Rate limiting
|
|
43
|
+
ThrottlerModule.forRoot([
|
|
44
|
+
{
|
|
45
|
+
name: 'short',
|
|
46
|
+
ttl: 1000,
|
|
47
|
+
limit: 10
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'medium',
|
|
51
|
+
ttl: 10000,
|
|
52
|
+
limit: 50
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'long',
|
|
56
|
+
ttl: 60000,
|
|
57
|
+
limit: 200
|
|
58
|
+
}
|
|
59
|
+
]),
|
|
60
|
+
// Core modules (no authentication - immediate access)
|
|
61
|
+
DatabaseModule,
|
|
62
|
+
McpModule,
|
|
63
|
+
ProfilesModule,
|
|
64
|
+
OAuthModule,
|
|
65
|
+
ProxyModule,
|
|
66
|
+
HealthModule,
|
|
67
|
+
DebugModule
|
|
68
|
+
]
|
|
69
|
+
})
|
|
70
|
+
], AppModule);
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=app.module.js.map
|