@yinuo-ngm/mcp-server 0.1.2 → 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 +191 -208
- 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 +67 -10
- 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 +6 -1
- package/lib/tools/hub-v2/client.js +15 -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.js +138 -4
- package/lib/tools/hub-v2/index.js +2 -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.js +96 -6
- package/lib/tools/hub-v2/projects.tools.js +16 -3
- 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.js +167 -8
- package/lib/tools/hub-v2/schemas.d.ts +668 -71
- package/lib/tools/hub-v2/schemas.js +152 -1
- package/lib/tools/hub-v2/upload.tools.js +53 -5
- package/lib/tools/index.d.ts +1 -0
- package/lib/tools/index.js +22 -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.js +6 -1
- package/lib/utils/result.d.ts +9 -0
- package/lib/utils/result.js +9 -0
- 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 +5 -3
- package/lib/tools/hub-v2/config.d.ts +0 -34
- package/lib/tools/hub-v2/config.js +0 -297
package/README.md
CHANGED
|
@@ -1,69 +1,50 @@
|
|
|
1
|
-
# @yinuo-ngm/mcp-server
|
|
2
|
-
|
|
3
|
-
Local MCP
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
10
12
|
|
|
11
13
|
```text
|
|
12
|
-
|
|
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
|
|
13
45
|
```
|
|
14
46
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Hub V2 tools are the exception: they may call the Hub V2 Token HTTP API because that API is the integration contract Hub V2 exposes to AI Agents and other external clients. Those tools must keep token handling inside configuration/client layers and must not accept token values as tool arguments.
|
|
18
|
-
|
|
19
|
-
The MCP server must not provide arbitrary shell execution, mutate system environment settings, or remotely execute client-side commands.
|
|
20
|
-
|
|
21
|
-
## Safety
|
|
22
|
-
|
|
23
|
-
Tools are assigned one risk level:
|
|
24
|
-
|
|
25
|
-
```text
|
|
26
|
-
read
|
|
27
|
-
write
|
|
28
|
-
execute
|
|
29
|
-
dangerous
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Default policy:
|
|
33
|
-
|
|
34
|
-
```text
|
|
35
|
-
read allowed
|
|
36
|
-
write blocked
|
|
37
|
-
execute blocked
|
|
38
|
-
dangerous blocked
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Write tools are registered only for scoped Hub V2 Personal Token workflows that require explicit tool confirmation when implemented. The server does not implement arbitrary shell execution, task start/stop/restart, git pull/checkout/commit/reset, proxy reload, runtime install/remove, file deletion, system environment mutation, or remote client command execution.
|
|
42
|
-
|
|
43
|
-
## Environment
|
|
44
|
-
|
|
45
|
-
```text
|
|
46
|
-
NGM_DATA_DIR ng-manager data directory. Defaults to ~/.ng-manager.
|
|
47
|
-
NGM_WORKSPACE_ROOT Optional workspace hint. Defaults to process.cwd().
|
|
48
|
-
NGM_MCP_UPLOAD_ROOT Optional extra root for Hub V2 markdown image uploads.
|
|
49
|
-
NGM_MCP_MAX_UPLOAD_BYTES Max Hub V2 markdown image upload bytes. Defaults to 5242880.
|
|
50
|
-
NGM_MCP_MAX_RESULT_CHARS Max MCP text result characters. Defaults to 120000.
|
|
51
|
-
NGM_MCP_ALLOW_WRITE Enables confirmed write tools. Defaults to false.
|
|
52
|
-
NGM_MCP_ALLOW_EXECUTE Enables execute tools. Defaults to false.
|
|
53
|
-
NGM_MCP_ALLOW_DANGEROUS Enables dangerous tools. Defaults to false.
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Commands
|
|
57
|
-
|
|
58
|
-
From the repository root:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
npm run mcp:dev
|
|
62
|
-
npm run mcp:build
|
|
63
|
-
npm run mcp:start
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Direct workspace commands:
|
|
47
|
+
Workspace commands:
|
|
67
48
|
|
|
68
49
|
```bash
|
|
69
50
|
npm run dev -w @yinuo-ngm/mcp-server
|
|
@@ -71,172 +52,174 @@ npm run build -w @yinuo-ngm/mcp-server
|
|
|
71
52
|
npm run start -w @yinuo-ngm/mcp-server
|
|
72
53
|
```
|
|
73
54
|
|
|
74
|
-
CLI
|
|
55
|
+
CLI:
|
|
75
56
|
|
|
76
57
|
```bash
|
|
77
58
|
ngm mcp
|
|
78
59
|
```
|
|
79
60
|
|
|
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
|
-
"-w",
|
|
117
|
-
"@yinuo-ngm/mcp-server"
|
|
118
|
-
],
|
|
119
|
-
"env": {
|
|
120
|
-
"NGM_DATA_DIR": "C:/Users/you/.ng-manager",
|
|
121
|
-
"NGM_WORKSPACE_ROOT": "D:/ng-manager"
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
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
|
+
}
|
|
125
97
|
}
|
|
126
98
|
```
|
|
127
99
|
|
|
128
|
-
|
|
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
|
|
129
123
|
|
|
130
|
-
|
|
124
|
+
### Nginx
|
|
131
125
|
|
|
132
|
-
|
|
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:
|
|
133
155
|
|
|
134
156
|
```text
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
read
|
|
158
|
+
write
|
|
159
|
+
execute
|
|
160
|
+
dangerous
|
|
139
161
|
```
|
|
140
162
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
## Tools
|
|
144
|
-
|
|
145
|
-
Project:
|
|
146
|
-
|
|
147
|
-
```text
|
|
148
|
-
ngm.project.list
|
|
149
|
-
ngm.project.get
|
|
150
|
-
ngm.project.getScripts
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
Task:
|
|
154
|
-
|
|
155
|
-
```text
|
|
156
|
-
ngm.task.list
|
|
157
|
-
ngm.task.getStatus
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Log:
|
|
161
|
-
|
|
162
|
-
```text
|
|
163
|
-
ngm.log.tail
|
|
164
|
-
ngm.log.search
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
Git:
|
|
168
|
-
|
|
169
|
-
```text
|
|
170
|
-
ngm.git.status
|
|
171
|
-
ngm.git.diff
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
The Git tools are registered in this MVP but return a clear "not implemented in core yet" error through the Git service stub. A future phase should add a read-only Git service to `packages/core` first.
|
|
175
|
-
|
|
176
|
-
Runtime:
|
|
163
|
+
Default policy:
|
|
177
164
|
|
|
178
165
|
```text
|
|
179
|
-
|
|
180
|
-
|
|
166
|
+
read allowed
|
|
167
|
+
write blocked
|
|
168
|
+
execute blocked
|
|
169
|
+
dangerous blocked
|
|
181
170
|
```
|
|
182
171
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
|
191
184
|
|
|
192
|
-
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Documentation
|
|
188
|
+
|
|
189
|
+
Detailed documentation is maintained under:
|
|
190
|
+
|
|
191
|
+
```text
|
|
192
|
+
packages/mcp-server/docs/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Recommended structure:
|
|
193
196
|
|
|
194
197
|
```text
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
hub_v2_rd_list
|
|
207
|
-
hub_v2_rd_get
|
|
208
|
-
hub_v2_rd_stage_tasks_list
|
|
209
|
-
hub_v2_rd_create
|
|
210
|
-
hub_v2_rd_advance_stage
|
|
211
|
-
hub_v2_rd_stage_tasks_create
|
|
212
|
-
hub_v2_rd_update_progress
|
|
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
|
|
213
209
|
```
|
|
214
210
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
Errors use:
|
|
231
|
-
|
|
232
|
-
```json
|
|
233
|
-
{
|
|
234
|
-
"ok": false,
|
|
235
|
-
"tool": "ngm.project.get",
|
|
236
|
-
"error": "projectId or projectPath is required"
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Replacing Stubs
|
|
241
|
-
|
|
242
|
-
Add missing capabilities to `packages/core` first, then replace the corresponding service inside `ToolContext.services`. MCP tools should remain thin adapters that validate input, enforce policy, call core services, and cap output size.
|
|
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[];
|