@cronicorn/mcp-server 1.22.3 → 1.23.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Cronicorn MCP Server
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/@cronicorn%2Fmcp-server.svg)](https://www.npmjs.com/package/@cronicorn/mcp-server)
4
- [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-blue)](https://registry.modelcontextprotocol.io/servers/io.github.weskerllc/cronicorn-mcp-server)
4
+ [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-blue)](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.weskerllc%2Fcronicorn-mcp-server)
5
5
 
6
6
  Manage cron jobs by talking to your AI assistant.
7
7
 
@@ -11,7 +11,7 @@ mcp:
11
11
  uri: file:///docs/api-reference.md
12
12
  mimeType: text/markdown
13
13
  priority: 0.90
14
- lastModified: 2026-02-03T00:00:00Z
14
+ lastModified: 2026-02-11T00:00:00Z
15
15
  ---
16
16
 
17
17
  # API Reference
@@ -461,6 +461,37 @@ curl -H "x-api-key: YOUR_API_KEY" \
461
461
  }
462
462
  ```
463
463
 
464
+ ### Test Endpoint
465
+
466
+ Execute an endpoint immediately and return the result. Creates a run record with `source: "test"` but does **not** affect scheduling state (`nextRunAt`, `lastRunAt`, `failureCount`). Works on paused endpoints. Blocked on archived endpoints.
467
+
468
+ ```bash
469
+ curl -X POST -H "x-api-key: YOUR_API_KEY" \
470
+ https://cronicorn.com/api/endpoints/ep_xyz789/test
471
+ ```
472
+
473
+ **Response:**
474
+ ```json
475
+ {
476
+ "runId": "run_test_abc123",
477
+ "status": "success",
478
+ "durationMs": 234,
479
+ "statusCode": 200,
480
+ "responseBody": { "healthy": true }
481
+ }
482
+ ```
483
+
484
+ If the endpoint fails:
485
+ ```json
486
+ {
487
+ "runId": "run_test_def456",
488
+ "status": "failed",
489
+ "durationMs": 5012,
490
+ "statusCode": 503,
491
+ "errorMessage": "HTTP 503 Service Unavailable"
492
+ }
493
+ ```
494
+
464
495
  ### Get Dashboard Stats
465
496
 
466
497
  ```bash
@@ -470,6 +501,67 @@ curl -H "x-api-key: YOUR_API_KEY" \
470
501
 
471
502
  ---
472
503
 
504
+ ## Signing Keys API
505
+
506
+ Manage your HMAC signing key for [webhook verification](./guides/webhook-verification.md). Each account has one signing key used to sign all outbound requests.
507
+
508
+ ### Get Signing Key Info
509
+
510
+ ```bash
511
+ curl -H "x-api-key: YOUR_API_KEY" \
512
+ https://cronicorn.com/api/signing-keys
513
+ ```
514
+
515
+ **Response:**
516
+ ```json
517
+ {
518
+ "hasKey": true,
519
+ "keyPrefix": "sk_a1b2c3d4",
520
+ "createdAt": "2026-02-10T15:30:00.000Z",
521
+ "rotatedAt": null
522
+ }
523
+ ```
524
+
525
+ ### Create Signing Key
526
+
527
+ Generate a new signing key. Returns the raw key **once** — store it securely.
528
+
529
+ ```bash
530
+ curl -X POST -H "x-api-key: YOUR_API_KEY" \
531
+ https://cronicorn.com/api/signing-keys
532
+ ```
533
+
534
+ **Response (201):**
535
+ ```json
536
+ {
537
+ "rawKey": "a1b2c3d4e5f6...64_hex_chars",
538
+ "keyPrefix": "sk_a1b2c3d4"
539
+ }
540
+ ```
541
+
542
+ Returns `409 Conflict` if a key already exists. Use rotate instead.
543
+
544
+ ### Rotate Signing Key
545
+
546
+ Replace the current signing key. The old key is **immediately invalidated**.
547
+
548
+ ```bash
549
+ curl -X POST -H "x-api-key: YOUR_API_KEY" \
550
+ https://cronicorn.com/api/signing-keys/rotate
551
+ ```
552
+
553
+ **Response:**
554
+ ```json
555
+ {
556
+ "rawKey": "f6e5d4c3b2a1...64_hex_chars",
557
+ "keyPrefix": "sk_f6e5d4c3"
558
+ }
559
+ ```
560
+
561
+ Returns `404` if no key exists. Use create first.
562
+
563
+ ---
564
+
473
565
  ## AI Analysis API
