@yinuo-ngm/mcp-server 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -188
- package/lib/audit/audit-event.d.ts +14 -0
- package/lib/audit/audit-event.js +2 -0
- package/lib/audit/audit-log.service.d.ts +7 -0
- package/lib/audit/audit-log.service.js +187 -0
- package/lib/audit/redact.d.ts +3 -0
- package/lib/audit/redact.js +28 -0
- package/lib/catalog/capabilities/blocked-local-actions.d.ts +1 -0
- package/lib/catalog/capabilities/blocked-local-actions.js +18 -0
- package/lib/catalog/capabilities/frontend-standard.d.ts +2 -0
- package/lib/catalog/capabilities/frontend-standard.js +36 -0
- package/lib/catalog/capabilities/hub-v2.d.ts +2 -0
- package/lib/catalog/capabilities/hub-v2.js +34 -0
- package/lib/catalog/capabilities/nginx.d.ts +2 -0
- package/lib/catalog/capabilities/nginx.js +23 -0
- package/lib/catalog/capabilities/project.d.ts +2 -0
- package/lib/catalog/capabilities/project.js +23 -0
- package/lib/catalog/capabilities/router.d.ts +2 -0
- package/lib/catalog/capabilities/router.js +11 -0
- package/lib/catalog/capabilities/runtime.d.ts +2 -0
- package/lib/catalog/capabilities/runtime.js +17 -0
- package/lib/catalog/capabilities/workspace.d.ts +2 -0
- package/lib/catalog/capabilities/workspace.js +23 -0
- package/lib/catalog/helpers.d.ts +3 -0
- package/lib/catalog/helpers.js +42 -0
- package/lib/catalog/index.d.ts +4 -0
- package/lib/catalog/index.js +23 -0
- package/lib/catalog/tools/frontend-standard.d.ts +2 -0
- package/lib/catalog/tools/frontend-standard.js +166 -0
- package/lib/catalog/tools/hub-v2-api.d.ts +2 -0
- package/lib/catalog/tools/hub-v2-api.js +124 -0
- package/lib/catalog/tools/hub-v2-docs.d.ts +2 -0
- package/lib/catalog/tools/hub-v2-docs.js +40 -0
- package/lib/catalog/tools/nginx.d.ts +2 -0
- package/lib/catalog/tools/nginx.js +96 -0
- package/lib/catalog/tools/project.d.ts +2 -0
- package/lib/catalog/tools/project.js +138 -0
- package/lib/catalog/tools/router.d.ts +2 -0
- package/lib/catalog/tools/router.js +26 -0
- package/lib/catalog/tools/runtime.d.ts +2 -0
- package/lib/catalog/tools/runtime.js +47 -0
- package/lib/catalog/tools/workspace.d.ts +2 -0
- package/lib/catalog/tools/workspace.js +75 -0
- package/lib/catalog/types.d.ts +15 -0
- package/lib/catalog/types.js +2 -0
- package/lib/context/create-tool-context.js +11 -10
- package/lib/context/local-server-client.d.ts +2 -0
- package/lib/context/local-server-client.js +174 -0
- package/lib/context/tool-context.d.ts +36 -0
- package/lib/doctor.d.ts +8 -0
- package/lib/doctor.js +221 -0
- package/lib/errors/error-codes.d.ts +12 -0
- package/lib/errors/error-codes.js +14 -0
- package/lib/errors/mcp-tool-error.d.ts +8 -0
- package/lib/errors/mcp-tool-error.js +14 -0
- package/lib/filesystem/project-files.d.ts +18 -0
- package/lib/filesystem/project-files.js +112 -0
- package/lib/git/local-git-read-service.d.ts +2 -0
- package/lib/git/local-git-read-service.js +96 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +4 -0
- package/lib/policy/assert-tool-policy.js +10 -1
- package/lib/register-tools.js +70 -9
- package/lib/registry/tool-names.d.ts +95 -0
- package/lib/registry/tool-names.js +97 -0
- package/lib/services/path-guard.service.d.ts +4 -0
- package/lib/services/path-guard.service.js +75 -0
- package/lib/services/permission.service.d.ts +5 -0
- package/lib/services/permission.service.js +38 -0
- package/lib/services/project-resolver.service.d.ts +32 -0
- package/lib/services/project-resolver.service.js +95 -0
- package/lib/standard/frontend-standard.default.d.ts +2 -0
- package/lib/standard/frontend-standard.default.js +51 -0
- package/lib/standard/frontend-standard.schema.d.ts +196 -0
- package/lib/standard/frontend-standard.schema.js +61 -0
- package/lib/standard/frontend-standard.service.d.ts +79 -0
- package/lib/standard/frontend-standard.service.js +115 -0
- package/lib/standard/project-scan.d.ts +9 -0
- package/lib/standard/project-scan.js +91 -0
- package/lib/standard/validators/angular-structure.validator.d.ts +4 -0
- package/lib/standard/validators/angular-structure.validator.js +75 -0
- package/lib/standard/validators/component.validator.d.ts +4 -0
- package/lib/standard/validators/component.validator.js +94 -0
- package/lib/standard/validators/git.validator.d.ts +8 -0
- package/lib/standard/validators/git.validator.js +32 -0
- package/lib/standard/validators/review.validator.d.ts +15 -0
- package/lib/standard/validators/review.validator.js +67 -0
- package/lib/standard/validators/test.validator.d.ts +19 -0
- package/lib/standard/validators/test.validator.js +89 -0
- package/lib/tool-catalog.d.ts +2 -0
- package/lib/tool-catalog.js +6 -0
- package/lib/tools/angular/angular-standard.tools.d.ts +2 -0
- package/lib/tools/angular/angular-standard.tools.js +53 -0
- package/lib/tools/angular/index.d.ts +1 -0
- package/lib/tools/angular/index.js +5 -0
- package/lib/tools/capability.tools.d.ts +2 -0
- package/lib/tools/capability.tools.js +205 -0
- package/lib/tools/controlled/index.d.ts +2 -0
- package/lib/tools/controlled/index.js +13 -0
- package/lib/tools/controlled/local-server.d.ts +6 -0
- package/lib/tools/controlled/local-server.js +17 -0
- package/lib/tools/controlled/operation-policy.d.ts +22 -0
- package/lib/tools/controlled/operation-policy.js +50 -0
- package/lib/tools/controlled/operation-result.d.ts +30 -0
- package/lib/tools/controlled/operation-result.js +33 -0
- package/lib/tools/controlled/schemas.d.ts +159 -0
- package/lib/tools/controlled/schemas.js +49 -0
- package/lib/tools/controlled.tools.d.ts +1 -0
- package/lib/tools/controlled.tools.js +5 -0
- package/lib/tools/file-write.tools.d.ts +2 -0
- package/lib/tools/file-write.tools.js +70 -0
- package/lib/tools/git.tools.js +109 -8
- package/lib/tools/hub-v2/client.d.ts +20 -0
- package/lib/tools/hub-v2/client.js +112 -0
- package/lib/tools/hub-v2/config/config-paths.d.ts +2 -0
- package/lib/tools/hub-v2/config/config-paths.js +17 -0
- package/lib/tools/hub-v2/config/env.d.ts +1 -0
- package/lib/tools/hub-v2/config/env.js +12 -0
- package/lib/tools/hub-v2/config/index.d.ts +8 -0
- package/lib/tools/hub-v2/config/index.js +18 -0
- package/lib/tools/hub-v2/config/jsonc.d.ts +5 -0
- package/lib/tools/hub-v2/config/jsonc.js +86 -0
- package/lib/tools/hub-v2/config/load-config.d.ts +18 -0
- package/lib/tools/hub-v2/config/load-config.js +93 -0
- package/lib/tools/hub-v2/config/project-selector.d.ts +5 -0
- package/lib/tools/hub-v2/config/project-selector.js +92 -0
- package/lib/tools/hub-v2/config/resolve-context.d.ts +13 -0
- package/lib/tools/hub-v2/config/resolve-context.js +33 -0
- package/lib/tools/hub-v2/docs.tools.d.ts +2 -0
- package/lib/tools/hub-v2/docs.tools.js +215 -0
- package/lib/tools/hub-v2/errors.d.ts +8 -0
- package/lib/tools/hub-v2/errors.js +27 -0
- package/lib/tools/hub-v2/index.d.ts +2 -0
- package/lib/tools/hub-v2/index.js +19 -0
- package/lib/tools/hub-v2/issues-workflow.tools.d.ts +2 -0
- package/lib/tools/hub-v2/issues-workflow.tools.js +199 -0
- package/lib/tools/hub-v2/issues.tools.d.ts +2 -0
- package/lib/tools/hub-v2/issues.tools.js +244 -0
- package/lib/tools/hub-v2/projects.tools.d.ts +2 -0
- package/lib/tools/hub-v2/projects.tools.js +41 -0
- package/lib/tools/hub-v2/raw.d.ts +8 -0
- package/lib/tools/hub-v2/raw.js +33 -0
- package/lib/tools/hub-v2/rd.tools.d.ts +2 -0
- package/lib/tools/hub-v2/rd.tools.js +361 -0
- package/lib/tools/hub-v2/schemas.d.ts +1182 -0
- package/lib/tools/hub-v2/schemas.js +318 -0
- package/lib/tools/hub-v2/upload.tools.d.ts +2 -0
- package/lib/tools/hub-v2/upload.tools.js +198 -0
- package/lib/tools/index.d.ts +3 -0
- package/lib/tools/index.js +24 -0
- package/lib/tools/log.tools.js +33 -6
- package/lib/tools/nginx/index.d.ts +1 -0
- package/lib/tools/nginx/index.js +5 -0
- package/lib/tools/nginx/nginx-control.tools.d.ts +2 -0
- package/lib/tools/nginx/nginx-control.tools.js +133 -0
- package/lib/tools/nginx/nginx-proxy.d.ts +24 -0
- package/lib/tools/nginx/nginx-proxy.js +154 -0
- package/lib/tools/nginx.tools.d.ts +2 -0
- package/lib/tools/nginx.tools.js +111 -0
- package/lib/tools/project/index.d.ts +2 -0
- package/lib/tools/project/index.js +7 -0
- package/lib/tools/project/launch-status.d.ts +10 -0
- package/lib/tools/project/launch-status.js +78 -0
- package/lib/tools/project/local-diagnostics.d.ts +19 -0
- package/lib/tools/project/local-diagnostics.js +97 -0
- package/lib/tools/project/observe-redaction.d.ts +3 -0
- package/lib/tools/project/observe-redaction.js +25 -0
- package/lib/tools/project/observe-runtime.d.ts +72 -0
- package/lib/tools/project/observe-runtime.js +147 -0
- package/lib/tools/project/project-control.tools.d.ts +2 -0
- package/lib/tools/project/project-control.tools.js +216 -0
- package/lib/tools/project/project-observe.tools.d.ts +2 -0
- package/lib/tools/project/project-observe.tools.js +191 -0
- package/lib/tools/project/runtime-config.d.ts +7 -0
- package/lib/tools/project/runtime-config.js +50 -0
- package/lib/tools/project-observe.tools.d.ts +1 -0
- package/lib/tools/project-observe.tools.js +5 -0
- package/lib/tools/project.tools.d.ts +8 -0
- package/lib/tools/project.tools.js +97 -6
- package/lib/tools/proxy.tools.js +4 -4
- package/lib/tools/review/index.d.ts +1 -0
- package/lib/tools/review/index.js +5 -0
- package/lib/tools/review/review.tools.d.ts +2 -0
- package/lib/tools/review/review.tools.js +152 -0
- package/lib/tools/runtime/index.d.ts +1 -0
- package/lib/tools/runtime/index.js +5 -0
- package/lib/tools/runtime/runtime-control.tools.d.ts +2 -0
- package/lib/tools/runtime/runtime-control.tools.js +89 -0
- package/lib/tools/runtime.tools.js +41 -4
- package/lib/tools/standard/index.d.ts +1 -0
- package/lib/tools/standard/index.js +5 -0
- package/lib/tools/standard/standard.tools.d.ts +2 -0
- package/lib/tools/standard/standard.tools.js +91 -0
- package/lib/tools/task.tools.js +44 -9
- package/lib/tools/test/index.d.ts +1 -0
- package/lib/tools/test/index.js +5 -0
- package/lib/tools/test/test-standard.tools.d.ts +2 -0
- package/lib/tools/test/test-standard.tools.js +51 -0
- package/lib/tools/tool-catalog.d.ts +2 -0
- package/lib/tools/tool-catalog.js +7 -0
- package/lib/tools/workflow/frontend-workflow.tools.d.ts +2 -0
- package/lib/tools/workflow/frontend-workflow.tools.js +364 -0
- package/lib/tools/workflow/index.d.ts +1 -0
- package/lib/tools/workflow/index.js +5 -0
- package/lib/tools/workspace-package.d.ts +22 -0
- package/lib/tools/workspace-package.js +130 -0
- package/lib/tools/workspace.tools.d.ts +7 -0
- package/lib/tools/workspace.tools.js +336 -0
- package/lib/utils/errors.d.ts +5 -0
- package/lib/utils/errors.js +17 -0
- package/lib/utils/result.d.ts +20 -2
- package/lib/utils/result.js +108 -3
- package/lib/workflow/frontend-task.schema.d.ts +83 -0
- package/lib/workflow/frontend-task.schema.js +25 -0
- package/lib/workflow/frontend-task.service.d.ts +57 -0
- package/lib/workflow/frontend-task.service.js +195 -0
- package/lib/workflow/workflow-status.d.ts +2 -0
- package/lib/workflow/workflow-status.js +14 -0
- package/lib/workflow/workflow-transition.d.ts +9 -0
- package/lib/workflow/workflow-transition.js +38 -0
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,188 +1,225 @@
|
|
|
1
|
-
# @yinuo-ngm/mcp-server
|
|
2
|
-
|
|
3
|
-
Local MCP
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
1
|
+
# @yinuo-ngm/mcp-server
|
|
2
|
+
|
|
3
|
+
Local MCP Server for ng-manager.
|
|
4
|
+
|
|
5
|
+
Provides MCP tools that expose ng-manager capabilities to AI Agents such as Codex, OpenCode, Claude Code, Cursor, and other MCP-compatible clients.
|
|
6
|
+
|
|
7
|
+
The MCP server is an adapter layer only. Business logic belongs in `packages/core`.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Architecture
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
AI Agent
|
|
15
|
+
↓
|
|
16
|
+
MCP Client
|
|
17
|
+
↓
|
|
18
|
+
packages/mcp-server
|
|
19
|
+
↓
|
|
20
|
+
ToolContext.services
|
|
21
|
+
↓
|
|
22
|
+
packages/core
|
|
23
|
+
↓
|
|
24
|
+
Local Services
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Principles:
|
|
28
|
+
|
|
29
|
+
- MCP tools are thin adapters
|
|
30
|
+
- No duplicated business logic
|
|
31
|
+
- No Fastify dependency
|
|
32
|
+
- No Electron dependency
|
|
33
|
+
- Reuse the same core services as CLI, UI, and Local Server
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
Repository root:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm run mcp:dev
|
|
43
|
+
npm run mcp:build
|
|
44
|
+
npm run mcp:start
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Workspace commands:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm run dev -w @yinuo-ngm/mcp-server
|
|
51
|
+
npm run build -w @yinuo-ngm/mcp-server
|
|
52
|
+
npm run start -w @yinuo-ngm/mcp-server
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
CLI:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
ngm mcp
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Diagnostics:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
ngm mcp doctor
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Environment Variables
|
|
70
|
+
|
|
71
|
+
| Variable | Description |
|
|
72
|
+
|-----------|-------------|
|
|
73
|
+
| NGM_DATA_DIR | ng-manager data directory |
|
|
74
|
+
| NGM_MCP_ALLOW_WRITE | Enable write tools |
|
|
75
|
+
| NGM_MCP_ALLOW_EXECUTE | Enable execute tools |
|
|
76
|
+
| NGM_MCP_ALLOW_DANGEROUS | Enable dangerous tools |
|
|
77
|
+
| NGM_MCP_ALLOW_HUB | Enable Hub V2 write operations |
|
|
78
|
+
| NGM_MCP_MAX_RESULT_CHARS | MCP response size limit |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## MCP Client Example
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"mcpServers": {
|
|
87
|
+
"ng-manager": {
|
|
88
|
+
"command": "node",
|
|
89
|
+
"args": [
|
|
90
|
+
"packages/mcp-server/lib/index.js"
|
|
91
|
+
],
|
|
92
|
+
"env": {
|
|
93
|
+
"NGM_DATA_DIR": "~/.ng-manager"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Tool Categories
|
|
103
|
+
|
|
104
|
+
### Workspace
|
|
105
|
+
|
|
106
|
+
- Workspace discovery
|
|
107
|
+
- Package metadata
|
|
108
|
+
- Capability routing
|
|
109
|
+
- Context generation
|
|
110
|
+
|
|
111
|
+
### Project
|
|
112
|
+
|
|
113
|
+
- Project metadata
|
|
114
|
+
- Package.json access
|
|
115
|
+
- Script discovery
|
|
116
|
+
- Task status and logs
|
|
117
|
+
|
|
118
|
+
### Runtime
|
|
119
|
+
|
|
120
|
+
- Node runtime discovery
|
|
121
|
+
- Runtime resolution
|
|
122
|
+
- Project runtime configuration
|
|
123
|
+
|
|
124
|
+
### Nginx
|
|
125
|
+
|
|
126
|
+
- Status inspection
|
|
127
|
+
- Configuration validation
|
|
128
|
+
- Proxy management
|
|
129
|
+
|
|
130
|
+
### Git
|
|
131
|
+
|
|
132
|
+
- Status and diff
|
|
133
|
+
- Commit message generation
|
|
134
|
+
- Review assistance
|
|
135
|
+
|
|
136
|
+
### Frontend Workflow
|
|
137
|
+
|
|
138
|
+
- Standards validation
|
|
139
|
+
- Review scanning
|
|
140
|
+
- Task planning
|
|
141
|
+
- Delivery reports
|
|
142
|
+
|
|
143
|
+
### Hub V2
|
|
144
|
+
|
|
145
|
+
- Documents
|
|
146
|
+
- Issues
|
|
147
|
+
- RD workflows
|
|
148
|
+
- File uploads
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Safety Model
|
|
153
|
+
|
|
154
|
+
Risk levels:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
read
|
|
158
|
+
write
|
|
159
|
+
execute
|
|
160
|
+
dangerous
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Default policy:
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
read allowed
|
|
167
|
+
write blocked
|
|
168
|
+
execute blocked
|
|
169
|
+
dangerous blocked
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Write and execute operations require:
|
|
173
|
+
|
|
174
|
+
- `confirm=true`
|
|
175
|
+
- Matching environment flag enabled
|
|
176
|
+
- Policy validation passed
|
|
177
|
+
|
|
178
|
+
The MCP server does not provide:
|
|
179
|
+
|
|
180
|
+
- Arbitrary shell execution
|
|
181
|
+
- Arbitrary file system access
|
|
182
|
+
- System environment mutation
|
|
183
|
+
- Remote client command execution
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Documentation
|
|
188
|
+
|
|
189
|
+
Detailed documentation is maintained under:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
packages/mcp-server/docs/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Recommended structure:
|
|
196
|
+
|
|
197
|
+
```text
|
|
198
|
+
docs/
|
|
199
|
+
├─ architecture.md
|
|
200
|
+
├─ security.md
|
|
201
|
+
├─ configuration.md
|
|
202
|
+
└─ tools/
|
|
203
|
+
├─ ngm-workspace.md
|
|
204
|
+
├─ ngm-project.md
|
|
205
|
+
├─ ngm-runtime.md
|
|
206
|
+
├─ ngm-nginx.md
|
|
207
|
+
├─ ngm-git.md
|
|
208
|
+
└─ hub-v2.md
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Design Goal
|
|
214
|
+
|
|
215
|
+
ng-manager MCP Server is the unified AI integration layer for local-first engineering workflows.
|
|
216
|
+
|
|
217
|
+
```text
|
|
218
|
+
AI Agent
|
|
219
|
+
↓
|
|
220
|
+
MCP
|
|
221
|
+
↓
|
|
222
|
+
ng-manager Core
|
|
223
|
+
↓
|
|
224
|
+
Local Control Plane
|
|
225
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ToolRiskLevel } from "../policy/tool-policy";
|
|
2
|
+
import type { ToolResult } from "../utils/result";
|
|
3
|
+
export type AuditToolEvent = {
|
|
4
|
+
tool: string;
|
|
5
|
+
riskLevel: ToolRiskLevel;
|
|
6
|
+
args?: unknown;
|
|
7
|
+
result?: ToolResult;
|
|
8
|
+
error?: unknown;
|
|
9
|
+
durationMs: number;
|
|
10
|
+
};
|
|
11
|
+
export type AuditWarning = {
|
|
12
|
+
code: "AUDIT_LOG_WRITE_FAILED";
|
|
13
|
+
message: string;
|
|
14
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolRiskLevel } from "../policy/tool-policy";
|
|
2
|
+
import type { ToolContext } from "../context/tool-context";
|
|
3
|
+
import type { AuditToolEvent, AuditWarning } from "./audit-event";
|
|
4
|
+
export declare function summarizeAuditArgs(args: unknown): Record<string, unknown>;
|
|
5
|
+
export declare function writeAuditLog(context: ToolContext, event: AuditToolEvent): Promise<void>;
|
|
6
|
+
export declare function shouldAuditTool(toolName: string, riskLevel: ToolRiskLevel): boolean;
|
|
7
|
+
export declare function auditWarning(error: unknown): AuditWarning;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.summarizeAuditArgs = summarizeAuditArgs;
|
|
37
|
+
exports.writeAuditLog = writeAuditLog;
|
|
38
|
+
exports.shouldAuditTool = shouldAuditTool;
|
|
39
|
+
exports.auditWarning = auditWarning;
|
|
40
|
+
const fs = __importStar(require("fs/promises"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const project_files_1 = require("../filesystem/project-files");
|
|
43
|
+
const redact_1 = require("./redact");
|
|
44
|
+
function isRecord(value) {
|
|
45
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
46
|
+
}
|
|
47
|
+
function getString(value, key) {
|
|
48
|
+
return isRecord(value) && typeof value[key] === "string" ? value[key] : undefined;
|
|
49
|
+
}
|
|
50
|
+
function normalizePath(value) {
|
|
51
|
+
const resolved = path.resolve(value);
|
|
52
|
+
return process.platform === "win32" ? resolved.replace(/\\/g, "/").toLowerCase() : resolved;
|
|
53
|
+
}
|
|
54
|
+
async function registeredProjectByPath(context, projectPath) {
|
|
55
|
+
const list = context.services.core?.project?.list;
|
|
56
|
+
if (typeof list !== "function")
|
|
57
|
+
return null;
|
|
58
|
+
let projects;
|
|
59
|
+
try {
|
|
60
|
+
projects = await list.call(context.services.core.project);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (!Array.isArray(projects))
|
|
66
|
+
return null;
|
|
67
|
+
const requested = normalizePath(projectPath);
|
|
68
|
+
const matched = projects.find((project) => typeof project?.root === "string" && normalizePath(project.root) === requested);
|
|
69
|
+
return matched ? {
|
|
70
|
+
projectId: typeof matched.id === "string" ? matched.id : undefined,
|
|
71
|
+
projectName: typeof matched.name === "string" ? matched.name : undefined,
|
|
72
|
+
projectRoot: path.resolve(matched.root),
|
|
73
|
+
} : null;
|
|
74
|
+
}
|
|
75
|
+
async function resolveAuditProjectRoot(context, args) {
|
|
76
|
+
const projectId = getString(args, "projectId");
|
|
77
|
+
if (projectId) {
|
|
78
|
+
const project = await context.services.core.project.get(projectId);
|
|
79
|
+
return {
|
|
80
|
+
projectId: project.id,
|
|
81
|
+
projectName: project.name,
|
|
82
|
+
projectRoot: path.resolve(project.root),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const projectPath = getString(args, "projectPath");
|
|
86
|
+
if (projectPath) {
|
|
87
|
+
const requestedRoot = path.resolve(projectPath);
|
|
88
|
+
const registered = await registeredProjectByPath(context, requestedRoot);
|
|
89
|
+
if (registered)
|
|
90
|
+
return registered;
|
|
91
|
+
throw new Error("Audit projectPath must match a registered project root");
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
projectRoot: path.resolve(context.workspaceRoot),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function byteLength(value) {
|
|
98
|
+
return typeof value === "string" ? Buffer.byteLength(value, "utf-8") : undefined;
|
|
99
|
+
}
|
|
100
|
+
function shortText(value, maxChars = 200) {
|
|
101
|
+
if (typeof value !== "string")
|
|
102
|
+
return undefined;
|
|
103
|
+
const redacted = (0, redact_1.redactText)(value);
|
|
104
|
+
return redacted.length > maxChars ? `${redacted.slice(0, maxChars)}...` : redacted;
|
|
105
|
+
}
|
|
106
|
+
function summarizeAuditArgs(args) {
|
|
107
|
+
const source = isRecord(args) ? args : {};
|
|
108
|
+
const out = {};
|
|
109
|
+
for (const key of ["projectId", "projectPath", "taskId"]) {
|
|
110
|
+
const value = getString(source, key);
|
|
111
|
+
if (value)
|
|
112
|
+
out[key] = value;
|
|
113
|
+
}
|
|
114
|
+
for (const key of ["confirm", "dryRun", "overwrite"]) {
|
|
115
|
+
if (typeof source[key] === "boolean")
|
|
116
|
+
out[key] = source[key];
|
|
117
|
+
}
|
|
118
|
+
const title = shortText(source.title);
|
|
119
|
+
if (title)
|
|
120
|
+
out.title = title;
|
|
121
|
+
const patchBytes = byteLength(source.patch);
|
|
122
|
+
if (patchBytes !== undefined)
|
|
123
|
+
out.patchBytes = patchBytes;
|
|
124
|
+
const contextBytes = byteLength(source.context);
|
|
125
|
+
if (contextBytes !== undefined)
|
|
126
|
+
out.contextBytes = contextBytes;
|
|
127
|
+
const markdownBytes = byteLength(source.markdown);
|
|
128
|
+
if (markdownBytes !== undefined)
|
|
129
|
+
out.markdownBytes = markdownBytes;
|
|
130
|
+
const summaryBytes = byteLength(source.summary);
|
|
131
|
+
if (summaryBytes !== undefined)
|
|
132
|
+
out.summaryBytes = summaryBytes;
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
function resultStatus(result, error) {
|
|
136
|
+
if (error) {
|
|
137
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
138
|
+
return message.includes("blocked by policy") ? "blocked" : "failed";
|
|
139
|
+
}
|
|
140
|
+
if (!result)
|
|
141
|
+
return "unknown";
|
|
142
|
+
if (!result.ok)
|
|
143
|
+
return "failed";
|
|
144
|
+
const data = isRecord(result.data) ? result.data : {};
|
|
145
|
+
const operation = isRecord(data.operation) ? data.operation : undefined;
|
|
146
|
+
return typeof operation?.status === "string" ? operation.status : "ok";
|
|
147
|
+
}
|
|
148
|
+
function changedFilesFromResult(result) {
|
|
149
|
+
if (!result?.ok || !isRecord(result.data))
|
|
150
|
+
return [];
|
|
151
|
+
const value = result.data.changedFiles;
|
|
152
|
+
if (!Array.isArray(value))
|
|
153
|
+
return [];
|
|
154
|
+
return value.filter((item) => typeof item === "string").slice(0, 100);
|
|
155
|
+
}
|
|
156
|
+
function todayFileName(now = new Date()) {
|
|
157
|
+
return `mcp-${now.toISOString().slice(0, 10)}.jsonl`;
|
|
158
|
+
}
|
|
159
|
+
async function writeAuditLog(context, event) {
|
|
160
|
+
const args = isRecord(event.args) ? event.args : {};
|
|
161
|
+
const project = await resolveAuditProjectRoot(context, args);
|
|
162
|
+
const auditPath = (0, project_files_1.resolveNgManagerPath)(project.projectRoot, "audit", todayFileName());
|
|
163
|
+
const entry = {
|
|
164
|
+
time: new Date().toISOString(),
|
|
165
|
+
tool: event.tool,
|
|
166
|
+
riskLevel: event.riskLevel,
|
|
167
|
+
projectId: getString(args, "projectId") ?? project.projectId,
|
|
168
|
+
projectRoot: project.projectRoot,
|
|
169
|
+
taskId: getString(args, "taskId"),
|
|
170
|
+
status: resultStatus(event.result, event.error),
|
|
171
|
+
changedFiles: changedFilesFromResult(event.result),
|
|
172
|
+
durationMs: event.durationMs,
|
|
173
|
+
error: event.error ? (0, redact_1.redactValue)(event.error instanceof Error ? event.error.message : String(event.error)) : undefined,
|
|
174
|
+
argsSummary: summarizeAuditArgs(event.args),
|
|
175
|
+
};
|
|
176
|
+
await fs.mkdir(path.dirname(auditPath), { recursive: true });
|
|
177
|
+
await fs.appendFile(auditPath, `${JSON.stringify(entry)}\n`, "utf-8");
|
|
178
|
+
}
|
|
179
|
+
function shouldAuditTool(toolName, riskLevel) {
|
|
180
|
+
return riskLevel !== "read" || toolName.startsWith("ngm_workflow_");
|
|
181
|
+
}
|
|
182
|
+
function auditWarning(error) {
|
|
183
|
+
return {
|
|
184
|
+
code: "AUDIT_LOG_WRITE_FAILED",
|
|
185
|
+
message: error instanceof Error ? error.message : String(error),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SENSITIVE_KEY_RE = void 0;
|
|
4
|
+
exports.redactText = redactText;
|
|
5
|
+
exports.redactValue = redactValue;
|
|
6
|
+
exports.SENSITIVE_KEY_RE = /(authorization|cookie|token|password|passwd|secret|api[-_]?key|access[-_]?token|refresh[-_]?token|private[-_]?key|env)/i;
|
|
7
|
+
function redactText(value) {
|
|
8
|
+
return value
|
|
9
|
+
.replace(/(^|\n)([A-Z0-9_]*(?:TOKEN|PASSWORD|PASSWD|SECRET|API_KEY|ACCESS_TOKEN|REFRESH_TOKEN|AUTHORIZATION|COOKIE)[A-Z0-9_]*\s*=\s*)[^\r\n]+/gi, "$1$2[REDACTED]")
|
|
10
|
+
.replace(/(^|\n)(\s*[A-Za-z0-9_.-]*\.env\s*[:=]\s*)[^\r\n]+/gi, "$1$2[REDACTED]")
|
|
11
|
+
.replace(/(authorization\s*[:=]\s*)(bearer\s+)?[^\s,;]+/gi, "$1[REDACTED]")
|
|
12
|
+
.replace(/(cookie\s*[:=]\s*)[^\r\n]+/gi, "$1[REDACTED]")
|
|
13
|
+
.replace(/((?:token|password|passwd|secret|api[-_]?key|access[-_]?token|refresh[-_]?token|private[-_]?key)\s*[:=]\s*)("[^"]*"|'[^']*'|[^\s,;&]+)/gi, "$1[REDACTED]")
|
|
14
|
+
.replace(/([?&](?:token|password|passwd|secret|api[-_]?key|access[-_]?token|refresh[-_]?token)=)[^&\s]+/gi, "$1[REDACTED]");
|
|
15
|
+
}
|
|
16
|
+
function redactValue(value) {
|
|
17
|
+
if (typeof value === "string")
|
|
18
|
+
return redactText(value);
|
|
19
|
+
if (Array.isArray(value))
|
|
20
|
+
return value.map(redactValue);
|
|
21
|
+
if (typeof value !== "object" || value === null)
|
|
22
|
+
return value;
|
|
23
|
+
const out = {};
|
|
24
|
+
for (const [key, item] of Object.entries(value)) {
|
|
25
|
+
out[key] = exports.SENSITIVE_KEY_RE.test(key) ? "[REDACTED]" : redactValue(item);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const blockedLocalActions: string[];
|