@nestcorehq/mcp-server 0.0.0-stage → 1.8.0
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 +26 -0
- package/.mcp.json +3 -0
- package/README.md +510 -3
- package/dist/auth/credentials.service.d.ts +12 -0
- package/dist/auth/credentials.service.d.ts.map +1 -0
- package/dist/auth/credentials.service.js +120 -0
- package/dist/auth/credentials.service.js.map +1 -0
- package/dist/auth/oauth-login.d.ts +25 -0
- package/dist/auth/oauth-login.d.ts.map +1 -0
- package/dist/auth/oauth-login.js +146 -0
- package/dist/auth/oauth-login.js.map +1 -0
- package/dist/auth/session.service.d.ts +20 -0
- package/dist/auth/session.service.d.ts.map +1 -0
- package/dist/auth/session.service.js +185 -0
- package/dist/auth/session.service.js.map +1 -0
- package/dist/auth/token.service.d.ts +5 -0
- package/dist/auth/token.service.d.ts.map +1 -0
- package/dist/auth/token.service.js +31 -0
- package/dist/auth/token.service.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +45 -0
- package/dist/config.js.map +1 -0
- package/dist/context/project.service.d.ts +8 -0
- package/dist/context/project.service.d.ts.map +1 -0
- package/dist/context/project.service.js +20 -0
- package/dist/context/project.service.js.map +1 -0
- package/dist/context/schema.service.d.ts +12 -0
- package/dist/context/schema.service.d.ts.map +1 -0
- package/dist/context/schema.service.js +45 -0
- package/dist/context/schema.service.js.map +1 -0
- package/dist/context/session-tracker.d.ts +32 -0
- package/dist/context/session-tracker.d.ts.map +1 -0
- package/dist/context/session-tracker.js +55 -0
- package/dist/context/session-tracker.js.map +1 -0
- package/dist/context/workspace.service.d.ts +15 -0
- package/dist/context/workspace.service.d.ts.map +1 -0
- package/dist/context/workspace.service.js +74 -0
- package/dist/context/workspace.service.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/legacy-tool-names.d.ts +16 -0
- package/dist/legacy-tool-names.d.ts.map +1 -0
- package/dist/legacy-tool-names.js +38 -0
- package/dist/legacy-tool-names.js.map +1 -0
- package/dist/migrations/index.d.ts +11 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +18 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migrationExecutor.d.ts +12 -0
- package/dist/migrations/migrationExecutor.d.ts.map +1 -0
- package/dist/migrations/migrationExecutor.js +25 -0
- package/dist/migrations/migrationExecutor.js.map +1 -0
- package/dist/migrations/migrationRegistry.d.ts +12 -0
- package/dist/migrations/migrationRegistry.d.ts.map +1 -0
- package/dist/migrations/migrationRegistry.js +57 -0
- package/dist/migrations/migrationRegistry.js.map +1 -0
- package/dist/migrations/migrationRunner.d.ts +30 -0
- package/dist/migrations/migrationRunner.d.ts.map +1 -0
- package/dist/migrations/migrationRunner.js +104 -0
- package/dist/migrations/migrationRunner.js.map +1 -0
- package/dist/migrations/migrationScanner.d.ts +10 -0
- package/dist/migrations/migrationScanner.d.ts.map +1 -0
- package/dist/migrations/migrationScanner.js +66 -0
- package/dist/migrations/migrationScanner.js.map +1 -0
- package/dist/migrations/types.d.ts +67 -0
- package/dist/migrations/types.d.ts.map +1 -0
- package/dist/migrations/types.js +13 -0
- package/dist/migrations/types.js.map +1 -0
- package/dist/prompts/project-intelligence.prompts.d.ts +4 -0
- package/dist/prompts/project-intelligence.prompts.d.ts.map +1 -0
- package/dist/prompts/project-intelligence.prompts.js +66 -0
- package/dist/prompts/project-intelligence.prompts.js.map +1 -0
- package/dist/safety/auth-table.guard.d.ts +6 -0
- package/dist/safety/auth-table.guard.d.ts.map +1 -0
- package/dist/safety/auth-table.guard.js +56 -0
- package/dist/safety/auth-table.guard.js.map +1 -0
- package/dist/safety/operation.guard.d.ts +5 -0
- package/dist/safety/operation.guard.d.ts.map +1 -0
- package/dist/safety/operation.guard.js +26 -0
- package/dist/safety/operation.guard.js.map +1 -0
- package/dist/safety/sql.guard.d.ts +17 -0
- package/dist/safety/sql.guard.d.ts.map +1 -0
- package/dist/safety/sql.guard.js +82 -0
- package/dist/safety/sql.guard.js.map +1 -0
- package/dist/sdk/endpoints.d.ts +186 -0
- package/dist/sdk/endpoints.d.ts.map +1 -0
- package/dist/sdk/endpoints.js +222 -0
- package/dist/sdk/endpoints.js.map +1 -0
- package/dist/sdk/nestcore.client.d.ts +464 -0
- package/dist/sdk/nestcore.client.d.ts.map +1 -0
- package/dist/sdk/nestcore.client.js +907 -0
- package/dist/sdk/nestcore.client.js.map +1 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +190 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/admin.tools.d.ts +4 -0
- package/dist/tools/admin.tools.d.ts.map +1 -0
- package/dist/tools/admin.tools.js +137 -0
- package/dist/tools/admin.tools.js.map +1 -0
- package/dist/tools/analytics.tools.d.ts +4 -0
- package/dist/tools/analytics.tools.d.ts.map +1 -0
- package/dist/tools/analytics.tools.js +265 -0
- package/dist/tools/analytics.tools.js.map +1 -0
- package/dist/tools/auth.tools.d.ts +4 -0
- package/dist/tools/auth.tools.d.ts.map +1 -0
- package/dist/tools/auth.tools.js +201 -0
- package/dist/tools/auth.tools.js.map +1 -0
- package/dist/tools/background-jobs.tools.d.ts +4 -0
- package/dist/tools/background-jobs.tools.d.ts.map +1 -0
- package/dist/tools/background-jobs.tools.js +197 -0
- package/dist/tools/background-jobs.tools.js.map +1 -0
- package/dist/tools/branches.tools.d.ts +10 -0
- package/dist/tools/branches.tools.d.ts.map +1 -0
- package/dist/tools/branches.tools.js +114 -0
- package/dist/tools/branches.tools.js.map +1 -0
- package/dist/tools/credits.tools.d.ts +9 -0
- package/dist/tools/credits.tools.d.ts.map +1 -0
- package/dist/tools/credits.tools.js +63 -0
- package/dist/tools/credits.tools.js.map +1 -0
- package/dist/tools/dashboard.tools.d.ts +4 -0
- package/dist/tools/dashboard.tools.d.ts.map +1 -0
- package/dist/tools/dashboard.tools.js +36 -0
- package/dist/tools/dashboard.tools.js.map +1 -0
- package/dist/tools/database.tools.d.ts +4 -0
- package/dist/tools/database.tools.d.ts.map +1 -0
- package/dist/tools/database.tools.js +301 -0
- package/dist/tools/database.tools.js.map +1 -0
- package/dist/tools/function.tools.d.ts +4 -0
- package/dist/tools/function.tools.d.ts.map +1 -0
- package/dist/tools/function.tools.js +237 -0
- package/dist/tools/function.tools.js.map +1 -0
- package/dist/tools/index.d.ts +19 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +41 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/integrations.tools.d.ts +4 -0
- package/dist/tools/integrations.tools.d.ts.map +1 -0
- package/dist/tools/integrations.tools.js +308 -0
- package/dist/tools/integrations.tools.js.map +1 -0
- package/dist/tools/logging.tools.d.ts +4 -0
- package/dist/tools/logging.tools.d.ts.map +1 -0
- package/dist/tools/logging.tools.js +105 -0
- package/dist/tools/logging.tools.js.map +1 -0
- package/dist/tools/migration.tools.d.ts +4 -0
- package/dist/tools/migration.tools.d.ts.map +1 -0
- package/dist/tools/migration.tools.js +106 -0
- package/dist/tools/migration.tools.js.map +1 -0
- package/dist/tools/project-intelligence.tools.d.ts +4 -0
- package/dist/tools/project-intelligence.tools.d.ts.map +1 -0
- package/dist/tools/project-intelligence.tools.js +436 -0
- package/dist/tools/project-intelligence.tools.js.map +1 -0
- package/dist/tools/project.tools.d.ts +4 -0
- package/dist/tools/project.tools.d.ts.map +1 -0
- package/dist/tools/project.tools.js +275 -0
- package/dist/tools/project.tools.js.map +1 -0
- package/dist/tools/realtime.tools.d.ts +4 -0
- package/dist/tools/realtime.tools.d.ts.map +1 -0
- package/dist/tools/realtime.tools.js +96 -0
- package/dist/tools/realtime.tools.js.map +1 -0
- package/dist/tools/rls.tools.d.ts +4 -0
- package/dist/tools/rls.tools.d.ts.map +1 -0
- package/dist/tools/rls.tools.js +143 -0
- package/dist/tools/rls.tools.js.map +1 -0
- package/dist/tools/smtp.tools.d.ts +4 -0
- package/dist/tools/smtp.tools.d.ts.map +1 -0
- package/dist/tools/smtp.tools.js +51 -0
- package/dist/tools/smtp.tools.js.map +1 -0
- package/dist/tools/storage.tools.d.ts +4 -0
- package/dist/tools/storage.tools.d.ts.map +1 -0
- package/dist/tools/storage.tools.js +221 -0
- package/dist/tools/storage.tools.js.map +1 -0
- package/dist/types/api.types.d.ts +144 -0
- package/dist/types/api.types.d.ts.map +1 -0
- package/dist/types/api.types.js +2 -0
- package/dist/types/api.types.js.map +1 -0
- package/dist/types/config.types.d.ts +13 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +2 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/session.types.d.ts +95 -0
- package/dist/types/session.types.d.ts.map +1 -0
- package/dist/types/session.types.js +2 -0
- package/dist/types/session.types.js.map +1 -0
- package/dist/utils/errors.d.ts +37 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +107 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +42 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validators.d.ts +4 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +21 -0
- package/dist/utils/validators.js.map +1 -0
- package/package.json +54 -6
- package/src/auth/credentials.service.ts +104 -0
- package/src/auth/oauth-login.ts +189 -0
- package/src/auth/session.service.ts +211 -0
- package/src/auth/token.service.ts +28 -0
- package/src/config.ts +50 -0
- package/src/context/project.service.ts +24 -0
- package/src/context/schema.service.ts +55 -0
- package/src/context/session-tracker.ts +72 -0
- package/src/context/workspace.service.ts +78 -0
- package/src/index.ts +61 -0
- package/src/legacy-tool-names.ts +42 -0
- package/src/migrations/index.ts +21 -0
- package/src/migrations/migrationExecutor.ts +26 -0
- package/src/migrations/migrationRegistry.ts +75 -0
- package/src/migrations/migrationRunner.ts +128 -0
- package/src/migrations/migrationScanner.ts +77 -0
- package/src/migrations/types.ts +68 -0
- package/src/prompts/project-intelligence.prompts.ts +70 -0
- package/src/safety/auth-table.guard.ts +67 -0
- package/src/safety/operation.guard.ts +41 -0
- package/src/safety/sql.guard.ts +122 -0
- package/src/sdk/endpoints.ts +240 -0
- package/src/sdk/nestcore.client.ts +1089 -0
- package/src/server.ts +217 -0
- package/src/tools/admin.tools.ts +140 -0
- package/src/tools/analytics.tools.ts +267 -0
- package/src/tools/auth.tools.ts +205 -0
- package/src/tools/background-jobs.tools.ts +203 -0
- package/src/tools/branches.tools.ts +124 -0
- package/src/tools/credits.tools.ts +68 -0
- package/src/tools/dashboard.tools.ts +38 -0
- package/src/tools/database.tools.ts +306 -0
- package/src/tools/function.tools.ts +244 -0
- package/src/tools/index.ts +60 -0
- package/src/tools/integrations.tools.ts +314 -0
- package/src/tools/logging.tools.ts +109 -0
- package/src/tools/migration.tools.ts +116 -0
- package/src/tools/project-intelligence.tools.ts +453 -0
- package/src/tools/project.tools.ts +281 -0
- package/src/tools/realtime.tools.ts +102 -0
- package/src/tools/rls.tools.ts +145 -0
- package/src/tools/smtp.tools.ts +53 -0
- package/src/tools/storage.tools.ts +224 -0
- package/src/types/api.types.ts +176 -0
- package/src/types/config.types.ts +12 -0
- package/src/types/session.types.ts +106 -0
- package/src/utils/errors.ts +117 -0
- package/src/utils/logger.ts +44 -0
- package/src/utils/validators.ts +25 -0
- package/tsconfig.json +20 -0
package/.env.example
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# NestCore Backend Configuration
|
|
2
|
+
# NESTCORE_API_URL must point at the NestCore API whose console hosts the
|
|
3
|
+
# OAuth callback page — used by the nestcore_login (Google/GitHub/Apple) tool.
|
|
4
|
+
NESTCORE_API_URL=https://api.nestcore.io
|
|
5
|
+
NESTCORE_API_BASE_PATH=/api
|
|
6
|
+
# (The pre-rename ORBITNEST_API_URL / ORBITNEST_API_BASE_PATH are still read as fallbacks.)
|
|
7
|
+
|
|
8
|
+
# Authentication
|
|
9
|
+
# Sign in at runtime with nestcore_admin_signin (email + password) or
|
|
10
|
+
# nestcore_login (Google/GitHub/Apple via browser). Tokens are stored in
|
|
11
|
+
# ~/.nestcore/credentials.json — no token needs to be set here.
|
|
12
|
+
|
|
13
|
+
# MCP Server Configuration
|
|
14
|
+
MCP_SERVER_NAME=nestcore
|
|
15
|
+
LOG_LEVEL=info
|
|
16
|
+
|
|
17
|
+
# Workspace Configuration (optional, can be detected)
|
|
18
|
+
DEFAULT_PROJECT_ID=
|
|
19
|
+
|
|
20
|
+
# Safety Configuration
|
|
21
|
+
ENABLE_SQL_GUARD=true
|
|
22
|
+
BLOCK_AUTH_TABLE_MUTATIONS=true
|
|
23
|
+
|
|
24
|
+
# Cache Configuration
|
|
25
|
+
SCHEMA_CACHE_TTL=300000
|
|
26
|
+
TOKEN_REFRESH_THRESHOLD=60000
|
package/.mcp.json
ADDED
package/README.md
CHANGED
|
@@ -1,3 +1,510 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# NestCore MCP Server
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for [NestCore](https://nestcore.io) that enables AI agents (Claude, etc.) to manage your NestCore projects, databases, edge functions, storage, and more through a structured tool interface.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Claude / AI Agent
|
|
9
|
+
↓ MCP Protocol (stdio)
|
|
10
|
+
NestCore MCP Server ← this project
|
|
11
|
+
↓ REST API + JWT
|
|
12
|
+
NestCore Backend (https://api.nestcore.io)
|
|
13
|
+
↓
|
|
14
|
+
PostgreSQL / Storage / Edge Functions
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The MCP server **never accesses the database directly** — all operations are proxied through the NestCore backend API with full JWT authentication.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Prerequisites
|
|
22
|
+
|
|
23
|
+
- **Node.js** v18 or later
|
|
24
|
+
- **npm** v9 or later
|
|
25
|
+
- Access to the GitHub repository `Orbitnest/nestcore_mcp` (or install `@nestcorehq/mcp-server` from npm)
|
|
26
|
+
- NestCore account — sign in at [nestcore.io](https://nestcore.io)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
### Option A — Install directly from GitHub (recommended for new devices)
|
|
33
|
+
|
|
34
|
+
No cloning required. `npm install` downloads the package from GitHub and automatically compiles it via the `prepare` script.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g github:Orbitnest/nestcore_mcp
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
After installation the `nestcore-mcp` binary is available globally:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
nestcore-mcp # starts the MCP server
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The pre-rename `orbitnest-mcp` command is installed too and starts the same server.
|
|
47
|
+
|
|
48
|
+
To install a specific commit or tag:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g github:Orbitnest/nestcore_mcp#v1.0.0
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> **Private repo?** Make sure the machine has GitHub access. Either:
|
|
55
|
+
> - SSH key added to the GitHub account (`git@github.com:...`), or
|
|
56
|
+
> - A [Personal Access Token](https://github.com/settings/tokens) with `repo` scope configured in `~/.npmrc`:
|
|
57
|
+
> ```
|
|
58
|
+
> //npm.pkg.github.com/:_authToken=YOUR_TOKEN
|
|
59
|
+
> ```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Option B — Clone and build locally (for development)
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/Orbitnest/nestcore_mcp.git
|
|
67
|
+
cd nestcore_mcp
|
|
68
|
+
npm install # also runs `npm run build` automatically via prepare script
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
All settings are passed as environment variables. No `.env` file is required when configuring via an MCP client (see below) — simply set them in the `env` block of your MCP config.
|
|
76
|
+
|
|
77
|
+
For standalone use, copy the example file:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
cp .env.example .env
|
|
81
|
+
# then edit .env as needed
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
| Variable | Default | Description |
|
|
85
|
+
|----------|---------|-------------|
|
|
86
|
+
| `NESTCORE_API_URL` | `https://api.nestcore.io` | NestCore backend URL (falls back to `ORBITNEST_API_URL`) |
|
|
87
|
+
| `NESTCORE_API_BASE_PATH` | `/api` | API base path (falls back to `ORBITNEST_API_BASE_PATH`) |
|
|
88
|
+
| `NESTCORE_MIGRATIONS_DIR` | `migrations` | Default migrations directory (falls back to `ORBITNEST_MIGRATIONS_DIR`) |
|
|
89
|
+
| `MCP_SERVER_NAME` | `nestcore` | MCP server identifier |
|
|
90
|
+
| `LOG_LEVEL` | `info` | Logging level: `debug`, `info`, `warn`, `error` |
|
|
91
|
+
| `DEFAULT_PROJECT_ID` | _(empty)_ | Auto-select project on startup |
|
|
92
|
+
| `ENABLE_SQL_GUARD` | `true` | Validate SQL before execution |
|
|
93
|
+
| `BLOCK_AUTH_TABLE_MUTATIONS` | `true` | Block writes to `auth_*` tables |
|
|
94
|
+
| `SCHEMA_CACHE_TTL` | `300000` | Schema cache lifetime in ms (5 min) |
|
|
95
|
+
| `TOKEN_REFRESH_THRESHOLD` | `60000` | Refresh token when < 60s from expiry |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Connecting to Claude Code
|
|
100
|
+
|
|
101
|
+
### Option 1 — Via GitHub (no local clone needed)
|
|
102
|
+
|
|
103
|
+
Add the server globally so it is available in any project. Claude Code will run it directly from the GitHub package:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
claude mcp add nestcore -- npx -y github:Orbitnest/nestcore_mcp
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or edit `~/.claude.json` manually:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"nestcore": {
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["-y", "github:Orbitnest/nestcore_mcp"],
|
|
117
|
+
"env": {
|
|
118
|
+
"NESTCORE_API_URL": "https://api.nestcore.io"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Option 2 — Via globally installed binary
|
|
126
|
+
|
|
127
|
+
If you installed with `npm install -g`:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
claude mcp add nestcore -- nestcore-mcp
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Option 3 — Project-level from local clone
|
|
134
|
+
|
|
135
|
+
The repository's `.mcp.json` is picked up automatically when you open this directory in Claude Code:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm run build # only needed the first time if prepare didn't run
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Verifying the connection
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
claude mcp list
|
|
145
|
+
# Should show: nestcore connected
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Connecting to VSCode
|
|
151
|
+
|
|
152
|
+
The repository includes `.vscode/mcp.json` which is automatically picked up by the **GitHub Copilot / Claude VSCode extension** with MCP support enabled.
|
|
153
|
+
|
|
154
|
+
**Using a local clone (development):**
|
|
155
|
+
|
|
156
|
+
1. Open this folder in VSCode
|
|
157
|
+
2. The `nestcore` server entry in `.vscode/mcp.json` points to `dist/index.js` and starts automatically
|
|
158
|
+
|
|
159
|
+
**Using GitHub install on any other machine:**
|
|
160
|
+
|
|
161
|
+
1. Create or edit `.vscode/mcp.json` in your project:
|
|
162
|
+
|
|
163
|
+
```jsonc
|
|
164
|
+
{
|
|
165
|
+
"servers": {
|
|
166
|
+
"nestcore": {
|
|
167
|
+
"type": "stdio",
|
|
168
|
+
"command": "npx",
|
|
169
|
+
"args": ["-y", "github:Orbitnest/nestcore_mcp"],
|
|
170
|
+
"env": {
|
|
171
|
+
"NESTCORE_API_URL": "https://api.nestcore.io",
|
|
172
|
+
"LOG_LEVEL": "info",
|
|
173
|
+
"ENABLE_SQL_GUARD": "true",
|
|
174
|
+
"BLOCK_AUTH_TABLE_MUTATIONS": "true"
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. Reload the VSCode window (`Ctrl+Shift+P` → `Developer: Reload Window`) — the server starts automatically.
|
|
182
|
+
|
|
183
|
+
To point at a different backend URL, change `NESTCORE_API_URL` in the `env` block.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## First-Time Setup
|
|
188
|
+
|
|
189
|
+
Once connected via Claude Code or VSCode, authenticate and set your project context:
|
|
190
|
+
|
|
191
|
+
**1. Sign in as admin:**
|
|
192
|
+
|
|
193
|
+
If your account has a password:
|
|
194
|
+
```
|
|
195
|
+
Use nestcore_admin_signin with:
|
|
196
|
+
email: "admin@example.com"
|
|
197
|
+
password: "your-password"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
If you signed up with **Google, GitHub, or Apple** (no password), use OAuth.
|
|
201
|
+
This opens your browser to complete sign-in and captures the session
|
|
202
|
+
automatically via a one-time localhost callback:
|
|
203
|
+
```
|
|
204
|
+
Use nestcore_login with:
|
|
205
|
+
provider: "google" # or "github" / "apple"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Credentials are saved to `~/.nestcore/credentials.json` and reloaded automatically on subsequent starts.
|
|
209
|
+
|
|
210
|
+
> `nestcore_login` opens a browser, so run it on the machine where the MCP
|
|
211
|
+
> server runs. It requires `NESTCORE_API_URL` to point at the NestCore API
|
|
212
|
+
> whose console hosts the OAuth callback page (default `https://api.nestcore.io`).
|
|
213
|
+
|
|
214
|
+
**2. List your projects:**
|
|
215
|
+
```
|
|
216
|
+
Use nestcore_list_projects
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**3. Set active project:**
|
|
220
|
+
```
|
|
221
|
+
Use nestcore_set_active_project with:
|
|
222
|
+
projectId: "proj_abc123"
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
All subsequent tools automatically use the active project — you rarely need to specify `projectId` again.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Available Tools
|
|
230
|
+
|
|
231
|
+
Every tool is named `nestcore_*`. Tools were called `orbitnest_*` before the
|
|
232
|
+
rename: `tools/list` only returns the new names, but a `tools/call` for an old
|
|
233
|
+
`orbitnest_*` name still runs the matching `nestcore_*` tool, so clients with a
|
|
234
|
+
cached tool list keep working.
|
|
235
|
+
|
|
236
|
+
### Authentication (8 tools)
|
|
237
|
+
| Tool | Description |
|
|
238
|
+
|------|-------------|
|
|
239
|
+
| `nestcore_admin_signin` | Sign in with email + password and save JWT credentials |
|
|
240
|
+
| `nestcore_login` | Sign in with Google / GitHub / Apple via browser (for password-less accounts) |
|
|
241
|
+
| `nestcore_admin_signup` | Create a new admin account |
|
|
242
|
+
| `nestcore_admin_signup_verified` | Signup with email verification |
|
|
243
|
+
| `nestcore_request_verification` | Request verification code |
|
|
244
|
+
| `nestcore_refresh_token` | Manually refresh JWT token |
|
|
245
|
+
| `nestcore_admin_signout` | Sign out and clear saved credentials |
|
|
246
|
+
| `nestcore_get_profile` | Get current admin profile |
|
|
247
|
+
|
|
248
|
+
### Projects (7 tools)
|
|
249
|
+
| Tool | Description |
|
|
250
|
+
|------|-------------|
|
|
251
|
+
| `nestcore_create_project` | Create project with dedicated database |
|
|
252
|
+
| `nestcore_list_projects` | List all projects |
|
|
253
|
+
| `nestcore_get_project` | Get project details |
|
|
254
|
+
| `nestcore_update_project` | Rename or update project settings |
|
|
255
|
+
| `nestcore_delete_project` | Delete project (requires `confirmDeletion: true`) |
|
|
256
|
+
| `nestcore_get_project_stats` | Get project statistics |
|
|
257
|
+
| `nestcore_get_project_health` | Check project health status |
|
|
258
|
+
|
|
259
|
+
### Database (12 tools)
|
|
260
|
+
| Tool | Description |
|
|
261
|
+
|------|-------------|
|
|
262
|
+
| `nestcore_get_schema` | Fetch full database schema (cached 5 min) |
|
|
263
|
+
| `nestcore_execute_sql` | Execute raw SQL with safety validation |
|
|
264
|
+
| `nestcore_create_table` | Create a table from a structured definition |
|
|
265
|
+
| `nestcore_list_tables` | List all tables |
|
|
266
|
+
| `nestcore_get_table_data` | Query table data with pagination and filtering |
|
|
267
|
+
| `nestcore_insert_row` | Insert a single row |
|
|
268
|
+
| `nestcore_update_row` | Update a row by ID |
|
|
269
|
+
| `nestcore_delete_row` | Delete a row by ID |
|
|
270
|
+
| `nestcore_bulk_insert` | Insert multiple rows |
|
|
271
|
+
| `nestcore_bulk_update` | Update multiple rows |
|
|
272
|
+
| `nestcore_bulk_delete` | Delete multiple rows |
|
|
273
|
+
| `nestcore_get_sql_history` | Retrieve SQL query history |
|
|
274
|
+
|
|
275
|
+
### Row-Level Security (6 tools)
|
|
276
|
+
| Tool | Description |
|
|
277
|
+
|------|-------------|
|
|
278
|
+
| `nestcore_get_rls_status` | Check RLS status on a table |
|
|
279
|
+
| `nestcore_enable_rls` | Enable RLS on a table |
|
|
280
|
+
| `nestcore_disable_rls` | Disable RLS on a table |
|
|
281
|
+
| `nestcore_list_policies` | List RLS policies |
|
|
282
|
+
| `nestcore_create_policy` | Create a new RLS policy |
|
|
283
|
+
| `nestcore_delete_policy` | Delete an RLS policy |
|
|
284
|
+
|
|
285
|
+
### Edge Functions (7 tools)
|
|
286
|
+
| Tool | Description |
|
|
287
|
+
|------|-------------|
|
|
288
|
+
| `nestcore_create_function` | Create an edge function |
|
|
289
|
+
| `nestcore_list_functions` | List all functions |
|
|
290
|
+
| `nestcore_get_function` | Get function details |
|
|
291
|
+
| `nestcore_update_function` | Update function source code |
|
|
292
|
+
| `nestcore_delete_function` | Delete a function |
|
|
293
|
+
| `nestcore_invoke_function` | Execute a function |
|
|
294
|
+
| `nestcore_get_function_logs` | Get function execution logs |
|
|
295
|
+
|
|
296
|
+
> **Function environment:** inside a function, read env vars with `Deno.env.get('NAME')`. Available by default: `NESTCORE_URL`, `NESTCORE_ANON_KEY` (public/RLS-protected), `PROJECT_ID`, `PROJECT_URL`, `FUNCTION_NAME`, plus any project env vars you add. **`NESTCORE_SERVICE_ROLE_KEY` (RLS-bypassing) is NOT provided by default** — if a function needs privileged DB access, add it as a project env var (copy the service_role key from the dashboard → API Keys, or use `nestcore_create_env_variable`). See `docs/known-issues.md` §7.
|
|
297
|
+
|
|
298
|
+
### Storage (9 tools)
|
|
299
|
+
| Tool | Description |
|
|
300
|
+
|------|-------------|
|
|
301
|
+
| `nestcore_list_buckets` | List storage buckets |
|
|
302
|
+
| `nestcore_create_bucket` | Create a new bucket |
|
|
303
|
+
| `nestcore_upload_file` | Upload a file to a bucket |
|
|
304
|
+
| `nestcore_download_file` | Download a file |
|
|
305
|
+
| `nestcore_list_files` | List files in a bucket |
|
|
306
|
+
| `nestcore_delete_files` | Delete files |
|
|
307
|
+
| `nestcore_delete_bucket` | Delete a bucket |
|
|
308
|
+
| `nestcore_get_bucket_size` | Get bucket storage usage |
|
|
309
|
+
| `nestcore_get_public_url` | Get a public file URL |
|
|
310
|
+
|
|
311
|
+
### Logging (6 tools)
|
|
312
|
+
| Tool | Description |
|
|
313
|
+
|------|-------------|
|
|
314
|
+
| `nestcore_get_logs` | Get general logs with filtering |
|
|
315
|
+
| `nestcore_get_database_logs` | Get database operation logs |
|
|
316
|
+
| `nestcore_get_slow_query_logs` | Get slow query logs |
|
|
317
|
+
| `nestcore_get_auth_logs` | Get authentication logs |
|
|
318
|
+
| `nestcore_get_edge_function_logs` | Get edge function logs |
|
|
319
|
+
| `nestcore_export_logs` | Export logs in a specified format |
|
|
320
|
+
|
|
321
|
+
### Admin Management (6 tools)
|
|
322
|
+
| Tool | Description |
|
|
323
|
+
|------|-------------|
|
|
324
|
+
| `nestcore_list_admins` | List all admin users |
|
|
325
|
+
| `nestcore_create_admin` | Create a new admin |
|
|
326
|
+
| `nestcore_get_admin` | Get admin details |
|
|
327
|
+
| `nestcore_update_admin` | Update admin settings |
|
|
328
|
+
| `nestcore_delete_admin` | Delete an admin user |
|
|
329
|
+
| `nestcore_update_admin_password` | Reset admin password |
|
|
330
|
+
|
|
331
|
+
### SMTP (4 tools)
|
|
332
|
+
| Tool | Description |
|
|
333
|
+
|------|-------------|
|
|
334
|
+
| `nestcore_get_smtp_settings` | Get SMTP configuration |
|
|
335
|
+
| `nestcore_update_smtp_settings` | Update SMTP settings |
|
|
336
|
+
| `nestcore_delete_smtp_settings` | Remove SMTP configuration |
|
|
337
|
+
| `nestcore_test_smtp_connection` | Test SMTP connectivity |
|
|
338
|
+
|
|
339
|
+
### Integrations (13 tools)
|
|
340
|
+
| Tool | Description |
|
|
341
|
+
|------|-------------|
|
|
342
|
+
| `nestcore_get_connection_string` | Get the direct Postgres connection string (when enabled) |
|
|
343
|
+
| `nestcore_get_auth_security` | End-user auth limits in force (code length, wrong codes, codes per hour, lockout) |
|
|
344
|
+
| `nestcore_set_auth_security` | Change those limits (admin) |
|
|
345
|
+
| `nestcore_get_ai_settings` | AI gateway keys (masked), default models and spend caps |
|
|
346
|
+
| `nestcore_ai_usage` | AI calls, tokens and cost per day, model and end user |
|
|
347
|
+
| `nestcore_list_webhooks` | List database webhooks |
|
|
348
|
+
| `nestcore_create_webhook` | Create a signed row-change webhook |
|
|
349
|
+
| `nestcore_delete_webhook` | Delete a webhook |
|
|
350
|
+
| `nestcore_test_webhook` | Send a test event to a webhook |
|
|
351
|
+
| `nestcore_get_sms_config` | Get the project's Twilio/SMS config |
|
|
352
|
+
| `nestcore_set_sms_config` | Configure Twilio (auth token stored encrypted) |
|
|
353
|
+
| `nestcore_test_sms` | Send a test SMS |
|
|
354
|
+
| `nestcore_enable_extension` | Enable a Postgres extension (e.g. `vector` for pgvector) |
|
|
355
|
+
|
|
356
|
+
### AI data (6 tools)
|
|
357
|
+
| Tool | Description |
|
|
358
|
+
|------|-------------|
|
|
359
|
+
| `nestcore_ai_overview` | Counts of memories, subjects, collections, documents, threads, messages, traces (24 h) and embedded columns |
|
|
360
|
+
| `nestcore_list_collections` | Vector collections with model, chunking and document counts |
|
|
361
|
+
| `nestcore_memory_subjects` | Subjects that have memories (`user:<id>`, `agent:support`, ...) with counts |
|
|
362
|
+
| `nestcore_list_embeddings` | Automatically embedded columns with progress (rows, embedded, pending, failed, last error) |
|
|
363
|
+
| `nestcore_ai_traces` | Recent AI calls: model, tokens, cost, latency, status (never prompt text) |
|
|
364
|
+
| `nestcore_enable_embeddings` | Embed a table's text columns into a `vector(768)` column kept up to date (admin; requires `confirmEnable: true`) |
|
|
365
|
+
|
|
366
|
+
### AI credits (3 tools)
|
|
367
|
+
Prepaid AI credit is per workspace and pays for AI calls of projects without their own provider key (a project's own key always wins). Calls paid from credit fail with `CREDITS_EXHAUSTED` (`reason`: `balance` or `spend_cap`, plus `buyUrl`) when the balance is gone or the monthly cap is reached.
|
|
368
|
+
|
|
369
|
+
| Tool | Description |
|
|
370
|
+
|------|-------------|
|
|
371
|
+
| `nestcore_get_credits` | Balance, monthly cap, this month's spend, availability, credit packs and the recent ledger |
|
|
372
|
+
| `nestcore_set_credit_cap` | Set the monthly cap in USD, or `null` to remove it (admin) |
|
|
373
|
+
| `nestcore_buy_credits` | Stripe Checkout link for a credit pack, for a person to open and pay (admin; adds no credit by itself) |
|
|
374
|
+
|
|
375
|
+
### Dashboard (2 tools)
|
|
376
|
+
| Tool | Description |
|
|
377
|
+
|------|-------------|
|
|
378
|
+
| `nestcore_get_dashboard_stats` | Get overall statistics |
|
|
379
|
+
| `nestcore_get_dashboard_activity` | Get recent activity feed |
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## Safety Features
|
|
384
|
+
|
|
385
|
+
### SQL Guard
|
|
386
|
+
- Detects and blocks SQL injection patterns
|
|
387
|
+
- Requires `confirmDestructive: true` for `DROP`, `TRUNCATE`, `DELETE` without `WHERE`
|
|
388
|
+
- Blocks mutations on `auth_*` tables (configurable via `BLOCK_AUTH_TABLE_MUTATIONS`)
|
|
389
|
+
|
|
390
|
+
### Operation Guard
|
|
391
|
+
- Bulk operations affecting more than 1,000 rows require explicit confirmation
|
|
392
|
+
- Project deletion always requires `confirmDeletion: true`
|
|
393
|
+
- RLS cannot be disabled on auth tables
|
|
394
|
+
|
|
395
|
+
### Auth Table Protection
|
|
396
|
+
- Tables prefixed with `auth_` are read-only by default
|
|
397
|
+
- Schema changes and direct mutations are blocked
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Common Workflows
|
|
402
|
+
|
|
403
|
+
**Create a table with RLS:**
|
|
404
|
+
```
|
|
405
|
+
nestcore_create_table({
|
|
406
|
+
tableName: "posts",
|
|
407
|
+
columns: [
|
|
408
|
+
{ name: "id", type: "uuid", primaryKey: true, default: "gen_random_uuid()" },
|
|
409
|
+
{ name: "title", type: "text", nullable: false },
|
|
410
|
+
{ name: "body", type: "text" },
|
|
411
|
+
{ name: "created_at", type: "timestamptz", default: "now()" }
|
|
412
|
+
],
|
|
413
|
+
enableRLS: true
|
|
414
|
+
})
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Execute a safe query:**
|
|
418
|
+
```
|
|
419
|
+
nestcore_execute_sql({ sql: "SELECT * FROM posts ORDER BY created_at DESC LIMIT 10" })
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Execute a destructive query (requires explicit confirmation):**
|
|
423
|
+
```
|
|
424
|
+
nestcore_execute_sql({
|
|
425
|
+
sql: "DELETE FROM posts WHERE status = 'draft'",
|
|
426
|
+
confirmDestructive: true
|
|
427
|
+
})
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Deploy an edge function:**
|
|
431
|
+
```
|
|
432
|
+
nestcore_create_function({
|
|
433
|
+
name: "send-welcome",
|
|
434
|
+
sourceCode: "export default async (req) => { return new Response('Hello!'); }"
|
|
435
|
+
})
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Development
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
npm install # installs deps and runs `npm run build` automatically (prepare script)
|
|
444
|
+
npm run dev # TypeScript watch mode (tsx)
|
|
445
|
+
npm run build # Compile to dist/
|
|
446
|
+
npm start # Run compiled server
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Logs are written to **stderr** (MCP protocol uses stdout for communication), so they do not interfere with the MCP message stream.
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Workspace Auto-Detection
|
|
454
|
+
|
|
455
|
+
If your project root contains `.nestcore/config.json`, the MCP server automatically loads the project context on startup:
|
|
456
|
+
|
|
457
|
+
```json
|
|
458
|
+
{
|
|
459
|
+
"projectId": "proj_abc123",
|
|
460
|
+
"projectSlug": "my-project",
|
|
461
|
+
"name": "My Project",
|
|
462
|
+
"apiUrl": "https://api.nestcore.io"
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
This is the same file `nestcore link` (the CLI) writes; older CLI versions wrote `slug` instead of `projectSlug`, which is still read. A pre-rename `.orbitnest/config.json` is read when a directory has no `.nestcore/config.json`; saving the active project then writes `.nestcore/config.json`. `nestcore_set_active_project` updates this file when one was found, and never creates one elsewhere.
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## Credentials Storage
|
|
471
|
+
|
|
472
|
+
After signing in, tokens are persisted to `~/.nestcore/credentials.json` (mode `0600`) and automatically reloaded on the next server start. If that file doesn't exist yet, the pre-rename `~/.orbitnest/credentials.json` is used (and kept in sync while it exists, so older CLI/MCP versions sharing it stay signed in). Tokens are refreshed automatically when they are within 60 seconds of expiry.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## Troubleshooting
|
|
477
|
+
|
|
478
|
+
**Server fails to start**
|
|
479
|
+
- If using a local clone, run `npm run build` — the `dist/` directory must exist
|
|
480
|
+
- Check that Node.js v18+ is installed: `node --version`
|
|
481
|
+
- If using `npx github:Orbitnest/nestcore_mcp`, ensure you have GitHub access (SSH key or token)
|
|
482
|
+
|
|
483
|
+
**`Not authenticated` errors**
|
|
484
|
+
- Run `nestcore_admin_signin` to sign in
|
|
485
|
+
- Credentials are stored in `~/.nestcore/credentials.json`
|
|
486
|
+
|
|
487
|
+
**`No active project` errors**
|
|
488
|
+
- Run `nestcore_list_projects` then `nestcore_set_active_project`
|
|
489
|
+
- Or set `DEFAULT_PROJECT_ID` in your environment / MCP `env` block
|
|
490
|
+
|
|
491
|
+
**MCP server not appearing in VSCode**
|
|
492
|
+
- Ensure MCP support is enabled in the extension settings
|
|
493
|
+
- Confirm `npm run build` has been run if using a local clone
|
|
494
|
+
- Reload the VSCode window (`Ctrl+Shift+P` → `Developer: Reload Window`)
|
|
495
|
+
- When using `npx github:...`, the first start may take a few seconds while npm downloads the package
|
|
496
|
+
|
|
497
|
+
**MCP server not appearing in Claude Code**
|
|
498
|
+
- Run `claude mcp list` to see registered servers
|
|
499
|
+
- Re-register: `claude mcp remove nestcore && claude mcp add nestcore -- npx -y github:Orbitnest/nestcore_mcp`
|
|
500
|
+
- If using project-level `.mcp.json`, ensure you opened Claude Code from this project directory
|
|
501
|
+
|
|
502
|
+
**GitHub access errors during npx install**
|
|
503
|
+
- Add your SSH key: `ssh-add ~/.ssh/id_rsa`
|
|
504
|
+
- Or create a GitHub Personal Access Token with `repo` scope and set it in `~/.npmrc`:
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## License
|
|
509
|
+
|
|
510
|
+
MIT — NestCore Team
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StoredCredentials } from '../types/session.types.js';
|
|
2
|
+
export declare function loadCredentials(): StoredCredentials | null;
|
|
3
|
+
/**
|
|
4
|
+
* Merge into the existing file (keeps fields the CLI owns, e.g. `apiUrl`) and
|
|
5
|
+
* write atomically (temp file + rename) so a concurrent reader never sees a
|
|
6
|
+
* partial file.
|
|
7
|
+
*/
|
|
8
|
+
export declare function saveCredentials(credentials: StoredCredentials): void;
|
|
9
|
+
/** Run `fn` while holding the cross-process credentials lock (shared with the CLI). */
|
|
10
|
+
export declare function withCredentialsLock<T>(fn: () => Promise<T>): Promise<T>;
|
|
11
|
+
export declare function clearCredentials(): void;
|
|
12
|
+
//# sourceMappingURL=credentials.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.service.d.ts","sourceRoot":"","sources":["../../src/auth/credentials.service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAYnE,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAa1D;AAgBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAapE;AAED,uFAAuF;AACvF,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAuB7E;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAYvC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import * as os from 'node:os';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
const CREDENTIALS_DIR = path.join(os.homedir(), '.nestcore');
|
|
6
|
+
const CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, 'credentials.json');
|
|
7
|
+
// Pre-rename location: read when the new file is absent, and kept in sync while it
|
|
8
|
+
// exists so an older CLI/MCP sharing it never replays a rotated refresh token.
|
|
9
|
+
const LEGACY_CREDENTIALS_FILE = path.join(os.homedir(), '.orbitnest', 'credentials.json');
|
|
10
|
+
// Advisory lock shared with the NestCore CLI — serialises refresh-token
|
|
11
|
+
// rotation across processes (the API revokes every session of the admin when a
|
|
12
|
+
// consumed refresh token is replayed).
|
|
13
|
+
const CREDENTIALS_LOCK = path.join(CREDENTIALS_DIR, 'credentials.lock');
|
|
14
|
+
export function loadCredentials() {
|
|
15
|
+
try {
|
|
16
|
+
const file = [CREDENTIALS_FILE, LEGACY_CREDENTIALS_FILE].find((f) => fs.existsSync(f));
|
|
17
|
+
if (!file) {
|
|
18
|
+
logger.debug('No credentials file found');
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const raw = fs.readFileSync(file, 'utf-8');
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
logger.warn('Failed to load credentials', { error: String(err) });
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeAtomic(file, body) {
|
|
30
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
31
|
+
fs.writeFileSync(tmp, body, { mode: 0o600 });
|
|
32
|
+
try {
|
|
33
|
+
fs.renameSync(tmp, file);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// Windows can refuse the rename while another process has the file open.
|
|
37
|
+
fs.writeFileSync(file, body, { mode: 0o600 });
|
|
38
|
+
try {
|
|
39
|
+
fs.unlinkSync(tmp);
|
|
40
|
+
}
|
|
41
|
+
catch { /* ignore */ }
|
|
42
|
+
}
|
|
43
|
+
// `mode` only applies on creation — tighten a pre-existing wider file too.
|
|
44
|
+
try {
|
|
45
|
+
fs.chmodSync(file, 0o600);
|
|
46
|
+
}
|
|
47
|
+
catch { /* no-op on Windows */ }
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Merge into the existing file (keeps fields the CLI owns, e.g. `apiUrl`) and
|
|
51
|
+
* write atomically (temp file + rename) so a concurrent reader never sees a
|
|
52
|
+
* partial file.
|
|
53
|
+
*/
|
|
54
|
+
export function saveCredentials(credentials) {
|
|
55
|
+
try {
|
|
56
|
+
fs.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });
|
|
57
|
+
const body = JSON.stringify({ ...(loadCredentials() ?? {}), ...credentials }, null, 2);
|
|
58
|
+
writeAtomic(CREDENTIALS_FILE, body);
|
|
59
|
+
if (fs.existsSync(LEGACY_CREDENTIALS_FILE)) {
|
|
60
|
+
try {
|
|
61
|
+
writeAtomic(LEGACY_CREDENTIALS_FILE, body);
|
|
62
|
+
}
|
|
63
|
+
catch { /* best-effort */ }
|
|
64
|
+
}
|
|
65
|
+
logger.info('Credentials saved');
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
logger.error('Failed to save credentials', { error: String(err) });
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Run `fn` while holding the cross-process credentials lock (shared with the CLI). */
|
|
73
|
+
export async function withCredentialsLock(fn) {
|
|
74
|
+
fs.mkdirSync(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });
|
|
75
|
+
const deadline = Date.now() + 90_000;
|
|
76
|
+
let fd;
|
|
77
|
+
while (fd === undefined) {
|
|
78
|
+
try {
|
|
79
|
+
fd = fs.openSync(CREDENTIALS_LOCK, 'wx');
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
if (e.code !== 'EEXIST')
|
|
83
|
+
throw e;
|
|
84
|
+
// A holder that crashed leaves the lock behind; a refresh never takes 75s.
|
|
85
|
+
try {
|
|
86
|
+
if (Date.now() - fs.statSync(CREDENTIALS_LOCK).mtimeMs > 75_000)
|
|
87
|
+
fs.unlinkSync(CREDENTIALS_LOCK);
|
|
88
|
+
}
|
|
89
|
+
catch { /* raced with the holder */ }
|
|
90
|
+
if (Date.now() > deadline)
|
|
91
|
+
throw new Error(`Timed out waiting for ${CREDENTIALS_LOCK}`);
|
|
92
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
return await fn();
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
fs.closeSync(fd);
|
|
100
|
+
try {
|
|
101
|
+
fs.unlinkSync(CREDENTIALS_LOCK);
|
|
102
|
+
}
|
|
103
|
+
catch { /* ignore */ }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function clearCredentials() {
|
|
107
|
+
try {
|
|
108
|
+
// Clear the pre-rename file too, or it would be read back as a fallback.
|
|
109
|
+
for (const file of [CREDENTIALS_FILE, LEGACY_CREDENTIALS_FILE]) {
|
|
110
|
+
if (fs.existsSync(file)) {
|
|
111
|
+
fs.unlinkSync(file);
|
|
112
|
+
logger.info('Credentials cleared', { file });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
logger.warn('Failed to clear credentials', { error: String(err) });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=credentials.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.service.js","sourceRoot":"","sources":["../../src/auth/credentials.service.ts"],"names":[],"mappings":"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"}
|