474
566
 
475
567
  Access AI scheduling explanations and analysis history.
@@ -666,4 +758,5 @@ Rate limit headers:
666
758
 
667
759
  - **[Quick Start](./quick-start.md)** - Create your first job via UI
668
760
  - **[MCP Server](./mcp-server.md)** - Manage jobs via AI assistant
761
+ - **[Webhook Verification](./guides/webhook-verification.md)** - Verify request signatures in your endpoints
669
762
  - **[Technical Reference](./technical/reference.md)** - Schema and field details
@@ -0,0 +1,184 @@
1
+ ---
2
+ title: Webhook Verification
3
+ description: How to verify that incoming requests are genuinely from Cronicorn
4
+ tags:
5
+ - user
6
+ - security
7
+ - webhooks
8
+ sidebar_position: 1
9
+ mcp:
10
+ uri: "cronicorn://guides/webhook-verification"
11
+ mimeType: text/markdown
12
+ priority: 0.85
13
+ lastModified: 2026-02-11T00:00:00Z
14
+ ---
15
+
16
+ # Webhook Verification
17
+
18
+ Every outbound request from Cronicorn includes HMAC-SHA256 signature headers that let your endpoints verify the request is genuine.
19
+
20
+ ## How It Works
21
+
22
+ Each request includes two headers:
23
+
24
+ | Header | Example | Description |
25
+ |--------|---------|-------------|
26
+ | `X-Cronicorn-Signature` | `sha256=a1b2c3...` | HMAC-SHA256 of `"{timestamp}.{body}"` |
27
+ | `X-Cronicorn-Timestamp` | `1700000000` | Unix timestamp (seconds) when the request was signed |
28
+
29
+ The signature is computed as:
30
+
31
+ ```
32
+ HMAC-SHA256(your_signing_key, "{timestamp}.{body}")
33
+ ```
34
+
35
+ Where `body` is the raw request body string (empty string for GET/HEAD requests).
36
+
37
+ ## Getting Your Signing Key
38
+
39
+ Your signing key is automatically created when your account is set up. You can view, create, or rotate it via:
40
+
41
+ - **API**: `GET /api/signing-keys`, `POST /api/signing-keys`, `POST /api/signing-keys/rotate`
42
+ - **MCP**: `getSigningKey`, `createSigningKey`, `rotateSigningKey` tools
43
+
44
+ The raw key is only shown once when created or rotated. Store it securely.
45
+
46
+ ## Verification Examples
47
+
48
+ ### Node.js
49
+
50
+ ```javascript
51
+ import crypto from 'node:crypto';
52
+
53
+ function verifySignature(req, signingKey) {
54
+ const signature = req.headers['x-cronicorn-signature'];
55
+ const timestamp = req.headers['x-cronicorn-timestamp'];
56
+
57
+ if (!signature || !timestamp) return false;
58
+
59
+ // Replay protection: reject requests older than 5 minutes
60
+ const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
61
+ if (age > 300) return false;
62
+
63
+ // Compute expected signature
64
+ const body = req.body ? JSON.stringify(req.body) : '';
65
+ const payload = `${timestamp}.${body}`;
66
+ const expected = crypto.createHmac('sha256', signingKey)
67
+ .update(payload)
68
+ .digest('hex');
69
+
70
+ // Constant-time comparison to prevent timing attacks
71
+ const actual = signature.replace('sha256=', '');
72
+ return crypto.timingSafeEqual(
73
+ Buffer.from(expected),
74
+ Buffer.from(actual)
75
+ );
76
+ }
77
+ ```
78
+
79
+ ### Python
80
+
81
+ ```python
82
+ import hmac
83
+ import hashlib
84
+ import time
85
+
86
+ def verify_signature(headers, body, signing_key):
87
+ signature = headers.get('X-Cronicorn-Signature', '')
88
+ timestamp = headers.get('X-Cronicorn-Timestamp', '')
89
+
90
+ if not signature or not timestamp:
91
+ return False
92
+
93
+ # Replay protection: reject requests older than 5 minutes
94
+ age = int(time.time()) - int(timestamp)
95
+ if age > 300:
96
+ return False
97
+
98
+ # Compute expected signature
99
+ payload = f"{timestamp}.{body}"
100
+ expected = hmac.new(
101
+ signing_key.encode(),
102
+ payload.encode(),
103
+ hashlib.sha256
104
+ ).hexdigest()
105
+
106
+ # Constant-time comparison
107
+ actual = signature.replace('sha256=', '')
108
+ return hmac.compare_digest(expected, actual)
109
+ ```
110
+
111
+ ### Go
112
+
113
+ ```go
114
+ package main
115
+
116
+ import (
117
+ "crypto/hmac"
118
+ "crypto/sha256"
119
+ "encoding/hex"
120
+ "fmt"
121
+ "net/http"
122
+ "strconv"
123
+ "strings"
124
+ "time"
125
+ )
126
+
127
+ func verifySignature(r *http.Request, body []byte, signingKey string) bool {
128
+ signature := r.Header.Get("X-Cronicorn-Signature")
129
+ timestamp := r.Header.Get("X-Cronicorn-Timestamp")
130
+
131
+ if signature == "" || timestamp == "" {
132
+ return false
133
+ }
134
+
135
+ // Replay protection
136
+ ts, err := strconv.ParseInt(timestamp, 10, 64)
137
+ if err != nil {
138
+ return false
139
+ }
140
+ if time.Now().Unix()-ts > 300 {
141
+ return false
142
+ }
143
+
144
+ // Compute expected signature
145
+ payload := fmt.Sprintf("%s.%s", timestamp, string(body))
146
+ mac := hmac.New(sha256.New, []byte(signingKey))
147
+ mac.Write([]byte(payload))
148
+ expected := hex.EncodeToString(mac.Sum(nil))
149
+
150
+ actual := strings.TrimPrefix(signature, "sha256=")
151
+ return hmac.Equal([]byte(expected), []byte(actual))
152
+ }
153
+ ```
154
+
155
+ ## Replay Protection
156
+
157
+ The `X-Cronicorn-Timestamp` header enables replay protection. Reject requests where the timestamp is older than your tolerance window (5 minutes recommended):
158
+
159
+ ```javascript
160
+ const age = Math.floor(Date.now() / 1000) - parseInt(timestamp);
161
+ if (age > 300) {
162
+ // Request is too old — possible replay attack
163
+ return res.status(401).send('Request expired');
164
+ }
165
+ ```
166
+
167
+ ## Key Rotation
168
+
169
+ When you rotate your signing key:
170
+
171
+ 1. The old key is **immediately invalidated**
172
+ 2. All subsequent requests use the new key
173
+ 3. Any in-flight requests signed with the old key will fail verification
174
+
175
+ Plan rotation during low-traffic periods to minimize verification failures.
176
+
177
+ ## Troubleshooting
178
+
179
+ | Symptom | Cause | Fix |
180
+ |---------|-------|-----|
181
+ | Signature mismatch | Body was modified (e.g., by middleware) | Verify against raw body before parsing |
182
+ | All signatures fail | Wrong signing key | Check `GET /api/signing-keys` for key prefix |
183
+ | Intermittent failures | Clock skew | Increase timestamp tolerance window |
184
+ | No signature headers | No signing key configured | Create one via `POST /api/signing-keys` |
@@ -11,7 +11,7 @@ mcp:
11
11
  uri: file:///docs/mcp-server.md
