create-guardio 0.0.5 → 0.0.7
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/index.mjs +94 -47
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
|
-
import { mkdir, writeFile
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
4
|
import { resolve, dirname } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
|
|
@@ -21,33 +21,83 @@ function ask(question, defaultAnswer = "") {
|
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
function askYesNo(question, defaultAnswer = "n") {
|
|
25
|
+
return ask(question + " (y/n)", defaultAnswer).then((a) =>
|
|
26
|
+
/^y(es)?|1$/i.test(a),
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
async function main() {
|
|
25
31
|
console.log("\nCreate Guardio\n");
|
|
26
32
|
|
|
27
33
|
const guardioDir = await ask("Guardio directory", "./mcp-server-gated");
|
|
28
34
|
const guardioPath = resolve(process.cwd(), guardioDir);
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
// Servers: at least one, with name + URL
|
|
37
|
+
const servers = [];
|
|
38
|
+
let serverName = await ask("First MCP server name", "default");
|
|
39
|
+
let serverUrl = await ask("MCP server URL", "https://example.com/mcp");
|
|
40
|
+
servers.push({ name: serverName, type: "url", url: serverUrl });
|
|
41
|
+
|
|
42
|
+
while (await askYesNo("Add another MCP server?", "n")) {
|
|
43
|
+
serverName = await ask("MCP server name", "server-" + (servers.length + 1));
|
|
44
|
+
serverUrl = await ask("MCP server URL", "https://example.com/mcp");
|
|
45
|
+
servers.push({ name: serverName, type: "url", url: serverUrl });
|
|
46
|
+
}
|
|
47
|
+
|
|
31
48
|
const portStr = await ask("Guardio HTTP server port", "3939");
|
|
32
49
|
const port = parseInt(portStr, 10) || 3939;
|
|
33
50
|
|
|
51
|
+
const installDashboard = await askYesNo("Install dashboard?", "n");
|
|
52
|
+
|
|
53
|
+
// Built-in plugins: by category
|
|
54
|
+
console.log("\nPolicy plugins:");
|
|
55
|
+
console.log(" 1) none");
|
|
56
|
+
console.log(" 2) deny-tool-access");
|
|
57
|
+
console.log(" 3) regex");
|
|
58
|
+
console.log(" 4) both");
|
|
59
|
+
const policyChoice = await ask("Policy plugins (1-4)", "1");
|
|
60
|
+
const policyNum = parseInt(policyChoice, 10) || 1;
|
|
61
|
+
const policyPlugins = [];
|
|
62
|
+
if (policyNum === 2 || policyNum === 4) policyPlugins.push({ type: "policy", name: "deny-tool-access" });
|
|
63
|
+
if (policyNum === 3 || policyNum === 4) policyPlugins.push({ type: "policy", name: "regex" });
|
|
64
|
+
|
|
65
|
+
const useStorage = await askYesNo("Use storage and events (for dashboard / policy state)?", installDashboard ? "y" : "n");
|
|
66
|
+
|
|
67
|
+
const plugins = [...policyPlugins];
|
|
68
|
+
if (useStorage) {
|
|
69
|
+
console.log(" 1) sqlite (local file)");
|
|
70
|
+
console.log(" 2) postgres");
|
|
71
|
+
const storageBackend = await ask("Storage backend (1-2)", "1");
|
|
72
|
+
if (storageBackend === "2") {
|
|
73
|
+
const pgConnectionString = await ask(
|
|
74
|
+
"PostgreSQL connection string",
|
|
75
|
+
"postgresql://localhost:5432/guardio",
|
|
76
|
+
);
|
|
77
|
+
const pgConfig = { connectionString: pgConnectionString };
|
|
78
|
+
plugins.push({ type: "storage", name: "postgres", config: pgConfig });
|
|
79
|
+
plugins.push({ type: "eventSink", name: "postgres" });
|
|
80
|
+
plugins.push({ type: "eventSinkStore", name: "postgres" });
|
|
81
|
+
} else {
|
|
82
|
+
const sqliteConfig = { database: "guardio.sqlite" };
|
|
83
|
+
plugins.push({ type: "storage", name: "sqlite", config: sqliteConfig });
|
|
84
|
+
plugins.push({ type: "eventSink", name: "sqlite", config: sqliteConfig });
|
|
85
|
+
plugins.push({ type: "eventSinkStore", name: "sqlite", config: sqliteConfig });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const addExamplePlugin = await askYesNo("Add example custom policy plugin?", "n");
|
|
90
|
+
if (addExamplePlugin) {
|
|
91
|
+
plugins.push({ type: "policy", name: "example", path: "./plugins/example" });
|
|
92
|
+
}
|
|
93
|
+
|
|
34
94
|
const config = {
|
|
35
|
-
|
|
36
|
-
client: {
|
|
37
|
-
plugins
|
|
38
|
-
{ type: "policy", name: "default", config: { blockedTools: [] } },
|
|
39
|
-
{
|
|
40
|
-
type: "policy",
|
|
41
|
-
name: "example",
|
|
42
|
-
path: "./plugins/example",
|
|
43
|
-
config: {},
|
|
44
|
-
},
|
|
45
|
-
],
|
|
95
|
+
servers,
|
|
96
|
+
client: { port, host: "127.0.0.1" },
|
|
97
|
+
plugins,
|
|
46
98
|
};
|
|
47
99
|
|
|
48
100
|
await mkdir(guardioPath, { recursive: true });
|
|
49
|
-
await mkdir(resolve(guardioPath, "bin"), { recursive: true });
|
|
50
|
-
await mkdir(resolve(guardioPath, "plugins", "example"), { recursive: true });
|
|
51
101
|
|
|
52
102
|
const packageJson = {
|
|
53
103
|
name: "guardio-project",
|
|
@@ -56,14 +106,20 @@ async function main() {
|
|
|
56
106
|
description: "Guardio-gated MCP server with optional local plugins",
|
|
57
107
|
scripts: {
|
|
58
108
|
build: "tsc",
|
|
59
|
-
guardio:
|
|
109
|
+
guardio:
|
|
110
|
+
"node --import tsx ./node_modules/@guardiojs/guardio/dist/cli.js --config guardio.config.ts",
|
|
60
111
|
},
|
|
61
112
|
dependencies: { "@guardiojs/guardio": "*" },
|
|
62
113
|
devDependencies: {
|
|
63
114
|
typescript: "^5.6.0",
|
|
64
115
|
"@types/node": "^22.0.0",
|
|
116
|
+
tsx: "^4.19.0",
|
|
65
117
|
},
|
|
66
118
|
};
|
|
119
|
+
if (installDashboard) {
|
|
120
|
+
packageJson.dependencies["@guardiojs/dashboard"] = "*";
|
|
121
|
+
packageJson.scripts.dashboard = "guardio-dashboard";
|
|
122
|
+
}
|
|
67
123
|
await writeFile(
|
|
68
124
|
resolve(guardioPath, "package.json"),
|
|
69
125
|
JSON.stringify(packageJson, null, 2),
|
|
@@ -99,25 +155,9 @@ export default config;
|
|
|
99
155
|
"utf-8",
|
|
100
156
|
);
|
|
101
157
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
import
|
|
105
|
-
import { fileURLToPath } from "url";
|
|
106
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
107
|
-
const configPath = path.resolve(__dirname, "..", "guardio.config.ts");
|
|
108
|
-
const result = spawnSync(
|
|
109
|
-
"npx",
|
|
110
|
-
["-y", "@guardiojs/guardio", "--config", configPath],
|
|
111
|
-
{ stdio: "inherit" }
|
|
112
|
-
);
|
|
113
|
-
process.exit(result.status ?? 1);
|
|
114
|
-
`;
|
|
115
|
-
|
|
116
|
-
const binPath = resolve(guardioPath, "bin", "guardio.mjs");
|
|
117
|
-
await writeFile(binPath, binContent, "utf-8");
|
|
118
|
-
await chmod(binPath, 0o755);
|
|
119
|
-
|
|
120
|
-
const examplePluginContent = `import type {
|
|
158
|
+
if (addExamplePlugin) {
|
|
159
|
+
await mkdir(resolve(guardioPath, "plugins", "example"), { recursive: true });
|
|
160
|
+
const examplePluginContent = `import type {
|
|
121
161
|
PolicyPluginInterface,
|
|
122
162
|
PolicyRequestContext,
|
|
123
163
|
PolicyResult,
|
|
@@ -133,30 +173,29 @@ class ExamplePolicyPlugin implements PolicyPluginInterface {
|
|
|
133
173
|
|
|
134
174
|
evaluate(context: PolicyRequestContext): PolicyResult {
|
|
135
175
|
// Example: allow all calls. Replace with your policy logic.
|
|
136
|
-
return "
|
|
176
|
+
return { verdict: "allow" };
|
|
137
177
|
}
|
|
138
178
|
}
|
|
139
179
|
|
|
140
180
|
export default new ExamplePolicyPlugin();
|
|
141
181
|
`;
|
|
182
|
+
await writeFile(
|
|
183
|
+
resolve(guardioPath, "plugins", "example", "index.ts"),
|
|
184
|
+
examplePluginContent,
|
|
185
|
+
"utf-8",
|
|
186
|
+
);
|
|
187
|
+
}
|
|
142
188
|
|
|
143
|
-
await
|
|
144
|
-
resolve(guardioPath, "plugins", "example", "index.ts"),
|
|
145
|
-
examplePluginContent,
|
|
146
|
-
"utf-8",
|
|
147
|
-
);
|
|
148
|
-
|
|
189
|
+
await mkdir(resolve(guardioPath, "plugins"), { recursive: true });
|
|
149
190
|
const pluginsReadme = `# Custom plugins (path-based)
|
|
150
191
|
|
|
151
192
|
Add a plugin by setting \`path\` in \`guardio.config.ts\` to a directory that contains \`index.js\` or \`index.mjs\` (compile from \`index.ts\` with \`npm run build\`).
|
|
152
193
|
|
|
153
194
|
- The directory must have \`index.js\` or \`index.mjs\` whose **default export is the plugin instance** (no descriptor).
|
|
154
195
|
- Policy: implement \`PolicyPluginInterface\` (name, evaluate). Config: \`{ "type": "policy", "name": "my-policy", "path": "./plugins/my-policy" }\`.
|
|
155
|
-
- Intervention: implement \`InterventionPluginInterface\` (name, act). Config: \`{ "type": "intervention", "name": "my-intervention", "path": "./plugins/my-intervention" }\`.
|
|
156
196
|
|
|
157
|
-
Import types from "@guardiojs/guardio"
|
|
197
|
+
Import types from "@guardiojs/guardio".${addExamplePlugin ? " See example/ for a policy plugin." : ""}
|
|
158
198
|
`;
|
|
159
|
-
|
|
160
199
|
await writeFile(
|
|
161
200
|
resolve(guardioPath, "plugins", "README.md"),
|
|
162
201
|
pluginsReadme,
|
|
@@ -166,11 +205,19 @@ Import types from "@guardiojs/guardio". See example/ for a policy plugin.
|
|
|
166
205
|
console.log("\n---\n");
|
|
167
206
|
console.log("Next steps");
|
|
168
207
|
console.log(" cd " + guardioDir + " && npm install");
|
|
169
|
-
|
|
208
|
+
if (addExamplePlugin) {
|
|
209
|
+
console.log(" npm run build # compile plugins (index.ts → index.js)");
|
|
210
|
+
}
|
|
170
211
|
console.log("");
|
|
171
212
|
console.log("Run Guardio as HTTP server:");
|
|
172
|
-
console.log("
|
|
213
|
+
console.log(" npm run guardio");
|
|
173
214
|
console.log("");
|
|
215
|
+
if (installDashboard) {
|
|
216
|
+
console.log("Run dashboard (point it at Guardio URL):");
|
|
217
|
+
console.log(" npm run dashboard");
|
|
218
|
+
console.log(" # Dashboard needs Guardio base URL, e.g. http://127.0.0.1:" + port);
|
|
219
|
+
console.log("");
|
|
220
|
+
}
|
|
174
221
|
console.log("Add to MCP client (use URL):");
|
|
175
222
|
console.log(' "url": "http://127.0.0.1:' + port + '"');
|
|
176
223
|
console.log("");
|