mcp-nervous-system 1.5.1 → 1.6.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/README.md +2 -2
- package/README.md.bak.1772792496 +172 -0
- package/README.md.bak.1772792812 +172 -0
- package/index.js +290 -71
- package/nervous-system.config.example.json +10 -0
- package/package.json +3 -3
- package/package.json.bak.1772792496 +42 -0
- package/package.json.bak.1772792812 +42 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
7 mechanically enforced rules that prevent the most common failure modes when LLMs have access to real infrastructure: context loss, silent failures, file damage, goal drift, and overreach.
|
|
6
6
|
|
|
7
|
-
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System.
|
|
7
|
+
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System. 16 tools including configuration drift detection and emergency kill switch. Battle-tested on an 11-member AI family running 30 processes 24/7 on a single VPS. 58+ violations logged, 0 bypassed.
|
|
8
8
|
|
|
9
9
|
## The Problem
|
|
10
10
|
|
|
@@ -60,7 +60,7 @@ Protocol: MCP 2024-11-05 (Streamable HTTP + SSE)
|
|
|
60
60
|
Authentication: None required
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
## NEW in v1.5.
|
|
63
|
+
## NEW in v1.5.1
|
|
64
64
|
|
|
65
65
|
**drift_audit** (free tier)
|
|
66
66
|
Configuration drift detection across 5 scopes: roles, versions, files, processes, and website. Scans source-of-truth files (family-roles.json, package.json, UNTOUCHABLE_FILES.txt) against all downstream references - HTML pages, JSON configs, markdown docs, and running PM2 processes. Change one file, drift_audit tells you everywhere else that needs updating. The closed loop that keeps your entire system consistent.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# The Nervous System
|
|
2
|
+
|
|
3
|
+
**LLM Behavioral Enforcement Framework**
|
|
4
|
+
|
|
5
|
+
7 mechanically enforced rules that prevent the most common failure modes when LLMs have access to real infrastructure: context loss, silent failures, file damage, goal drift, and overreach.
|
|
6
|
+
|
|
7
|
+
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System. 15 tools including configuration drift detection and emergency kill switch. Battle-tested on an 11-member AI family running 28 processes 24/7 on a single VPS. 58+ violations logged, 0 bypassed.
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
When you give an LLM access to your file system, bash, and production infrastructure, it will eventually:
|
|
12
|
+
|
|
13
|
+
- Edit a file it shouldn't touch
|
|
14
|
+
- Lose context between sessions and start over
|
|
15
|
+
- Drift from the original objective during long tasks
|
|
16
|
+
- Fail silently when a session times out
|
|
17
|
+
- Make logic changes without asking
|
|
18
|
+
- Disappear into debug loops
|
|
19
|
+
|
|
20
|
+
The Nervous System solves all of these with rules enforced by external mechanisms the LLM cannot override.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
### Claude Desktop
|
|
25
|
+
|
|
26
|
+
Add to your `claude_desktop_config.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"nervous-system": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "mcp-nervous-system"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Claude Code
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
claude mcp add nervous-system npx mcp-nervous-system
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Direct
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx mcp-nervous-system
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Server starts on port 3475 with SSE, HTTP, and health endpoints.
|
|
52
|
+
|
|
53
|
+
### Hosted (No Install)
|
|
54
|
+
|
|
55
|
+
The server is live and ready to use:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
URL: https://api.100levelup.com/mcp-ns/
|
|
59
|
+
Protocol: MCP 2024-11-05 (Streamable HTTP + SSE)
|
|
60
|
+
Authentication: None required
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## NEW in v1.5.0
|
|
64
|
+
|
|
65
|
+
**drift_audit** (free tier)
|
|
66
|
+
Configuration drift detection across 5 scopes: roles, versions, files, processes, and website. Scans source-of-truth files (family-roles.json, package.json, UNTOUCHABLE_FILES.txt) against all downstream references - HTML pages, JSON configs, markdown docs, and running PM2 processes. Change one file, drift_audit tells you everywhere else that needs updating. The closed loop that keeps your entire system consistent.
|
|
67
|
+
|
|
68
|
+
**Positioning: Auto mode decides what Claude CAN do. The Nervous System governs HOW it behaves while doing it.**
|
|
69
|
+
|
|
70
|
+
## The 7 Rules
|
|
71
|
+
|
|
72
|
+
| # | Rule | What It Prevents |
|
|
73
|
+
|---|------|-----------------|
|
|
74
|
+
| 1 | **Dispatch Don't Do** | Debug loops, rabbit holes. Tasks > 2 messages get dispatched. |
|
|
75
|
+
| 2 | **Untouchable** | File damage. Protected files mechanically blocked from editing. |
|
|
76
|
+
| 3 | **Write Progress** | Silent failures. Progress noted before each action. |
|
|
77
|
+
| 4 | **Step Back Every 4** | Goal drift. Forced reflection every 4 messages. |
|
|
78
|
+
| 5 | **Delegate and Return** | Invisible work. Background tasks reported immediately. |
|
|
79
|
+
| 6 | **Ask Before Touching** | Unauthorized changes. Logic changes need human approval. |
|
|
80
|
+
| 7 | **Hand Off** | Context loss. Written handoffs every 3-4 exchanges. |
|
|
81
|
+
|
|
82
|
+
## MCP Tools (12)
|
|
83
|
+
|
|
84
|
+
| Tool | Description |
|
|
85
|
+
|------|------------|
|
|
86
|
+
| `get_framework` | Complete framework: all rules, permission protocol, enforcement patterns |
|
|
87
|
+
| `guardrail_rules` | The 7 core rules with triggers, enforcement, and failure modes |
|
|
88
|
+
| `preflight_check` | File protection system: shell script blocks edits to protected files |
|
|
89
|
+
| `session_handoff` | Context preservation: templates for handoff documents |
|
|
90
|
+
| `worklog` | Progress documentation pattern |
|
|
91
|
+
| `violation_logging` | Audit trail: timestamp, type, context for every violation |
|
|
92
|
+
| `step_back_check` | Forced reflection system |
|
|
93
|
+
| `get_nervous_system_info` | System overview and operational stats |
|
|
94
|
+
| `emergency_kill_switch` | Emergency shutdown of all PM2 processes. Requires kill switch secret. Logs to tamper-evident audit trail |
|
|
95
|
+
| `verify_audit_chain` | Walks the SHA-256 hash-chained audit log and verifies every entry. Returns chain integrity status |
|
|
96
|
+
| `dispatch_to_llm` | Spawns a background LLM agent to handle a task. Checks RAM, enforces max 2 concurrent dispatches |
|
|
97
|
+
| `drift_audit` | Configuration drift detection across roles, versions, files, processes, and website. Finds stale values everywhere. |
|
|
98
|
+
|
|
99
|
+
## Kill Switch
|
|
100
|
+
|
|
101
|
+
The `emergency_kill_switch` tool provides an emergency shutdown capability. Send a POST request to `/kill` with the kill switch secret to immediately stop all PM2 processes. Every activation is logged to the tamper-evident audit trail with SHA-256 hash chaining, so kill switch events cannot be hidden or altered after the fact.
|
|
102
|
+
|
|
103
|
+
- Requires authentication (kill switch secret)
|
|
104
|
+
- Logs to hash-chained audit trail
|
|
105
|
+
- Returns confirmation with affected process count
|
|
106
|
+
|
|
107
|
+
## Tamper-Evident Audit Trail
|
|
108
|
+
|
|
109
|
+
Every guardrail violation, kill switch activation, and dispatch event is recorded in a SHA-256 hash-chained audit log. Each entry includes the hash of the previous entry, making it cryptographically impossible to alter or delete past records without breaking the chain.
|
|
110
|
+
|
|
111
|
+
- Use `verify_audit_chain` to walk the entire chain and verify integrity
|
|
112
|
+
- Returns: valid/invalid status, entry count, and break point if tampered
|
|
113
|
+
- 58+ violations logged, 0 bypassed, 0 chain breaks
|
|
114
|
+
|
|
115
|
+
## Dispatch to LLM
|
|
116
|
+
|
|
117
|
+
The `dispatch_to_llm` tool enables a brain + agents architecture. Instead of one LLM session doing everything, complex tasks get dispatched to background agents that run independently under the same 7 rules.
|
|
118
|
+
|
|
119
|
+
- Checks available RAM (requires 500MB+)
|
|
120
|
+
- Enforces max 2 concurrent dispatches
|
|
121
|
+
- Returns PID and log file path for monitoring
|
|
122
|
+
- Every dispatched agent runs under the same nervous system guardrails
|
|
123
|
+
|
|
124
|
+
## EU AI Act Compliance
|
|
125
|
+
|
|
126
|
+
The Nervous System provides practical compliance tools for the EU AI Act. See the full compliance page at:
|
|
127
|
+
|
|
128
|
+
https://api.100levelup.com/family/eu-ai-act.html
|
|
129
|
+
|
|
130
|
+
## Resources (5)
|
|
131
|
+
|
|
132
|
+
- `nervous-system://framework` - The complete framework
|
|
133
|
+
- `nervous-system://quick-start` - Quick start guide
|
|
134
|
+
- `nervous-system://rules` - The 7 core rules
|
|
135
|
+
- `nervous-system://templates` - Templates for handoffs, worklogs, preflight
|
|
136
|
+
- `nervous-system://drift-audit` - Configuration drift detection
|
|
137
|
+
|
|
138
|
+
## Production Stats
|
|
139
|
+
|
|
140
|
+
From the live Palyan Family AI System deployment (Feb 28 - Mar 5, 2026):
|
|
141
|
+
|
|
142
|
+
- **58+** violations caught
|
|
143
|
+
- **29** edits blocked by preflight
|
|
144
|
+
- **13** unique files protected
|
|
145
|
+
- **0** rules bypassed
|
|
146
|
+
- **28** processes monitored
|
|
147
|
+
- **7** days continuous operation
|
|
148
|
+
|
|
149
|
+
## Live Demo
|
|
150
|
+
|
|
151
|
+
Try it yourself (no login required):
|
|
152
|
+
|
|
153
|
+
- **[Interactive Demo](https://api.100levelup.com/family/arthur.html?guest=1)** - Talk to a governed LLM and try to break the rules
|
|
154
|
+
- **[Audit Dashboard](https://api.100levelup.com/family/audit.html)** - See real violation history with timeline
|
|
155
|
+
- **[System Status](https://api.100levelup.com/family/status.html)** - Live health checks
|
|
156
|
+
- **[API Documentation](https://api.100levelup.com/family/api-docs.html)** - Full tool and resource reference
|
|
157
|
+
- **[Case Study](https://api.100levelup.com/family/case-study.html)** - Production deployment data
|
|
158
|
+
- **[Plain English Rules](https://api.100levelup.com/family/rules-plain.html)** - For non-technical stakeholders
|
|
159
|
+
- **[Incident Response](https://api.100levelup.com/family/incident-response.html)** - Detection, containment, resolution
|
|
160
|
+
- **[EU AI Act Compliance](https://api.100levelup.com/family/eu-ai-act.html)** - Practical EU AI Act compliance tools
|
|
161
|
+
|
|
162
|
+
## Philosophy
|
|
163
|
+
|
|
164
|
+
> "LLMs can't reliably self-enforce promises. Guardrails work via preflight.sh, violation logs, and catching drift. Build enforcement systems, don't make promises."
|
|
165
|
+
|
|
166
|
+
If a guardrail can be violated by the thing it guards, it is not a guardrail. It is a suggestion.
|
|
167
|
+
|
|
168
|
+
Every rule in the Nervous System is enforced by an external mechanism: a shell script, a timer, a separate monitoring process. The LLM cannot override, circumvent, or ignore them.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# The Nervous System
|
|
2
|
+
|
|
3
|
+
**LLM Behavioral Enforcement Framework**
|
|
4
|
+
|
|
5
|
+
7 mechanically enforced rules that prevent the most common failure modes when LLMs have access to real infrastructure: context loss, silent failures, file damage, goal drift, and overreach.
|
|
6
|
+
|
|
7
|
+
Built by [Arthur Palyan](https://www.levelsofself.com) at Palyan Family AI System. 15 tools including configuration drift detection and emergency kill switch. Battle-tested on an 11-member AI family running 30 processes 24/7 on a single VPS. 58+ violations logged, 0 bypassed.
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
When you give an LLM access to your file system, bash, and production infrastructure, it will eventually:
|
|
12
|
+
|
|
13
|
+
- Edit a file it shouldn't touch
|
|
14
|
+
- Lose context between sessions and start over
|
|
15
|
+
- Drift from the original objective during long tasks
|
|
16
|
+
- Fail silently when a session times out
|
|
17
|
+
- Make logic changes without asking
|
|
18
|
+
- Disappear into debug loops
|
|
19
|
+
|
|
20
|
+
The Nervous System solves all of these with rules enforced by external mechanisms the LLM cannot override.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
### Claude Desktop
|
|
25
|
+
|
|
26
|
+
Add to your `claude_desktop_config.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"nervous-system": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "mcp-nervous-system"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Claude Code
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
claude mcp add nervous-system npx mcp-nervous-system
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Direct
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npx mcp-nervous-system
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Server starts on port 3475 with SSE, HTTP, and health endpoints.
|
|
52
|
+
|
|
53
|
+
### Hosted (No Install)
|
|
54
|
+
|
|
55
|
+
The server is live and ready to use:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
URL: https://api.100levelup.com/mcp-ns/
|
|
59
|
+
Protocol: MCP 2024-11-05 (Streamable HTTP + SSE)
|
|
60
|
+
Authentication: None required
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## NEW in v1.5.0
|
|
64
|
+
|
|
65
|
+
**drift_audit** (free tier)
|
|
66
|
+
Configuration drift detection across 5 scopes: roles, versions, files, processes, and website. Scans source-of-truth files (family-roles.json, package.json, UNTOUCHABLE_FILES.txt) against all downstream references - HTML pages, JSON configs, markdown docs, and running PM2 processes. Change one file, drift_audit tells you everywhere else that needs updating. The closed loop that keeps your entire system consistent.
|
|
67
|
+
|
|
68
|
+
**Positioning: Auto mode decides what Claude CAN do. The Nervous System governs HOW it behaves while doing it.**
|
|
69
|
+
|
|
70
|
+
## The 7 Rules
|
|
71
|
+
|
|
72
|
+
| # | Rule | What It Prevents |
|
|
73
|
+
|---|------|-----------------|
|
|
74
|
+
| 1 | **Dispatch Don't Do** | Debug loops, rabbit holes. Tasks > 2 messages get dispatched. |
|
|
75
|
+
| 2 | **Untouchable** | File damage. Protected files mechanically blocked from editing. |
|
|
76
|
+
| 3 | **Write Progress** | Silent failures. Progress noted before each action. |
|
|
77
|
+
| 4 | **Step Back Every 4** | Goal drift. Forced reflection every 4 messages. |
|
|
78
|
+
| 5 | **Delegate and Return** | Invisible work. Background tasks reported immediately. |
|
|
79
|
+
| 6 | **Ask Before Touching** | Unauthorized changes. Logic changes need human approval. |
|
|
80
|
+
| 7 | **Hand Off** | Context loss. Written handoffs every 3-4 exchanges. |
|
|
81
|
+
|
|
82
|
+
## MCP Tools (12)
|
|
83
|
+
|
|
84
|
+
| Tool | Description |
|
|
85
|
+
|------|------------|
|
|
86
|
+
| `get_framework` | Complete framework: all rules, permission protocol, enforcement patterns |
|
|
87
|
+
| `guardrail_rules` | The 7 core rules with triggers, enforcement, and failure modes |
|
|
88
|
+
| `preflight_check` | File protection system: shell script blocks edits to protected files |
|
|
89
|
+
| `session_handoff` | Context preservation: templates for handoff documents |
|
|
90
|
+
| `worklog` | Progress documentation pattern |
|
|
91
|
+
| `violation_logging` | Audit trail: timestamp, type, context for every violation |
|
|
92
|
+
| `step_back_check` | Forced reflection system |
|
|
93
|
+
| `get_nervous_system_info` | System overview and operational stats |
|
|
94
|
+
| `emergency_kill_switch` | Emergency shutdown of all PM2 processes. Requires kill switch secret. Logs to tamper-evident audit trail |
|
|
95
|
+
| `verify_audit_chain` | Walks the SHA-256 hash-chained audit log and verifies every entry. Returns chain integrity status |
|
|
96
|
+
| `dispatch_to_llm` | Spawns a background LLM agent to handle a task. Checks RAM, enforces max 2 concurrent dispatches |
|
|
97
|
+
| `drift_audit` | Configuration drift detection across roles, versions, files, processes, and website. Finds stale values everywhere. |
|
|
98
|
+
|
|
99
|
+
## Kill Switch
|
|
100
|
+
|
|
101
|
+
The `emergency_kill_switch` tool provides an emergency shutdown capability. Send a POST request to `/kill` with the kill switch secret to immediately stop all PM2 processes. Every activation is logged to the tamper-evident audit trail with SHA-256 hash chaining, so kill switch events cannot be hidden or altered after the fact.
|
|
102
|
+
|
|
103
|
+
- Requires authentication (kill switch secret)
|
|
104
|
+
- Logs to hash-chained audit trail
|
|
105
|
+
- Returns confirmation with affected process count
|
|
106
|
+
|
|
107
|
+
## Tamper-Evident Audit Trail
|
|
108
|
+
|
|
109
|
+
Every guardrail violation, kill switch activation, and dispatch event is recorded in a SHA-256 hash-chained audit log. Each entry includes the hash of the previous entry, making it cryptographically impossible to alter or delete past records without breaking the chain.
|
|
110
|
+
|
|
111
|
+
- Use `verify_audit_chain` to walk the entire chain and verify integrity
|
|
112
|
+
- Returns: valid/invalid status, entry count, and break point if tampered
|
|
113
|
+
- 58+ violations logged, 0 bypassed, 0 chain breaks
|
|
114
|
+
|
|
115
|
+
## Dispatch to LLM
|
|
116
|
+
|
|
117
|
+
The `dispatch_to_llm` tool enables a brain + agents architecture. Instead of one LLM session doing everything, complex tasks get dispatched to background agents that run independently under the same 7 rules.
|
|
118
|
+
|
|
119
|
+
- Checks available RAM (requires 500MB+)
|
|
120
|
+
- Enforces max 2 concurrent dispatches
|
|
121
|
+
- Returns PID and log file path for monitoring
|
|
122
|
+
- Every dispatched agent runs under the same nervous system guardrails
|
|
123
|
+
|
|
124
|
+
## EU AI Act Compliance
|
|
125
|
+
|
|
126
|
+
The Nervous System provides practical compliance tools for the EU AI Act. See the full compliance page at:
|
|
127
|
+
|
|
128
|
+
https://api.100levelup.com/family/eu-ai-act.html
|
|
129
|
+
|
|
130
|
+
## Resources (5)
|
|
131
|
+
|
|
132
|
+
- `nervous-system://framework` - The complete framework
|
|
133
|
+
- `nervous-system://quick-start` - Quick start guide
|
|
134
|
+
- `nervous-system://rules` - The 7 core rules
|
|
135
|
+
- `nervous-system://templates` - Templates for handoffs, worklogs, preflight
|
|
136
|
+
- `nervous-system://drift-audit` - Configuration drift detection
|
|
137
|
+
|
|
138
|
+
## Production Stats
|
|
139
|
+
|
|
140
|
+
From the live Palyan Family AI System deployment (Feb 28 - Mar 5, 2026):
|
|
141
|
+
|
|
142
|
+
- **58+** violations caught
|
|
143
|
+
- **29** edits blocked by preflight
|
|
144
|
+
- **13** unique files protected
|
|
145
|
+
- **0** rules bypassed
|
|
146
|
+
- **28** processes monitored
|
|
147
|
+
- **7** days continuous operation
|
|
148
|
+
|
|
149
|
+
## Live Demo
|
|
150
|
+
|
|
151
|
+
Try it yourself (no login required):
|
|
152
|
+
|
|
153
|
+
- **[Interactive Demo](https://api.100levelup.com/family/arthur.html?guest=1)** - Talk to a governed LLM and try to break the rules
|
|
154
|
+
- **[Audit Dashboard](https://api.100levelup.com/family/audit.html)** - See real violation history with timeline
|
|
155
|
+
- **[System Status](https://api.100levelup.com/family/status.html)** - Live health checks
|
|
156
|
+
- **[API Documentation](https://api.100levelup.com/family/api-docs.html)** - Full tool and resource reference
|
|
157
|
+
- **[Case Study](https://api.100levelup.com/family/case-study.html)** - Production deployment data
|
|
158
|
+
- **[Plain English Rules](https://api.100levelup.com/family/rules-plain.html)** - For non-technical stakeholders
|
|
159
|
+
- **[Incident Response](https://api.100levelup.com/family/incident-response.html)** - Detection, containment, resolution
|
|
160
|
+
- **[EU AI Act Compliance](https://api.100levelup.com/family/eu-ai-act.html)** - Practical EU AI Act compliance tools
|
|
161
|
+
|
|
162
|
+
## Philosophy
|
|
163
|
+
|
|
164
|
+
> "LLMs can't reliably self-enforce promises. Guardrails work via preflight.sh, violation logs, and catching drift. Build enforcement systems, don't make promises."
|
|
165
|
+
|
|
166
|
+
If a guardrail can be violated by the thing it guards, it is not a guardrail. It is a suggestion.
|
|
167
|
+
|
|
168
|
+
Every rule in the Nervous System is enforced by an external mechanism: a shell script, a timer, a separate monitoring process. The LLM cannot override, circumvent, or ignore them.
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
package/index.js
CHANGED
|
@@ -5,11 +5,62 @@ const crypto = require('crypto');
|
|
|
5
5
|
const { spawn } = require('child_process');
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
// ============================================================
|
|
12
|
+
// PROJECT CONFIGURATION - Auto-discover or use config file
|
|
13
|
+
// ============================================================
|
|
14
|
+
|
|
15
|
+
function loadProjectConfig() {
|
|
16
|
+
const configPaths = [
|
|
17
|
+
process.env.NS_CONFIG_PATH,
|
|
18
|
+
path.join(process.cwd(), 'nervous-system.config.json'),
|
|
19
|
+
path.join(os.homedir(), '.nervous-system', 'config.json'),
|
|
20
|
+
path.join(__dirname, 'nervous-system.config.json'),
|
|
21
|
+
].filter(Boolean);
|
|
22
|
+
|
|
23
|
+
for (const cp of configPaths) {
|
|
24
|
+
try {
|
|
25
|
+
const raw = fs.readFileSync(cp, 'utf8');
|
|
26
|
+
const cfg = JSON.parse(raw);
|
|
27
|
+
cfg._source = cp;
|
|
28
|
+
return cfg;
|
|
29
|
+
} catch (e) { continue; }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Return defaults that work for any project
|
|
33
|
+
return {
|
|
34
|
+
_source: 'defaults',
|
|
35
|
+
project_root: process.cwd(),
|
|
36
|
+
data_dir: null,
|
|
37
|
+
logs_dir: null,
|
|
38
|
+
html_dir: null,
|
|
39
|
+
protected_files_list: null,
|
|
40
|
+
config_file: null,
|
|
41
|
+
roles_file: null,
|
|
42
|
+
docs_to_audit: [],
|
|
43
|
+
pm2_managed: false,
|
|
44
|
+
html_pages: [],
|
|
45
|
+
package_json: null,
|
|
46
|
+
github_repo: null,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const PROJECT = loadProjectConfig();
|
|
51
|
+
|
|
52
|
+
function projectPath(key) {
|
|
53
|
+
const val = PROJECT[key];
|
|
54
|
+
if (!val) return null;
|
|
55
|
+
if (path.isAbsolute(val)) return val;
|
|
56
|
+
return path.join(PROJECT.project_root || process.cwd(), val);
|
|
57
|
+
}
|
|
58
|
+
|
|
8
59
|
const PORT = 3475;
|
|
9
60
|
|
|
10
61
|
const KILL_SECRET = process.env.KILL_SECRET || 'ns-kill-2026';
|
|
11
|
-
const AUDIT_CHAIN_FILE = '
|
|
12
|
-
const VIOLATIONS_LOG = '
|
|
62
|
+
const AUDIT_CHAIN_FILE = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'audit-chain.json') : path.join(os.homedir(), '.nervous-system', 'audit-chain.json');
|
|
63
|
+
const VIOLATIONS_LOG = projectPath('logs_dir') ? path.join(projectPath('logs_dir'), 'guardrail-violations.log') : path.join(os.homedir(), '.nervous-system', 'guardrail-violations.log');
|
|
13
64
|
const GENESIS_HASH = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
14
65
|
const activeDispatches = [];
|
|
15
66
|
const MAX_CONCURRENT_DISPATCHES = 2;
|
|
@@ -108,7 +159,7 @@ function dispatchToLLM(task, maxTurns) {
|
|
|
108
159
|
const freeMB = getFreeMB();
|
|
109
160
|
if (freeMB < 500) return { dispatched: false, error: `Insufficient RAM: ${freeMB}MB free (need 500MB+)` };
|
|
110
161
|
const ts = Date.now();
|
|
111
|
-
const logFile =
|
|
162
|
+
const logFile = projectPath('logs_dir') ? `${projectPath('logs_dir')}/dispatch-${ts}.log` : path.join(os.homedir(), '.nervous-system', `dispatch-${ts}.log`);
|
|
112
163
|
const turns = maxTurns || 15;
|
|
113
164
|
try {
|
|
114
165
|
const escaped = task.replace(/"/g, '\\"');
|
|
@@ -129,7 +180,7 @@ const MCP_VERSION = '2024-11-05';
|
|
|
129
180
|
// Server info
|
|
130
181
|
const SERVER_INFO = {
|
|
131
182
|
name: 'nervous-system',
|
|
132
|
-
version: '1.
|
|
183
|
+
version: '1.6.0'
|
|
133
184
|
};
|
|
134
185
|
|
|
135
186
|
// ============================================================
|
|
@@ -138,7 +189,7 @@ const SERVER_INFO = {
|
|
|
138
189
|
|
|
139
190
|
const FRAMEWORK = {
|
|
140
191
|
name: 'The Nervous System',
|
|
141
|
-
version: '1.
|
|
192
|
+
version: '1.6.0',
|
|
142
193
|
author: 'Arthur Palyan',
|
|
143
194
|
tagline: 'Anthropic built the brain. Arthur built the nervous system that keeps it from hurting itself.',
|
|
144
195
|
problem: 'LLMs lose context between sessions, loop on problems instead of dispatching, silently fail without progress notes, edit protected files, drift from the real problem, and solve instead of asking.',
|
|
@@ -475,7 +526,7 @@ const NERVOUS_SYSTEM_INFO = {
|
|
|
475
526
|
]
|
|
476
527
|
},
|
|
477
528
|
origin_story: {
|
|
478
|
-
context: 'Arthur Palyan runs a startup with 12 AI family members, each with distinct roles. The entire operation runs on a $
|
|
529
|
+
context: 'Arthur Palyan runs a startup with 12 AI family members, each with distinct roles. The entire operation runs on a $24/month VPS with a $200/month LLM subscription.',
|
|
479
530
|
problem_discovered: 'After months of building, patterns emerged: LLMs would break working systems while trying to improve them. They would loop on debugging instead of dispatching. They would silently fail when sessions timed out. They would lose all context between sessions.',
|
|
480
531
|
solution_built: 'Arthur built the nervous system - not by changing the LLM model, but by wrapping it in behavioral rules enforced through scripts, file checks, and prompt engineering. The LLM itself became the enforcement mechanism, trained to check before acting.',
|
|
481
532
|
philosophy: 'The brain (LLM) is powerful but needs a nervous system to keep it from hurting itself. Just like a human nervous system sends pain signals before you touch a hot stove, this system sends BLOCKED/PROTECTED signals before the LLM edits a critical file.',
|
|
@@ -507,7 +558,7 @@ const NERVOUS_SYSTEM_INFO = {
|
|
|
507
558
|
reflection_trigger: 'Every 4 messages',
|
|
508
559
|
processes_managed: '22+ autonomous PM2 processes',
|
|
509
560
|
family_members: 12,
|
|
510
|
-
monthly_cost: '$
|
|
561
|
+
monthly_cost: 'Under $300/month total infrastructure',
|
|
511
562
|
uptime: '24/7 autonomous operation',
|
|
512
563
|
deployment: 'Single VPS, single LLM subscription'
|
|
513
564
|
}
|
|
@@ -649,6 +700,21 @@ const TOOLS = [
|
|
|
649
700
|
page: { type: 'string', description: "Specific page to check (e.g. 'gateway.html'), or 'all' for everything" }
|
|
650
701
|
}
|
|
651
702
|
}
|
|
703
|
+
},
|
|
704
|
+
// NEW: Pre-Publish Audit
|
|
705
|
+
{
|
|
706
|
+
name: 'pre_publish_audit',
|
|
707
|
+
annotations: { title: 'Pre-Publish Audit', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
708
|
+
description: 'Scans the Nervous System source code itself before publishing. Catches hardcoded secrets, personal data, non-portable paths, and internal naming that should not ship to clients. RUN THIS BEFORE EVERY npm publish.',
|
|
709
|
+
inputSchema: {
|
|
710
|
+
type: 'object',
|
|
711
|
+
properties: {
|
|
712
|
+
source_file: {
|
|
713
|
+
type: 'string',
|
|
714
|
+
description: 'Path to the NS source file to audit. Defaults to own index.js'
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
652
718
|
}
|
|
653
719
|
];
|
|
654
720
|
|
|
@@ -686,7 +752,10 @@ function safeReadFile(filePath) {
|
|
|
686
752
|
function auditRoles() {
|
|
687
753
|
const drifts = [];
|
|
688
754
|
let cleanChecks = 0;
|
|
689
|
-
const rolesFile = '
|
|
755
|
+
const rolesFile = projectPath('roles_file');
|
|
756
|
+
if (!rolesFile) {
|
|
757
|
+
return { drifts: [], cleanChecks: 0, skipped: 'roles_file not configured' };
|
|
758
|
+
}
|
|
690
759
|
const roles = safeReadJSON(rolesFile);
|
|
691
760
|
if (!roles || !roles.members) {
|
|
692
761
|
drifts.push({ type: 'missing_source', source: rolesFile, target: '', field: '', expected: 'valid JSON with members array', found: 'missing or invalid' });
|
|
@@ -699,7 +768,8 @@ function auditRoles() {
|
|
|
699
768
|
}
|
|
700
769
|
|
|
701
770
|
// Check family-status.json
|
|
702
|
-
const statusFile = '
|
|
771
|
+
const statusFile = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'family-status.json') : null;
|
|
772
|
+
if (!statusFile) { return { drifts, cleanChecks }; }
|
|
703
773
|
const status = safeReadJSON(statusFile);
|
|
704
774
|
if (status && status.members) {
|
|
705
775
|
for (const m of status.members) {
|
|
@@ -715,8 +785,8 @@ function auditRoles() {
|
|
|
715
785
|
}
|
|
716
786
|
|
|
717
787
|
// Check system-config.json
|
|
718
|
-
const configFile = '
|
|
719
|
-
const config = safeReadJSON(configFile);
|
|
788
|
+
const configFile = projectPath('config_file');
|
|
789
|
+
const config = configFile ? safeReadJSON(configFile) : null;
|
|
720
790
|
if (config && config.family_members) {
|
|
721
791
|
for (const m of config.family_members) {
|
|
722
792
|
const src = sourceRoles[m.id];
|
|
@@ -731,8 +801,8 @@ function auditRoles() {
|
|
|
731
801
|
}
|
|
732
802
|
|
|
733
803
|
// Check family-guide.json
|
|
734
|
-
const guideFile = '
|
|
735
|
-
const guide = safeReadJSON(guideFile);
|
|
804
|
+
const guideFile = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'family-guide.json') : null;
|
|
805
|
+
const guide = guideFile ? safeReadJSON(guideFile) : null;
|
|
736
806
|
if (guide && guide.members) {
|
|
737
807
|
for (const m of guide.members) {
|
|
738
808
|
const src = sourceRoles[m.id];
|
|
@@ -747,11 +817,12 @@ function auditRoles() {
|
|
|
747
817
|
}
|
|
748
818
|
|
|
749
819
|
// Check HTML files for role references
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
{ path: '
|
|
753
|
-
{ path: '
|
|
754
|
-
|
|
820
|
+
const htmlDir = projectPath('html_dir');
|
|
821
|
+
const htmlFiles = htmlDir ? [
|
|
822
|
+
{ path: path.join(htmlDir, 'index.html'), name: 'index.html' },
|
|
823
|
+
{ path: path.join(htmlDir, 'explorer.html'), name: 'explorer.html' },
|
|
824
|
+
{ path: path.join(htmlDir, 'meet.html'), name: 'meet.html' }
|
|
825
|
+
] : [];
|
|
755
826
|
for (const hf of htmlFiles) {
|
|
756
827
|
const content = safeReadFile(hf.path);
|
|
757
828
|
if (!content) continue;
|
|
@@ -761,7 +832,7 @@ function auditRoles() {
|
|
|
761
832
|
}
|
|
762
833
|
|
|
763
834
|
// Check mcp-ops-server.js
|
|
764
|
-
const opsContent = safeReadFile('
|
|
835
|
+
const opsContent = projectPath('project_root') ? safeReadFile(path.join(projectPath('project_root') || process.cwd(), 'mcp-ops-server.js')) : null;
|
|
765
836
|
if (opsContent) {
|
|
766
837
|
for (const [id, src] of Object.entries(sourceRoles)) {
|
|
767
838
|
if (opsContent.includes(`"${src.aka}"`) || opsContent.includes(`'${src.aka}'`)) {
|
|
@@ -776,7 +847,10 @@ function auditRoles() {
|
|
|
776
847
|
function auditVersions() {
|
|
777
848
|
const drifts = [];
|
|
778
849
|
let cleanChecks = 0;
|
|
779
|
-
const pkgFile = '
|
|
850
|
+
const pkgFile = projectPath('package_json');
|
|
851
|
+
if (!pkgFile) {
|
|
852
|
+
return { drifts: [], cleanChecks: 0, skipped: 'package_json not configured' };
|
|
853
|
+
}
|
|
780
854
|
const pkg = safeReadJSON(pkgFile);
|
|
781
855
|
const expectedVersion = pkg ? pkg.version : null;
|
|
782
856
|
if (!expectedVersion) {
|
|
@@ -785,7 +859,8 @@ function auditVersions() {
|
|
|
785
859
|
}
|
|
786
860
|
|
|
787
861
|
// Check SERVER_INFO.version and FRAMEWORK.version in index.js
|
|
788
|
-
const
|
|
862
|
+
const ghRepo = projectPath('github_repo');
|
|
863
|
+
const indexContent = ghRepo ? safeReadFile(path.join(ghRepo, 'index.js')) : null;
|
|
789
864
|
if (indexContent) {
|
|
790
865
|
const siMatch = indexContent.match(/SERVER_INFO\s*=\s*\{[^}]*version:\s*'([^']+)'/);
|
|
791
866
|
if (siMatch) {
|
|
@@ -826,7 +901,7 @@ function auditVersions() {
|
|
|
826
901
|
}
|
|
827
902
|
|
|
828
903
|
// Check BUSINESS_BUILDER.md
|
|
829
|
-
const bbContent = safeReadFile('
|
|
904
|
+
const bbContent = projectPath('data_dir') ? safeReadFile(path.join(projectPath('data_dir'), 'BUSINESS_BUILDER.md')) : null;
|
|
830
905
|
if (bbContent) {
|
|
831
906
|
const bbMatch = bbContent.match(/[Nn]ervous [Ss]ystem.*?v?(\d+\.\d+\.\d+)/);
|
|
832
907
|
if (bbMatch && bbMatch[1] !== expectedVersion) {
|
|
@@ -835,7 +910,7 @@ function auditVersions() {
|
|
|
835
910
|
}
|
|
836
911
|
|
|
837
912
|
// Check gateway.html
|
|
838
|
-
const gwContent = safeReadFile('
|
|
913
|
+
const gwContent = projectPath('html_dir') ? safeReadFile(path.join(projectPath('html_dir'), 'gateway.html')) : null;
|
|
839
914
|
if (gwContent) {
|
|
840
915
|
const gwMatch = gwContent.match(/[Vv]ersion[:\s]*v?(\d+\.\d+\.\d+)/);
|
|
841
916
|
if (gwMatch && gwMatch[1] !== expectedVersion) {
|
|
@@ -844,7 +919,7 @@ function auditVersions() {
|
|
|
844
919
|
}
|
|
845
920
|
|
|
846
921
|
// Check README.md
|
|
847
|
-
const readmeContent = safeReadFile('
|
|
922
|
+
const readmeContent = ghRepo ? safeReadFile(path.join(ghRepo, 'README.md')) : null;
|
|
848
923
|
if (readmeContent) {
|
|
849
924
|
const rmMatch = readmeContent.match(/[Vv]ersion[:\s]*v?(\d+\.\d+\.\d+)/);
|
|
850
925
|
if (rmMatch && rmMatch[1] !== expectedVersion) {
|
|
@@ -853,7 +928,7 @@ function auditVersions() {
|
|
|
853
928
|
}
|
|
854
929
|
|
|
855
930
|
// Check family-roles.json stats
|
|
856
|
-
const roles = safeReadJSON('
|
|
931
|
+
const roles = projectPath('roles_file') ? safeReadJSON(projectPath('roles_file')) : null;
|
|
857
932
|
if (roles && roles.stats) {
|
|
858
933
|
if (roles.stats.ns_version && roles.stats.ns_version !== expectedVersion) {
|
|
859
934
|
drifts.push({ type: 'version_mismatch', source: 'package.json', target: 'family-roles.json', field: 'stats.ns_version', expected: expectedVersion, found: roles.stats.ns_version });
|
|
@@ -874,10 +949,13 @@ function auditFiles() {
|
|
|
874
949
|
let cleanChecks = 0;
|
|
875
950
|
|
|
876
951
|
// Check UNTOUCHABLE_FILES.txt - verify each file exists
|
|
877
|
-
const
|
|
952
|
+
const untouchableFile = projectPath('protected_files_list');
|
|
953
|
+
const untouchableContent = untouchableFile ? safeReadFile(untouchableFile) : null;
|
|
878
954
|
if (untouchableContent) {
|
|
879
955
|
const lines = untouchableContent.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
|
|
880
|
-
for (const
|
|
956
|
+
for (const rawLine of lines) {
|
|
957
|
+
const filePath = rawLine.split(/\s*[\(\#]/)[0].trim();
|
|
958
|
+
if (!filePath || !filePath.startsWith('/')) continue;
|
|
881
959
|
if (fs.existsSync(filePath)) {
|
|
882
960
|
cleanChecks++;
|
|
883
961
|
} else {
|
|
@@ -887,10 +965,8 @@ function auditFiles() {
|
|
|
887
965
|
}
|
|
888
966
|
|
|
889
967
|
// Check LLM_STARTUP.md and BUSINESS_BUILDER.md for file references
|
|
890
|
-
const
|
|
891
|
-
|
|
892
|
-
{ path: '/root/family-data/BUSINESS_BUILDER.md', name: 'BUSINESS_BUILDER.md' }
|
|
893
|
-
];
|
|
968
|
+
const docsToAudit = PROJECT.docs_to_audit || [];
|
|
969
|
+
const docsToCheck = docsToAudit.map(p => ({ path: p, name: path.basename(p) }));
|
|
894
970
|
|
|
895
971
|
// Get PM2 running scripts
|
|
896
972
|
let pm2Scripts = {};
|
|
@@ -906,7 +982,8 @@ function auditFiles() {
|
|
|
906
982
|
const content = safeReadFile(doc.path);
|
|
907
983
|
if (!content) continue;
|
|
908
984
|
// Look for .js file references
|
|
909
|
-
|
|
985
|
+
// Match .js files but exclude .json, .jsonl, .jsx
|
|
986
|
+
const jsRefs = (content.match(/\/[^\s)]+\.js\b/g) || []).filter(r => !r.match(/\.json[l]?$/));
|
|
910
987
|
for (const ref of jsRefs) {
|
|
911
988
|
if (fs.existsSync(ref)) {
|
|
912
989
|
cleanChecks++;
|
|
@@ -928,7 +1005,8 @@ function auditFiles() {
|
|
|
928
1005
|
}
|
|
929
1006
|
|
|
930
1007
|
// Check system-config.json syntax_check_scripts
|
|
931
|
-
const
|
|
1008
|
+
const sysConfigFile = projectPath('config_file');
|
|
1009
|
+
const config = sysConfigFile ? safeReadJSON(sysConfigFile) : null;
|
|
932
1010
|
if (config && config.syntax_check_scripts) {
|
|
933
1011
|
for (const script of config.syntax_check_scripts) {
|
|
934
1012
|
if (fs.existsSync(script)) {
|
|
@@ -955,10 +1033,10 @@ function auditProcesses() {
|
|
|
955
1033
|
return { drifts, cleanChecks };
|
|
956
1034
|
}
|
|
957
1035
|
|
|
958
|
-
const
|
|
1036
|
+
const procConfigFile = projectPath('config_file');
|
|
1037
|
+
const config = procConfigFile ? safeReadJSON(procConfigFile) : null;
|
|
959
1038
|
if (!config || !config.processes) {
|
|
960
|
-
|
|
961
|
-
const roles = safeReadJSON('/root/family-data/family-roles.json');
|
|
1039
|
+
const roles = projectPath('roles_file') ? safeReadJSON(projectPath('roles_file')) : null;
|
|
962
1040
|
if (roles && roles.members) {
|
|
963
1041
|
const expectedProcs = [];
|
|
964
1042
|
for (const m of roles.members) {
|
|
@@ -1007,18 +1085,19 @@ function auditWebsite() {
|
|
|
1007
1085
|
let cleanChecks = 0;
|
|
1008
1086
|
|
|
1009
1087
|
// Source of truth values
|
|
1010
|
-
const pkgFile = '
|
|
1011
|
-
const pkg = safeReadJSON(pkgFile);
|
|
1012
|
-
const expectedVersion = pkg ? pkg.version :
|
|
1088
|
+
const pkgFile = projectPath('package_json');
|
|
1089
|
+
const pkg = pkgFile ? safeReadJSON(pkgFile) : null;
|
|
1090
|
+
const expectedVersion = pkg ? pkg.version : SERVER_INFO.version;
|
|
1013
1091
|
const actualToolCount = TOOLS.length;
|
|
1014
1092
|
const actualResourceCount = RESOURCES.length;
|
|
1015
1093
|
|
|
1016
|
-
const roles = safeReadJSON('
|
|
1094
|
+
const roles = projectPath('roles_file') ? safeReadJSON(projectPath('roles_file')) : null;
|
|
1017
1095
|
const expectedMemberCount = roles && roles.stats ? roles.stats.member_count : 11;
|
|
1018
1096
|
const expectedProcessCount = roles && roles.stats ? roles.stats.process_count : 28;
|
|
1019
1097
|
|
|
1020
1098
|
// Count protected files (non-comment, non-blank lines starting with /)
|
|
1021
|
-
const
|
|
1099
|
+
const protListFile = projectPath('protected_files_list');
|
|
1100
|
+
const untouchableContent = protListFile ? safeReadFile(protListFile) : null;
|
|
1022
1101
|
let protectedFileCount = 0;
|
|
1023
1102
|
if (untouchableContent) {
|
|
1024
1103
|
protectedFileCount = untouchableContent.split('\n').filter(l => l.trim() && !l.trim().startsWith('#') && l.trim().startsWith('/')).length;
|
|
@@ -1028,7 +1107,10 @@ function auditWebsite() {
|
|
|
1028
1107
|
const roleNames = roles && roles.members ? roles.members.map(m => m.name) : [];
|
|
1029
1108
|
|
|
1030
1109
|
// 1. Check all .html files in /root/family-home/
|
|
1031
|
-
const familyHomeDir = '
|
|
1110
|
+
const familyHomeDir = projectPath('html_dir');
|
|
1111
|
+
if (!familyHomeDir) {
|
|
1112
|
+
return { drifts: [], cleanChecks: 0, skipped: 'html_dir not configured' };
|
|
1113
|
+
}
|
|
1032
1114
|
let htmlFiles = [];
|
|
1033
1115
|
try {
|
|
1034
1116
|
htmlFiles = fs.readdirSync(familyHomeDir).filter(f => f.endsWith('.html')).map(f => familyHomeDir + f);
|
|
@@ -1091,7 +1173,8 @@ function auditWebsite() {
|
|
|
1091
1173
|
}
|
|
1092
1174
|
|
|
1093
1175
|
// 2. Check family-guide.json
|
|
1094
|
-
const
|
|
1176
|
+
const guideFile2 = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'family-guide.json') : null;
|
|
1177
|
+
const guide = guideFile2 ? safeReadJSON(guideFile2) : null;
|
|
1095
1178
|
if (guide) {
|
|
1096
1179
|
const guideStr = JSON.stringify(guide);
|
|
1097
1180
|
// Check version refs
|
|
@@ -1117,7 +1200,7 @@ function auditWebsite() {
|
|
|
1117
1200
|
} else { cleanChecks++; }
|
|
1118
1201
|
|
|
1119
1202
|
// 3. Check mcp-stripe-checkout.js for version refs
|
|
1120
|
-
const checkoutContent = safeReadFile('
|
|
1203
|
+
const checkoutContent = projectPath('project_root') ? safeReadFile(path.join(projectPath('project_root') || process.cwd(), 'mcp-stripe-checkout.js')) : null;
|
|
1121
1204
|
if (checkoutContent) {
|
|
1122
1205
|
const checkoutVersions = checkoutContent.match(/v(\d+\.\d+\.\d+)/g) || [];
|
|
1123
1206
|
for (const cv of checkoutVersions) {
|
|
@@ -1130,7 +1213,8 @@ function auditWebsite() {
|
|
|
1130
1213
|
}
|
|
1131
1214
|
|
|
1132
1215
|
// 4. Check system-config.json for version/tool counts
|
|
1133
|
-
const
|
|
1216
|
+
const sysConfigFile2 = projectPath('config_file');
|
|
1217
|
+
const sysConfig = sysConfigFile2 ? safeReadJSON(sysConfigFile2) : null;
|
|
1134
1218
|
if (sysConfig) {
|
|
1135
1219
|
const scStr = JSON.stringify(sysConfig);
|
|
1136
1220
|
const scVersions = scStr.match(/v(\d+\.\d+\.\d+)/g) || [];
|
|
@@ -1144,7 +1228,7 @@ function auditWebsite() {
|
|
|
1144
1228
|
}
|
|
1145
1229
|
|
|
1146
1230
|
// 5. Check FREE_TOOLS in mcp-api-middleware.js match actual tool names
|
|
1147
|
-
const middlewareContent = safeReadFile('
|
|
1231
|
+
const middlewareContent = projectPath('project_root') ? safeReadFile(path.join(projectPath('project_root') || process.cwd(), 'mcp-api-middleware.js')) : null;
|
|
1148
1232
|
if (middlewareContent) {
|
|
1149
1233
|
const freeToolsMatch = middlewareContent.match(/'nervous-system':\s*\[([^\]]+)\]/);
|
|
1150
1234
|
if (freeToolsMatch) {
|
|
@@ -1164,7 +1248,7 @@ function auditWebsite() {
|
|
|
1164
1248
|
}
|
|
1165
1249
|
|
|
1166
1250
|
// 6. Check sitemap.xml has all public pages
|
|
1167
|
-
const sitemapContent = safeReadFile('
|
|
1251
|
+
const sitemapContent = familyHomeDir ? safeReadFile(path.join(familyHomeDir, 'sitemap.xml')) : null;
|
|
1168
1252
|
if (sitemapContent && htmlFiles.length > 0) {
|
|
1169
1253
|
const publicPages = htmlFiles.filter(f => {
|
|
1170
1254
|
const name = f.split('/').pop();
|
|
@@ -1226,17 +1310,21 @@ function runSecurityAudit() {
|
|
|
1226
1310
|
let checksPassed = 0;
|
|
1227
1311
|
|
|
1228
1312
|
// 1. Scan HTML files for hardcoded passwords/secrets
|
|
1229
|
-
const htmlDir = '
|
|
1313
|
+
const htmlDir = projectPath('html_dir');
|
|
1314
|
+
if (!htmlDir) {
|
|
1315
|
+
return { status: 'skipped', vulnerability_count: 0, checks_passed: 0, vulnerabilities: [], skipped: 'html_dir not configured' };
|
|
1316
|
+
}
|
|
1230
1317
|
const secretPatterns = [
|
|
1231
|
-
/
|
|
1232
|
-
/
|
|
1233
|
-
|
|
1234
|
-
/
|
|
1235
|
-
/npm_[A-Za-z0-9]{20,}/g,
|
|
1236
|
-
/ghp_[A-Za-z0-9]{20,}/g,
|
|
1237
|
-
/BOT_TOKEN\s*[:=]\s*['"][^'"]+['"]/gi,
|
|
1238
|
-
/
|
|
1239
|
-
/
|
|
1318
|
+
/\d{10}:AA[A-Za-z0-9_-]{30,}/g, // Telegram bot tokens
|
|
1319
|
+
/sk-ant-[a-zA-Z0-9_-]+/g, // Anthropic API keys
|
|
1320
|
+
/sk_live_[a-zA-Z0-9]+/g, // Stripe live keys
|
|
1321
|
+
/sk_test_[a-zA-Z0-9]+/g, // Stripe test keys
|
|
1322
|
+
/npm_[A-Za-z0-9]{20,}/g, // npm tokens
|
|
1323
|
+
/ghp_[A-Za-z0-9]{20,}/g, // GitHub PATs
|
|
1324
|
+
/BOT_TOKEN\s*[:=]\s*['"][^'"]+['"]/gi, // Generic bot tokens
|
|
1325
|
+
/password\s*[:=]\s*['"][^'"]{8,}['"]/gi, // Hardcoded passwords
|
|
1326
|
+
/api[_-]?key\s*[:=]\s*['"][A-Za-z0-9_\-]{20,}['"]/gi, // API keys
|
|
1327
|
+
/secret\s*[:=]\s*['"][A-Za-z0-9_\-]{16,}['"]/gi, // Secrets
|
|
1240
1328
|
];
|
|
1241
1329
|
try {
|
|
1242
1330
|
const htmlFiles = fs.readdirSync(htmlDir).filter(f => f.endsWith('.html'));
|
|
@@ -1244,11 +1332,24 @@ function runSecurityAudit() {
|
|
|
1244
1332
|
const content = safeReadFile(htmlDir + hf);
|
|
1245
1333
|
if (!content) continue;
|
|
1246
1334
|
let fileClean = true;
|
|
1335
|
+
const contentLines = content.split('\n');
|
|
1247
1336
|
for (const pat of secretPatterns) {
|
|
1248
1337
|
pat.lastIndex = 0;
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1338
|
+
let realMatches = 0;
|
|
1339
|
+
for (const line of contentLines) {
|
|
1340
|
+
// Skip lines that are defining detection patterns (not actual secrets)
|
|
1341
|
+
if (line.trim().match(/^\s*\/.*\/[gim]*,?\s*$/) ||
|
|
1342
|
+
line.includes('SENS_PAT') ||
|
|
1343
|
+
line.includes('secretPatterns') ||
|
|
1344
|
+
line.includes('leakPatterns') ||
|
|
1345
|
+
line.includes('dangerPatterns') ||
|
|
1346
|
+
line.includes('redact')) continue;
|
|
1347
|
+
pat.lastIndex = 0;
|
|
1348
|
+
const m = line.match(pat);
|
|
1349
|
+
if (m) realMatches += m.length;
|
|
1350
|
+
}
|
|
1351
|
+
if (realMatches > 0) {
|
|
1352
|
+
vulnerabilities.push({ type: 'hardcoded_secret', file: hf, pattern: pat.source, count: realMatches });
|
|
1252
1353
|
fileClean = false;
|
|
1253
1354
|
}
|
|
1254
1355
|
}
|
|
@@ -1259,7 +1360,7 @@ function runSecurityAudit() {
|
|
|
1259
1360
|
}
|
|
1260
1361
|
|
|
1261
1362
|
// 2. Check auth endpoints use server-side validation
|
|
1262
|
-
const serverContent = safeReadFile('
|
|
1363
|
+
const serverContent = htmlDir ? safeReadFile(path.join(htmlDir, 'server.js')) : null;
|
|
1263
1364
|
if (serverContent) {
|
|
1264
1365
|
if (serverContent.includes('getSessionFromReq') || serverContent.includes('getAccessLevel')) {
|
|
1265
1366
|
checksPassed++;
|
|
@@ -1291,7 +1392,8 @@ function runSecurityAudit() {
|
|
|
1291
1392
|
}
|
|
1292
1393
|
|
|
1293
1394
|
// 5. Check bridge rate limiting
|
|
1294
|
-
|
|
1395
|
+
const projRoot = projectPath('project_root') || process.cwd();
|
|
1396
|
+
if (serverContent && serverContent.includes('rate') || fs.existsSync(path.join(projRoot, 'rate-limit.js')) || fs.existsSync(path.join(projRoot, 'bridge-ratelimit.js'))) {
|
|
1295
1397
|
checksPassed++;
|
|
1296
1398
|
} else {
|
|
1297
1399
|
vulnerabilities.push({ type: 'missing_rate_limit', file: 'bridge', detail: 'No rate limiting found for bridge' });
|
|
@@ -1315,7 +1417,8 @@ function runSecurityAudit() {
|
|
|
1315
1417
|
|
|
1316
1418
|
// 7. Check api-credentials.json permissions
|
|
1317
1419
|
try {
|
|
1318
|
-
const credFile = '
|
|
1420
|
+
const credFile = projectPath('data_dir') ? path.join(projectPath('data_dir'), 'api-credentials.json') : null;
|
|
1421
|
+
if (!credFile) { checksPassed++; }
|
|
1319
1422
|
if (fs.existsSync(credFile)) {
|
|
1320
1423
|
const stats = fs.statSync(credFile);
|
|
1321
1424
|
const mode = (stats.mode & 0o777).toString(8);
|
|
@@ -1367,10 +1470,14 @@ function runSecurityAudit() {
|
|
|
1367
1470
|
|
|
1368
1471
|
function runAutoPropagators() {
|
|
1369
1472
|
const results = [];
|
|
1473
|
+
const workersDir = projectPath('project_root') ? path.join(projectPath('project_root') || process.cwd(), 'family-workers') : null;
|
|
1474
|
+
if (!workersDir || !fs.existsSync(workersDir)) {
|
|
1475
|
+
return { timestamp: new Date().toISOString(), propagators_run: 0, results: [], skipped: 'family-workers directory not found' };
|
|
1476
|
+
}
|
|
1370
1477
|
const scripts = [
|
|
1371
|
-
{ name: 'role', path: '
|
|
1372
|
-
{ name: 'version', path: '
|
|
1373
|
-
{ name: 'content', path: '
|
|
1478
|
+
{ name: 'role', path: path.join(workersDir, 'role-propagator.js') },
|
|
1479
|
+
{ name: 'version', path: path.join(workersDir, 'version-propagator.js') },
|
|
1480
|
+
{ name: 'content', path: path.join(workersDir, 'content-propagator.js') }
|
|
1374
1481
|
];
|
|
1375
1482
|
for (const script of scripts) {
|
|
1376
1483
|
try {
|
|
@@ -1393,7 +1500,10 @@ function runAutoPropagators() {
|
|
|
1393
1500
|
// ============================================================
|
|
1394
1501
|
|
|
1395
1502
|
function runPageHealth(page) {
|
|
1396
|
-
const FAMILY_HOME = '
|
|
1503
|
+
const FAMILY_HOME = projectPath('html_dir');
|
|
1504
|
+
if (!FAMILY_HOME) {
|
|
1505
|
+
return { status: 'skipped', pages_checked: 0, issue_count: 0, issues: [], skipped: 'html_dir not configured' };
|
|
1506
|
+
}
|
|
1397
1507
|
const issues = [];
|
|
1398
1508
|
|
|
1399
1509
|
let htmlFiles;
|
|
@@ -1547,6 +1657,111 @@ function runPageHealth(page) {
|
|
|
1547
1657
|
};
|
|
1548
1658
|
}
|
|
1549
1659
|
|
|
1660
|
+
|
|
1661
|
+
// ============================================================
|
|
1662
|
+
// PRE-PUBLISH AUDIT ENGINE
|
|
1663
|
+
// ============================================================
|
|
1664
|
+
|
|
1665
|
+
function runPrePublishAudit(sourceFile) {
|
|
1666
|
+
const findings = [];
|
|
1667
|
+
const file = sourceFile || __filename;
|
|
1668
|
+
let content;
|
|
1669
|
+
try {
|
|
1670
|
+
content = fs.readFileSync(file, 'utf8');
|
|
1671
|
+
} catch (e) {
|
|
1672
|
+
return { status: 'error', error: 'Cannot read file: ' + e.message };
|
|
1673
|
+
}
|
|
1674
|
+
const lines = content.split('\n');
|
|
1675
|
+
|
|
1676
|
+
// 1. Check for hardcoded absolute paths (non-portable)
|
|
1677
|
+
lines.forEach((line, idx) => {
|
|
1678
|
+
if (line.trim().startsWith('//')) return;
|
|
1679
|
+
if (line.includes('description:') || line.includes('context:')) return;
|
|
1680
|
+
if (line.includes('description,') || line.includes("description'")) return;
|
|
1681
|
+
|
|
1682
|
+
if (line.match(/['"\`]\/root\//)) {
|
|
1683
|
+
findings.push({
|
|
1684
|
+
type: 'hardcoded_path',
|
|
1685
|
+
line: idx + 1,
|
|
1686
|
+
preview: line.trim().substring(0, 100),
|
|
1687
|
+
fix: 'Use projectPath() or configurable path'
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
if (line.match(/['"\`]\/home\//)) {
|
|
1691
|
+
findings.push({
|
|
1692
|
+
type: 'hardcoded_path',
|
|
1693
|
+
line: idx + 1,
|
|
1694
|
+
preview: line.trim().substring(0, 100),
|
|
1695
|
+
fix: 'Use projectPath() or os.homedir()'
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
});
|
|
1699
|
+
|
|
1700
|
+
// 2. Check for personal data that should not ship
|
|
1701
|
+
const personalPatterns = [
|
|
1702
|
+
{ name: 'email_address', pat: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g },
|
|
1703
|
+
{ name: 'phone_number', pat: /\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/g },
|
|
1704
|
+
{ name: 'ip_address', pat: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g },
|
|
1705
|
+
];
|
|
1706
|
+
lines.forEach((line, idx) => {
|
|
1707
|
+
if (line.trim().startsWith('//') || line.includes('description')) return;
|
|
1708
|
+
if (line.includes('regex') || line.includes('pattern') || line.includes('pat:')) return;
|
|
1709
|
+
for (const pp of personalPatterns) {
|
|
1710
|
+
pp.pat.lastIndex = 0;
|
|
1711
|
+
if (pp.pat.test(line)) {
|
|
1712
|
+
findings.push({
|
|
1713
|
+
type: 'personal_data',
|
|
1714
|
+
subtype: pp.name,
|
|
1715
|
+
line: idx + 1,
|
|
1716
|
+
preview: line.trim().substring(0, 100),
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
});
|
|
1721
|
+
|
|
1722
|
+
// 3. Check for internal naming that should be generic
|
|
1723
|
+
const internalTerms = [
|
|
1724
|
+
'family-data', 'family-home', 'family-logs', 'family-roles',
|
|
1725
|
+
'family-guide', 'family-status', 'family-workers',
|
|
1726
|
+
'PAPA_FULL', 'PAPA_READ', 'ARTHUR_CHAT_ID',
|
|
1727
|
+
];
|
|
1728
|
+
lines.forEach((line, idx) => {
|
|
1729
|
+
if (line.trim().startsWith('//')) return;
|
|
1730
|
+
if (line.includes('description:') || line.includes('context:') || line.includes('tagline:')) return;
|
|
1731
|
+
if (line.includes('origin_story')) return;
|
|
1732
|
+
for (const term of internalTerms) {
|
|
1733
|
+
if (line.toLowerCase().includes(term.toLowerCase()) &&
|
|
1734
|
+
!line.includes('// ')) {
|
|
1735
|
+
findings.push({
|
|
1736
|
+
type: 'internal_naming',
|
|
1737
|
+
term: term,
|
|
1738
|
+
line: idx + 1,
|
|
1739
|
+
preview: line.trim().substring(0, 100),
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
});
|
|
1744
|
+
|
|
1745
|
+
// 4. GATE: Block publish if critical findings
|
|
1746
|
+
const critical = findings.filter(f =>
|
|
1747
|
+
f.type === 'personal_data' ||
|
|
1748
|
+
(f.type === 'hardcoded_path' && !f.preview.includes('description'))
|
|
1749
|
+
);
|
|
1750
|
+
|
|
1751
|
+
return {
|
|
1752
|
+
status: findings.length === 0 ? 'ready_to_publish' :
|
|
1753
|
+
critical.length > 0 ? 'BLOCKED_critical_findings' : 'warnings_only',
|
|
1754
|
+
total_findings: findings.length,
|
|
1755
|
+
critical_count: critical.length,
|
|
1756
|
+
findings: findings,
|
|
1757
|
+
recommendation: critical.length > 0 ?
|
|
1758
|
+
'DO NOT PUBLISH. Fix critical findings first.' :
|
|
1759
|
+
findings.length > 0 ?
|
|
1760
|
+
'Review warnings before publishing. None are blockers.' :
|
|
1761
|
+
'Clean. Safe to publish.'
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1550
1765
|
// ============================================================
|
|
1551
1766
|
// Handle tool calls
|
|
1552
1767
|
// ============================================================
|
|
@@ -1672,6 +1887,10 @@ function handleToolCall(name, args) {
|
|
|
1672
1887
|
return runPageHealth(args.page || 'all');
|
|
1673
1888
|
}
|
|
1674
1889
|
|
|
1890
|
+
case 'pre_publish_audit': {
|
|
1891
|
+
return runPrePublishAudit(args.source_file);
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1675
1894
|
default:
|
|
1676
1895
|
return { error: 'Unknown tool' };
|
|
1677
1896
|
}
|
|
@@ -1793,7 +2012,7 @@ const server = http.createServer((req, res) => {
|
|
|
1793
2012
|
// Health check
|
|
1794
2013
|
if (req.method === 'GET' && url.pathname === '/health') {
|
|
1795
2014
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1796
|
-
res.end(JSON.stringify({ status: 'ok', service: 'nervous-system-mcp', version: '1.
|
|
2015
|
+
res.end(JSON.stringify({ status: 'ok', service: 'nervous-system-mcp', version: '1.6.0', protocol: MCP_VERSION }));
|
|
1797
2016
|
return;
|
|
1798
2017
|
}
|
|
1799
2018
|
|
|
@@ -1910,7 +2129,7 @@ const server = http.createServer((req, res) => {
|
|
|
1910
2129
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1911
2130
|
res.end(JSON.stringify({
|
|
1912
2131
|
name: 'The Nervous System MCP Server',
|
|
1913
|
-
version: '1.
|
|
2132
|
+
version: '1.6.0',
|
|
1914
2133
|
protocol: MCP_VERSION,
|
|
1915
2134
|
description: 'LLM behavioral enforcement framework. 7 core rules, preflight checks, session handoffs, worklogs, violation logging, kill switch, hash-chained audit, and forced reflection cycles. Built by Arthur Palyan.',
|
|
1916
2135
|
endpoints: {
|
|
@@ -1932,8 +2151,8 @@ const server = http.createServer((req, res) => {
|
|
|
1932
2151
|
migrateExistingViolations();
|
|
1933
2152
|
|
|
1934
2153
|
server.listen(PORT, '127.0.0.1', () => {
|
|
1935
|
-
console.error(`[MCP Server] Nervous System v1.
|
|
2154
|
+
console.error(`[MCP Server] Nervous System v1.6.0 running on port ${PORT}`);
|
|
1936
2155
|
console.error(`[MCP Server] SSE: /sse | HTTP: /mcp | Health: /health | Kill: POST /kill | Audit: GET /audit/verify | Dispatches: GET /dispatches`);
|
|
1937
2156
|
console.error(`[MCP Server] Protocol: ${MCP_VERSION}`);
|
|
1938
|
-
console.error(`[MCP Server] Tools: ${TOOLS.length} (including kill switch, audit chain, dispatch, drift audit, page health)`);
|
|
2157
|
+
console.error(`[MCP Server] Tools: ${TOOLS.length} (including kill switch, audit chain, dispatch, drift audit, page health, pre-publish audit)`);
|
|
1939
2158
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-nervous-system",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "The Nervous System - LLM Behavioral Enforcement Framework. 7 mechanically enforced rules,
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"description": "The Nervous System - LLM Behavioral Enforcement Framework. 7 mechanically enforced rules, 17 tools including kill switch, audit chain, dispatch, drift audit, security audit, page health, pre-publish audit, and session close. MCP server for Claude Desktop, Claude Code, and any MCP-compatible client.",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mcp-nervous-system": "./stdio.js"
|
|
@@ -39,4 +39,4 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-nervous-system",
|
|
3
|
+
"version": "1.5.1",
|
|
4
|
+
"description": "The Nervous System - LLM Behavioral Enforcement Framework. 7 mechanically enforced rules, 16 tools including kill switch, audit chain, dispatch, drift audit, security audit, page health, and session close. MCP server for Claude Desktop, Claude Code, and any MCP-compatible client.",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcp-nervous-system": "./stdio.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node server.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"model-context-protocol",
|
|
15
|
+
"llm",
|
|
16
|
+
"ai-safety",
|
|
17
|
+
"ai-governance",
|
|
18
|
+
"behavioral-enforcement",
|
|
19
|
+
"guardrails",
|
|
20
|
+
"claude",
|
|
21
|
+
"anthropic",
|
|
22
|
+
"nervous-system",
|
|
23
|
+
"kill-switch",
|
|
24
|
+
"audit-trail"
|
|
25
|
+
],
|
|
26
|
+
"author": "Arthur Palyan <palyanai@gmail.com>",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/levelsofself/mcp-nervous-system"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://api.100levelup.com/family/gateway.html",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/levelsofself/mcp-nervous-system/issues"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-nervous-system",
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "The Nervous System - LLM Behavioral Enforcement Framework. 7 mechanically enforced rules, 16 tools including kill switch, audit chain, dispatch, drift audit, security audit, page health, and session close. MCP server for Claude Desktop, Claude Code, and any MCP-compatible client.",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcp-nervous-system": "./stdio.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node server.js"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"mcp",
|
|
14
|
+
"model-context-protocol",
|
|
15
|
+
"llm",
|
|
16
|
+
"ai-safety",
|
|
17
|
+
"ai-governance",
|
|
18
|
+
"behavioral-enforcement",
|
|
19
|
+
"guardrails",
|
|
20
|
+
"claude",
|
|
21
|
+
"anthropic",
|
|
22
|
+
"nervous-system",
|
|
23
|
+
"kill-switch",
|
|
24
|
+
"audit-trail"
|
|
25
|
+
],
|
|
26
|
+
"author": "Arthur Palyan <palyanai@gmail.com>",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/levelsofself/mcp-nervous-system"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://api.100levelup.com/family/gateway.html",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/levelsofself/mcp-nervous-system/issues"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|