skedyul 0.2.160 → 0.3.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 +134 -472
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,250 +1,158 @@
|
|
|
1
1
|
# skedyul
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The official Node.js SDK for building Skedyul integration apps. This package provides everything you need to create MCP (Model Context Protocol) servers, handle webhooks, manage lifecycle events, and interact with the Skedyul platform.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
7
|
+
- **MCP Server**: Build tools that AI agents can invoke via the Model Context Protocol
|
|
8
|
+
- **Webhooks**: Receive and process external events (SMS, emails, API callbacks)
|
|
9
|
+
- **Lifecycle Hooks**: Handle app installation, provisioning, and cleanup
|
|
10
|
+
- **Core API Client**: Interact with Skedyul resources (workplaces, channels, instances)
|
|
11
|
+
- **CLI**: Develop and test locally with hot-reload and tunneling
|
|
10
12
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
Every `ToolHandler` must return both its result payload (`output`) and a `billing` object describing the credits consumed:
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
export const helloWorld: ToolHandler<HelloWorldInput, HelloWorldOutput> = async ({
|
|
17
|
-
input,
|
|
18
|
-
context,
|
|
19
|
-
}) => {
|
|
20
|
-
// Do your work here...
|
|
21
|
-
const credits = calculateCredits(input, context) // e.g. characters × rate
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
output: {
|
|
25
|
-
message: `Hello, ${input.name ?? 'world'}`,
|
|
26
|
-
environmentName: context.env.SKEDYUL_ENV ?? 'local',
|
|
27
|
-
},
|
|
28
|
-
billing: { credits },
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Servers attach that `billing` data to every MCP response, so callers always know the final credit cost. Since pricing may depend on runtime data (like message length), compute credits inside the registry or another secure helper that can read your pricing tables, rather than in the shared server logic.
|
|
34
|
-
|
|
35
|
-
## Estimate endpoint
|
|
36
|
-
|
|
37
|
-
Both transports expose a dedicated `POST /estimate` endpoint that reuses the same registry to calculate projected billing without executing charged work. Callers supply a tool name and inputs, and the server forwards the request to the registry with `context.mode === 'estimate'`. The response contains only the `billing` block:
|
|
38
|
-
|
|
39
|
-
```json
|
|
40
|
-
POST /estimate
|
|
41
|
-
{
|
|
42
|
-
"name": "hello-world",
|
|
43
|
-
"inputs": { "name": "demo" }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
200 OK
|
|
47
|
-
{
|
|
48
|
-
"billing": { "credits": 4 }
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
Treat `/estimate` as an authentication-protected route (if your runtime supports auth) because it exposes pricing metadata. Keep your pricing tables and cost calculations in a guarded part of your stack, and never return internal secrets through `estimate`.
|
|
53
|
-
|
|
54
|
-
## Core API hooks
|
|
55
|
-
|
|
56
|
-
For integration-specific RPCs that belong to your platform rather than a tool, provide a `coreApi` implementation when calling `server.create`. The property accepts:
|
|
57
|
-
|
|
58
|
-
- `service`: an object implementing `createCommunicationChannel`, `updateCommunicationChannel`, `deleteCommunicationChannel`, `getCommunicationChannel`, `getCommunicationChannels`, and `sendMessage`.
|
|
59
|
-
- `webhookHandler`: an optional `(request: WebhookRequest) => Promise<WebhookResponse>` callback that will receive forwarded HTTP webhooks.
|
|
60
|
-
|
|
61
|
-
The MCP server exposes `POST /core` (with `{ method, params }`) and `POST /core/webhook` for these operations. They never appear under `tools/list` unlesstaken explicit MCP tooling—they are separate transport-level handlers and do not count against tool request limits. Make sure your service returns the structured channel/message data defined in `src/core/types.ts` so the responses stay consistent, and guard `/core`/`/core/webhook` with your platform’s preferred authentication if you surface them externally.
|
|
62
|
-
|
|
63
|
-
## Core API Client
|
|
64
|
-
|
|
65
|
-
The SDK includes a client for the Skedyul Core API that enables lookups across workplaces. This is especially useful in webhook handlers where you need to identify which workspace a request belongs to.
|
|
66
|
-
|
|
67
|
-
### Configuration
|
|
68
|
-
|
|
69
|
-
Configure the client using environment variables or programmatically:
|
|
70
|
-
|
|
71
|
-
**Environment Variables:**
|
|
13
|
+
## Installation
|
|
72
14
|
|
|
73
15
|
```bash
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# Your API token (App API or Workplace API)
|
|
78
|
-
SKEDYUL_API_TOKEN=sk_app_xxxxx
|
|
16
|
+
npm install skedyul
|
|
17
|
+
# or
|
|
18
|
+
pnpm add skedyul
|
|
79
19
|
```
|
|
80
20
|
|
|
81
|
-
|
|
21
|
+
## Quick Start
|
|
82
22
|
|
|
83
|
-
|
|
84
|
-
import { configure } from 'skedyul'
|
|
23
|
+
### 1. Create your configuration
|
|
85
24
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
25
|
+
```ts
|
|
26
|
+
// skedyul.config.ts
|
|
27
|
+
import { defineConfig } from 'skedyul'
|
|
28
|
+
|
|
29
|
+
export default defineConfig({
|
|
30
|
+
name: 'my-integration',
|
|
31
|
+
version: '1.0.0',
|
|
32
|
+
computeLayer: 'serverless',
|
|
33
|
+
tools: import('./src/tools/registry'),
|
|
34
|
+
webhooks: import('./src/webhooks/registry'),
|
|
89
35
|
})
|
|
90
36
|
```
|
|
91
37
|
|
|
92
|
-
###
|
|
93
|
-
|
|
94
|
-
- **App API Token (`sk_app_*`)**: Grants access to all workplaces where your app is installed. Use this for webhooks where you need to look up resources across workplaces.
|
|
95
|
-
- **Workplace API Token (`sk_wkp_*`)**: Scoped to a single workplace. Use this when you know the target workspace (e.g., MCP tools).
|
|
96
|
-
|
|
97
|
-
### Available Methods
|
|
98
|
-
|
|
99
|
-
- `workplace.list({ filter?, limit? })` - List workplaces
|
|
100
|
-
- `workplace.get(id)` - Get a single workplace
|
|
101
|
-
- `communicationChannel.list({ filter?, limit? })` - List communication channels
|
|
102
|
-
- `communicationChannel.get(id)` - Get a single channel
|
|
103
|
-
|
|
104
|
-
### Example: Webhook Handler
|
|
38
|
+
### 2. Define a tool
|
|
105
39
|
|
|
106
40
|
```ts
|
|
107
|
-
|
|
41
|
+
// src/tools/hello.ts
|
|
42
|
+
import { z } from 'skedyul'
|
|
43
|
+
import type { ToolHandler, ToolDefinition } from 'skedyul'
|
|
108
44
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
baseUrl: process.env.SKEDYUL_API_URL,
|
|
112
|
-
apiToken: process.env.SKEDYUL_API_TOKEN,
|
|
45
|
+
const inputSchema = z.object({
|
|
46
|
+
name: z.string().optional(),
|
|
113
47
|
})
|
|
114
48
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// Find the channel across all workplaces where your app is installed
|
|
118
|
-
const channels = await communicationChannel.list({
|
|
119
|
-
filter: { identifierValue: phoneNumber },
|
|
120
|
-
limit: 1,
|
|
121
|
-
})
|
|
49
|
+
type Input = z.infer<typeof inputSchema>
|
|
50
|
+
type Output = { message: string }
|
|
122
51
|
|
|
123
|
-
|
|
124
|
-
|
|
52
|
+
const handler: ToolHandler<Input, Output> = async (input, context) => {
|
|
53
|
+
return {
|
|
54
|
+
output: { message: `Hello, ${input.name ?? 'world'}!` },
|
|
55
|
+
billing: { credits: 1 },
|
|
56
|
+
meta: { success: true, message: 'Greeting sent', toolName: 'hello' },
|
|
125
57
|
}
|
|
126
|
-
|
|
127
|
-
const channel = channels[0]
|
|
128
|
-
console.log(`Found channel in workplace: ${channel.workplaceId}`)
|
|
129
|
-
|
|
130
|
-
// Now you can process the message in the correct workspace context
|
|
131
|
-
return channel
|
|
132
58
|
}
|
|
133
|
-
```
|
|
134
59
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
60
|
+
export const helloTool: ToolDefinition<Input, Output> = {
|
|
61
|
+
name: 'hello',
|
|
62
|
+
description: 'Say hello to someone',
|
|
63
|
+
inputSchema,
|
|
64
|
+
handler,
|
|
65
|
+
}
|
|
141
66
|
```
|
|
142
67
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
### Define your registry
|
|
146
|
-
|
|
147
|
-
Each tool should follow the shared handler signature:
|
|
68
|
+
### 3. Start the server
|
|
148
69
|
|
|
149
70
|
```ts
|
|
150
|
-
|
|
71
|
+
// src/server.ts
|
|
72
|
+
import { server } from 'skedyul'
|
|
73
|
+
import { toolRegistry } from './tools/registry'
|
|
151
74
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
75
|
+
const mcpServer = server.create(
|
|
76
|
+
{
|
|
77
|
+
computeLayer: 'dedicated',
|
|
78
|
+
metadata: { name: 'my-integration', version: '1.0.0' },
|
|
79
|
+
},
|
|
80
|
+
toolRegistry,
|
|
81
|
+
)
|
|
155
82
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
environmentName: string
|
|
159
|
-
}
|
|
83
|
+
await mcpServer.listen(3000)
|
|
84
|
+
```
|
|
160
85
|
|
|
161
|
-
|
|
162
|
-
input,
|
|
163
|
-
context,
|
|
164
|
-
}) => {
|
|
165
|
-
const name = input.name?.trim() || 'world'
|
|
166
|
-
const environmentName = context.env.SKEDYUL_ENV ?? 'local'
|
|
86
|
+
## Documentation
|
|
167
87
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
88
|
+
| Guide | Description |
|
|
89
|
+
|-------|-------------|
|
|
90
|
+
| [Authentication](./docs/authentication.md) | Token types, scopes, and configuration |
|
|
91
|
+
| [Tools](./docs/tools.md) | Building MCP tools with handlers and schemas |
|
|
92
|
+
| [Webhooks](./docs/webhooks.md) | Receiving external events and callbacks |
|
|
93
|
+
| [Lifecycle Hooks](./docs/lifecycle-hooks.md) | Install, provision, and uninstall handlers |
|
|
94
|
+
| [Core API](./docs/core-api.md) | Client for Skedyul platform resources |
|
|
95
|
+
| [Configuration](./docs/configuration.md) | skedyul.config.ts reference |
|
|
96
|
+
| [Errors](./docs/errors.md) | Error types and handling patterns |
|
|
173
97
|
|
|
174
|
-
|
|
175
|
-
'hello-world': helloWorld,
|
|
176
|
-
}
|
|
177
|
-
```
|
|
98
|
+
## Server Modes
|
|
178
99
|
|
|
179
|
-
### Dedicated
|
|
100
|
+
### Dedicated (Docker/ECS)
|
|
180
101
|
|
|
181
|
-
|
|
182
|
-
import { server } from 'skedyul'
|
|
183
|
-
import { registry } from './registry'
|
|
102
|
+
Long-running HTTP server with request counting and graceful shutdown:
|
|
184
103
|
|
|
104
|
+
```ts
|
|
185
105
|
const mcpServer = server.create(
|
|
186
106
|
{
|
|
187
107
|
computeLayer: 'dedicated',
|
|
188
|
-
metadata: {
|
|
189
|
-
name: 'my-dedicated-server',
|
|
190
|
-
version: '1.0.0',
|
|
191
|
-
},
|
|
108
|
+
metadata: { name: 'my-app', version: '1.0.0' },
|
|
192
109
|
defaultPort: 3000,
|
|
193
110
|
maxRequests: 1000,
|
|
194
111
|
ttlExtendSeconds: 3600,
|
|
195
112
|
},
|
|
196
|
-
|
|
113
|
+
toolRegistry,
|
|
114
|
+
webhookRegistry,
|
|
197
115
|
)
|
|
198
116
|
|
|
199
117
|
await mcpServer.listen()
|
|
200
118
|
```
|
|
201
119
|
|
|
202
|
-
### Serverless
|
|
120
|
+
### Serverless (AWS Lambda)
|
|
203
121
|
|
|
204
|
-
|
|
205
|
-
import { server } from 'skedyul'
|
|
206
|
-
import { registry } from './registry'
|
|
122
|
+
Export a Lambda handler with automatic CORS:
|
|
207
123
|
|
|
124
|
+
```ts
|
|
208
125
|
const mcpServer = server.create(
|
|
209
126
|
{
|
|
210
127
|
computeLayer: 'serverless',
|
|
211
|
-
metadata: {
|
|
212
|
-
|
|
213
|
-
version: '1.0.0',
|
|
214
|
-
},
|
|
215
|
-
cors: {
|
|
216
|
-
allowOrigin: '*',
|
|
217
|
-
},
|
|
128
|
+
metadata: { name: 'my-app', version: '1.0.0' },
|
|
129
|
+
cors: { allowOrigin: '*' },
|
|
218
130
|
},
|
|
219
|
-
|
|
131
|
+
toolRegistry,
|
|
132
|
+
webhookRegistry,
|
|
220
133
|
)
|
|
221
134
|
|
|
222
135
|
export const handler = mcpServer.handler
|
|
223
136
|
```
|
|
224
137
|
|
|
225
|
-
##
|
|
226
|
-
|
|
227
|
-
- **`computeLayer`**: Choose `dedicated` to expose an HTTP server (`listen`) or `serverless` to get a Lambda handler (`handler`).
|
|
228
|
-
- **`metadata`**: Used for the MCP server versioning payload.
|
|
229
|
-
- **`maxRequests` / `ttlExtendSeconds`**: Control request capping logic that triggers a graceful shutdown (dedicated) or throttles health stats.
|
|
230
|
-
- **`cors`**: Serverless handlers automatically add the configured CORS headers to every response.
|
|
231
|
-
- **Runtime env overrides**: `MCP_ENV_JSON` (build-time) and `MCP_ENV` (container runtime) merge into `process.env` before every request, while request-level `env` arguments temporarily override env vars per tool call.
|
|
232
|
-
|
|
233
|
-
## Health metadata
|
|
234
|
-
|
|
235
|
-
Both adapters expose `getHealthStatus()`, returning:
|
|
138
|
+
## Endpoints
|
|
236
139
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
140
|
+
| Endpoint | Method | Description |
|
|
141
|
+
|----------|--------|-------------|
|
|
142
|
+
| `/mcp` | POST | MCP JSON-RPC (tools/list, tools/call) |
|
|
143
|
+
| `/webhooks/{name}` | * | Webhook handlers |
|
|
144
|
+
| `/health` | GET | Server health status |
|
|
145
|
+
| `/estimate` | POST | Billing estimation |
|
|
146
|
+
| `/install` | POST | Installation handler |
|
|
147
|
+
| `/provision` | POST | Provisioning handler |
|
|
148
|
+
| `/uninstall` | POST | Uninstall handler |
|
|
149
|
+
| `/oauth_callback` | POST | OAuth callback handler |
|
|
242
150
|
|
|
243
151
|
---
|
|
244
152
|
|
|
245
153
|
# Skedyul CLI
|
|
246
154
|
|
|
247
|
-
The
|
|
155
|
+
The CLI provides local development tools for building and testing Skedyul apps.
|
|
248
156
|
|
|
249
157
|
## Quick Start
|
|
250
158
|
|
|
@@ -253,7 +161,7 @@ The Skedyul CLI (`skedyul`) is a powerful command-line interface for developing,
|
|
|
253
161
|
skedyul auth login
|
|
254
162
|
|
|
255
163
|
# 2. Navigate to your app directory
|
|
256
|
-
cd
|
|
164
|
+
cd integrations/my-app
|
|
257
165
|
|
|
258
166
|
# 3. Link to a workplace
|
|
259
167
|
skedyul dev link --workplace my-clinic
|
|
@@ -262,342 +170,96 @@ skedyul dev link --workplace my-clinic
|
|
|
262
170
|
skedyul dev serve --workplace my-clinic
|
|
263
171
|
```
|
|
264
172
|
|
|
265
|
-
|
|
266
|
-
- Prompt for any missing environment variables
|
|
173
|
+
The CLI will:
|
|
174
|
+
- Prompt for any missing environment variables
|
|
267
175
|
- Start an ngrok tunnel automatically
|
|
268
176
|
- Register your local machine with Skedyul
|
|
269
|
-
- Route tool calls
|
|
270
|
-
|
|
271
|
-
## Installation
|
|
272
|
-
|
|
273
|
-
The CLI is included with the `skedyul` package:
|
|
274
|
-
|
|
275
|
-
```bash
|
|
276
|
-
npm install skedyul
|
|
277
|
-
# or
|
|
278
|
-
pnpm add skedyul
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
Run commands with `npx skedyul` or install globally:
|
|
282
|
-
|
|
283
|
-
```bash
|
|
284
|
-
npm link # In the skedyul-node package directory
|
|
285
|
-
skedyul --help
|
|
286
|
-
```
|
|
177
|
+
- Route tool calls to your local server
|
|
287
178
|
|
|
288
179
|
## Commands
|
|
289
180
|
|
|
290
181
|
### Authentication
|
|
291
182
|
|
|
292
183
|
```bash
|
|
293
|
-
# Log in via browser OAuth
|
|
294
|
-
skedyul auth
|
|
295
|
-
|
|
296
|
-
# Check authentication status
|
|
297
|
-
skedyul auth status
|
|
298
|
-
|
|
299
|
-
# Log out
|
|
300
|
-
skedyul auth logout
|
|
184
|
+
skedyul auth login # Log in via browser OAuth
|
|
185
|
+
skedyul auth status # Check authentication status
|
|
186
|
+
skedyul auth logout # Log out
|
|
301
187
|
```
|
|
302
188
|
|
|
303
189
|
### Configuration
|
|
304
190
|
|
|
305
191
|
```bash
|
|
306
|
-
# Set global configuration
|
|
307
|
-
skedyul config
|
|
308
|
-
|
|
309
|
-
# Get a config value
|
|
310
|
-
skedyul config get <key>
|
|
311
|
-
|
|
312
|
-
# List all configuration
|
|
313
|
-
skedyul config list
|
|
192
|
+
skedyul config set <key> <value> # Set global configuration
|
|
193
|
+
skedyul config get <key> # Get a config value
|
|
194
|
+
skedyul config list # List all configuration
|
|
314
195
|
```
|
|
315
196
|
|
|
316
|
-
**Available config keys:**
|
|
317
|
-
|
|
318
197
|
| Key | Description | Default |
|
|
319
198
|
|-----|-------------|---------|
|
|
320
199
|
| `defaultServer` | Skedyul server URL | `https://admin.skedyul.it` |
|
|
321
|
-
| `ngrokAuthtoken` | Your ngrok authtoken
|
|
322
|
-
|
|
323
|
-
### Development Commands
|
|
200
|
+
| `ngrokAuthtoken` | Your ngrok authtoken | - |
|
|
324
201
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
Links your local app to a Skedyul workplace. This creates a personal `local-{username}` AppVersion for testing.
|
|
202
|
+
### Development
|
|
328
203
|
|
|
329
204
|
```bash
|
|
330
|
-
skedyul dev link --workplace <subdomain>
|
|
331
|
-
|
|
332
|
-
#
|
|
333
|
-
skedyul dev
|
|
205
|
+
skedyul dev link --workplace <subdomain> # Link to a workplace
|
|
206
|
+
skedyul dev unlink --workplace <subdomain> # Remove a link
|
|
207
|
+
skedyul dev serve --workplace <subdomain> # Start dev server
|
|
208
|
+
skedyul dev invoke <tool-name> # Test a single tool
|
|
209
|
+
skedyul dev tools # List all tools
|
|
210
|
+
skedyul dev validate # Validate config
|
|
211
|
+
skedyul dev diff # Preview deploy changes
|
|
334
212
|
```
|
|
335
213
|
|
|
336
|
-
|
|
337
|
-
- Creates (or finds) a `local-{username}` AppVersion in the target workplace
|
|
338
|
-
- Creates an AppInstallation for your app in that workplace
|
|
339
|
-
- Saves link configuration to `.skedyul/links/{subdomain}.json`
|
|
340
|
-
|
|
341
|
-
#### `skedyul dev unlink`
|
|
342
|
-
|
|
343
|
-
Removes a workplace link.
|
|
344
|
-
|
|
345
|
-
```bash
|
|
346
|
-
skedyul dev unlink --workplace <subdomain>
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
#### `skedyul dev serve`
|
|
350
|
-
|
|
351
|
-
Starts a local MCP server for testing your tools.
|
|
352
|
-
|
|
353
|
-
```bash
|
|
354
|
-
# Standalone mode (no Skedyul connection)
|
|
355
|
-
skedyul dev serve
|
|
356
|
-
|
|
357
|
-
# Connected to Skedyul (sidecar mode)
|
|
358
|
-
skedyul dev serve --workplace <subdomain>
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
**Options:**
|
|
214
|
+
### Serve Options
|
|
362
215
|
|
|
363
216
|
| Flag | Description |
|
|
364
217
|
|------|-------------|
|
|
365
218
|
| `--workplace, -w` | Workplace subdomain (enables sidecar mode) |
|
|
366
|
-
| `--port, -p` | Port to listen on (default: 60000
|
|
367
|
-
| `--registry, -r` | Path to registry file
|
|
219
|
+
| `--port, -p` | Port to listen on (default: 60000) |
|
|
220
|
+
| `--registry, -r` | Path to registry file |
|
|
368
221
|
| `--no-tunnel` | Don't start ngrok tunnel |
|
|
369
222
|
| `--tunnel-url` | Use existing tunnel URL |
|
|
370
|
-
| `--env, -e` | Set environment variable
|
|
223
|
+
| `--env, -e` | Set environment variable |
|
|
371
224
|
| `--env-file` | Load env vars from file |
|
|
372
225
|
|
|
373
|
-
**Sidecar Mode:**
|
|
374
|
-
|
|
375
|
-
When you specify `--workplace`, the CLI:
|
|
376
|
-
1. Loads your link configuration
|
|
377
|
-
2. Prompts for any missing required environment variables
|
|
378
|
-
3. Starts an ngrok tunnel (or uses `--tunnel-url`)
|
|
379
|
-
4. Registers the tunnel URL with Skedyul
|
|
380
|
-
5. Sends heartbeats to keep the connection alive
|
|
381
|
-
6. Routes incoming tool calls to your local server
|
|
382
|
-
|
|
383
|
-
```bash
|
|
384
|
-
# Full example with custom port
|
|
385
|
-
skedyul dev serve --workplace demo-clinic --port 8080
|
|
386
|
-
|
|
387
|
-
# Use existing ngrok tunnel
|
|
388
|
-
skedyul dev serve --workplace demo-clinic --tunnel-url https://abc123.ngrok.io
|
|
389
|
-
```
|
|
390
|
-
|
|
391
|
-
#### `skedyul dev invoke`
|
|
392
|
-
|
|
393
|
-
Invoke a single tool for quick testing.
|
|
394
|
-
|
|
395
|
-
```bash
|
|
396
|
-
skedyul dev invoke <tool-name> [options]
|
|
397
|
-
|
|
398
|
-
# Examples
|
|
399
|
-
skedyul dev invoke appointment_types_list
|
|
400
|
-
skedyul dev invoke clients_search --args '{"phone": "+1234567890"}'
|
|
401
|
-
|
|
402
|
-
# With linked credentials
|
|
403
|
-
skedyul dev invoke appointment_types_list --workplace demo-clinic
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
#### `skedyul dev tools`
|
|
407
|
-
|
|
408
|
-
List all tools in your registry.
|
|
409
|
-
|
|
410
|
-
```bash
|
|
411
|
-
skedyul dev tools
|
|
412
|
-
skedyul dev tools --registry ./dist/registry.js
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
#### `skedyul dev validate`
|
|
416
|
-
|
|
417
|
-
Validate your `skedyul.config.ts` file.
|
|
418
|
-
|
|
419
|
-
```bash
|
|
420
|
-
skedyul dev validate
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
#### `skedyul dev diff`
|
|
424
|
-
|
|
425
|
-
Preview what would change on deploy.
|
|
426
|
-
|
|
427
|
-
```bash
|
|
428
|
-
skedyul dev diff
|
|
429
|
-
```
|
|
430
|
-
|
|
431
226
|
## Configuration Files
|
|
432
227
|
|
|
433
|
-
The CLI uses several configuration files:
|
|
434
|
-
|
|
435
228
|
| File | Purpose |
|
|
436
229
|
|------|---------|
|
|
437
230
|
| `~/.skedyul/credentials.json` | Authentication tokens |
|
|
438
|
-
| `~/.skedyul/config.json` | Global configuration
|
|
439
|
-
| `.skedyul.local.json` | Local project overrides
|
|
440
|
-
| `.skedyul/links/{workplace}.json` | Per-workplace link
|
|
441
|
-
| `.skedyul/env/{workplace}.env` | Per-workplace
|
|
442
|
-
|
|
443
|
-
### Local Development Override
|
|
444
|
-
|
|
445
|
-
To use a local Skedyul server during development, create `.skedyul.local.json` in your project root:
|
|
446
|
-
|
|
447
|
-
```json
|
|
448
|
-
{
|
|
449
|
-
"serverUrl": "http://localhost:3000"
|
|
450
|
-
}
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
## Environment Variables
|
|
454
|
-
|
|
455
|
-
### Install Configuration
|
|
456
|
-
|
|
457
|
-
Define required environment variables in your app's `config/install.config.ts`:
|
|
458
|
-
|
|
459
|
-
```typescript
|
|
460
|
-
import type { InstallConfig } from 'skedyul'
|
|
461
|
-
|
|
462
|
-
const config: InstallConfig = {
|
|
463
|
-
env: {
|
|
464
|
-
API_KEY: {
|
|
465
|
-
label: 'API Key',
|
|
466
|
-
required: true,
|
|
467
|
-
visibility: 'encrypted',
|
|
468
|
-
description: 'Your API key for authentication',
|
|
469
|
-
},
|
|
470
|
-
BASE_URL: {
|
|
471
|
-
label: 'Server URL',
|
|
472
|
-
required: true,
|
|
473
|
-
visibility: 'visible',
|
|
474
|
-
placeholder: 'https://api.example.com',
|
|
475
|
-
description: 'Base URL for the API',
|
|
476
|
-
},
|
|
477
|
-
},
|
|
478
|
-
}
|
|
231
|
+
| `~/.skedyul/config.json` | Global configuration |
|
|
232
|
+
| `.skedyul.local.json` | Local project overrides |
|
|
233
|
+
| `.skedyul/links/{workplace}.json` | Per-workplace link config |
|
|
234
|
+
| `.skedyul/env/{workplace}.env` | Per-workplace env vars |
|
|
479
235
|
|
|
480
|
-
|
|
481
|
-
```
|
|
482
|
-
|
|
483
|
-
The CLI will automatically prompt for these when you run `skedyul dev serve --workplace <name>` if they're not already configured.
|
|
484
|
-
|
|
485
|
-
### Visibility Options
|
|
486
|
-
|
|
487
|
-
| Visibility | Behavior |
|
|
488
|
-
|------------|----------|
|
|
489
|
-
| `visible` | Shown in plain text |
|
|
490
|
-
| `encrypted` | Hidden during input, masked in output |
|
|
491
|
-
|
|
492
|
-
## Ngrok Integration
|
|
493
|
-
|
|
494
|
-
The CLI uses ngrok to create public tunnels to your local server, allowing Skedyul to route requests to your machine.
|
|
495
|
-
|
|
496
|
-
### Setup
|
|
236
|
+
## Ngrok Setup
|
|
497
237
|
|
|
498
238
|
1. Get a free authtoken at [ngrok.com](https://dashboard.ngrok.com/get-started/your-authtoken)
|
|
499
|
-
2.
|
|
500
|
-
|
|
501
|
-
```bash
|
|
502
|
-
skedyul config set ngrokAuthtoken <your-token>
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
### Session Limits
|
|
506
|
-
|
|
507
|
-
ngrok's free tier allows 1 simultaneous session. If you see an error:
|
|
508
|
-
|
|
509
|
-
```
|
|
510
|
-
ngrok free tier only allows 1 simultaneous session.
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
**Solutions:**
|
|
514
|
-
1. Kill other ngrok sessions: `pkill -f ngrok`
|
|
515
|
-
2. Use an existing tunnel: `skedyul dev serve --workplace demo --tunnel-url https://existing.ngrok.io`
|
|
516
|
-
3. Upgrade to a paid ngrok plan
|
|
517
|
-
|
|
518
|
-
## Workflow Example
|
|
519
|
-
|
|
520
|
-
### Setting Up a New Integration
|
|
521
|
-
|
|
522
|
-
```bash
|
|
523
|
-
# 1. Navigate to your app
|
|
524
|
-
cd integrations/my-app
|
|
525
|
-
|
|
526
|
-
# 2. Authenticate
|
|
527
|
-
skedyul auth login
|
|
528
|
-
|
|
529
|
-
# 3. Link to your test workplace
|
|
530
|
-
skedyul dev link --workplace staging-clinic
|
|
531
|
-
|
|
532
|
-
# 4. Start development server (will prompt for env vars)
|
|
533
|
-
skedyul dev serve --workplace staging-clinic
|
|
534
|
-
|
|
535
|
-
# Server starts...
|
|
536
|
-
# ✓ Loaded 12 tools from registry
|
|
537
|
-
# ✓ Tunnel active: https://abc123.ngrok.io
|
|
538
|
-
# ✓ Registered with Skedyul
|
|
539
|
-
# Listening on http://localhost:60000
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
### Testing Individual Tools
|
|
543
|
-
|
|
544
|
-
```bash
|
|
545
|
-
# Quick test without full server
|
|
546
|
-
skedyul dev invoke appointment_types_list --workplace staging-clinic
|
|
547
|
-
|
|
548
|
-
# With arguments
|
|
549
|
-
skedyul dev invoke calendar_slots_availability_list \
|
|
550
|
-
--workplace staging-clinic \
|
|
551
|
-
--args '{"calendar_names": ["Room 1"], "dates": ["2024-01-15"]}'
|
|
552
|
-
```
|
|
239
|
+
2. Set it: `skedyul config set ngrokAuthtoken <your-token>`
|
|
553
240
|
|
|
554
241
|
## Troubleshooting
|
|
555
242
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
Run `skedyul dev link --workplace {workplace}`
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
Run `skedyul auth login` to authenticate.
|
|
563
|
-
|
|
564
|
-
### Port already in use
|
|
565
|
-
|
|
566
|
-
The CLI auto-increments from port 60000 if busy. Or specify: `--port 8080`
|
|
567
|
-
|
|
568
|
-
### ngrok authentication failed
|
|
569
|
-
|
|
570
|
-
Set your authtoken: `skedyul config set ngrokAuthtoken <token>`
|
|
571
|
-
|
|
572
|
-
### Environment variables not loading
|
|
573
|
-
|
|
574
|
-
Check that your `config/install.config.ts` exports the env configuration properly. Use `--debug` flag for verbose output.
|
|
243
|
+
| Issue | Solution |
|
|
244
|
+
|-------|----------|
|
|
245
|
+
| "Not linked to {workplace}" | Run `skedyul dev link --workplace {workplace}` |
|
|
246
|
+
| "Authentication required" | Run `skedyul auth login` |
|
|
247
|
+
| Port already in use | Use `--port 8080` or let CLI auto-increment |
|
|
248
|
+
| ngrok auth failed | Run `skedyul config set ngrokAuthtoken <token>` |
|
|
575
249
|
|
|
576
250
|
---
|
|
577
251
|
|
|
578
252
|
## Development
|
|
579
253
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
## Publishing
|
|
585
|
-
|
|
586
|
-
Before publishing:
|
|
587
|
-
|
|
588
|
-
1. Run `npm run build`.
|
|
589
|
-
2. Verify `dist/index.js` and `.d.ts` exist.
|
|
590
|
-
3. Ensure `package.json` metadata (name, version, description, repository, author, license) matches the npm listing.
|
|
591
|
-
|
|
592
|
-
Use `npm publish --access public` once the package is ready; the `files` array already limits the tarball to `dist/`.
|
|
254
|
+
```bash
|
|
255
|
+
npm run build # Compile TypeScript
|
|
256
|
+
npm test # Run tests
|
|
257
|
+
```
|
|
593
258
|
|
|
594
259
|
## Contributing
|
|
595
260
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
2. Keep MCP transports lean and share logic in `src/server.ts`.
|
|
600
|
-
3. Add unit tests under `tests/` and run them via `npm test`.
|
|
601
|
-
|
|
602
|
-
Open a PR with a clear summary so the release process can verify `dist/` artifacts before publishing.
|
|
261
|
+
1. Follow TypeScript style (strict types, async/await)
|
|
262
|
+
2. Keep MCP transports lean
|
|
263
|
+
3. Add unit tests under `tests/`
|
|
603
264
|
|
|
265
|
+
Open a PR with a clear summary for review.
|