daemora 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.
Files changed (115) hide show
  1. package/README.md +666 -0
  2. package/SOUL.md +104 -0
  3. package/config/hooks.json +14 -0
  4. package/config/mcp.json +145 -0
  5. package/package.json +86 -0
  6. package/skills/.gitkeep +0 -0
  7. package/skills/apple-notes.md +193 -0
  8. package/skills/apple-reminders.md +189 -0
  9. package/skills/camsnap.md +162 -0
  10. package/skills/coding.md +14 -0
  11. package/skills/documents.md +13 -0
  12. package/skills/email.md +13 -0
  13. package/skills/gif-search.md +196 -0
  14. package/skills/healthcheck.md +225 -0
  15. package/skills/image-gen.md +147 -0
  16. package/skills/model-usage.md +182 -0
  17. package/skills/obsidian.md +207 -0
  18. package/skills/pdf.md +211 -0
  19. package/skills/research.md +13 -0
  20. package/skills/skill-creator.md +142 -0
  21. package/skills/spotify.md +149 -0
  22. package/skills/summarize.md +230 -0
  23. package/skills/things.md +199 -0
  24. package/skills/tmux.md +204 -0
  25. package/skills/trello.md +183 -0
  26. package/skills/video-frames.md +202 -0
  27. package/skills/weather.md +127 -0
  28. package/src/a2a/A2AClient.js +136 -0
  29. package/src/a2a/A2AServer.js +316 -0
  30. package/src/a2a/AgentCard.js +79 -0
  31. package/src/agents/SubAgentManager.js +369 -0
  32. package/src/agents/Supervisor.js +192 -0
  33. package/src/channels/BaseChannel.js +104 -0
  34. package/src/channels/DiscordChannel.js +288 -0
  35. package/src/channels/EmailChannel.js +172 -0
  36. package/src/channels/GoogleChatChannel.js +316 -0
  37. package/src/channels/HttpChannel.js +26 -0
  38. package/src/channels/LineChannel.js +168 -0
  39. package/src/channels/SignalChannel.js +186 -0
  40. package/src/channels/SlackChannel.js +329 -0
  41. package/src/channels/TeamsChannel.js +272 -0
  42. package/src/channels/TelegramChannel.js +347 -0
  43. package/src/channels/WhatsAppChannel.js +219 -0
  44. package/src/channels/index.js +198 -0
  45. package/src/cli.js +1267 -0
  46. package/src/config/agentProfiles.js +120 -0
  47. package/src/config/channels.js +32 -0
  48. package/src/config/default.js +206 -0
  49. package/src/config/models.js +123 -0
  50. package/src/config/permissions.js +167 -0
  51. package/src/core/AgentLoop.js +446 -0
  52. package/src/core/Compaction.js +143 -0
  53. package/src/core/CostTracker.js +116 -0
  54. package/src/core/EventBus.js +46 -0
  55. package/src/core/Task.js +67 -0
  56. package/src/core/TaskQueue.js +206 -0
  57. package/src/core/TaskRunner.js +226 -0
  58. package/src/daemon/DaemonManager.js +301 -0
  59. package/src/hooks/HookRunner.js +230 -0
  60. package/src/index.js +482 -0
  61. package/src/mcp/MCPAgentRunner.js +112 -0
  62. package/src/mcp/MCPClient.js +186 -0
  63. package/src/mcp/MCPManager.js +412 -0
  64. package/src/models/ModelRouter.js +180 -0
  65. package/src/safety/AuditLog.js +135 -0
  66. package/src/safety/CircuitBreaker.js +126 -0
  67. package/src/safety/FilesystemGuard.js +169 -0
  68. package/src/safety/GitRollback.js +139 -0
  69. package/src/safety/HumanApproval.js +156 -0
  70. package/src/safety/InputSanitizer.js +72 -0
  71. package/src/safety/PermissionGuard.js +83 -0
  72. package/src/safety/Sandbox.js +70 -0
  73. package/src/safety/SecretScanner.js +100 -0
  74. package/src/safety/SecretVault.js +250 -0
  75. package/src/scheduler/Heartbeat.js +115 -0
  76. package/src/scheduler/Scheduler.js +228 -0
  77. package/src/services/models/outputSchema.js +15 -0
  78. package/src/services/openai.js +25 -0
  79. package/src/services/sessions.js +65 -0
  80. package/src/setup/theme.js +110 -0
  81. package/src/setup/wizard.js +788 -0
  82. package/src/skills/SkillLoader.js +168 -0
  83. package/src/storage/TaskStore.js +69 -0
  84. package/src/systemPrompt.js +526 -0
  85. package/src/tenants/TenantContext.js +19 -0
  86. package/src/tenants/TenantManager.js +379 -0
  87. package/src/tools/ToolRegistry.js +141 -0
  88. package/src/tools/applyPatch.js +144 -0
  89. package/src/tools/browserAutomation.js +223 -0
  90. package/src/tools/createDocument.js +265 -0
  91. package/src/tools/cronTool.js +105 -0
  92. package/src/tools/editFile.js +139 -0
  93. package/src/tools/executeCommand.js +123 -0
  94. package/src/tools/glob.js +67 -0
  95. package/src/tools/grep.js +121 -0
  96. package/src/tools/imageAnalysis.js +120 -0
  97. package/src/tools/index.js +173 -0
  98. package/src/tools/listDirectory.js +47 -0
  99. package/src/tools/manageAgents.js +47 -0
  100. package/src/tools/manageMCP.js +159 -0
  101. package/src/tools/memory.js +478 -0
  102. package/src/tools/messageChannel.js +45 -0
  103. package/src/tools/projectTracker.js +259 -0
  104. package/src/tools/readFile.js +52 -0
  105. package/src/tools/screenCapture.js +112 -0
  106. package/src/tools/searchContent.js +76 -0
  107. package/src/tools/searchFiles.js +75 -0
  108. package/src/tools/sendEmail.js +118 -0
  109. package/src/tools/sendFile.js +63 -0
  110. package/src/tools/textToSpeech.js +161 -0
  111. package/src/tools/transcribeAudio.js +82 -0
  112. package/src/tools/useMCP.js +29 -0
  113. package/src/tools/webFetch.js +150 -0
  114. package/src/tools/webSearch.js +134 -0
  115. package/src/tools/writeFile.js +26 -0
