mcp-ts-template 1.5.5 → 1.5.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/README.md +3 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/scheduling/index.d.ts +6 -0
- package/dist/utils/scheduling/index.js +6 -0
- package/dist/utils/scheduling/scheduler.d.ts +72 -0
- package/dist/utils/scheduling/scheduler.js +152 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# MCP TypeScript Template 🚀
|
|
2
2
|
|
|
3
3
|
[](https://www.typescriptlang.org/)
|
|
4
|
-
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
5
5
|
[](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/changelog.mdx)
|
|
6
|
-
[](./CHANGELOG.md)
|
|
7
7
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
8
|
[](https://github.com/cyanheads/mcp-ts-template/issues)
|
|
9
9
|
[](https://github.com/cyanheads/mcp-ts-template)
|
|
@@ -55,6 +55,7 @@ This template is already powering several MCP servers, demonstrating its flexibi
|
|
|
55
55
|
| [**obsidian-mcp-server**](https://github.com/cyanheads/obsidian-mcp-server) | MCP server for Obsidian, enabling AI agents to read, write, search, and manage notes via the Local REST API plugin. | Actively using this template. |
|
|
56
56
|
| [**atlas-mcp-server**](https://github.com/cyanheads/atlas-mcp-server) | Advanced task and knowledge management system with Neo4j backend, enabling structured data organization and complex querying for AI agents. | Aligned with this template (as of v2.8.8). |
|
|
57
57
|
| [**filesystem-mcp-server**](https://github.com/cyanheads/filesystem-mcp-server) | Offers platform-agnostic file system capabilities for AI agents via MCP. Enables reading, writing, updating, and managing files/directories, featuring advanced search/replace and directory traversal. | Actively using this template. |
|
|
58
|
+
| [**workflows-mcp-server**](https://github.com/cyanheads/workflows-mcp-server) | Empowers AI agents with a powerful, declarative workflow engine to discover, understand, and execute complex, multi-step workflows defined in simple YAML files. | Actively using this template. |
|
|
58
59
|
|
|
59
60
|
_Note: [**toolkit-mcp-server**](https://github.com/cyanheads/toolkit-mcp-server) was initially built using an older version of this template and is pending updates to the latest structure._
|
|
60
61
|
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./metrics/index.js";
|
|
|
10
10
|
export * from "./parsing/index.js";
|
|
11
11
|
export * from "./security/index.js";
|
|
12
12
|
export * from "./network/index.js";
|
|
13
|
+
export * from "./scheduling/index.js";
|
|
13
14
|
// It's good practice to have index.ts files in each subdirectory
|
|
14
15
|
// that export the contents of that directory.
|
|
15
16
|
// Assuming those will be created or already exist.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a singleton service for scheduling and managing cron jobs.
|
|
3
|
+
* This service wraps the 'node-cron' library to offer a unified interface for
|
|
4
|
+
* defining, starting, stopping, and listing recurring tasks within the application.
|
|
5
|
+
* @module src/utils/scheduling/scheduler
|
|
6
|
+
*/
|
|
7
|
+
import { ScheduledTask } from 'node-cron';
|
|
8
|
+
import { RequestContext } from '../internal/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Represents a scheduled job managed by the SchedulerService.
|
|
11
|
+
*/
|
|
12
|
+
export interface Job {
|
|
13
|
+
/** A unique identifier for the job. */
|
|
14
|
+
id: string;
|
|
15
|
+
/** The cron pattern defining the job's schedule. */
|
|
16
|
+
schedule: string;
|
|
17
|
+
/** A description of what the job does. */
|
|
18
|
+
description: string;
|
|
19
|
+
/** The underlying 'node-cron' task instance. */
|
|
20
|
+
task: ScheduledTask;
|
|
21
|
+
/** Indicates whether the job is currently running. */
|
|
22
|
+
isRunning: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A singleton service for scheduling and managing cron jobs.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SchedulerService {
|
|
28
|
+
private static instance;
|
|
29
|
+
private jobs;
|
|
30
|
+
/** @private */
|
|
31
|
+
private constructor();
|
|
32
|
+
/**
|
|
33
|
+
* Gets the singleton instance of the SchedulerService.
|
|
34
|
+
* @returns The singleton SchedulerService instance.
|
|
35
|
+
*/
|
|
36
|
+
static getInstance(): SchedulerService;
|
|
37
|
+
/**
|
|
38
|
+
* Schedules a new job.
|
|
39
|
+
*
|
|
40
|
+
* @param id - A unique identifier for the job.
|
|
41
|
+
* @param schedule - The cron pattern for the schedule (e.g., '* * * * *').
|
|
42
|
+
* @param taskFunction - The function to execute on schedule. It receives a RequestContext.
|
|
43
|
+
* @param description - A description of the job.
|
|
44
|
+
* @returns The newly created Job object.
|
|
45
|
+
*/
|
|
46
|
+
schedule(id: string, schedule: string, taskFunction: (context: RequestContext) => void | Promise<void>, description: string): Job;
|
|
47
|
+
/**
|
|
48
|
+
* Starts a scheduled job.
|
|
49
|
+
* @param id - The ID of the job to start.
|
|
50
|
+
*/
|
|
51
|
+
start(id: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Stops a scheduled job.
|
|
54
|
+
* @param id - The ID of the job to stop.
|
|
55
|
+
*/
|
|
56
|
+
stop(id: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Removes a job from the scheduler. The job is stopped before being removed.
|
|
59
|
+
* @param id - The ID of the job to remove.
|
|
60
|
+
*/
|
|
61
|
+
remove(id: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Gets a list of all scheduled jobs.
|
|
64
|
+
* @returns An array of all Job objects.
|
|
65
|
+
*/
|
|
66
|
+
listJobs(): Job[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The singleton instance of the SchedulerService.
|
|
70
|
+
* Use this instance for all job scheduling operations.
|
|
71
|
+
*/
|
|
72
|
+
export declare const schedulerService: SchedulerService;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Provides a singleton service for scheduling and managing cron jobs.
|
|
3
|
+
* This service wraps the 'node-cron' library to offer a unified interface for
|
|
4
|
+
* defining, starting, stopping, and listing recurring tasks within the application.
|
|
5
|
+
* @module src/utils/scheduling/scheduler
|
|
6
|
+
*/
|
|
7
|
+
import cron from 'node-cron';
|
|
8
|
+
import { logger } from '../internal/index.js';
|
|
9
|
+
import { requestContextService } from '../internal/requestContext.js';
|
|
10
|
+
/**
|
|
11
|
+
* A singleton service for scheduling and managing cron jobs.
|
|
12
|
+
*/
|
|
13
|
+
export class SchedulerService {
|
|
14
|
+
/** @private */
|
|
15
|
+
constructor() {
|
|
16
|
+
this.jobs = new Map();
|
|
17
|
+
logger.info('SchedulerService initialized.', {
|
|
18
|
+
requestId: 'scheduler-init',
|
|
19
|
+
timestamp: new Date().toISOString(),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Gets the singleton instance of the SchedulerService.
|
|
24
|
+
* @returns The singleton SchedulerService instance.
|
|
25
|
+
*/
|
|
26
|
+
static getInstance() {
|
|
27
|
+
if (!SchedulerService.instance) {
|
|
28
|
+
SchedulerService.instance = new SchedulerService();
|
|
29
|
+
}
|
|
30
|
+
return SchedulerService.instance;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Schedules a new job.
|
|
34
|
+
*
|
|
35
|
+
* @param id - A unique identifier for the job.
|
|
36
|
+
* @param schedule - The cron pattern for the schedule (e.g., '* * * * *').
|
|
37
|
+
* @param taskFunction - The function to execute on schedule. It receives a RequestContext.
|
|
38
|
+
* @param description - A description of the job.
|
|
39
|
+
* @returns The newly created Job object.
|
|
40
|
+
*/
|
|
41
|
+
schedule(id, schedule, taskFunction, description) {
|
|
42
|
+
if (this.jobs.has(id)) {
|
|
43
|
+
throw new Error(`Job with ID '${id}' already exists.`);
|
|
44
|
+
}
|
|
45
|
+
if (!cron.validate(schedule)) {
|
|
46
|
+
throw new Error(`Invalid cron schedule: ${schedule}`);
|
|
47
|
+
}
|
|
48
|
+
const task = cron.schedule(schedule, async () => {
|
|
49
|
+
const job = this.jobs.get(id);
|
|
50
|
+
if (job && job.isRunning) {
|
|
51
|
+
logger.warning(`Job '${id}' is already running. Skipping this execution.`, {
|
|
52
|
+
requestId: `job-skip-${id}`,
|
|
53
|
+
timestamp: new Date().toISOString(),
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (job) {
|
|
58
|
+
job.isRunning = true;
|
|
59
|
+
}
|
|
60
|
+
const context = requestContextService.createRequestContext({
|
|
61
|
+
jobId: id,
|
|
62
|
+
schedule,
|
|
63
|
+
});
|
|
64
|
+
logger.info(`Starting job '${id}'...`, context);
|
|
65
|
+
try {
|
|
66
|
+
await Promise.resolve(taskFunction(context));
|
|
67
|
+
logger.info(`Job '${id}' completed successfully.`, context);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
logger.error(`Job '${id}' failed.`, error, context);
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
if (job) {
|
|
74
|
+
job.isRunning = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}, {
|
|
78
|
+
scheduled: false, // Do not start immediately
|
|
79
|
+
});
|
|
80
|
+
const newJob = {
|
|
81
|
+
id,
|
|
82
|
+
schedule,
|
|
83
|
+
description,
|
|
84
|
+
task,
|
|
85
|
+
isRunning: false,
|
|
86
|
+
};
|
|
87
|
+
this.jobs.set(id, newJob);
|
|
88
|
+
logger.info(`Job '${id}' scheduled: ${description}`, {
|
|
89
|
+
requestId: `job-schedule-${id}`,
|
|
90
|
+
timestamp: new Date().toISOString(),
|
|
91
|
+
});
|
|
92
|
+
return newJob;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Starts a scheduled job.
|
|
96
|
+
* @param id - The ID of the job to start.
|
|
97
|
+
*/
|
|
98
|
+
start(id) {
|
|
99
|
+
const job = this.jobs.get(id);
|
|
100
|
+
if (!job) {
|
|
101
|
+
throw new Error(`Job with ID '${id}' not found.`);
|
|
102
|
+
}
|
|
103
|
+
job.task.start();
|
|
104
|
+
logger.info(`Job '${id}' started.`, {
|
|
105
|
+
requestId: `job-start-${id}`,
|
|
106
|
+
timestamp: new Date().toISOString(),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Stops a scheduled job.
|
|
111
|
+
* @param id - The ID of the job to stop.
|
|
112
|
+
*/
|
|
113
|
+
stop(id) {
|
|
114
|
+
const job = this.jobs.get(id);
|
|
115
|
+
if (!job) {
|
|
116
|
+
throw new Error(`Job with ID '${id}' not found.`);
|
|
117
|
+
}
|
|
118
|
+
job.task.stop();
|
|
119
|
+
logger.info(`Job '${id}' stopped.`, {
|
|
120
|
+
requestId: `job-stop-${id}`,
|
|
121
|
+
timestamp: new Date().toISOString(),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Removes a job from the scheduler. The job is stopped before being removed.
|
|
126
|
+
* @param id - The ID of the job to remove.
|
|
127
|
+
*/
|
|
128
|
+
remove(id) {
|
|
129
|
+
const job = this.jobs.get(id);
|
|
130
|
+
if (!job) {
|
|
131
|
+
throw new Error(`Job with ID '${id}' not found.`);
|
|
132
|
+
}
|
|
133
|
+
job.task.stop();
|
|
134
|
+
this.jobs.delete(id);
|
|
135
|
+
logger.info(`Job '${id}' removed.`, {
|
|
136
|
+
requestId: `job-remove-${id}`,
|
|
137
|
+
timestamp: new Date().toISOString(),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Gets a list of all scheduled jobs.
|
|
142
|
+
* @returns An array of all Job objects.
|
|
143
|
+
*/
|
|
144
|
+
listJobs() {
|
|
145
|
+
return Array.from(this.jobs.values());
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The singleton instance of the SchedulerService.
|
|
150
|
+
* Use this instance for all job scheduling operations.
|
|
151
|
+
*/
|
|
152
|
+
export const schedulerService = SchedulerService.getInstance();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-ts-template",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.7",
|
|
4
4
|
"description": "Jumpstart Model Context Protocol (MCP) development with this production-ready TypeScript template. Build robust MCP servers and clients with built-in utilities, authentication, and service integrations.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@types/validator": "13.15.2",
|
|
45
45
|
"chrono-node": "^2.8.0",
|
|
46
46
|
"dotenv": "^16.5.0",
|
|
47
|
-
"hono": "^4.8.
|
|
47
|
+
"hono": "^4.8.2",
|
|
48
48
|
"ignore": "^7.0.5",
|
|
49
49
|
"jose": "^6.0.11",
|
|
50
50
|
"openai": "^5.6.0",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"validator": "13.15.15",
|
|
57
57
|
"winston": "^3.17.0",
|
|
58
58
|
"winston-transport": "^4.9.0",
|
|
59
|
+
"node-cron": "^4.1.1",
|
|
59
60
|
"zod": "^3.25.67"
|
|
60
61
|
},
|
|
61
62
|
"keywords": [
|
|
@@ -96,10 +97,11 @@
|
|
|
96
97
|
},
|
|
97
98
|
"devDependencies": {
|
|
98
99
|
"@types/js-yaml": "^4.0.9",
|
|
100
|
+
"@types/node-cron": "^3.0.11",
|
|
99
101
|
"axios": "^1.10.0",
|
|
100
102
|
"depcheck": "^1.4.7",
|
|
101
103
|
"js-yaml": "^4.1.0",
|
|
102
|
-
"prettier": "^3.
|
|
104
|
+
"prettier": "^3.6.0",
|
|
103
105
|
"typedoc": "^0.28.5"
|
|
104
106
|
}
|
|
105
107
|
}
|