nexus-mcp-agent 0.1.2

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 (72) hide show
  1. package/.env.example +56 -0
  2. package/README.md +74 -0
  3. package/dist/core/config.d.ts +46 -0
  4. package/dist/core/config.d.ts.map +1 -0
  5. package/dist/core/config.js +68 -0
  6. package/dist/core/config.js.map +1 -0
  7. package/dist/core/logger.d.ts +7 -0
  8. package/dist/core/logger.d.ts.map +1 -0
  9. package/dist/core/logger.js +54 -0
  10. package/dist/core/logger.js.map +1 -0
  11. package/dist/core/registry.d.ts +21 -0
  12. package/dist/core/registry.d.ts.map +1 -0
  13. package/dist/core/registry.js +52 -0
  14. package/dist/core/registry.js.map +1 -0
  15. package/dist/core/server.d.ts +12 -0
  16. package/dist/core/server.d.ts.map +1 -0
  17. package/dist/core/server.js +120 -0
  18. package/dist/core/server.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +38 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/tools/agents/index.d.ts +18 -0
  24. package/dist/tools/agents/index.d.ts.map +1 -0
  25. package/dist/tools/agents/index.js +134 -0
  26. package/dist/tools/agents/index.js.map +1 -0
  27. package/dist/tools/automation/index.d.ts +4 -0
  28. package/dist/tools/automation/index.d.ts.map +1 -0
  29. package/dist/tools/automation/index.js +95 -0
  30. package/dist/tools/automation/index.js.map +1 -0
  31. package/dist/tools/filesystem/index.d.ts +4 -0
  32. package/dist/tools/filesystem/index.d.ts.map +1 -0
  33. package/dist/tools/filesystem/index.js +261 -0
  34. package/dist/tools/filesystem/index.js.map +1 -0
  35. package/dist/tools/git/index.d.ts +4 -0
  36. package/dist/tools/git/index.d.ts.map +1 -0
  37. package/dist/tools/git/index.js +177 -0
  38. package/dist/tools/git/index.js.map +1 -0
  39. package/dist/tools/memory/index.d.ts +4 -0
  40. package/dist/tools/memory/index.d.ts.map +1 -0
  41. package/dist/tools/memory/index.js +178 -0
  42. package/dist/tools/memory/index.js.map +1 -0
  43. package/dist/tools/system/index.d.ts +4 -0
  44. package/dist/tools/system/index.d.ts.map +1 -0
  45. package/dist/tools/system/index.js +121 -0
  46. package/dist/tools/system/index.js.map +1 -0
  47. package/dist/tools/terminal/index.d.ts +4 -0
  48. package/dist/tools/terminal/index.d.ts.map +1 -0
  49. package/dist/tools/terminal/index.js +86 -0
  50. package/dist/tools/terminal/index.js.map +1 -0
  51. package/dist/tools/web/index.d.ts +4 -0
  52. package/dist/tools/web/index.d.ts.map +1 -0
  53. package/dist/tools/web/index.js +193 -0
  54. package/dist/tools/web/index.js.map +1 -0
  55. package/docs/SECURITY.md +31 -0
  56. package/mcp-config.json +9 -0
  57. package/package.json +65 -0
  58. package/scripts/setup.js +102 -0
  59. package/src/core/config.ts +138 -0
  60. package/src/core/logger.ts +61 -0
  61. package/src/core/registry.ts +72 -0
  62. package/src/core/server.ts +144 -0
  63. package/src/index.ts +46 -0
  64. package/src/tools/agents/index.ts +172 -0
  65. package/src/tools/automation/index.ts +127 -0
  66. package/src/tools/filesystem/index.ts +303 -0
  67. package/src/tools/git/index.ts +201 -0
  68. package/src/tools/memory/index.ts +204 -0
  69. package/src/tools/system/index.ts +140 -0
  70. package/src/tools/terminal/index.ts +105 -0
  71. package/src/tools/web/index.ts +224 -0
  72. package/tsconfig.json +30 -0