@@ -0,0 +1,173 @@
1
+ // ─── Existing tools ────────────────────────────────────────────────────────────
2
+ import { executeCommand, executeCommandDescription } from "./executeCommand.js";
3
+ import { readFile, readFileDescription } from "./readFile.js";
4
+ import { writeFile, writeFileDescription } from "./writeFile.js";
5
+ import { editFile, editFileDescription } from "./editFile.js";
6
+ import { listDirectory, listDirectoryDescription } from "./listDirectory.js";
7
+ import { searchFiles, searchFilesDescription } from "./searchFiles.js";
8
+ import { searchContent, searchContentDescription } from "./searchContent.js";
9
+ import { webFetch, webFetchDescription } from "./webFetch.js";
10
+ import { webSearch, webSearchDescription } from "./webSearch.js";
11
+ import { sendEmail, sendEmailDescription } from "./sendEmail.js";
12
+ import { createDocument, createDocumentDescription } from "./createDocument.js";
13
+ import { browserAction, browserActionDescription } from "./browserAutomation.js";
14
+ import {
15
+ readMemory, readMemoryDescription,
16
+ writeMemory, writeMemoryDescription,
17
+ readDailyLog, readDailyLogDescription,
18
+ writeDailyLog, writeDailyLogDescription,
19
+ searchMemory, searchMemoryDescription,
20
+ pruneMemory, pruneMemoryDescription,
21
+ listMemoryCategories, listMemoryCategoriesDescription,
22
+ } from "./memory.js";
23
+ import { spawnSubAgent, spawnParallelAgents } from "../agents/SubAgentManager.js";
24
+ import { delegateToAgent, delegateToAgentDescription } from "../a2a/A2AClient.js";
25
+
26
+ // ─── Media tools ───────────────────────────────────────────────────────────────
27
+ import { transcribeAudio, transcribeAudioDescription } from "./transcribeAudio.js";
28
+ import { sendFile, sendFileDescription } from "./sendFile.js";
29
+ import { textToSpeech, textToSpeechDescription } from "./textToSpeech.js";
30
+
31
+ // ─── New tools ─────────────────────────────────────────────────────────────────
32
+ import { globSearch, globSearchDescription } from "./glob.js";
33
+ import { grep, grepDescription } from "./grep.js";
34
+ import { applyPatch, applyPatchDescription } from "./applyPatch.js";
35
+ import { imageAnalysis, imageAnalysisDescription } from "./imageAnalysis.js";
36
+ import { screenCapture, screenCaptureDescription } from "./screenCapture.js";
37
+ import { manageAgents, manageAgentsDescription } from "./manageAgents.js";
38
+ import { cron, cronDescription } from "./cronTool.js";
39
+ import { messageChannel, messageChannelDescription } from "./messageChannel.js";
40
+ import { projectTracker, projectTrackerDescription } from "./projectTracker.js";
41
+ import { manageMCP, manageMCPDescription } from "./manageMCP.js";
42
+ import { useMCP, useMCPDescription } from "./useMCP.js";
43
+
44
+ // ─── Wrap spawnAgent for the tool interface ────────────────────────────────────
45
+ function spawnAgent(taskDescription, optionsJson) {
46
+ const options = optionsJson ? JSON.parse(optionsJson) : {};
47
+ return spawnSubAgent(taskDescription, options);
48
+ }
49
+
50
+ const spawnAgentDescription =
51
+ 'spawnAgent(taskDescription: string, optionsJson?: string) - Spawn a sub-agent to handle a task independently. optionsJson: {"model":"openai:gpt-4.1-mini","tools":["readFile","searchContent"],"maxTurns":10,"parentContext":"shared spec here"}';
52
+
53
+ // ─── Wrap parallelAgents for the tool interface ────────────────────────────────
54
+ function parallelAgents(tasksJson, sharedOptionsJson) {
55
+ const tasks = typeof tasksJson === "string" ? JSON.parse(tasksJson) : (tasksJson || []);
56
+ const sharedOptions = typeof sharedOptionsJson === "string" ? JSON.parse(sharedOptionsJson) : (sharedOptionsJson || {});
57
+ return spawnParallelAgents(tasks, sharedOptions);
58
+ }
59
+
60
+ const parallelAgentsDescription =
61
+ `parallelAgents(tasksJson: string, sharedOptionsJson?: string) - Spawn multiple sub-agents in parallel with a shared spec/context.
62
+ CRITICAL: Always pass sharedContext so agents know about each other's work (e.g. HTML class names for CSS agent).
63
+ tasksJson: [{"description":"Write index.html with id=app, class=todo-item"},{"description":"Write style.css for .todo-item"}]
64
+ sharedOptionsJson: {"sharedContext":"Shared spec: HTML uses id=app, ul#todo-list, li.todo-item, button.delete-btn, input#new-todo"}
65
+ Each agent gets the sharedContext as its starting context before its own task description.`;
66
+
67
+ // ─── Tool Functions Map ────────────────────────────────────────────────────────
68
+
69
+ export const toolFunctions = {
70
+ // File operations
71
+ readFile,
72
+ writeFile,
73
+ editFile,
74
+ listDirectory,
75
+ searchFiles,
76
+ searchContent,
77
+ // Advanced search (new)
78
+ glob: globSearch,
79
+ grep,
80
+ applyPatch,
81
+ // System
82
+ executeCommand,
83
+ // Web
84
+ webFetch,
85
+ webSearch,
86
+ // Browser
87
+ browserAction,
88
+ // Communication
89
+ sendEmail,
90
+ messageChannel,
91
+ sendFile,
92
+ transcribeAudio,
93
+ textToSpeech,
94
+ // Documents
95
+ createDocument,
96
+ // Memory
97
+ readMemory,
98
+ writeMemory,
99
+ readDailyLog,
100
+ writeDailyLog,
101
+ searchMemory,
102
+ pruneMemory,
103
+ listMemoryCategories,
104
+ // Agents
105
+ spawnAgent,
106
+ parallelAgents,
107
+ delegateToAgent,
108
+ manageAgents,
109
+ // Project tracking
110
+ projectTracker,
111
+ // Automation
112
+ cron,
113
+ // Vision / Screen
114
+ imageAnalysis,
115
+ screenCapture,
116
+ // MCP management
117
+ manageMCP,
118
+ useMCP,
119
+ };
120
+
121
+ // ─── Tool Descriptions Array ───────────────────────────────────────────────────
122
+
123
+ export const toolDescriptions = [
124
+ // File operations
125
+ readFileDescription,
126
+ writeFileDescription,
127
+ editFileDescription,
128
+ listDirectoryDescription,
129
+ searchFilesDescription,
130
+ searchContentDescription,
131
+ // Advanced search
132
+ globSearchDescription,
133
+ grepDescription,
134
+ applyPatchDescription,
135
+ // System
136
+ executeCommandDescription,
137
+ // Web
138
+ webFetchDescription,
139
+ webSearchDescription,
140
+ // Browser
141
+ browserActionDescription,
142
+ // Communication
143
+ sendEmailDescription,
144
+ messageChannelDescription,
145
+ sendFileDescription,
146
+ transcribeAudioDescription,
147
+ textToSpeechDescription,
148
+ // Documents
149
+ createDocumentDescription,
150
+ // Memory
151
+ readMemoryDescription,
152
+ writeMemoryDescription,
153
+ readDailyLogDescription,
154
+ writeDailyLogDescription,
155
+ searchMemoryDescription,
156
+ pruneMemoryDescription,
157
+ listMemoryCategoriesDescription,
158
+ // Agents
159
+ spawnAgentDescription,
160
+ parallelAgentsDescription,
161
+ delegateToAgentDescription,
162
+ manageAgentsDescription,
163
+ // Project tracking
164
+ projectTrackerDescription,
165
+ // Automation
166
+ cronDescription,
167
+ // Vision / Screen
168
+ imageAnalysisDescription,
169
+ screenCaptureDescription,
170
+ // MCP management
171
+ manageMCPDescription,
172
+ useMCPDescription,
173
+ ];
@@ -0,0 +1,47 @@
1
+ import { readdirSync, statSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import filesystemGuard from "../safety/FilesystemGuard.js";
4
+
5
+ export function listDirectory(dirPath = ".") {
6
+ const guard = filesystemGuard.checkRead(dirPath);
7
+ if (!guard.allowed) {
8
+ console.log(` [listDirectory] BLOCKED: ${guard.reason}`);
9
+ return guard.reason;
10
+ }
11
+ console.log(` [listDirectory] Listing: ${dirPath}`);
12
+ try {
13
+ const entries = readdirSync(dirPath);
14
+ const results = entries
15
+ .filter((e) => e !== "node_modules" && e !== ".git")
16
+ .map((entry) => {
17
+ try {
18
+ const fullPath = join(dirPath, entry);
19
+ const stat = statSync(fullPath);
20
+ const type = stat.isDirectory() ? "[DIR]" : "[FILE]";
21
+ const size = stat.isFile()
22
+ ? ` (${formatSize(stat.size)})`
23
+ : "";
24
+ return `${type} ${entry}${size}`;
25
+ } catch {
26
+ return `[?] ${entry}`;
27
+ }
28
+ });
29
+
30
+ console.log(` [listDirectory] Found ${results.length} entries`);
31
+ return results.length > 0
32
+ ? `Directory: ${dirPath}\n\n${results.join("\n")}`
33
+ : `Directory ${dirPath} is empty.`;
34
+ } catch (error) {
35
+ console.log(` [listDirectory] Failed: ${error.message}`);
36
+ return `Error listing directory: ${error.message}`;
37
+ }
38
+ }
39
+
40
+ function formatSize(bytes) {
41
+ if (bytes < 1024) return `${bytes}B`;
42
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
43
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
44
+ }
45
+
46
+ export const listDirectoryDescription =
47
+ "listDirectory(dirPath: string) - Lists all files and folders in a directory with their types and sizes. Skips node_modules and .git automatically.";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * manageAgents(action, paramsJson?) — List, kill, or steer running sub-agents.
3
+ * Inspired by OpenClaw's subagents tool.
4
+ */
5
+ import {
6
+ listActiveAgents,
7
+ killAgent,
8
+ steerAgent,
9
+ } from "../agents/SubAgentManager.js";
10
+
11
+ export function manageAgents(action, paramsJson) {
12
+ try {
13
+ const params = paramsJson ? JSON.parse(paramsJson) : {};
14
+
15
+ switch (action) {
16
+ case "list": {
17
+ const agents = listActiveAgents();
18
+ if (agents.length === 0) return "No active sub-agents running.";
19
+ const lines = agents.map(
20
+ (a) => `• ${a.id} — "${a.task}" (running ${Math.round(a.elapsedMs / 1000)}s)`
21
+ );
22
+ return `Active sub-agents (${agents.length}):\n${lines.join("\n")}`;
23
+ }
24
+
25
+ case "kill": {
26
+ if (!params.agentId) return 'Error: agentId is required for "kill" action';
27
+ const result = killAgent(params.agentId);
28
+ return result;
29
+ }
30
+
31
+ case "steer": {
32
+ if (!params.agentId) return 'Error: agentId is required for "steer" action';
33
+ if (!params.message) return 'Error: message is required for "steer" action';
34
+ const result = steerAgent(params.agentId, params.message);
35
+ return result;
36
+ }
37
+
38
+ default:
39
+ return `Unknown action: "${action}". Available: list, kill, steer`;
40
+ }
41
+ } catch (error) {
42
+ return `Error managing agents: ${error.message}`;
43
+ }
44
+ }
45
+
46
+ export const manageAgentsDescription =
47
+ 'manageAgents(action: string, paramsJson?: string) - Manage running sub-agents. Actions: "list" (show all), "kill" ({"agentId":"id"}), "steer" ({"agentId":"id","message":"new instruction"}).';
@@ -0,0 +1,159 @@
1
+ import mcpManager from "../mcp/MCPManager.js";
2
+
3
+ /**
4
+ * manageMCP — inspect, add, remove, and reload MCP server connections at runtime.
5
+ *
6
+ * Actions:
7
+ * list — all configured servers and their tool names
8
+ * tools — full tool list with descriptions for a specific server
9
+ * status — connection status summary (same as list)
10
+ * add — add a new MCP server (saved to config/mcp.json + connected immediately)
11
+ * remove — disconnect and remove a server from config
12
+ * enable — enable a disabled server (reconnects it)
13
+ * disable — disable a server (disconnects it, keeps in config)
14
+ * reload — reconnect a server (useful after config changes)
15
+ */
16
+ export async function manageMCP(action, paramsJson) {
17
+ const params = paramsJson
18
+ ? (typeof paramsJson === "string" ? JSON.parse(paramsJson) : paramsJson)
19
+ : {};
20
+
21
+ switch (action) {
22
+
23
+ case "list":
24
+ case "status": {
25
+ // Show both connected and configured-but-disabled servers
26
+ const connected = mcpManager.list();
27
+ const allConfig = mcpManager.readConfig().mcpServers || {};
28
+ const configuredNames = Object.keys(allConfig).filter(k => !k.startsWith("_comment"));
29
+
30
+ if (configuredNames.length === 0 && connected.length === 0) {
31
+ return "No MCP servers configured. Use manageMCP(\"add\", {...}) to add one.";
32
+ }
33
+
34
+ const lines = [];
35
+ for (const name of configuredNames) {
36
+ const cfg = allConfig[name];
37
+ const live = connected.find(s => s.name === name);
38
+ if (cfg.enabled === false) {
39
+ lines.push(`⏸️ disabled ${name}`);
40
+ } else if (live?.connected) {
41
+ const toolList = live.tools.length > 0 ? live.tools.join(", ") : "(no tools)";
42
+ lines.push(`✅ connected ${name}: ${live.tools.length} tools — ${toolList}`);
43
+ } else {
44
+ lines.push(`❌ disconnected ${name}`);
45
+ }
46
+ }
47
+ // Any live servers not in config (shouldn't happen, but just in case)
48
+ for (const s of connected) {
49
+ if (!configuredNames.includes(s.name)) {
50
+ lines.push(`✅ connected ${s.name}: ${s.tools.length} tools (not in config)`);
51
+ }
52
+ }
53
+
54
+ return lines.join("\n");
55
+ }
56
+
57
+ case "tools": {
58
+ const { server } = params;
59
+ const servers = mcpManager.list();
60
+ if (!server) {
61
+ const all = servers.flatMap(s =>
62
+ s.tools.map(t => `mcp__${s.name}__${t}`)
63
+ );
64
+ if (all.length === 0) return "No MCP tools available. Connect servers first.";
65
+ return `All MCP tools (${all.length}):\n${all.map(t => ` ${t}`).join("\n")}`;
66
+ }
67
+ const srv = servers.find(s => s.name === server);
68
+ if (!srv) return `Server "${server}" not found or not connected. Use manageMCP("list") to see servers.`;
69
+ if (srv.tools.length === 0) return `No tools from server "${server}".`;
70
+ return `Tools from ${server}:\n${srv.tools.map(t => ` mcp__${server}__${t}`).join("\n")}`;
71
+ }
72
+
73
+ case "add": {
74
+ const { name, command, args, url, transport, env, headers } = params;
75
+ if (!name) return "Error: name is required";
76
+ if (!command && !url) return "Error: either 'command' (stdio) or 'url' (HTTP/SSE) is required";
77
+
78
+ const serverConfig = {};
79
+ if (command) {
80
+ // stdio — credentials go as env vars injected into the subprocess
81
+ serverConfig.command = command;
82
+ if (args) serverConfig.args = args;
83
+ if (env) serverConfig.env = env; // { "GITHUB_TOKEN": "ghp_..." }
84
+ } else {
85
+ // http/sse — credentials go as HTTP request headers
86
+ serverConfig.url = url;
87
+ if (transport) serverConfig.transport = transport; // "sse" or omit for HTTP
88
+ if (headers) serverConfig.headers = headers; // { "Authorization": "Bearer ${TOKEN}" }
89
+ }
90
+
91
+ try {
92
+ return await mcpManager.addServer(name, serverConfig);
93
+ } catch (err) {
94
+ return `Error adding server "${name}": ${err.message}`;
95
+ }
96
+ }
97
+
98
+ case "remove": {
99
+ const { name } = params;
100
+ if (!name) return "Error: name is required";
101
+ try {
102
+ return await mcpManager.removeServer(name);
103
+ } catch (err) {
104
+ return `Error removing server "${name}": ${err.message}`;
105
+ }
106
+ }
107
+
108
+ case "enable": {
109
+ const { name } = params;
110
+ if (!name) return "Error: name is required";
111
+ try {
112
+ return await mcpManager.setEnabled(name, true);
113
+ } catch (err) {
114
+ return `Error enabling server "${name}": ${err.message}`;
115
+ }
116
+ }
117
+
118
+ case "disable": {
119
+ const { name } = params;
120
+ if (!name) return "Error: name is required";
121
+ try {
122
+ return await mcpManager.setEnabled(name, false);
123
+ } catch (err) {
124
+ return `Error disabling server "${name}": ${err.message}`;
125
+ }
126
+ }
127
+
128
+ case "reload": {
129
+ const { name } = params;
130
+ if (!name) return "Error: name is required";
131
+ try {
132
+ return await mcpManager.reloadServer(name);
133
+ } catch (err) {
134
+ return `Error reloading server "${name}": ${err.message}`;
135
+ }
136
+ }
137
+
138
+ default:
139
+ return `Unknown action: "${action}". Valid actions: list, tools, status, add, remove, enable, disable, reload`;
140
+ }
141
+ }
142
+
143
+ export const manageMCPDescription =
144
+ `manageMCP(action: string, paramsJson?: string) - Manage MCP server connections at runtime. Changes saved to config/mcp.json.
145
+ Actions:
146
+ list/status - no params — all servers with connection status and tool names
147
+ tools - {"server":"github"} — full tool list for a server, or {} for all servers
148
+ add - Add and immediately connect a server:
149
+ stdio (auth via env vars passed to subprocess):
150
+ {"name":"github","command":"npx","args":["-y","@modelcontextprotocol/server-github"],"env":{"GITHUB_PERSONAL_ACCESS_TOKEN":"ghp_..."}}
151
+ HTTP (auth via Authorization/custom request headers):
152
+ {"name":"myapi","url":"https://api.example.com/mcp","headers":{"Authorization":"Bearer \${MY_TOKEN}"}}
153
+ SSE (auth via request headers, applied to both GET stream and POST calls):
154
+ {"name":"myapi","url":"https://api.example.com/sse","transport":"sse","headers":{"Authorization":"Bearer \${MY_TOKEN}","X-API-Key":"\${MY_KEY}"}}
155
+ Header values support \${VAR_NAME} — expanded from process.env at connect time.
156
+ remove - {"name":"github"} — disconnect and remove from config
157
+ enable - {"name":"github"} — re-enable a disabled server (reconnects)
158
+ disable - {"name":"github"} — disconnect and mark disabled in config
159
+ reload - {"name":"github"} — reconnect (useful after editing config)`;