12
12
  mimeType: text/markdown
13
13
  priority: 0.95
14
- lastModified: 2026-02-03T00:00:00Z
14
+ lastModified: 2026-02-11T00:00:00Z
15
15
  ---
16
16
 
17
17
  # MCP Server
@@ -76,14 +76,15 @@ From first idea to production — your AI assistant knows Cronicorn inside and o
76
76
  "My app is getting more traffic — should I tighten my health check intervals?"
77
77
  ```
78
78
 
79
- ## 21 Tools Available
79
+ ## 25 Tools Available
80
80
 
81
81
  | Category | Tools |
82
82
  |----------|-------|
83
83
  | **Jobs** | `createJob`, `listJobs`, `getJob`, `updateJob`, `archiveJob`, `pauseJob`, `resumeJob` |
84
84
  | **Endpoints** | `addEndpoint`, `listEndpoints`, `getEndpoint`, `updateEndpoint`, `archiveEndpoint`, `pauseResumeEndpoint` |
85
85
  | **AI Scheduling** | `applyIntervalHint`, `scheduleOneShot`, `clearHints`, `resetFailures` |
86
- | **Monitoring** | `listEndpointRuns`, `getRunDetails`, `getEndpointHealth`, `getDashboardStats` |
86
+ | **Monitoring** | `listEndpointRuns`, `getRunDetails`, `getEndpointHealth`, `getDashboardStats`, `testEndpoint` |
87
+ | **Security** | `getSigningKey`, `createSigningKey`, `rotateSigningKey` |
87
88
 
88
89
  ## Built-In Documentation
89
90
 
package/dist/index.js CHANGED
@@ -12748,6 +12748,7 @@ __export(schemas_base_exports, {
12748
12748
  RunDetailsResponseBaseSchema: () => RunDetailsResponseBaseSchema,
12749
12749
  RunSummaryResponseBaseSchema: () => RunSummaryResponseBaseSchema,
12750
12750
  ScheduleOneShotRequestBaseSchema: () => ScheduleOneShotRequestBaseSchema,
12751
+ TestEndpointResponseBaseSchema: () => TestEndpointResponseBaseSchema,
12751
12752
  UpdateEndpointRequestBaseSchema: () => UpdateEndpointRequestBaseSchema,
12752
12753
  UpdateJobRequestBaseSchema: () => UpdateJobRequestBaseSchema
12753
12754
  });
@@ -12904,6 +12905,14 @@ var HealthSummaryResponseBaseSchema = external_exports.object({
12904
12905
  }).nullable().describe("Last run information"),
12905
12906
  failureStreak: external_exports.number().int().describe("Current consecutive failure count")
12906
12907
  });
12908
+ var TestEndpointResponseBaseSchema = external_exports.object({
12909
+ runId: external_exports.string().describe("ID of the test run record"),
12910
+ status: external_exports.enum(["success", "failed"]).describe("Execution result"),
12911
+ durationMs: external_exports.number().describe("Execution duration in milliseconds"),
12912
+ statusCode: external_exports.number().int().optional().describe("HTTP status code"),
12913
+ responseBody: external_exports.any().nullable().optional().describe("Response body (JSON, within size limit)"),
12914
+ errorMessage: external_exports.string().optional().describe("Error message if failed")
12915
+ });
12907
12916
 
12908
12917
  // ../../packages/api-contracts/dist/jobs/schemas.js
12909
12918
  init_esm_shims();
@@ -13511,6 +13520,8 @@ var GetRunDetailsSummary = "Get run details";
13511
13520
  var GetRunDetailsDescription = "Get detailed information about a specific run. Includes full execution details, error messages, response body (if available), status code, and endpoint context.";
13512
13521
  var GetHealthSummarySummary = "Get endpoint health";
13513
13522
  var GetHealthSummaryDescription = "Get health summary for an endpoint. Returns success/failure counts, average duration, last run info, and current failure streak. Useful for monitoring and alerting.";
13523
+ var TestEndpointSummary = "Test endpoint";
13524
+ var TestEndpointDescription = "Execute an endpoint immediately and return the result. Creates a run record (source: 'test') but does NOT affect scheduling state (nextRunAt, lastRunAt, failureCount). Works on paused endpoints. Blocked on archived endpoints.";
13514
13525
  var RunDetailsResponseSchema = external_exports.object({
13515
13526
  id: external_exports.string().describe("Run ID"),
13516
13527
  endpointId: external_exports.string().describe("Endpoint ID"),
@@ -14207,6 +14218,60 @@ function registerGetRunDetails(server, apiClient) {
14207
14218
  });
14208
14219
  }
14209
14220
 
14221
+ // src/tools/api/get-signing-key.ts
14222
+ init_esm_shims();
14223
+
14224
+ // ../../packages/api-contracts/dist/signing-keys/index.js
14225
+ init_esm_shims();
14226
+
14227
+ // ../../packages/api-contracts/dist/signing-keys/schemas.base.js
14228
+ var schemas_base_exports3 = {};
14229
+ __export(schemas_base_exports3, {
14230
+ CreateSigningKeyDescription: () => CreateSigningKeyDescription,
14231
+ CreateSigningKeySummary: () => CreateSigningKeySummary,
14232
+ GetSigningKeyDescription: () => GetSigningKeyDescription,
14233
+ GetSigningKeySummary: () => GetSigningKeySummary,
14234
+ RotateSigningKeyDescription: () => RotateSigningKeyDescription,
14235
+ RotateSigningKeySummary: () => RotateSigningKeySummary,
14236
+ SigningKeyCreatedResponseBaseSchema: () => SigningKeyCreatedResponseBaseSchema,
14237
+ SigningKeyInfoResponseBaseSchema: () => SigningKeyInfoResponseBaseSchema
14238
+ });
14239
+ init_esm_shims();
14240
+ var SigningKeyInfoResponseBaseSchema = external_exports.object({
14241
+ hasKey: external_exports.boolean(),
14242
+ keyPrefix: external_exports.string().nullable(),
14243
+ createdAt: external_exports.string().datetime().nullable(),
14244
+ rotatedAt: external_exports.string().datetime().nullable()
14245
+ });
14246
+ var SigningKeyCreatedResponseBaseSchema = external_exports.object({
14247
+ rawKey: external_exports.string(),
14248
+ keyPrefix: external_exports.string()
14249
+ });
14250
+ var GetSigningKeySummary = "Get signing key info";
14251
+ var GetSigningKeyDescription = "Returns metadata about the user's signing key (prefix, dates). Never returns the raw key.";
14252
+ var CreateSigningKeySummary = "Generate signing key";
14253
+ var CreateSigningKeyDescription = "Generates a new HMAC-SHA256 signing key for outbound request verification. Returns the raw key once \u2014 store it securely. Returns 409 if a key already exists.";
14254
+ var RotateSigningKeySummary = "Rotate signing key";
14255
+ var RotateSigningKeyDescription = "Replaces the current signing key with a new one. The old key is immediately invalidated. Returns 404 if no key exists.";
14256
+
14257
+ // src/tools/api/get-signing-key.ts
14258
+ var EmptyInputSchema = external_exports.object({});
14259
+ var SigningKeyInfoResponseSchema = schemas_base_exports3.SigningKeyInfoResponseBaseSchema;
14260
+ function registerGetSigningKey(server, apiClient) {
14261
+ registerApiTool(server, apiClient, {
14262
+ name: "getSigningKey",
14263
+ title: GetSigningKeySummary,
14264
+ description: GetSigningKeyDescription,
14265
+ inputSchema: toShape(EmptyInputSchema),
14266
+ outputSchema: toShape(SigningKeyInfoResponseSchema),
14267
+ inputValidator: EmptyInputSchema,
14268
+ outputValidator: SigningKeyInfoResponseSchema,
14269
+ method: "GET",
14270
+ path: "/signing-keys",
14271
+ successMessage: (output) => output.hasKey ? `Signing key exists (prefix: ${output.keyPrefix}, created: ${output.createdAt})` : "No signing key configured. Use createSigningKey to generate one."
14272
+ });
14273
+ }
14274
+
14210
14275
  // src/tools/api/list-endpoints.ts
14211
14276
  init_esm_shims();
14212
14277
  var ListEndpointsRequestSchema = external_exports.object({
@@ -14509,6 +14574,68 @@ function registerPostResetFailures(server, apiClient) {
14509
14574
  });
14510
14575
  }
14511
14576
 
14577
+ // src/tools/api/post-rotate-signing-key.ts
14578
+ init_esm_shims();
14579
+ var EmptyInputSchema2 = external_exports.object({});
14580
+ var SigningKeyCreatedResponseSchema = schemas_base_exports3.SigningKeyCreatedResponseBaseSchema;
14581
+ function registerRotateSigningKey(server, apiClient) {
14582
+ registerApiTool(server, apiClient, {
14583
+ name: "rotateSigningKey",
14584
+ title: RotateSigningKeySummary,
14585
+ description: RotateSigningKeyDescription,
14586
+ inputSchema: toShape(EmptyInputSchema2),
14587
+ outputSchema: toShape(SigningKeyCreatedResponseSchema),
14588
+ inputValidator: EmptyInputSchema2,
14589
+ outputValidator: SigningKeyCreatedResponseSchema,
14590
+ method: "POST",
14591
+ path: "/signing-keys/rotate",
14592
+ transformInput: () => ({}),
14593
+ successMessage: (output) => `Signing key rotated (new prefix: ${output.keyPrefix}). Old key is immediately invalid. Save the new raw key securely \u2014 it will not be shown again: ${output.rawKey}`
14594
+ });
14595
+ }
14596
+
14597
+ // src/tools/api/post-signing-key.ts
14598
+ init_esm_shims();
14599
+ var EmptyInputSchema3 = external_exports.object({});
14600
+ var SigningKeyCreatedResponseSchema2 = schemas_base_exports3.SigningKeyCreatedResponseBaseSchema;
14601
+ function registerCreateSigningKey(server, apiClient) {
14602
+ registerApiTool(server, apiClient, {
14603
+ name: "createSigningKey",
14604
+ title: CreateSigningKeySummary,
14605
+ description: CreateSigningKeyDescription,
14606
+ inputSchema: toShape(EmptyInputSchema3),
14607
+ outputSchema: toShape(SigningKeyCreatedResponseSchema2),
14608
+ inputValidator: EmptyInputSchema3,
14609
+ outputValidator: SigningKeyCreatedResponseSchema2,
14610
+ method: "POST",
14611
+ path: "/signing-keys",
14612
+ transformInput: () => ({}),
14613
+ successMessage: (output) => `Signing key created (prefix: ${output.keyPrefix}). IMPORTANT: Save this raw key securely \u2014 it will not be shown again: ${output.rawKey}`
14614
+ });
14615
+ }
14616
+
14617
+ // src/tools/api/post-test-endpoint.ts
14618
+ init_esm_shims();
14619
+ var TestEndpointInputSchema = external_exports.object({
14620
+ id: external_exports.string().describe("Endpoint ID to test")
14621
+ });
14622
+ var TestEndpointResponseSchema = schemas_base_exports.TestEndpointResponseBaseSchema;
14623
+ function registerPostTestEndpoint(server, apiClient) {
14624
+ registerApiTool(server, apiClient, {
14625
+ name: "testEndpoint",
14626
+ title: TestEndpointSummary,
14627
+ description: TestEndpointDescription,
14628
+ inputSchema: toShape(TestEndpointInputSchema),
14629
+ outputSchema: toShape(TestEndpointResponseSchema),
14630
+ inputValidator: TestEndpointInputSchema,
14631
+ outputValidator: TestEndpointResponseSchema,
14632
+ method: "POST",
14633
+ path: (input) => `/endpoints/${input.id}/test`,
14634
+ transformInput: () => ({}),
14635
+ successMessage: (output) => output.status === "success" ? `\u2705 Endpoint test passed (${output.durationMs}ms, HTTP ${output.statusCode ?? "?"})` : `\u274C Endpoint test failed: ${output.errorMessage ?? "unknown error"} (${output.durationMs}ms)`
14636
+ });
14637
+ }
14638
+
14512
14639
  // src/tools/index.ts
14513
14640
  function registerTools(server, apiUrl, credentials) {
14514
14641
  const apiClient = createHttpApiClient({
@@ -14535,7 +14662,11 @@ function registerTools(server, apiUrl, credentials) {
14535
14662
  registerGetEndpointRuns(server, apiClient);
14536
14663
  registerGetRunDetails(server, apiClient);
14537
14664
  registerGetEndpointHealth(server, apiClient);
14665
+ registerPostTestEndpoint(server, apiClient);
14538
14666
  registerGetDashboardStats(server, apiClient);
14667
+ registerGetSigningKey(server, apiClient);
14668
+ registerCreateSigningKey(server, apiClient);
14669
+ registerRotateSigningKey(server, apiClient);
14539
14670
  }
14540
14671
 
14541
14672
  // src/index.ts
@@ -14546,7 +14677,7 @@ async function main() {
14546
14677
  {
14547
14678
  name: "cronicorn",
14548
14679
  // eslint-disable-next-line node/no-process-env
14549
- version: "1.22.3"
14680
+ version: "1.23.0"
14550
14681
  },
14551
14682
  {
14552
14683
  instructions: [
@@ -14562,19 +14693,19 @@ async function main() {
14562
14693
  "",
14563
14694
  "## How to Help Users",
14564
14695
  "",
14565
- "When users ask about Cronicorn concepts, integration patterns, self-hosting, or how scheduling works, read the bundled documentation resources on this server. Key resources:",
14696
+ "When users ask about Cronicorn concepts, integration patterns, self-hosting, or how scheduling works, read the bundled documentation resources on this server. Use the `file:///docs/` URI scheme to read resources. Key resources:",
14566
14697
  "",
