stpr 1.0.6 → 1.0.8
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/dist/cli.js +82 -23
- package/package.json +1 -1
- package/README.md +0 -159
package/dist/cli.js
CHANGED
|
@@ -2,19 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import * as
|
|
5
|
+
import * as path3 from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
8
|
// src/auth.ts
|
|
9
9
|
import * as childProcess from "child_process";
|
|
10
|
+
import * as crypto2 from "crypto";
|
|
11
|
+
import * as fs2 from "fs";
|
|
12
|
+
import * as os2 from "os";
|
|
13
|
+
import * as path2 from "path";
|
|
14
|
+
import { createServer } from "http";
|
|
15
|
+
|
|
16
|
+
// src/client.ts
|
|
10
17
|
import * as crypto from "crypto";
|
|
11
18
|
import * as fs from "fs";
|
|
12
19
|
import * as os from "os";
|
|
13
20
|
import * as path from "path";
|
|
14
|
-
import { createServer } from "http";
|
|
15
|
-
|
|
16
|
-
// src/client.ts
|
|
17
21
|
var DEFAULT_BASE_URL = "https://mcp.stepper.io";
|
|
22
|
+
var CACHE_DIR = path.join(
|
|
23
|
+
os.homedir(),
|
|
24
|
+
".config",
|
|
25
|
+
"stepper-skillsets",
|
|
26
|
+
"cache"
|
|
27
|
+
);
|
|
28
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
29
|
+
function getCachePath(key) {
|
|
30
|
+
const hash = crypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
31
|
+
return path.join(CACHE_DIR, `${hash}.json`);
|
|
32
|
+
}
|
|
33
|
+
function readCache(key) {
|
|
34
|
+
try {
|
|
35
|
+
const filePath = getCachePath(key);
|
|
36
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
37
|
+
const entry = JSON.parse(raw);
|
|
38
|
+
if (Date.now() - entry.timestamp < CACHE_TTL_MS) {
|
|
39
|
+
return entry.data;
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function writeCache(key, data) {
|
|
46
|
+
try {
|
|
47
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
|
|
48
|
+
const entry = { timestamp: Date.now(), data };
|
|
49
|
+
fs.writeFileSync(getCachePath(key), JSON.stringify(entry), { mode: 384 });
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
18
53
|
var StepperClient = class {
|
|
19
54
|
token;
|
|
20
55
|
baseUrl;
|
|
@@ -63,20 +98,36 @@ var StepperClient = class {
|
|
|
63
98
|
version: serverInfo.version ?? "1.0.0"
|
|
64
99
|
};
|
|
65
100
|
}
|
|
66
|
-
async listTools({
|
|
101
|
+
async listTools({
|
|
102
|
+
service,
|
|
103
|
+
noCache
|
|
104
|
+
}) {
|
|
105
|
+
const cacheKey = `tools-list:${this.baseUrl}:${this.token}`;
|
|
106
|
+
let allTools;
|
|
107
|
+
if (!noCache) {
|
|
108
|
+
const cached = readCache(cacheKey);
|
|
109
|
+
if (cached) {
|
|
110
|
+
allTools = cached;
|
|
111
|
+
return allTools.filter(
|
|
112
|
+
(tool) => service ? tool.service === service : !tool.service.startsWith("__")
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
67
116
|
const res = await this.rpc("tools/list");
|
|
68
117
|
if (res.error) {
|
|
69
118
|
throw new Error(`tools/list failed: ${res.error.message}`);
|
|
70
119
|
}
|
|
71
120
|
const tools = res.result.tools;
|
|
72
|
-
|
|
121
|
+
allTools = tools.map(
|
|
73
122
|
(tool) => ({
|
|
74
|
-
service: tool.name.split("
|
|
75
|
-
action: tool.name.split("
|
|
123
|
+
service: tool.name.split("__")[0],
|
|
124
|
+
action: tool.name.split("__")[1],
|
|
76
125
|
description: tool.description,
|
|
77
126
|
inputSchema: tool.inputSchema
|
|
78
127
|
})
|
|
79
|
-
)
|
|
128
|
+
);
|
|
129
|
+
writeCache(cacheKey, allTools);
|
|
130
|
+
return allTools.filter(
|
|
80
131
|
(tool) => service ? tool.service === service : !tool.service.startsWith("__")
|
|
81
132
|
);
|
|
82
133
|
}
|
|
@@ -121,7 +172,7 @@ var StepperClient = class {
|
|
|
121
172
|
|
|
122
173
|
// src/auth.ts
|
|
123
174
|
function openBrowser(url) {
|
|
124
|
-
const platform2 =
|
|
175
|
+
const platform2 = os2.platform();
|
|
125
176
|
if (platform2 === "darwin") {
|
|
126
177
|
childProcess.spawn("open", [url], { stdio: "ignore", detached: true });
|
|
127
178
|
} else if (platform2 === "win32") {
|
|
@@ -136,24 +187,24 @@ function openBrowser(url) {
|
|
|
136
187
|
var DEFAULT_BASE_URL2 = "https://mcp.stepper.io";
|
|
137
188
|
var OAUTH_CALLBACK_PORT = 3847;
|
|
138
189
|
var CALLBACK_PATH = "/callback";
|
|
139
|
-
var CONFIG_DIR =
|
|
140
|
-
var CONFIG_FILE =
|
|
190
|
+
var CONFIG_DIR = path2.join(os2.homedir(), ".config", "stepper-skillsets");
|
|
191
|
+
var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
|
|
141
192
|
function generatePKCE() {
|
|
142
|
-
const codeVerifier =
|
|
143
|
-
const codeChallenge =
|
|
193
|
+
const codeVerifier = crypto2.randomBytes(32).toString("base64url");
|
|
194
|
+
const codeChallenge = crypto2.createHash("sha256").update(codeVerifier).digest().toString("base64url");
|
|
144
195
|
return { codeVerifier, codeChallenge };
|
|
145
196
|
}
|
|
146
197
|
function loadConfig() {
|
|
147
198
|
try {
|
|
148
|
-
const data =
|
|
199
|
+
const data = fs2.readFileSync(CONFIG_FILE, "utf-8");
|
|
149
200
|
return JSON.parse(data);
|
|
150
201
|
} catch {
|
|
151
202
|
return { active: null, skillsets: {} };
|
|
152
203
|
}
|
|
153
204
|
}
|
|
154
205
|
function saveConfig(config) {
|
|
155
|
-
|
|
156
|
-
|
|
206
|
+
fs2.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
207
|
+
fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
|
|
157
208
|
mode: 384
|
|
158
209
|
});
|
|
159
210
|
}
|
|
@@ -282,7 +333,7 @@ async function runLoginFlow(baseUrl) {
|
|
|
282
333
|
const metadata = await fetchMetadata(normalizedBaseUrl);
|
|
283
334
|
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
284
335
|
const clientId = await registerClient(normalizedBaseUrl, redirectUri);
|
|
285
|
-
const state =
|
|
336
|
+
const state = crypto2.randomBytes(16).toString("hex");
|
|
286
337
|
const authUrl = new URL(metadata.authorization_endpoint);
|
|
287
338
|
authUrl.searchParams.set("response_type", "code");
|
|
288
339
|
authUrl.searchParams.set("client_id", clientId);
|
|
@@ -452,9 +503,9 @@ async function getValidToken(skillsetName, baseUrl) {
|
|
|
452
503
|
}
|
|
453
504
|
|
|
454
505
|
// src/cli.ts
|
|
455
|
-
var __dirname =
|
|
506
|
+
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
456
507
|
var pkg = createRequire(import.meta.url)(
|
|
457
|
-
|
|
508
|
+
path3.join(__dirname, "..", "package.json")
|
|
458
509
|
);
|
|
459
510
|
var VERSION = pkg.version ?? "0.0.0";
|
|
460
511
|
function readStdin() {
|
|
@@ -491,6 +542,8 @@ function parseArgs(argv) {
|
|
|
491
542
|
flags.cursor = argv[++i];
|
|
492
543
|
} else if (arg === "--call") {
|
|
493
544
|
boolFlags.call = true;
|
|
545
|
+
} else if (arg === "--no-cache") {
|
|
546
|
+
boolFlags.noCache = true;
|
|
494
547
|
} else if (arg === "--verbose") {
|
|
495
548
|
boolFlags.verbose = true;
|
|
496
549
|
} else if (arg === "--options" && i + 1 < argv.length) {
|
|
@@ -514,11 +567,12 @@ function parseArgs(argv) {
|
|
|
514
567
|
cursor: flags.cursor,
|
|
515
568
|
call: boolFlags.call ?? false,
|
|
516
569
|
verbose: boolFlags.verbose ?? false,
|
|
570
|
+
noCache: boolFlags.noCache ?? false,
|
|
517
571
|
options: flags.options
|
|
518
572
|
};
|
|
519
573
|
}
|
|
520
574
|
function toToolName(service, action) {
|
|
521
|
-
return `${service}
|
|
575
|
+
return `${service}__${action}`;
|
|
522
576
|
}
|
|
523
577
|
function formatToolsForList(tools, verbose) {
|
|
524
578
|
if (verbose) {
|
|
@@ -558,6 +612,7 @@ Options:
|
|
|
558
612
|
--skillset <name> Use a specific skill set
|
|
559
613
|
--call Execute the skill (default is to fetch parameters only)
|
|
560
614
|
--verbose Include inputSchema when listing skills
|
|
615
|
+
--no-cache Bypass the 5-minute tools list cache
|
|
561
616
|
-i, --input <json> JSON input for call, parameters or options (alternative to stdin)
|
|
562
617
|
--search <query> Search query for dynamic dropdown options
|
|
563
618
|
--cursor <cursor> Pagination cursor for dynamic dropdown options
|
|
@@ -605,6 +660,7 @@ async function main() {
|
|
|
605
660
|
cursor: cursorFlag,
|
|
606
661
|
call: callFlag,
|
|
607
662
|
verbose: verboseFlag,
|
|
663
|
+
noCache: noCacheFlag,
|
|
608
664
|
options: optionsFlag
|
|
609
665
|
} = parseArgs(process.argv.slice(2));
|
|
610
666
|
if (subcommand === "help") {
|
|
@@ -758,7 +814,10 @@ async function main() {
|
|
|
758
814
|
}
|
|
759
815
|
if (subcommand === "list") {
|
|
760
816
|
const service2 = args[0];
|
|
761
|
-
const tools = await client.listTools({
|
|
817
|
+
const tools = await client.listTools({
|
|
818
|
+
service: service2 ?? void 0,
|
|
819
|
+
noCache: noCacheFlag
|
|
820
|
+
});
|
|
762
821
|
const formatted = formatToolsForList(tools, verboseFlag);
|
|
763
822
|
if (!tools.length) {
|
|
764
823
|
die(
|
|
@@ -776,7 +835,7 @@ async function main() {
|
|
|
776
835
|
return;
|
|
777
836
|
}
|
|
778
837
|
if (!action) {
|
|
779
|
-
const tools = await client.listTools({ service });
|
|
838
|
+
const tools = await client.listTools({ service, noCache: noCacheFlag });
|
|
780
839
|
if (!tools.length) {
|
|
781
840
|
die(
|
|
782
841
|
service ? `No skills found for service "${service}".` : "No skills found."
|
package/package.json
CHANGED
package/README.md
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# stpr — Stepper Skills CLI
|
|
2
|
-
|
|
3
|
-
Skill Sets are a Stepper feature that let you bundle integration actions into curated, authenticated toolkits — and expose them to AI agents, CLIs, and any MCP-compatible client.
|
|
4
|
-
|
|
5
|
-
`stpr` is a command-line interface for interacting with [Stepper](https://stepper.io) Skill Sets. Discover, inspect, and execute integration actions directly from your terminal. This is perfect for OpenClaw or agents that can interact with a CLI, or for developers who want to use skills in their own scripts.
|
|
6
|
-
|
|
7
|
-
If you prefer, you can directly use the Stepper MCP server at `https://mcp.stepper.io/skill-sets/mcp`instead of the CLI.
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
npm install -g stpr
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Authentication
|
|
16
|
-
|
|
17
|
-
The CLI supports three authentication methods:
|
|
18
|
-
|
|
19
|
-
### OAuth Login (recommended)
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
stpr login
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
Opens your browser to authenticate and select a Skill Set. Credentials are saved to `~/.config/stepper-skillsets/config.json` and automatically refreshed when they expire.
|
|
26
|
-
|
|
27
|
-
### Static Token
|
|
28
|
-
|
|
29
|
-
Generate a token from [Stepper](https://app.stepper.io/flow/skill-sets) and pass it directly:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
stpr --token sst_your_token_here list
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Environment Variable
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
export STEPPER_SKILL_TOKEN=sst_your_token_here
|
|
39
|
-
stpr list
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Commands
|
|
43
|
-
|
|
44
|
-
### Profile Management
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
stpr login # Authenticate via OAuth (opens browser)
|
|
48
|
-
stpr logout [name] # Remove a saved profile, or all profiles if no name given
|
|
49
|
-
stpr profiles # List all saved profiles
|
|
50
|
-
stpr use <name> # Switch the active profile
|
|
51
|
-
stpr whoami # Show active profile and server info
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Discovering Skills
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
stpr list # List all available skills, grouped by service
|
|
58
|
-
stpr list --verbose # Include full input schemas
|
|
59
|
-
stpr list <service> # List skills for a specific service
|
|
60
|
-
stpr <service> # Shorthand for listing a service's skills
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Inspecting Parameters
|
|
64
|
-
|
|
65
|
-
Many skills have dynamic parameters — fields that change based on the values of other fields. Calling a skill without `--call` returns its current parameter schema.
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
# See what fields are needed for add_row, given a spreadsheet
|
|
69
|
-
stpr google-sheets add_row -i '{"spreadsheet_id": "abc123"}'
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Some parameters have dynamic dropdown options. Fetch them with `--options`:
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
stpr google-sheets add_row --options worksheet_id \
|
|
76
|
-
-i '{"spreadsheet_id": "abc123"}' \
|
|
77
|
-
--search "Sheet" \
|
|
78
|
-
--cursor "next_page"
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Calling Skills
|
|
82
|
-
|
|
83
|
-
Use the `--call` flag to execute an action:
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
stpr google-sheets create_sheet --call \
|
|
87
|
-
-i '{"name": "Q1 Report", "columns": "Name, Email, Phone"}'
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Polling Async Results
|
|
91
|
-
|
|
92
|
-
Component library tools run asynchronously. Poll for results with:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
stpr status <statusId>
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Input
|
|
99
|
-
|
|
100
|
-
Pass JSON input via the `-i` / `--input` flag or pipe it through stdin:
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
# Flag
|
|
104
|
-
stpr slack send_message --call -i '{"channel": "#general", "text": "Hello!"}'
|
|
105
|
-
|
|
106
|
-
# Stdin
|
|
107
|
-
echo '{"channel": "#general", "text": "Hello!"}' | stpr slack send_message --call
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
## Options Reference
|
|
111
|
-
|
|
112
|
-
| Flag | Description |
|
|
113
|
-
| -------------------- | --------------------------------------------------------------- |
|
|
114
|
-
| `--token <token>` | Auth token (overrides saved profiles and `STEPPER_SKILL_TOKEN`) |
|
|
115
|
-
| `--base-url <url>` | Override MCP server URL (default: `https://mcp.stepper.io`) |
|
|
116
|
-
| `--skillset <name>` | Use a specific saved profile instead of the active one |
|
|
117
|
-
| `--call` | Execute the skill (default behavior is parameter inspection) |
|
|
118
|
-
| `--verbose` | Include full `inputSchema` when listing skills |
|
|
119
|
-
| `-i, --input <json>` | JSON input for calls, parameter fetches, or option queries |
|
|
120
|
-
| `--options <param>` | Fetch dynamic dropdown options for a parameter |
|
|
121
|
-
| `--search <query>` | Filter dropdown options by search term |
|
|
122
|
-
| `--cursor <cursor>` | Pagination cursor for dropdown options |
|
|
123
|
-
| `-h, --help` | Show help |
|
|
124
|
-
| `-v, --version` | Show version |
|
|
125
|
-
|
|
126
|
-
## Environment Variables
|
|
127
|
-
|
|
128
|
-
| Variable | Description |
|
|
129
|
-
| --------------------- | ------------------------------------------------------------- |
|
|
130
|
-
| `STEPPER_SKILL_TOKEN` | Auth token (used when no `--token` flag and no saved profile) |
|
|
131
|
-
| `STEPPER_URL` | Override the MCP server base URL |
|
|
132
|
-
|
|
133
|
-
## Examples
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
# Authenticate
|
|
137
|
-
stpr login
|
|
138
|
-
|
|
139
|
-
# List everything available
|
|
140
|
-
stpr list
|
|
141
|
-
|
|
142
|
-
# Explore a service
|
|
143
|
-
stpr google-sheets
|
|
144
|
-
|
|
145
|
-
# Inspect dynamic parameters step by step
|
|
146
|
-
stpr google-sheets add_row -i '{}'
|
|
147
|
-
stpr google-sheets add_row -i '{"spreadsheet_id": "abc123"}'
|
|
148
|
-
|
|
149
|
-
# Fetch dropdown options
|
|
150
|
-
stpr google-sheets add_row --options worksheet_id -i '{"spreadsheet_id": "abc123"}'
|
|
151
|
-
|
|
152
|
-
# Execute
|
|
153
|
-
stpr google-sheets add_row --call -i '{"spreadsheet_id": "abc123", "worksheet_id": "Sheet1", "values": {"Name": "Alice"}}'
|
|
154
|
-
|
|
155
|
-
# Switch between skill sets
|
|
156
|
-
stpr profiles
|
|
157
|
-
stpr use "Production Tools"
|
|
158
|
-
stpr list
|
|
159
|
-
```
|