musonda 1.0.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/IMPLEMENTATION.md +432 -0
- package/README.md +119 -0
- package/dist/agent/harness.d.ts +25 -0
- package/dist/agent/harness.js +215 -0
- package/dist/agent/harness.js.map +1 -0
- package/dist/agent/openaiResponsesClient.d.ts +35 -0
- package/dist/agent/openaiResponsesClient.js +250 -0
- package/dist/agent/openaiResponsesClient.js.map +1 -0
- package/dist/agent/systemPrompt.d.ts +9 -0
- package/dist/agent/systemPrompt.js +100 -0
- package/dist/agent/systemPrompt.js.map +1 -0
- package/dist/agent/types.d.ts +53 -0
- package/dist/agent/types.js +2 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +6 -0
- package/dist/cli/commands/chat.js +8 -0
- package/dist/cli/commands/chat.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +4 -0
- package/dist/cli/commands/doctor.js +336 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/gateway.d.ts +20 -0
- package/dist/cli/commands/gateway.js +135 -0
- package/dist/cli/commands/gateway.js.map +1 -0
- package/dist/cli/commands/help.d.ts +4 -0
- package/dist/cli/commands/help.js +159 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/plugins.d.ts +18 -0
- package/dist/cli/commands/plugins.js +250 -0
- package/dist/cli/commands/plugins.js.map +1 -0
- package/dist/cli/commands/service.d.ts +16 -0
- package/dist/cli/commands/service.js +136 -0
- package/dist/cli/commands/service.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +4 -0
- package/dist/cli/commands/setup.js +8 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +4 -0
- package/dist/cli/commands/status.js +73 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/update.d.ts +22 -0
- package/dist/cli/commands/update.js +226 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/daemon.d.ts +33 -0
- package/dist/cli/daemon.js +208 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/interactiveMenu.d.ts +5 -0
- package/dist/cli/interactiveMenu.js +225 -0
- package/dist/cli/interactiveMenu.js.map +1 -0
- package/dist/cli/musondaCli.d.ts +30 -0
- package/dist/cli/musondaCli.js +269 -0
- package/dist/cli/musondaCli.js.map +1 -0
- package/dist/cli/ui.d.ts +49 -0
- package/dist/cli/ui.js +90 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +315 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +12 -0
- package/dist/config/loader.js +217 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/paths.d.ts +11 -0
- package/dist/config/paths.js +18 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/types.d.ts +246 -0
- package/dist/config/types.js +155 -0
- package/dist/config/types.js.map +1 -0
- package/dist/gateway/channels/cli.d.ts +37 -0
- package/dist/gateway/channels/cli.js +298 -0
- package/dist/gateway/channels/cli.js.map +1 -0
- package/dist/gateway/channels/discord.d.ts +18 -0
- package/dist/gateway/channels/discord.js +419 -0
- package/dist/gateway/channels/discord.js.map +1 -0
- package/dist/gateway/channels/slack.d.ts +26 -0
- package/dist/gateway/channels/slack.js +470 -0
- package/dist/gateway/channels/slack.js.map +1 -0
- package/dist/gateway/channels/webhook.d.ts +18 -0
- package/dist/gateway/channels/webhook.js +49 -0
- package/dist/gateway/channels/webhook.js.map +1 -0
- package/dist/gateway/http.d.ts +33 -0
- package/dist/gateway/http.js +605 -0
- package/dist/gateway/http.js.map +1 -0
- package/dist/gateway/server.d.ts +38 -0
- package/dist/gateway/server.js +233 -0
- package/dist/gateway/server.js.map +1 -0
- package/dist/gateway/types.d.ts +28 -0
- package/dist/gateway/types.js +2 -0
- package/dist/gateway/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/memoryManager.d.ts +22 -0
- package/dist/memory/memoryManager.js +200 -0
- package/dist/memory/memoryManager.js.map +1 -0
- package/dist/memory/storage.d.ts +24 -0
- package/dist/memory/storage.js +187 -0
- package/dist/memory/storage.js.map +1 -0
- package/dist/memory/types.d.ts +43 -0
- package/dist/memory/types.js +2 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/plugins/manifest.d.ts +23 -0
- package/dist/plugins/manifest.js +185 -0
- package/dist/plugins/manifest.js.map +1 -0
- package/dist/plugins/mcp/mcpBridge.d.ts +31 -0
- package/dist/plugins/mcp/mcpBridge.js +115 -0
- package/dist/plugins/mcp/mcpBridge.js.map +1 -0
- package/dist/plugins/mcp/mcpClient.d.ts +43 -0
- package/dist/plugins/mcp/mcpClient.js +309 -0
- package/dist/plugins/mcp/mcpClient.js.map +1 -0
- package/dist/plugins/mcp/mcpConfig.d.ts +34 -0
- package/dist/plugins/mcp/mcpConfig.js +326 -0
- package/dist/plugins/mcp/mcpConfig.js.map +1 -0
- package/dist/plugins/mcp/types.d.ts +48 -0
- package/dist/plugins/mcp/types.js +2 -0
- package/dist/plugins/mcp/types.js.map +1 -0
- package/dist/plugins/pluginManager.d.ts +164 -0
- package/dist/plugins/pluginManager.js +1016 -0
- package/dist/plugins/pluginManager.js.map +1 -0
- package/dist/plugins/skills/frontmatterParser.d.ts +28 -0
- package/dist/plugins/skills/frontmatterParser.js +189 -0
- package/dist/plugins/skills/frontmatterParser.js.map +1 -0
- package/dist/plugins/skills/skillDiscovery.d.ts +15 -0
- package/dist/plugins/skills/skillDiscovery.js +148 -0
- package/dist/plugins/skills/skillDiscovery.js.map +1 -0
- package/dist/plugins/skills/skillTools.d.ts +8 -0
- package/dist/plugins/skills/skillTools.js +195 -0
- package/dist/plugins/skills/skillTools.js.map +1 -0
- package/dist/plugins/skills/types.d.ts +25 -0
- package/dist/plugins/skills/types.js +2 -0
- package/dist/plugins/skills/types.js.map +1 -0
- package/dist/plugins/types.d.ts +30 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +25 -0
- package/dist/scheduler/scheduler.js +239 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/types.d.ts +39 -0
- package/dist/scheduler/types.js +2 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/security/childProcessEnv.d.ts +5 -0
- package/dist/security/childProcessEnv.js +42 -0
- package/dist/security/childProcessEnv.js.map +1 -0
- package/dist/security/fileSandbox.d.ts +153 -0
- package/dist/security/fileSandbox.js +779 -0
- package/dist/security/fileSandbox.js.map +1 -0
- package/dist/service/index.d.ts +30 -0
- package/dist/service/index.js +41 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/systemd.d.ts +36 -0
- package/dist/service/systemd.js +409 -0
- package/dist/service/systemd.js.map +1 -0
- package/dist/service/types.d.ts +118 -0
- package/dist/service/types.js +6 -0
- package/dist/service/types.js.map +1 -0
- package/dist/tools/builtin/calcTools.d.ts +2 -0
- package/dist/tools/builtin/calcTools.js +51 -0
- package/dist/tools/builtin/calcTools.js.map +1 -0
- package/dist/tools/builtin/fileTools.d.ts +11 -0
- package/dist/tools/builtin/fileTools.js +352 -0
- package/dist/tools/builtin/fileTools.js.map +1 -0
- package/dist/tools/builtin/memoryTools.d.ts +4 -0
- package/dist/tools/builtin/memoryTools.js +123 -0
- package/dist/tools/builtin/memoryTools.js.map +1 -0
- package/dist/tools/builtin/noteTools.d.ts +4 -0
- package/dist/tools/builtin/noteTools.js +91 -0
- package/dist/tools/builtin/noteTools.js.map +1 -0
- package/dist/tools/builtin/pluginTools.d.ts +29 -0
- package/dist/tools/builtin/pluginTools.js +406 -0
- package/dist/tools/builtin/pluginTools.js.map +1 -0
- package/dist/tools/builtin/scheduleTools.d.ts +4 -0
- package/dist/tools/builtin/scheduleTools.js +156 -0
- package/dist/tools/builtin/scheduleTools.js.map +1 -0
- package/dist/tools/builtin/timeTools.d.ts +2 -0
- package/dist/tools/builtin/timeTools.js +41 -0
- package/dist/tools/builtin/timeTools.js.map +1 -0
- package/dist/tools/builtin/webTools.d.ts +12 -0
- package/dist/tools/builtin/webTools.js +325 -0
- package/dist/tools/builtin/webTools.js.map +1 -0
- package/dist/tools/registry.d.ts +15 -0
- package/dist/tools/registry.js +111 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +41 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/logger.d.ts +29 -0
- package/dist/utils/logger.js +124 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/wizard/onboarding.d.ts +3 -0
- package/dist/wizard/onboarding.js +408 -0
- package/dist/wizard/onboarding.js.map +1 -0
- package/package.json +69 -0
- package/plugins/example-calc/mcp.json +11 -0
- package/plugins/example-calc/plugin.json +12 -0
- package/plugins/example-calc/server.mjs +92 -0
- package/plugins/example-calc/skills/math-assistant/SKILL.md +15 -0
- package/plugins/plugin-builder/plugin.json +12 -0
- package/plugins/plugin-builder/skills/create-plugin/SKILL.md +149 -0
- package/plugins/plugin-builder/skills/manage-plugins/SKILL.md +157 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { MCP_SCHEMA_V1, } from './types.js';
|
|
4
|
+
import { logger } from '../../utils/logger.js';
|
|
5
|
+
export class McpConfigValidator {
|
|
6
|
+
/**
|
|
7
|
+
* Expands ${PLUGIN_ROOT} and ${PLUGIN_DATA} in a string value.
|
|
8
|
+
* Single-pass, non-recursive textual replacement.
|
|
9
|
+
*/
|
|
10
|
+
static expandVariables(value, pluginRoot, pluginData) {
|
|
11
|
+
return value
|
|
12
|
+
.replaceAll('${PLUGIN_ROOT}', pluginRoot)
|
|
13
|
+
.replaceAll('${PLUGIN_DATA}', pluginData);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validates top-level mcp.json document structure.
|
|
17
|
+
*/
|
|
18
|
+
static validateTopLevel(data) {
|
|
19
|
+
const errors = [];
|
|
20
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
21
|
+
return { valid: false, errors: ['mcp.json must be a JSON object.'] };
|
|
22
|
+
}
|
|
23
|
+
const obj = data;
|
|
24
|
+
const allowedKeys = new Set(['$schema', 'mcpServers']);
|
|
25
|
+
// Check unknown top-level keys
|
|
26
|
+
for (const key of Object.keys(obj)) {
|
|
27
|
+
if (!allowedKeys.has(key)) {
|
|
28
|
+
errors.push(`Unknown top-level field "${key}" in mcp.json is not permitted.`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Required $schema
|
|
32
|
+
if (!obj.$schema || typeof obj.$schema !== 'string') {
|
|
33
|
+
errors.push('mcp.json missing required string property "$schema".');
|
|
34
|
+
}
|
|
35
|
+
else if (obj.$schema !== MCP_SCHEMA_V1) {
|
|
36
|
+
errors.push(`Unsupported $schema in mcp.json: "${obj.$schema}". Expected "${MCP_SCHEMA_V1}".`);
|
|
37
|
+
}
|
|
38
|
+
// Required mcpServers
|
|
39
|
+
if (obj.mcpServers === undefined || obj.mcpServers === null) {
|
|
40
|
+
errors.push('mcp.json missing required property "mcpServers".');
|
|
41
|
+
}
|
|
42
|
+
else if (typeof obj.mcpServers !== 'object' || Array.isArray(obj.mcpServers)) {
|
|
43
|
+
errors.push('"mcpServers" must be an object.');
|
|
44
|
+
}
|
|
45
|
+
if (errors.length > 0) {
|
|
46
|
+
return { valid: false, errors };
|
|
47
|
+
}
|
|
48
|
+
return { valid: true, doc: obj, errors: [] };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validates and resolves an individual server entry from mcpServers.
|
|
52
|
+
*/
|
|
53
|
+
static validateServer(serverName, rawConfig, pluginName, pluginRoot, pluginData) {
|
|
54
|
+
const errors = [];
|
|
55
|
+
if (!rawConfig || typeof rawConfig !== 'object' || Array.isArray(rawConfig)) {
|
|
56
|
+
return { valid: false, errors: [`Server "${serverName}" configuration must be an object.`] };
|
|
57
|
+
}
|
|
58
|
+
const type = rawConfig.type;
|
|
59
|
+
if (type !== 'stdio' && type !== 'streamable-http' && type !== 'sse') {
|
|
60
|
+
return {
|
|
61
|
+
valid: false,
|
|
62
|
+
errors: [`Server "${serverName}" has unknown or missing type "${type}". Allowed: stdio, streamable-http, sse.`],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const resolvedRoot = path.resolve(pluginRoot);
|
|
66
|
+
const resolvedData = path.resolve(pluginData);
|
|
67
|
+
if (type === 'stdio') {
|
|
68
|
+
const allowedStdioFields = new Set(['type', 'command', 'args', 'env', 'cwd']);
|
|
69
|
+
for (const k of Object.keys(rawConfig)) {
|
|
70
|
+
if (!allowedStdioFields.has(k)) {
|
|
71
|
+
errors.push(`Server "${serverName}" of type stdio contains disallowed property "${k}".`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const command = rawConfig.command;
|
|
75
|
+
if (!command || typeof command !== 'string') {
|
|
76
|
+
errors.push(`Server "${serverName}" missing required string property "command".`);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Must be single token, bare executable or plugin-relative ./
|
|
80
|
+
if (command.includes(' ') && !command.startsWith('./')) {
|
|
81
|
+
errors.push(`Server "${serverName}" command must be a single executable token, not a shell string.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Check containment if plugin-relative
|
|
85
|
+
let resolvedCommand = command;
|
|
86
|
+
if (typeof command === 'string' && command.startsWith('./')) {
|
|
87
|
+
const cmdPath = path.resolve(resolvedRoot, command);
|
|
88
|
+
if (!cmdPath.startsWith(resolvedRoot)) {
|
|
89
|
+
errors.push(`Server "${serverName}" command "${command}" escapes plugin root.`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
resolvedCommand = cmdPath;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Validate env
|
|
96
|
+
let resolvedEnv = undefined;
|
|
97
|
+
if (rawConfig.env !== undefined) {
|
|
98
|
+
if (typeof rawConfig.env !== 'object' || rawConfig.env === null || Array.isArray(rawConfig.env)) {
|
|
99
|
+
errors.push(`Server "${serverName}" "env" must be an object of strings.`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
resolvedEnv = {};
|
|
103
|
+
for (const [k, v] of Object.entries(rawConfig.env)) {
|
|
104
|
+
if (k.toUpperCase() === 'PLUGIN_ROOT' || k.toUpperCase() === 'PLUGIN_DATA') {
|
|
105
|
+
errors.push(`Server "${serverName}" "env" must not contain reserved key "${k}".`);
|
|
106
|
+
}
|
|
107
|
+
else if (typeof v !== 'string') {
|
|
108
|
+
errors.push(`Server "${serverName}" env["${k}"] must be a string.`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
resolvedEnv[k] = this.expandVariables(v, resolvedRoot, resolvedData);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Validate args
|
|
117
|
+
let resolvedArgs = undefined;
|
|
118
|
+
if (rawConfig.args !== undefined) {
|
|
119
|
+
if (!Array.isArray(rawConfig.args) || rawConfig.args.some((a) => typeof a !== 'string')) {
|
|
120
|
+
errors.push(`Server "${serverName}" "args" must be an array of strings.`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
resolvedArgs = rawConfig.args.map((a) => this.expandVariables(a, resolvedRoot, resolvedData));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Validate cwd
|
|
127
|
+
let resolvedCwd = resolvedRoot;
|
|
128
|
+
if (rawConfig.cwd !== undefined) {
|
|
129
|
+
if (typeof rawConfig.cwd !== 'string') {
|
|
130
|
+
errors.push(`Server "${serverName}" "cwd" must be a string.`);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
const expandedCwd = this.expandVariables(rawConfig.cwd, resolvedRoot, resolvedData);
|
|
134
|
+
if (rawConfig.cwd.startsWith('./')) {
|
|
135
|
+
const cwdPath = path.resolve(resolvedRoot, rawConfig.cwd);
|
|
136
|
+
if (!cwdPath.startsWith(resolvedRoot)) {
|
|
137
|
+
errors.push(`Server "${serverName}" cwd "${rawConfig.cwd}" escapes plugin root.`);
|
|
138
|
+
}
|
|
139
|
+
resolvedCwd = cwdPath;
|
|
140
|
+
}
|
|
141
|
+
else if (rawConfig.cwd === '${PLUGIN_ROOT}' ||
|
|
142
|
+
rawConfig.cwd.startsWith('${PLUGIN_ROOT}/') ||
|
|
143
|
+
rawConfig.cwd.startsWith('${PLUGIN_ROOT}\\')) {
|
|
144
|
+
const cwdPath = path.resolve(expandedCwd);
|
|
145
|
+
if (!cwdPath.startsWith(resolvedRoot)) {
|
|
146
|
+
errors.push(`Server "${serverName}" cwd escapes plugin root.`);
|
|
147
|
+
}
|
|
148
|
+
resolvedCwd = cwdPath;
|
|
149
|
+
}
|
|
150
|
+
else if (rawConfig.cwd === '${PLUGIN_DATA}' ||
|
|
151
|
+
rawConfig.cwd.startsWith('${PLUGIN_DATA}/') ||
|
|
152
|
+
rawConfig.cwd.startsWith('${PLUGIN_DATA}\\')) {
|
|
153
|
+
const cwdPath = path.resolve(expandedCwd);
|
|
154
|
+
if (!cwdPath.startsWith(resolvedData)) {
|
|
155
|
+
errors.push(`Server "${serverName}" cwd escapes plugin data directory.`);
|
|
156
|
+
}
|
|
157
|
+
resolvedCwd = cwdPath;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
errors.push(`Server "${serverName}" cwd must start with "./", "\${PLUGIN_ROOT}", or "\${PLUGIN_DATA}".`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (errors.length > 0) {
|
|
165
|
+
return { valid: false, errors };
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
valid: true,
|
|
169
|
+
server: {
|
|
170
|
+
name: serverName,
|
|
171
|
+
pluginName,
|
|
172
|
+
config: rawConfig,
|
|
173
|
+
resolvedCommand,
|
|
174
|
+
resolvedArgs,
|
|
175
|
+
resolvedEnv,
|
|
176
|
+
resolvedCwd,
|
|
177
|
+
},
|
|
178
|
+
errors: [],
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// Remote HTTP / SSE transports
|
|
182
|
+
const allowedHttpFields = new Set(['type', 'url', 'headers']);
|
|
183
|
+
for (const k of Object.keys(rawConfig)) {
|
|
184
|
+
if (!allowedHttpFields.has(k)) {
|
|
185
|
+
errors.push(`Server "${serverName}" of type ${type} contains disallowed property "${k}".`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const urlStr = rawConfig.url;
|
|
189
|
+
if (!urlStr || typeof urlStr !== 'string') {
|
|
190
|
+
errors.push(`Server "${serverName}" missing required string property "url".`);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
try {
|
|
194
|
+
const parsedUrl = new URL(urlStr);
|
|
195
|
+
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
|
196
|
+
errors.push(`Server "${serverName}" url protocol must be http: or https:.`);
|
|
197
|
+
}
|
|
198
|
+
if (parsedUrl.username || parsedUrl.password) {
|
|
199
|
+
errors.push(`Server "${serverName}" url must not contain user information.`);
|
|
200
|
+
}
|
|
201
|
+
if (parsedUrl.hash) {
|
|
202
|
+
errors.push(`Server "${serverName}" url must not contain a fragment.`);
|
|
203
|
+
}
|
|
204
|
+
const isLoopback = parsedUrl.hostname === 'localhost' ||
|
|
205
|
+
parsedUrl.hostname === '127.0.0.1' ||
|
|
206
|
+
parsedUrl.hostname === '::1';
|
|
207
|
+
if (parsedUrl.protocol === 'http:' && !isLoopback) {
|
|
208
|
+
errors.push(`Server "${serverName}" non-loopback endpoints must use HTTPS.`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
errors.push(`Server "${serverName}" has invalid URL: ${err.message}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Validate headers
|
|
216
|
+
if (rawConfig.headers !== undefined) {
|
|
217
|
+
if (typeof rawConfig.headers !== 'object' ||
|
|
218
|
+
rawConfig.headers === null ||
|
|
219
|
+
Array.isArray(rawConfig.headers)) {
|
|
220
|
+
errors.push(`Server "${serverName}" "headers" must be an object of strings.`);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
const seenHeaders = new Set();
|
|
224
|
+
for (const [hk, hv] of Object.entries(rawConfig.headers)) {
|
|
225
|
+
const lowerHk = hk.toLowerCase();
|
|
226
|
+
if (seenHeaders.has(lowerHk)) {
|
|
227
|
+
errors.push(`Server "${serverName}" contains duplicate header "${hk}".`);
|
|
228
|
+
}
|
|
229
|
+
seenHeaders.add(lowerHk);
|
|
230
|
+
if (typeof hv !== 'string') {
|
|
231
|
+
errors.push(`Server "${serverName}" header "${hk}" value must be a string.`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (errors.length > 0) {
|
|
237
|
+
return { valid: false, errors };
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
valid: true,
|
|
241
|
+
server: {
|
|
242
|
+
name: serverName,
|
|
243
|
+
pluginName,
|
|
244
|
+
config: rawConfig,
|
|
245
|
+
},
|
|
246
|
+
errors: [],
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Discovers and parses mcp.json from a plugin directory.
|
|
251
|
+
*/
|
|
252
|
+
static loadFromDirectory(pluginRootDir, pluginName, pluginDataDir) {
|
|
253
|
+
const resolvedRoot = path.resolve(pluginRootDir);
|
|
254
|
+
const mcpPath = path.join(resolvedRoot, 'mcp.json');
|
|
255
|
+
const result = {
|
|
256
|
+
valid: true,
|
|
257
|
+
servers: [],
|
|
258
|
+
errors: [],
|
|
259
|
+
warnings: [],
|
|
260
|
+
};
|
|
261
|
+
if (!fs.existsSync(mcpPath)) {
|
|
262
|
+
// Optional component
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
// Check containment
|
|
266
|
+
const resolvedMcpPath = path.resolve(mcpPath);
|
|
267
|
+
if (!resolvedMcpPath.startsWith(resolvedRoot)) {
|
|
268
|
+
result.valid = false;
|
|
269
|
+
result.errors.push(`mcp.json path escapes plugin root.`);
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
let stat;
|
|
273
|
+
try {
|
|
274
|
+
stat = fs.statSync(resolvedMcpPath);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
result.valid = false;
|
|
278
|
+
result.errors.push(`Failed to stat mcp.json: ${err.message}`);
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
if (!stat.isFile()) {
|
|
282
|
+
result.valid = false;
|
|
283
|
+
result.errors.push(`Fixed component location "mcp.json" exists but is not a regular file.`);
|
|
284
|
+
return result;
|
|
285
|
+
}
|
|
286
|
+
let fileContent;
|
|
287
|
+
try {
|
|
288
|
+
fileContent = fs.readFileSync(resolvedMcpPath, 'utf8');
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
result.valid = false;
|
|
292
|
+
result.errors.push(`Failed to read mcp.json: ${err.message}`);
|
|
293
|
+
return result;
|
|
294
|
+
}
|
|
295
|
+
let parsed;
|
|
296
|
+
try {
|
|
297
|
+
parsed = JSON.parse(fileContent);
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
result.valid = false;
|
|
301
|
+
result.errors.push(`mcp.json is not valid JSON: ${err.message}`);
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
// Top-level validation
|
|
305
|
+
const topLevelCheck = this.validateTopLevel(parsed);
|
|
306
|
+
if (!topLevelCheck.valid) {
|
|
307
|
+
result.valid = false;
|
|
308
|
+
result.errors.push(...topLevelCheck.errors);
|
|
309
|
+
return result;
|
|
310
|
+
}
|
|
311
|
+
const doc = topLevelCheck.doc;
|
|
312
|
+
// Validate each server entry independently (narrow failure boundary)
|
|
313
|
+
for (const [sName, sCfg] of Object.entries(doc.mcpServers)) {
|
|
314
|
+
const serverCheck = this.validateServer(sName, sCfg, pluginName, resolvedRoot, pluginDataDir);
|
|
315
|
+
if (!serverCheck.valid) {
|
|
316
|
+
logger.warn(`[Plugin: ${pluginName}] Invalid MCP server "${sName}": ${serverCheck.errors.join('; ')}`);
|
|
317
|
+
result.warnings.push(`MCP server "${sName}" is invalid: ${serverCheck.errors.join('; ')}`);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
result.servers.push(serverCheck.server);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=mcpConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpConfig.js","sourceRoot":"","sources":["../../../src/plugins/mcp/mcpConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export declare const MCP_SCHEMA_V1 = "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json";
|
|
2
|
+
export interface McpStdioConfig {
|
|
3
|
+
type: 'stdio';
|
|
4
|
+
command: string;
|
|
5
|
+
args?: string[];
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface McpHttpConfig {
|
|
10
|
+
type: 'streamable-http';
|
|
11
|
+
url: string;
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export interface McpSseConfig {
|
|
15
|
+
type: 'sse';
|
|
16
|
+
url: string;
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export type McpServerConfig = McpStdioConfig | McpHttpConfig | McpSseConfig;
|
|
20
|
+
export interface McpDocument {
|
|
21
|
+
$schema: string;
|
|
22
|
+
mcpServers: Record<string, McpServerConfig>;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}
|
|
25
|
+
export interface McpToolSchema {
|
|
26
|
+
name: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object';
|
|
30
|
+
properties?: Record<string, any>;
|
|
31
|
+
required?: string[];
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface McpValidationResult {
|
|
36
|
+
valid: boolean;
|
|
37
|
+
doc?: McpDocument;
|
|
38
|
+
errors: string[];
|
|
39
|
+
}
|
|
40
|
+
export interface ResolvedMcpServer {
|
|
41
|
+
name: string;
|
|
42
|
+
pluginName: string;
|
|
43
|
+
config: McpServerConfig;
|
|
44
|
+
resolvedCwd?: string;
|
|
45
|
+
resolvedCommand?: string;
|
|
46
|
+
resolvedArgs?: string[];
|
|
47
|
+
resolvedEnv?: Record<string, string>;
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/plugins/mcp/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAG,yDAAyD,CAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { MusondaConfig } from '../config/types.js';
|
|
2
|
+
import { ToolRegistry } from '../tools/registry.js';
|
|
3
|
+
import { PluginPackage, PluginManifest } from './types.js';
|
|
4
|
+
import { AgentSkill } from './skills/types.js';
|
|
5
|
+
import { McpBridge } from './mcp/mcpBridge.js';
|
|
6
|
+
export declare class PluginManager {
|
|
7
|
+
private config;
|
|
8
|
+
private plugins;
|
|
9
|
+
private skills;
|
|
10
|
+
private mcpBridge;
|
|
11
|
+
private isLoaded;
|
|
12
|
+
constructor(config: MusondaConfig);
|
|
13
|
+
getAllSkills(): AgentSkill[];
|
|
14
|
+
getAllPlugins(): PluginPackage[];
|
|
15
|
+
getMcpBridge(): McpBridge;
|
|
16
|
+
/**
|
|
17
|
+
* Discovers and loads all plugins from configured plugin directories.
|
|
18
|
+
* Registers skills and MCP tools into Musonda's ToolRegistry.
|
|
19
|
+
*/
|
|
20
|
+
loadAll(toolRegistry: ToolRegistry): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Loads a single plugin from a directory.
|
|
23
|
+
*/
|
|
24
|
+
loadPluginFromDirectory(pluginDir: string, baseDataDir: string, disabledSet: Set<string>, toolRegistry: ToolRegistry): Promise<PluginPackage | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Unloads a plugin from runtime: terminates its MCP servers, removes its bridged tools and skills.
|
|
27
|
+
*/
|
|
28
|
+
unloadPlugin(pluginName: string, toolRegistry?: ToolRegistry): Promise<boolean>;
|
|
29
|
+
/**
|
|
30
|
+
* Reloads a specific plugin from disk into the live runtime.
|
|
31
|
+
*/
|
|
32
|
+
reloadPlugin(pluginName: string, toolRegistry: ToolRegistry): Promise<PluginPackage | null>;
|
|
33
|
+
/**
|
|
34
|
+
* Reloads all plugins from configured directories without shutting down the gateway.
|
|
35
|
+
*/
|
|
36
|
+
reloadAll(toolRegistry: ToolRegistry): Promise<{
|
|
37
|
+
loaded: number;
|
|
38
|
+
skills: number;
|
|
39
|
+
mcpServers: number;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Scaffolds a new plugin on disk with valid manifest, optional skills, and optional MCP servers,
|
|
43
|
+
* then immediately activates it in the live runtime.
|
|
44
|
+
*/
|
|
45
|
+
createAndLoadPlugin(params: {
|
|
46
|
+
name: string;
|
|
47
|
+
description: string;
|
|
48
|
+
version?: string;
|
|
49
|
+
author?: {
|
|
50
|
+
name: string;
|
|
51
|
+
email?: string;
|
|
52
|
+
};
|
|
53
|
+
skills?: Array<{
|
|
54
|
+
name: string;
|
|
55
|
+
description: string;
|
|
56
|
+
content: string;
|
|
57
|
+
scripts?: Array<{
|
|
58
|
+
filename: string;
|
|
59
|
+
content: string;
|
|
60
|
+
}>;
|
|
61
|
+
}>;
|
|
62
|
+
mcp?: Record<string, any>;
|
|
63
|
+
targetDir?: string;
|
|
64
|
+
}, toolRegistry: ToolRegistry): Promise<{
|
|
65
|
+
success: boolean;
|
|
66
|
+
plugin?: PluginPackage;
|
|
67
|
+
error?: string;
|
|
68
|
+
skillsLoaded: number;
|
|
69
|
+
toolsRegistered: string[];
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Installs an Agent Plugin from a local directory path, Git repository URL (e.g. GitHub), or npm package,
|
|
73
|
+
* validates its specification conformance (https://agent-plugins.org), installs any package dependencies,
|
|
74
|
+
* and immediately activates it in the live Musonda Gateway runtime without restarting the server.
|
|
75
|
+
*/
|
|
76
|
+
installPlugin(params: {
|
|
77
|
+
source: string;
|
|
78
|
+
name?: string;
|
|
79
|
+
installDependencies?: boolean;
|
|
80
|
+
targetDir?: string;
|
|
81
|
+
}, toolRegistry: ToolRegistry): Promise<{
|
|
82
|
+
success: boolean;
|
|
83
|
+
plugin?: PluginPackage;
|
|
84
|
+
error?: string;
|
|
85
|
+
skillsLoaded: number;
|
|
86
|
+
toolsRegistered: string[];
|
|
87
|
+
installedPath?: string;
|
|
88
|
+
}>;
|
|
89
|
+
/**
|
|
90
|
+
* Unloads and uninstalls an Agent Plugin: stops its MCP servers, removes bridged tools and skills
|
|
91
|
+
* from runtime, optionally deletes its files from disk, and optionally purges its persistent data directory.
|
|
92
|
+
*/
|
|
93
|
+
removePlugin(params: {
|
|
94
|
+
pluginName: string;
|
|
95
|
+
deleteFiles?: boolean;
|
|
96
|
+
purgeData?: boolean;
|
|
97
|
+
}, toolRegistry?: ToolRegistry): Promise<{
|
|
98
|
+
success: boolean;
|
|
99
|
+
error?: string;
|
|
100
|
+
pluginName: string;
|
|
101
|
+
unloaded: boolean;
|
|
102
|
+
deletedFiles: boolean;
|
|
103
|
+
purgedData: boolean;
|
|
104
|
+
skillsRemoved: string[];
|
|
105
|
+
toolsUnregistered: string[];
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Discovers Agent Plugins locally on disk and across the ecosystem (official repositories, GitHub, npm).
|
|
109
|
+
*/
|
|
110
|
+
findPlugins(params?: {
|
|
111
|
+
query?: string;
|
|
112
|
+
source?: 'all' | 'local' | 'remote';
|
|
113
|
+
}): Promise<{
|
|
114
|
+
query?: string;
|
|
115
|
+
totalFound: number;
|
|
116
|
+
local: Array<{
|
|
117
|
+
name: string;
|
|
118
|
+
version?: string;
|
|
119
|
+
description?: string;
|
|
120
|
+
isLoaded: boolean;
|
|
121
|
+
path: string;
|
|
122
|
+
skills: string[];
|
|
123
|
+
mcpServers: string[];
|
|
124
|
+
}>;
|
|
125
|
+
remote: Array<{
|
|
126
|
+
name: string;
|
|
127
|
+
description?: string;
|
|
128
|
+
repository: string;
|
|
129
|
+
url?: string;
|
|
130
|
+
author?: string;
|
|
131
|
+
keywords?: string[];
|
|
132
|
+
official?: boolean;
|
|
133
|
+
isInstalled: boolean;
|
|
134
|
+
}>;
|
|
135
|
+
}>;
|
|
136
|
+
/**
|
|
137
|
+
* Returns detailed inspection information for a specific plugin.
|
|
138
|
+
*/
|
|
139
|
+
getPluginInfo(pluginNameOrPath: string): {
|
|
140
|
+
found: boolean;
|
|
141
|
+
isLoaded: boolean;
|
|
142
|
+
manifest?: PluginManifest;
|
|
143
|
+
rootDir?: string;
|
|
144
|
+
dataDir?: string;
|
|
145
|
+
skills: Array<{
|
|
146
|
+
name: string;
|
|
147
|
+
description: string;
|
|
148
|
+
instructionsSummary?: string;
|
|
149
|
+
}>;
|
|
150
|
+
mcpServers: Array<{
|
|
151
|
+
name: string;
|
|
152
|
+
type: string;
|
|
153
|
+
command?: string;
|
|
154
|
+
url?: string;
|
|
155
|
+
tools?: string[];
|
|
156
|
+
}>;
|
|
157
|
+
activeTools?: string[];
|
|
158
|
+
error?: string;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Shuts down all active plugin resources (MCP subprocesses).
|
|
162
|
+
*/
|
|
163
|
+
shutdownAll(): Promise<void>;
|
|
164
|
+
}
|