@@ -0,0 +1,72 @@
1
+ import { createContextLogger } from './logger.js';
2
+
3
+ const log = createContextLogger('registry');
4
+
5
+ export interface ToolMetadata {
6
+ name: string;
7
+ category: string;
8
+ description: string;
9
+ parameters?: any;
10
+ handler: (params: any) => Promise<any>;
11
+ requiresConfirmation?: boolean;
12
+ sideEffects?: boolean;
13
+ }
14
+
15
+ export class ToolRegistry {
16
+ private tools: Map<string, ToolMetadata> = new Map();
17
+
18
+ register(tool: ToolMetadata): void {
19
+ if (this.tools.has(tool.name)) {
20
+ log.warn(`Tool ${tool.name} already registered, overwriting`);
21
+ }
22
+ this.tools.set(tool.name, tool);
23
+ log.debug(`Registered tool: ${tool.name} (${tool.category})`);
24
+ }
25
+
26
+ get(name: string): ToolMetadata | undefined {
27
+ return this.tools.get(name);
28
+ }
29
+
30
+ has(name: string): boolean {
31
+ return this.tools.has(name);
32
+ }
33
+
34
+ list(): ToolMetadata[] {
35
+ return Array.from(this.tools.values());
36
+ }
37
+
38
+ listByCategory(category: string): ToolMetadata[] {
39
+ return this.list().filter(t => t.category === category);
40
+ }
41
+
42
+ getCategories(): string[] {
43
+ const categories = new Set<string>();
44
+ this.tools.forEach(t => categories.add(t.category));
45
+ return Array.from(categories);
46
+ }
47
+
48
+ getToolCount(): number {
49
+ return this.tools.size;
50
+ }
51
+
52
+ async execute(name: string, params: any): Promise<any> {
53
+ const tool = this.tools.get(name);
54
+ if (!tool) {
55
+ throw new Error(`Tool not found: ${name}`);
56
+ }
57
+
58
+ log.info({ params }, `Executing tool: ${name}`);
59
+ const startTime = Date.now();
60
+
61
+ try {
62
+ const result = await tool.handler(params);
63
+ const duration = Date.now() - startTime;
64
+ log.info({ duration }, `Tool ${name} completed`);
65
+ return result;
66
+ } catch (error) {
67
+ const duration = Date.now() - startTime;
68
+ log.error({ error, duration }, `Tool ${name} failed`);
69
+ throw error;
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,144 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { createContextLogger } from './logger.js';
4
+ import { nexusConfig, validateConfig } from './config.js';
5
+ import { ToolRegistry } from './registry.js';
6
+
7
+ // Import tool modules
8
+ import { registerWebTools } from '../tools/web/index.js';
9
+ import { registerFilesystemTools } from '../tools/filesystem/index.js';
10
+ import { registerTerminalTools } from '../tools/terminal/index.js';
11
+ import { registerGitTools } from '../tools/git/index.js';
12
+ import { registerMemoryTools } from '../tools/memory/index.js';
13
+ import { registerAutomationTools } from '../tools/automation/index.js';
14
+ import { registerAgentTools } from '../tools/agents/index.js';
15
+ import { registerSystemTools } from '../tools/system/index.js';
16
+
17
+ const log = createContextLogger('server');
18
+
19
+ export class NexusServer {
20
+ private server: McpServer;
21
+ private registry: ToolRegistry;
22
+ private transport: StdioServerTransport | null = null;
23
+
24
+ constructor() {
25
+ this.server = new McpServer({
26
+ name: 'NEXUS',
27
+ version: '0.1.0',
28
+ description: 'Autonomous AI Agent Ecosystem - Self-empowered MCP Server',
29
+ });
30
+
31
+ this.registry = new ToolRegistry();
32
+ }
33
+
34
+ async initialize(): Promise<void> {
35
+ log.info('Initializing NEXUS server...');
36
+
37
+ // Validate configuration
38
+ const warnings = validateConfig();
39
+ warnings.forEach(w => log.warn(w));
40
+
41
+ // Register all tool categories
42
+ log.info('Registering tools...');
43
+ registerWebTools(this.server, this.registry);
44
+ registerFilesystemTools(this.server, this.registry);
45
+ registerTerminalTools(this.server, this.registry);
46
+ registerGitTools(this.server, this.registry);
47
+ registerMemoryTools(this.server, this.registry);
48
+ registerAutomationTools(this.server, this.registry);
49
+ registerAgentTools(this.server, this.registry);
50
+ registerSystemTools(this.server, this.registry);
51
+
52
+ const toolCount = this.registry.getToolCount();
53
+ log.info(`Registered ${toolCount} tools`);
54
+
55
+ // Register resources
56
+ this.registerResources();
57
+
58
+ // Register prompts
59
+ this.registerPrompts();
60
+ }
61
+
62
+ private registerResources(): void {
63
+ // System info resource
64
+ this.server.resource(
65
+ 'system-info',
66
+ 'nexus://system/info',
67
+ async (uri) => ({
68
+ contents: [{
69
+ uri: uri.href,
70
+ text: JSON.stringify({
71
+ name: 'NEXUS',
72
+ version: '0.1.0',
73
+ uptime: process.uptime(),
74
+ memory: process.memoryUsage(),
75
+ config: {
76
+ llmProvider: nexusConfig.llm.provider,
77
+ llmModel: nexusConfig.llm.model,
78
+ searchProvider: nexusConfig.search.provider,
79
+ vectorDb: nexusConfig.vector.type,
80
+ toolCount: this.registry.getToolCount(),
81
+ },
82
+ }, null, 2),
83
+ }],
84
+ })
85
+ );
86
+
87
+ log.info('Registered resources');
88
+ }
89
+
90
+ private registerPrompts(): void {
91
+ // System prompt for autonomous agent
92
+ this.server.prompt(
93
+ 'autonomous-agent',
94
+ 'System prompt for autonomous operation',
95
+ () => ({
96
+ messages: [{
97
+ role: 'user',
98
+ content: {
99
+ type: 'text',
100
+ text: `You are NEXUS, an autonomous AI agent with full system access.
101
+
102
+ You have the following capabilities:
103
+ - Web research (search, browse, scrape)
104
+ - File system operations (read, write, search)
105
+ - Terminal access (execute commands, spawn processes)
106
+ - Git operations
107
+ - Persistent memory (store and recall information)
108
+ - Task scheduling (cron jobs, workflows)
109
+ - Multi-agent orchestration
110
+
111
+ Guidelines:
112
+ 1. Always verify your actions before executing
113
+ 2. Log all significant operations
114
+ 3. Store important discoveries in memory
115
+ 4. Use sub-agents for complex parallel tasks
116
+ 5. Respect security boundaries
117
+ 6. Ask for confirmation on destructive operations
118
+
119
+ Current workspace: ${nexusConfig.paths.workspace}
120
+ Allowed directories: ${nexusConfig.security.allowedDirs.join(', ')}`,
121
+ },
122
+ }],
123
+ })
124
+ );
125
+
126
+ log.info('Registered prompts');
127
+ }
128
+
129
+ async start(): Promise<void> {
130
+ log.info('Starting MCP server on stdio...');
131
+ this.transport = new StdioServerTransport();
132
+ await this.server.connect(this.transport);
133
+ log.info('NEXUS server is running');
134
+ }
135
+
136
+ async stop(): Promise<void> {
137
+ log.info('Stopping NEXUS server...');
138
+ if (this.transport) {
139
+ await this.transport.close();
140
+ }
141
+ await this.server.close();
142
+ log.info('NEXUS server stopped');
143
+ }
144
+ }
package/src/index.ts ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { NexusServer } from './core/server.js';
4
+ import { createContextLogger } from './core/logger.js';
5
+
6
+ const log = createContextLogger('main');
7
+
8
+ async function main() {
9
+ log.info('🧠 NEXUS - Autonomous AI Agent Ecosystem');
10
+ log.info('========================================');
11
+
12
+ const server = new NexusServer();
13
+
14
+ // Handle graceful shutdown
15
+ process.on('SIGINT', async () => {
16
+ log.info('Received SIGINT, shutting down...');
17
+ await server.stop();
18
+ process.exit(0);
19
+ });
20
+
21
+ process.on('SIGTERM', async () => {
22
+ log.info('Received SIGTERM, shutting down...');
23
+ await server.stop();
24
+ process.exit(0);
25
+ });
26
+
27
+ process.on('uncaughtException', (error) => {
28
+ log.fatal({ error }, 'Uncaught exception');
29
+ process.exit(1);
30
+ });
31
+
32
+ process.on('unhandledRejection', (reason) => {
33
+ log.fatal({ reason }, 'Unhandled rejection');
34
+ process.exit(1);
35
+ });
36
+
37
+ try {
38
+ await server.initialize();
39
+ await server.start();
40
+ } catch (error) {
41
+ log.fatal({ error }, 'Failed to start NEXUS server');
42
+ process.exit(1);
43
+ }
44
+ }
45
+
46
+ main();
@@ -0,0 +1,172 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod/v3';
3
+ import { v4 as uuid } from 'uuid';
4
+ import { ToolRegistry } from '../../core/registry.js';
5
+ import { createContextLogger } from '../../core/logger.js';
6
+
7
+ const log = createContextLogger('tools/agents');
8
+
9
+ export interface Agent {
10
+ id: string;
11
+ name: string;
12
+ role: string;
13
+ systemPrompt: string;
14
+ skills: string[];
15
+ tools: string[];
16
+ status: 'idle' | 'running' | 'completed' | 'error';
17
+ createdAt: number;
18
+ lastActive?: number;
19
+ }
20
+
21
+ const agentTemplates: Record<string, Partial<Agent>> = {
22
+ researcher: {
23
+ name: 'Researcher',
24
+ role: 'Web research and information gathering',
25
+ systemPrompt: 'You are an expert researcher. Search the web thoroughly, verify information from multiple sources, and synthesize comprehensive answers.',
26
+ skills: ['web-research', 'fact-checking', 'synthesis'],
27
+ tools: ['web_search', 'web_browse', 'web_scrape', 'memory_store'],
28
+ },
29
+ coder: {
30
+ name: 'Coder',
31
+ role: 'Code generation and implementation',
32
+ systemPrompt: 'You are a senior fullstack developer. Write clean, well-tested code following best practices. Explain your decisions.',
33
+ skills: ['coding', 'testing', 'debugging'],
34
+ tools: ['fs_read', 'fs_write', 'shell_exec', 'git_commit'],
35
+ },
36
+ reviewer: {
37
+ name: 'Reviewer',
38
+ role: 'Code review and quality assurance',
39
+ systemPrompt: 'You are a code review expert. Identify bugs, security issues, performance problems, and style issues. Be constructive.',
40
+ skills: ['code-review', 'security-audit', 'best-practices'],
41
+ tools: ['fs_read', 'git_diff', 'git_log'],
42
+ },
43
+ sysadmin: {
44
+ name: 'Sysadmin',
45
+ role: 'System administration and DevOps',
46
+ systemPrompt: 'You are a system administrator. Manage servers, deployments, and infrastructure. Be careful with destructive operations.',
47
+ skills: ['server-management', 'deployment', 'monitoring'],
48
+ tools: ['shell_exec', 'fs_read', 'fs_write', 'process_list'],
49
+ },
50
+ analyst: {
51
+ name: 'Analyst',
52
+ role: 'Data analysis and insights',
53
+ systemPrompt: 'You are a data analyst. Analyze data, identify patterns, and provide actionable insights. Use Python/pandas when needed.',
54
+ skills: ['data-analysis', 'visualization', 'statistics'],
55
+ tools: ['shell_exec', 'fs_read', 'fs_write', 'memory_store'],
56
+ },
57
+ };
58
+
59
+ const agents: Map<string, Agent> = new Map();
60
+
61
+ const AgentCreateSchema = z.object({
62
+ type: z.enum(['researcher', 'coder', 'reviewer', 'sysadmin', 'analyst']).optional(),
63
+ name: z.string().optional(),
64
+ role: z.string().optional(),
65
+ systemPrompt: z.string().optional(),
66
+ });
67
+
68
+ const AgentGetSchema = z.object({
69
+ id: z.string(),
70
+ });
71
+
72
+ const AgentDeleteSchema = z.object({
73
+ id: z.string(),
74
+ });
75
+
76
+ type AgentCreateParams = z.infer<typeof AgentCreateSchema>;
77
+ type AgentGetParams = z.infer<typeof AgentGetSchema>;
78
+ type AgentDeleteParams = z.infer<typeof AgentDeleteSchema>;
79
+
80
+ async function agentCreate(params: AgentCreateParams): Promise<any> {
81
+ const { type, name, role, systemPrompt } = params;
82
+
83
+ const id = uuid();
84
+ const template = type ? agentTemplates[type] : {};
85
+
86
+ const agent: Agent = {
87
+ id,
88
+ name: name || template.name || 'Custom Agent',
89
+ role: role || template.role || 'General purpose',
90
+ systemPrompt: systemPrompt || template.systemPrompt || 'You are a helpful assistant.',
91
+ skills: template.skills || [],
92
+ tools: template.tools || [],
93
+ status: 'idle',
94
+ createdAt: Date.now(),
95
+ };
96
+
97
+ agents.set(id, agent);
98
+ log.info(`Created agent: ${agent.name} (${id})`);
99
+
100
+ return { success: true, agent };
101
+ }
102
+
103
+ async function agentList(): Promise<any> {
104
+ const agentList = Array.from(agents.values());
105
+ return { success: true, count: agentList.length, agents: agentList };
106
+ }
107
+
108
+ async function agentGet(params: AgentGetParams): Promise<any> {
109
+ const agent = agents.get(params.id);
110
+ if (!agent) return { success: false, error: 'Agent not found' };
111
+ return { success: true, agent };
112
+ }
113
+
114
+ async function agentDelete(params: AgentDeleteParams): Promise<any> {
115
+ if (!agents.has(params.id)) return { success: false, error: 'Agent not found' };
116
+ agents.delete(params.id);
117
+ return { success: true };
118
+ }
119
+
120
+ async function agentTemplates_(): Promise<any> {
121
+ return {
122
+ success: true,
123
+ templates: Object.entries(agentTemplates).map(([key, t]) => ({
124
+ type: key,
125
+ name: t.name,
126
+ role: t.role,
127
+ skills: t.skills,
128
+ tools: t.tools,
129
+ })),
130
+ };
131
+ }
132
+
133
+ export function registerAgentTools(server: McpServer, registry: ToolRegistry): void {
134
+ server.registerTool('agent_create', {
135
+ description: 'Create a new agent',
136
+ inputSchema: AgentCreateSchema,
137
+ }, async (params) => ({
138
+ content: [{ type: 'text', text: JSON.stringify(await agentCreate(params), null, 2) }],
139
+ }));
140
+
141
+ server.tool('agent_list', 'List all agents', {}, async () => ({
142
+ content: [{ type: 'text', text: JSON.stringify(await agentList(), null, 2) }],
143
+ }));
144
+
145
+ server.registerTool('agent_get', {
146
+ description: 'Get agent details',
147
+ inputSchema: AgentGetSchema,
148
+ }, async (params) => ({
149
+ content: [{ type: 'text', text: JSON.stringify(await agentGet(params), null, 2) }],
150
+ }));
151
+
152
+ server.registerTool('agent_delete', {
153
+ description: 'Delete an agent',
154
+ inputSchema: AgentDeleteSchema,
155
+ }, async (params) => ({
156
+ content: [{ type: 'text', text: JSON.stringify(await agentDelete(params), null, 2) }],
157
+ }));
158
+
159
+ server.tool('agent_templates', 'List available agent templates', {}, async () => ({
160
+ content: [{ type: 'text', text: JSON.stringify(await agentTemplates_(), null, 2) }],
161
+ }));
162
+
163
+ registry.register({ name: 'agent_create', category: 'agents', description: 'Create agent', handler: agentCreate });
164
+ registry.register({ name: 'agent_list', category: 'agents', description: 'List agents', handler: agentList });
165
+ registry.register({ name: 'agent_get', category: 'agents', description: 'Get agent', handler: agentGet });
166
+ registry.register({ name: 'agent_delete', category: 'agents', description: 'Delete agent', handler: agentDelete });
167
+ registry.register({ name: 'agent_templates', category: 'agents', description: 'Agent templates', handler: agentTemplates_ });
168
+
169
+ log.info('Registered 5 agent tools');
170
+ }
171
+
172
+ export { agents, agentTemplates };
@@ -0,0 +1,127 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod/v3';
3
+ import cron from 'node-cron';
4
+ import { v4 as uuid } from 'uuid';
5
+ import { ToolRegistry } from '../../core/registry.js';
6
+ import { createContextLogger } from '../../core/logger.js';
7
+
8
+ const log = createContextLogger('tools/automation');
9
+
10
+ interface CronJob {
11
+ id: string;
12
+ schedule: string;
13
+ task: string;
14
+ enabled: boolean;
15
+ createdAt: number;
16
+ lastRun?: number;
17
+ taskFn: any;
18
+ }
19
+
20
+ const cronJobs: Map<string, CronJob> = new Map();
21
+
22
+ const CronAddSchema = z.object({
23
+ schedule: z.string().describe('Cron expression (e.g. "*/5 * * * *")'),
24
+ task: z.string().describe('Description of the task'),
25
+ });
26
+
27
+ const CronRemoveSchema = z.object({
28
+ id: z.string(),
29
+ });
30
+
31
+ const CronToggleSchema = z.object({
32
+ id: z.string(),
33
+ enabled: z.boolean(),
34
+ });
35
+
36
+ type CronAddParams = z.infer<typeof CronAddSchema>;
37
+ type CronRemoveParams = z.infer<typeof CronRemoveSchema>;
38
+ type CronToggleParams = z.infer<typeof CronToggleSchema>;
39
+
40
+ async function cronAdd(params: CronAddParams): Promise<any> {
41
+ const { schedule, task } = params;
42
+
43
+ if (!cron.validate(schedule)) {
44
+ return { success: false, error: 'Invalid cron schedule' };
45
+ }
46
+
47
+ const id = uuid();
48
+ log.info(`Adding cron job: ${id} (${schedule})`);
49
+
50
+ const job = {
51
+ id,
52
+ schedule,
53
+ task,
54
+ enabled: true,
55
+ createdAt: Date.now(),
56
+ taskFn: cron.schedule(schedule, () => {
57
+ log.info(`Cron job triggered: ${id} - ${task}`);
58
+ const jobData = cronJobs.get(id);
59
+ if (jobData) jobData.lastRun = Date.now();
60
+ }),
61
+ };
62
+
63
+ cronJobs.set(id, job);
64
+ return { success: true, id, schedule, task };
65
+ }
66
+
67
+ async function cronList(): Promise<any> {
68
+ const jobs = Array.from(cronJobs.values()).map(({ id, schedule, task, enabled, createdAt, lastRun }) => ({
69
+ id, schedule, task, enabled, createdAt, lastRun,
70
+ }));
71
+ return { success: true, count: jobs.length, jobs };
72
+ }
73
+
74
+ async function cronRemove(params: CronRemoveParams): Promise<any> {
75
+ const job = cronJobs.get(params.id);
76
+ if (!job) return { success: false, error: 'Job not found' };
77
+
78
+ job.taskFn.stop();
79
+ cronJobs.delete(params.id);
80
+ log.info(`Removed cron job: ${params.id}`);
81
+ return { success: true };
82
+ }
83
+
84
+ async function cronToggle(params: CronToggleParams): Promise<any> {
85
+ const job = cronJobs.get(params.id);
86
+ if (!job) return { success: false, error: 'Job not found' };
87
+
88
+ job.enabled = params.enabled;
89
+ if (params.enabled) job.taskFn.start();
90
+ else job.taskFn.stop();
91
+
92
+ return { success: true, id: params.id, enabled: params.enabled };
93
+ }
94
+
95
+ export function registerAutomationTools(server: McpServer, registry: ToolRegistry): void {
96
+ server.registerTool('cron_add', {
97
+ description: 'Add a scheduled task',
98
+ inputSchema: CronAddSchema,
99
+ }, async (params) => ({
100
+ content: [{ type: 'text', text: JSON.stringify(await cronAdd(params), null, 2) }],
101
+ }));
102
+
103
+ server.tool('cron_list', 'List scheduled tasks', {}, async () => ({
104
+ content: [{ type: 'text', text: JSON.stringify(await cronList(), null, 2) }],
105
+ }));
106
+
107
+ server.registerTool('cron_remove', {
108
+ description: 'Remove a scheduled task',
109
+ inputSchema: CronRemoveSchema,
110
+ }, async (params) => ({
111
+ content: [{ type: 'text', text: JSON.stringify(await cronRemove(params), null, 2) }],
112
+ }));
113
+
114
+ server.registerTool('cron_toggle', {
115
+ description: 'Enable/disable a task',
116
+ inputSchema: CronToggleSchema,
117
+ }, async (params) => ({
118
+ content: [{ type: 'text', text: JSON.stringify(await cronToggle(params), null, 2) }],
119
+ }));
120
+
121
+ registry.register({ name: 'cron_add', category: 'automation', description: 'Add cron job', handler: cronAdd });
122
+ registry.register({ name: 'cron_list', category: 'automation', description: 'List cron jobs', handler: cronList });
123
+ registry.register({ name: 'cron_remove', category: 'automation', description: 'Remove cron job', handler: cronRemove });
124
+ registry.register({ name: 'cron_toggle', category: 'automation', description: 'Toggle cron job', handler: cronToggle });
125
+
126
+ log.info('Registered 4 automation tools');
127
+ }