machine-bridge-mcp 0.8.2 → 0.9.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/CHANGELOG.md +14 -0
- package/README.md +37 -1
- package/SECURITY.md +10 -0
- package/docs/AGENT_CONTEXT.md +206 -0
- package/docs/ARCHITECTURE.md +9 -0
- package/docs/TESTING.md +1 -0
- package/package.json +5 -4
- package/src/local/agent-context.mjs +708 -0
- package/src/local/runtime.mjs +32 -0
- package/src/shared/server-metadata.json +1 -0
- package/src/shared/tool-catalog.json +172 -0
- package/src/worker/index.ts +1 -1
package/src/local/runtime.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { classifyOperationalError } from "./log.mjs";
|
|
|
14
14
|
import { ManagedJobManager } from "./managed-jobs.mjs";
|
|
15
15
|
import { generateRegisteredSshKey } from "./resource-operations.mjs";
|
|
16
16
|
import { expandHome } from "./state.mjs";
|
|
17
|
+
import { AgentContextManager } from "./agent-context.mjs";
|
|
17
18
|
|
|
18
19
|
export const MAX_WRITE_BYTES = 5 * 1024 * 1024;
|
|
19
20
|
const MAX_WS_MESSAGE_BYTES = 8 * 1024 * 1024;
|
|
@@ -27,6 +28,11 @@ const SLOW_TOOL_CALL_MS = 30_000;
|
|
|
27
28
|
const RUNTIME_TOOL_HANDLERS = Object.freeze({
|
|
28
29
|
server_info: (runtime) => runtime.runtimeInfo(),
|
|
29
30
|
project_overview: (runtime, _args, context) => runtime.projectOverview(context),
|
|
31
|
+
agent_context: (runtime, args, context) => runtime.agentContextManager.agentContext(args, context),
|
|
32
|
+
list_local_skills: (runtime, args, context) => runtime.agentContextManager.listLocalSkills(args, context),
|
|
33
|
+
load_local_skill: (runtime, args, context) => runtime.agentContextManager.loadLocalSkill(args, context),
|
|
34
|
+
list_local_commands: (runtime, args, context) => runtime.agentContextManager.listLocalCommands(args, context),
|
|
35
|
+
run_local_command: (runtime, args, context) => runtime.runLocalCommand(args, context),
|
|
30
36
|
list_roots: (runtime) => runtime.listRoots(),
|
|
31
37
|
list_dir: (runtime, args, context) => runtime.listDir(args.path || ".", context),
|
|
32
38
|
list_files: (runtime, args, context) => runtime.listFiles(args.path || ".", clampInt(args.max_files, 1000, 1, 10000), context),
|
|
@@ -101,6 +107,13 @@ export class LocalRuntime {
|
|
|
101
107
|
displayPath: (value) => this.displayPath(value),
|
|
102
108
|
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
103
109
|
});
|
|
110
|
+
this.agentContextManager = new AgentContextManager({
|
|
111
|
+
workspace: this.workspace,
|
|
112
|
+
policy: this.policy,
|
|
113
|
+
displayPath: (value) => this.displayPath(value),
|
|
114
|
+
resolveExistingPath: (value) => this.resolveExistingPath(value),
|
|
115
|
+
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
116
|
+
});
|
|
104
117
|
this.relay = createRelayConnection(this, {
|
|
105
118
|
workerUrl: remoteWorkerUrl,
|
|
106
119
|
secret: remoteSecret,
|
|
@@ -733,6 +746,25 @@ export class LocalRuntime {
|
|
|
733
746
|
return this.runProcess(argv[0], argv.slice(1), clampInt(args.timeout_seconds, 120, 1, 600) * 1000, false, 512 * 1024, context, cwd);
|
|
734
747
|
}
|
|
735
748
|
|
|
749
|
+
async runLocalCommand(args, context = {}) {
|
|
750
|
+
if (this.policy.execMode !== "direct" && this.policy.execMode !== "shell") throw new Error("run_local_command is disabled by daemon policy");
|
|
751
|
+
const command = await this.agentContextManager.resolveLocalCommand(args, context);
|
|
752
|
+
const argv = validateArgv(command.argv);
|
|
753
|
+
const cwd = await this.resolveExistingPath(command.cwd);
|
|
754
|
+
if (!(await stat(cwd)).isDirectory()) throw new Error("registered command cwd is not a directory");
|
|
755
|
+
const requestedTimeout = args.timeout_seconds === undefined
|
|
756
|
+
? command.timeoutSeconds
|
|
757
|
+
: clampInt(args.timeout_seconds, command.timeoutSeconds, 1, 600);
|
|
758
|
+
const timeoutSeconds = Math.min(requestedTimeout, command.timeoutSeconds);
|
|
759
|
+
const result = await this.runProcess(argv[0], argv.slice(1), timeoutSeconds * 1000, false, 512 * 1024, context, cwd);
|
|
760
|
+
return {
|
|
761
|
+
name: command.name,
|
|
762
|
+
cwd: this.displayPath(cwd),
|
|
763
|
+
timeout_seconds: timeoutSeconds,
|
|
764
|
+
...result,
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
|
|
736
768
|
async execCommand(command, timeoutSeconds, context = {}) {
|
|
737
769
|
if (this.policy.execMode !== "shell") throw new Error("exec_command requires shell execution mode");
|
|
738
770
|
if (!command || typeof command !== "string") throw new Error("command is required");
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
],
|
|
9
9
|
"instructions": [
|
|
10
10
|
"You are connected to a local workspace through machine-bridge-mcp.",
|
|
11
|
+
"For substantive workspace tasks, call agent_context for the relevant target path before editing or executing. Apply returned instruction files in precedence order, load only relevant local skills, and prefer registered local commands for repeatable workflows.",
|
|
11
12
|
"Remote mode uses a Cloudflare relay; stdio mode runs on the local machine. File and command operations execute on the user's local runtime, not in the Worker.",
|
|
12
13
|
"Filesystem scope and path display follow the active local policy; the default full profile is unrestricted.",
|
|
13
14
|
"Filename sensitivity is not classified by this server; the MCP host, connector gateway, local OS, or endpoint-security software may enforce additional independent rules.",
|
|
@@ -31,6 +31,178 @@
|
|
|
31
31
|
"additionalProperties": false
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
|
+
{
|
|
35
|
+
"name": "agent_context",
|
|
36
|
+
"title": "Load agent context",
|
|
37
|
+
"description": "Discover Codex-compatible global and root-to-target instruction precedence, progressively disclosed local skills, and registered commands for a target path.",
|
|
38
|
+
"availability": "always",
|
|
39
|
+
"annotations": {
|
|
40
|
+
"readOnlyHint": true,
|
|
41
|
+
"destructiveHint": false,
|
|
42
|
+
"idempotentHint": true,
|
|
43
|
+
"openWorldHint": false
|
|
44
|
+
},
|
|
45
|
+
"inputSchema": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"properties": {
|
|
48
|
+
"path": {
|
|
49
|
+
"type": "string",
|
|
50
|
+
"default": ".",
|
|
51
|
+
"maxLength": 32768
|
|
52
|
+
},
|
|
53
|
+
"include_instruction_content": {
|
|
54
|
+
"type": "boolean",
|
|
55
|
+
"default": true
|
|
56
|
+
},
|
|
57
|
+
"max_skills": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"minimum": 1,
|
|
60
|
+
"maximum": 500,
|
|
61
|
+
"default": 100
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"additionalProperties": false
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "list_local_skills",
|
|
69
|
+
"title": "List local skills",
|
|
70
|
+
"description": "Search bounded SKILL.md or skill.md bundles from Codex-compatible and explicitly configured skill roots without executing them.",
|
|
71
|
+
"availability": "always",
|
|
72
|
+
"annotations": {
|
|
73
|
+
"readOnlyHint": true,
|
|
74
|
+
"destructiveHint": false,
|
|
75
|
+
"idempotentHint": true,
|
|
76
|
+
"openWorldHint": false
|
|
77
|
+
},
|
|
78
|
+
"inputSchema": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"path": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"default": ".",
|
|
84
|
+
"maxLength": 32768
|
|
85
|
+
},
|
|
86
|
+
"query": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"default": "",
|
|
89
|
+
"maxLength": 1000
|
|
90
|
+
},
|
|
91
|
+
"max_results": {
|
|
92
|
+
"type": "integer",
|
|
93
|
+
"minimum": 1,
|
|
94
|
+
"maximum": 500,
|
|
95
|
+
"default": 100
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"additionalProperties": false
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "load_local_skill",
|
|
103
|
+
"title": "Load local skill",
|
|
104
|
+
"description": "Load one discovered local skill entrypoint and a bounded relative file inventory. Loading returns instructions and never executes skill files implicitly.",
|
|
105
|
+
"availability": "always",
|
|
106
|
+
"annotations": {
|
|
107
|
+
"readOnlyHint": true,
|
|
108
|
+
"destructiveHint": false,
|
|
109
|
+
"idempotentHint": true,
|
|
110
|
+
"openWorldHint": false
|
|
111
|
+
},
|
|
112
|
+
"inputSchema": {
|
|
113
|
+
"type": "object",
|
|
114
|
+
"properties": {
|
|
115
|
+
"skill": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"minLength": 1,
|
|
118
|
+
"maxLength": 32768
|
|
119
|
+
},
|
|
120
|
+
"path": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"default": ".",
|
|
123
|
+
"maxLength": 32768
|
|
124
|
+
},
|
|
125
|
+
"max_files": {
|
|
126
|
+
"type": "integer",
|
|
127
|
+
"minimum": 1,
|
|
128
|
+
"maximum": 500,
|
|
129
|
+
"default": 200
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"required": [
|
|
133
|
+
"skill"
|
|
134
|
+
],
|
|
135
|
+
"additionalProperties": false
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "list_local_commands",
|
|
140
|
+
"title": "List registered local commands",
|
|
141
|
+
"description": "List commands registered by hierarchical .machine-bridge/agent.json manifests for the selected target path.",
|
|
142
|
+
"availability": "always",
|
|
143
|
+
"annotations": {
|
|
144
|
+
"readOnlyHint": true,
|
|
145
|
+
"destructiveHint": false,
|
|
146
|
+
"idempotentHint": true,
|
|
147
|
+
"openWorldHint": false
|
|
148
|
+
},
|
|
149
|
+
"inputSchema": {
|
|
150
|
+
"type": "object",
|
|
151
|
+
"properties": {
|
|
152
|
+
"path": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"default": ".",
|
|
155
|
+
"maxLength": 32768
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"additionalProperties": false
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"name": "run_local_command",
|
|
163
|
+
"title": "Run registered local command",
|
|
164
|
+
"description": "Execute a named command registered in .machine-bridge/agent.json as a direct argv process without shell parsing. Manifest timeout and argument policy remain authoritative.",
|
|
165
|
+
"availability": "direct-exec",
|
|
166
|
+
"annotations": {
|
|
167
|
+
"readOnlyHint": false,
|
|
168
|
+
"destructiveHint": true,
|
|
169
|
+
"idempotentHint": false,
|
|
170
|
+
"openWorldHint": true
|
|
171
|
+
},
|
|
172
|
+
"inputSchema": {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"properties": {
|
|
175
|
+
"name": {
|
|
176
|
+
"type": "string",
|
|
177
|
+
"minLength": 1,
|
|
178
|
+
"maxLength": 64
|
|
179
|
+
},
|
|
180
|
+
"path": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
"default": ".",
|
|
183
|
+
"maxLength": 32768
|
|
184
|
+
},
|
|
185
|
+
"args": {
|
|
186
|
+
"type": "array",
|
|
187
|
+
"items": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"maxLength": 65536
|
|
190
|
+
},
|
|
191
|
+
"maxItems": 64,
|
|
192
|
+
"default": []
|
|
193
|
+
},
|
|
194
|
+
"timeout_seconds": {
|
|
195
|
+
"type": "integer",
|
|
196
|
+
"minimum": 1,
|
|
197
|
+
"maximum": 600
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"required": [
|
|
201
|
+
"name"
|
|
202
|
+
],
|
|
203
|
+
"additionalProperties": false
|
|
204
|
+
}
|
|
205
|
+
},
|
|
34
206
|
{
|
|
35
207
|
"name": "list_roots",
|
|
36
208
|
"title": "List workspace roots",
|
package/src/worker/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import toolCatalog from "../shared/tool-catalog.json";
|
|
|
3
3
|
import serverMetadata from "../shared/server-metadata.json";
|
|
4
4
|
|
|
5
5
|
const SERVER_NAME = String(serverMetadata.name);
|
|
6
|
-
const SERVER_VERSION = "0.
|
|
6
|
+
const SERVER_VERSION = "0.9.0";
|
|
7
7
|
const MCP_PROTOCOL_VERSION = String(serverMetadata.protocolVersion);
|
|
8
8
|
const MCP_SUPPORTED_PROTOCOL_VERSIONS = serverMetadata.supportedProtocolVersions.map((value) => String(value));
|
|
9
9
|
const JSONRPC_VERSION = "2.0";
|