14567
- "- `introduction.md` \u2014 What Cronicorn is and why it exists",
14568
- "- `quick-start.md` \u2014 Creating your first job",
14569
- "- `core-concepts.md` \u2014 Jobs, endpoints, schedules, AI adaptation explained",
14570
- "- `recipes.md` \u2014 Common patterns with working examples",
14571
- "- `use-cases.md` \u2014 Real-world scenarios (health checks, data sync, auto-remediation)",
14572
- "- `api-reference.md` \u2014 Complete REST API documentation",
14573
- "- `code-examples.md` \u2014 Integration examples in multiple languages",
14574
- "- `troubleshooting.md` \u2014 Common issues and solutions",
14575
- "- `technical/how-ai-adaptation-works.md` \u2014 Deep dive into AI scheduling",
14576
- "- `technical/how-scheduling-works.md` \u2014 Scheduling mechanics and backoff behavior",
14577
- "- `self-hosting/index.md` \u2014 Docker Compose deployment guide",
14698
+ "- `file:///docs/introduction.md` \u2014 What Cronicorn is and why it exists",
14699
+ "- `file:///docs/quick-start.md` \u2014 Creating your first job",
14700
+ "- `file:///docs/core-concepts.md` \u2014 Jobs, endpoints, schedules, AI adaptation explained",
14701
+ "- `file:///docs/recipes.md` \u2014 Common patterns with working examples",
14702
+ "- `file:///docs/use-cases.md` \u2014 Real-world scenarios (health checks, data sync, auto-remediation)",
14703
+ "- `file:///docs/api-reference.md` \u2014 Complete REST API documentation",
14704
+ "- `file:///docs/code-examples.md` \u2014 Integration examples in multiple languages",
14705
+ "- `file:///docs/troubleshooting.md` \u2014 Common issues and solutions",
14706
+ "- `file:///docs/technical/how-ai-adaptation-works.md` \u2014 Deep dive into AI scheduling",
14707
+ "- `file:///docs/technical/how-scheduling-works.md` \u2014 Scheduling mechanics and backoff behavior",
14708
+ "- `file:///docs/self-hosting/index.md` \u2014 Docker Compose deployment guide",
14578
14709
  "",
14579
14710
  "Read the relevant resources before answering conceptual or integration questions. The docs are comprehensive \u2014 use them."
14580
14711
  ].join("\n")