@showly/mcp-server 0.4.1 → 0.4.3
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.d.ts +30 -5
- package/dist/cli.js +184 -10
- package/manifest.json +1 -1
- package/package.json +6 -3
package/dist/cli.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export type Target = "claude-code" | "codex" | "stdout";
|
|
3
|
+
export type LoginTarget = Target | "openclaw" | "hermes";
|
|
3
4
|
/**
|
|
4
5
|
* The host that will RECEIVE a token printed to stdout.
|
|
5
6
|
*
|
|
6
7
|
* `--to` describes where this CLI writes the credential; `--agent` describes
|
|
7
8
|
* which host will use it. They are the same for the two hosts we can write
|
|
8
9
|
* directly, but intentionally separate for `--print-token`, where another
|
|
9
|
-
* agent (OpenClaw / Cursor / Cline) receives the value after this process
|
|
10
|
+
* agent (OpenClaw / Cursor / Hermes / Cline) receives the value after this process
|
|
10
11
|
* exits.
|
|
11
12
|
*/
|
|
12
|
-
export declare const LOGIN_AGENTS: readonly ["claude-code", "codex", "cursor", "openclaw", "cline"];
|
|
13
|
+
export declare const LOGIN_AGENTS: readonly ["claude-code", "codex", "cursor", "openclaw", "hermes", "cline"];
|
|
13
14
|
export type LoginAgent = (typeof LOGIN_AGENTS)[number];
|
|
14
15
|
/**
|
|
15
16
|
* The version of THIS copy of the package, read from the manifest that ships
|
|
@@ -88,7 +89,7 @@ export declare const LOGIN_CLIENT_ID = "showly-mcp-cli";
|
|
|
88
89
|
* names; lookalikes stay neutral.
|
|
89
90
|
*/
|
|
90
91
|
export declare const LOGIN_AGENT_CLIENT_IDS: Record<LoginAgent, string>;
|
|
91
|
-
export declare function loginClientId(target:
|
|
92
|
+
export declare function loginClientId(target: LoginTarget, agent?: LoginAgent): string;
|
|
92
93
|
/** The env var name emitted into config snippets that must not hold a secret. */
|
|
93
94
|
export declare const TOKEN_ENV_VAR = "SHOWLY_TOKEN";
|
|
94
95
|
export type DeviceStart = {
|
|
@@ -138,6 +139,29 @@ export declare function buildCodexAuthSnippet(opts: {
|
|
|
138
139
|
url: string;
|
|
139
140
|
tokenEnvVar?: string;
|
|
140
141
|
}): string;
|
|
142
|
+
/** Secrets used by the two remote-agent targets the Hero prompt exercises. */
|
|
143
|
+
export declare const OPENCLAW_TOKEN_ENV_VAR = "SHOWLY_MCP_TOKEN";
|
|
144
|
+
export declare const HERMES_TOKEN_ENV_VAR = "MCP_SHOWLY_API_KEY";
|
|
145
|
+
/**
|
|
146
|
+
* Merge Showly into OpenClaw's user config without disturbing other Gateway
|
|
147
|
+
* settings. The token lives in the Gateway-owned env.vars store; the MCP entry
|
|
148
|
+
* contains only an environment placeholder. `auth: oauth` is removed because
|
|
149
|
+
* header auth and native OAuth are alternative modes in OpenClaw.
|
|
150
|
+
*/
|
|
151
|
+
export declare function buildOpenClawAuthConfig(opts: {
|
|
152
|
+
existing: Record<string, unknown>;
|
|
153
|
+
url: string;
|
|
154
|
+
token: string;
|
|
155
|
+
}): Record<string, unknown>;
|
|
156
|
+
/** Replace one dotenv assignment, remove duplicates, and preserve other lines. */
|
|
157
|
+
export declare function mergeDotEnvCredential(existing: string, name: string, token: string): string;
|
|
158
|
+
/**
|
|
159
|
+
* Update Hermes YAML through a real YAML document rather than `hermes config
|
|
160
|
+
* set`, whose secret masking corrupts the literal ${MCP_SHOWLY_API_KEY}
|
|
161
|
+
* placeholder. Parse errors are terminal: never replace a user's unreadable
|
|
162
|
+
* config with a guessed one.
|
|
163
|
+
*/
|
|
164
|
+
export declare function buildHermesAuthConfig(existing: string, url: string): string;
|
|
141
165
|
export type LoginDeps = {
|
|
142
166
|
fetchImpl?: typeof fetch;
|
|
143
167
|
/**
|
|
@@ -240,11 +264,12 @@ export declare function pollForDeviceToken(input: {
|
|
|
240
264
|
clientId?: string;
|
|
241
265
|
}, deps?: LoginDeps): Promise<DeviceToken>;
|
|
242
266
|
export type LoginResult = {
|
|
243
|
-
target:
|
|
267
|
+
target: LoginTarget;
|
|
244
268
|
token: string;
|
|
245
269
|
scope: string;
|
|
246
270
|
expiresAt: Date | null;
|
|
247
271
|
path: string | null;
|
|
272
|
+
credentialPath?: string;
|
|
248
273
|
wrote: boolean;
|
|
249
274
|
snippet: string;
|
|
250
275
|
};
|
|
@@ -259,7 +284,7 @@ export type LoginResult = {
|
|
|
259
284
|
* and out of every `ps` listing on the machine.
|
|
260
285
|
*/
|
|
261
286
|
export declare function performLogin(opts: {
|
|
262
|
-
target:
|
|
287
|
+
target: LoginTarget;
|
|
263
288
|
agent?: LoginAgent;
|
|
264
289
|
env?: NodeJS.ProcessEnv;
|
|
265
290
|
}, deps?: LoginDeps): Promise<LoginResult>;
|
package/dist/cli.js
CHANGED
|
@@ -34,6 +34,7 @@ import { readFileSync, readdirSync, mkdirSync, rmSync, writeFileSync, existsSync
|
|
|
34
34
|
import { dirname, join } from "node:path";
|
|
35
35
|
import { homedir } from "node:os";
|
|
36
36
|
import { pathToFileURL } from "node:url";
|
|
37
|
+
import { parseDocument } from "yaml";
|
|
37
38
|
import { loadManifest } from "./index.js";
|
|
38
39
|
import { SHOWLY_HOSTING_SKILL_DIRECTORY, SHOWLY_HOSTING_SKILL_NAME, SHOWLY_LEGACY_SKILL_NAME, } from "./showly-hosting-skill.js";
|
|
39
40
|
/**
|
|
@@ -42,7 +43,7 @@ import { SHOWLY_HOSTING_SKILL_DIRECTORY, SHOWLY_HOSTING_SKILL_NAME, SHOWLY_LEGAC
|
|
|
42
43
|
* `--to` describes where this CLI writes the credential; `--agent` describes
|
|
43
44
|
* which host will use it. They are the same for the two hosts we can write
|
|
44
45
|
* directly, but intentionally separate for `--print-token`, where another
|
|
45
|
-
* agent (OpenClaw / Cursor / Cline) receives the value after this process
|
|
46
|
+
* agent (OpenClaw / Cursor / Hermes / Cline) receives the value after this process
|
|
46
47
|
* exits.
|
|
47
48
|
*/
|
|
48
49
|
export const LOGIN_AGENTS = [
|
|
@@ -50,6 +51,7 @@ export const LOGIN_AGENTS = [
|
|
|
50
51
|
"codex",
|
|
51
52
|
"cursor",
|
|
52
53
|
"openclaw",
|
|
54
|
+
"hermes",
|
|
53
55
|
"cline",
|
|
54
56
|
];
|
|
55
57
|
/**
|
|
@@ -82,17 +84,19 @@ function usage() {
|
|
|
82
84
|
"",
|
|
83
85
|
"Usage:",
|
|
84
86
|
" showly-mcp install --to <claude-code|codex|stdout> [--with-skill]",
|
|
85
|
-
" showly-mcp login [--to <claude-code|codex|stdout>] [--agent <host>] [--print-token]",
|
|
87
|
+
" showly-mcp login [--to <claude-code|codex|openclaw|hermes|stdout>] [--agent <host>] [--print-token]",
|
|
86
88
|
" showly-mcp manifest",
|
|
87
89
|
" showly-mcp --version",
|
|
88
90
|
"",
|
|
89
91
|
"login authorizes this machine without a browser on it: it prints a short",
|
|
90
92
|
"code, you approve it on any device, and the credential lands in your host",
|
|
91
|
-
"config. --to
|
|
93
|
+
"config. --to openclaw and --to hermes safely merge the credential into",
|
|
94
|
+
"those hosts' user config; --to codex prints the SHOWLY_TOKEN export its",
|
|
95
|
+
"config reads,",
|
|
92
96
|
"so login also prints the export line that sets it. --print-token writes",
|
|
93
97
|
"ONLY the token to stdout (everything else goes to stderr) so CI can",
|
|
94
98
|
"capture it without it touching a file. When that token is for another",
|
|
95
|
-
"host, pass --agent <cursor|openclaw|cline> so My Agents can name it.",
|
|
99
|
+
"host, pass --agent <cursor|openclaw|hermes|cline> so My Agents can name it.",
|
|
96
100
|
"",
|
|
97
101
|
"Environment overrides:",
|
|
98
102
|
" SHOWLY_MCP_URL full URL to your MCP endpoint (default https://mcp.showly.ai)",
|
|
@@ -308,6 +312,24 @@ function safeReadJson(path) {
|
|
|
308
312
|
return {};
|
|
309
313
|
}
|
|
310
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* Read a host's primary config without the install helper's empty fallback.
|
|
317
|
+
* Login is about to add a live credential, so treating malformed JSON as `{}`
|
|
318
|
+
* would overwrite the user's whole Gateway after they had already approved.
|
|
319
|
+
*/
|
|
320
|
+
function readHostJson(path, label) {
|
|
321
|
+
let parsed;
|
|
322
|
+
try {
|
|
323
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
throw new Error(`Could not update ${label}: ${error instanceof Error ? error.message : String(error)}`);
|
|
327
|
+
}
|
|
328
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
329
|
+
throw new Error(`Could not update ${label}: the root must be a JSON object.`);
|
|
330
|
+
}
|
|
331
|
+
return parsed;
|
|
332
|
+
}
|
|
311
333
|
/**
|
|
312
334
|
* Write a file that holds (or will hold) a credential, 0600 on creation.
|
|
313
335
|
*
|
|
@@ -352,6 +374,7 @@ export const LOGIN_AGENT_CLIENT_IDS = {
|
|
|
352
374
|
codex: `${LOGIN_CLIENT_ID}/codex`,
|
|
353
375
|
cursor: `${LOGIN_CLIENT_ID}/cursor`,
|
|
354
376
|
openclaw: `${LOGIN_CLIENT_ID}/openclaw`,
|
|
377
|
+
hermes: `${LOGIN_CLIENT_ID}/hermes`,
|
|
355
378
|
cline: `${LOGIN_CLIENT_ID}/cline`,
|
|
356
379
|
};
|
|
357
380
|
export function loginClientId(target, agent) {
|
|
@@ -464,6 +487,89 @@ export function buildCodexAuthSnippet(opts) {
|
|
|
464
487
|
"",
|
|
465
488
|
].join("\n");
|
|
466
489
|
}
|
|
490
|
+
/** Secrets used by the two remote-agent targets the Hero prompt exercises. */
|
|
491
|
+
export const OPENCLAW_TOKEN_ENV_VAR = "SHOWLY_MCP_TOKEN";
|
|
492
|
+
export const HERMES_TOKEN_ENV_VAR = "MCP_SHOWLY_API_KEY";
|
|
493
|
+
function asRecord(value) {
|
|
494
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
495
|
+
? value
|
|
496
|
+
: {};
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Merge Showly into OpenClaw's user config without disturbing other Gateway
|
|
500
|
+
* settings. The token lives in the Gateway-owned env.vars store; the MCP entry
|
|
501
|
+
* contains only an environment placeholder. `auth: oauth` is removed because
|
|
502
|
+
* header auth and native OAuth are alternative modes in OpenClaw.
|
|
503
|
+
*/
|
|
504
|
+
export function buildOpenClawAuthConfig(opts) {
|
|
505
|
+
const env = asRecord(opts.existing.env);
|
|
506
|
+
const vars = asRecord(env.vars);
|
|
507
|
+
const mcp = asRecord(opts.existing.mcp);
|
|
508
|
+
const servers = asRecord(mcp.servers);
|
|
509
|
+
const currentShowly = asRecord(servers.showly);
|
|
510
|
+
const currentHeaders = asRecord(currentShowly.headers);
|
|
511
|
+
const { auth: _nativeOauth, ...showlyWithoutOauth } = currentShowly;
|
|
512
|
+
return {
|
|
513
|
+
...opts.existing,
|
|
514
|
+
env: {
|
|
515
|
+
...env,
|
|
516
|
+
vars: { ...vars, [OPENCLAW_TOKEN_ENV_VAR]: opts.token },
|
|
517
|
+
},
|
|
518
|
+
mcp: {
|
|
519
|
+
...mcp,
|
|
520
|
+
servers: {
|
|
521
|
+
...servers,
|
|
522
|
+
showly: {
|
|
523
|
+
...showlyWithoutOauth,
|
|
524
|
+
url: opts.url,
|
|
525
|
+
transport: "streamable-http",
|
|
526
|
+
headers: {
|
|
527
|
+
...currentHeaders,
|
|
528
|
+
Authorization: `Bearer \${${OPENCLAW_TOKEN_ENV_VAR}}`,
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
/** Replace one dotenv assignment, remove duplicates, and preserve other lines. */
|
|
536
|
+
export function mergeDotEnvCredential(existing, name, token) {
|
|
537
|
+
const assignment = `${name}=${token}`;
|
|
538
|
+
const matcher = new RegExp(`^(?:export\\s+)?${name}=`);
|
|
539
|
+
const lines = existing.split(/\r?\n/);
|
|
540
|
+
if (lines.at(-1) === "")
|
|
541
|
+
lines.pop();
|
|
542
|
+
const merged = [];
|
|
543
|
+
let wrote = false;
|
|
544
|
+
for (const line of lines) {
|
|
545
|
+
if (!matcher.test(line)) {
|
|
546
|
+
merged.push(line);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (!wrote)
|
|
550
|
+
merged.push(assignment);
|
|
551
|
+
wrote = true;
|
|
552
|
+
}
|
|
553
|
+
if (!wrote)
|
|
554
|
+
merged.push(assignment);
|
|
555
|
+
return `${merged.join("\n")}\n`;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Update Hermes YAML through a real YAML document rather than `hermes config
|
|
559
|
+
* set`, whose secret masking corrupts the literal ${MCP_SHOWLY_API_KEY}
|
|
560
|
+
* placeholder. Parse errors are terminal: never replace a user's unreadable
|
|
561
|
+
* config with a guessed one.
|
|
562
|
+
*/
|
|
563
|
+
export function buildHermesAuthConfig(existing, url) {
|
|
564
|
+
const doc = parseDocument(existing.trim().length > 0 ? existing : "{}\n");
|
|
565
|
+
if (doc.errors.length > 0) {
|
|
566
|
+
throw new Error(`Could not update ~/.hermes/config.yaml: ${doc.errors[0].message}`);
|
|
567
|
+
}
|
|
568
|
+
doc.setIn(["mcp_servers", "showly", "url"], url);
|
|
569
|
+
doc.deleteIn(["mcp_servers", "showly", "auth"]);
|
|
570
|
+
doc.setIn(["mcp_servers", "showly", "headers", "Authorization"], `Bearer \${${HERMES_TOKEN_ENV_VAR}}`);
|
|
571
|
+
return doc.toString({ lineWidth: 0 });
|
|
572
|
+
}
|
|
467
573
|
/**
|
|
468
574
|
* How long ONE HTTP request may take before it is abandoned.
|
|
469
575
|
*
|
|
@@ -761,6 +867,22 @@ export async function performLogin(opts, deps = {}) {
|
|
|
761
867
|
const env = opts.env ?? process.env;
|
|
762
868
|
const { url, apiUrl } = resolveUrls(env);
|
|
763
869
|
const log = deps.log ?? ((line) => console.error(line));
|
|
870
|
+
// Validate destination files before asking a human to approve anything.
|
|
871
|
+
// Re-read them after approval before merging, so a change made during the
|
|
872
|
+
// device wait is preserved too.
|
|
873
|
+
const openClawPath = opts.target === "openclaw"
|
|
874
|
+
? join(homedir(), ".openclaw", "openclaw.json")
|
|
875
|
+
: null;
|
|
876
|
+
if (openClawPath && existsSync(openClawPath)) {
|
|
877
|
+
readHostJson(openClawPath, "~/.openclaw/openclaw.json");
|
|
878
|
+
}
|
|
879
|
+
const hermesDirectory = opts.target === "hermes" ? join(homedir(), ".hermes") : null;
|
|
880
|
+
const hermesConfigPath = hermesDirectory
|
|
881
|
+
? join(hermesDirectory, "config.yaml")
|
|
882
|
+
: null;
|
|
883
|
+
if (hermesConfigPath && existsSync(hermesConfigPath)) {
|
|
884
|
+
buildHermesAuthConfig(readFileSync(hermesConfigPath, "utf8"), url);
|
|
885
|
+
}
|
|
764
886
|
const clientId = loginClientId(opts.target, opts.agent);
|
|
765
887
|
const started = await startDeviceFlow(apiUrl, deps, clientId);
|
|
766
888
|
const expiresAt = new Date(Date.now() + started.expires_in * 1000);
|
|
@@ -852,6 +974,54 @@ export async function performLogin(opts, deps = {}) {
|
|
|
852
974
|
snippet,
|
|
853
975
|
};
|
|
854
976
|
}
|
|
977
|
+
if (opts.target === "openclaw") {
|
|
978
|
+
const path = openClawPath;
|
|
979
|
+
const existing = existsSync(path)
|
|
980
|
+
? readHostJson(path, "~/.openclaw/openclaw.json")
|
|
981
|
+
: {};
|
|
982
|
+
const merged = buildOpenClawAuthConfig({
|
|
983
|
+
existing,
|
|
984
|
+
url,
|
|
985
|
+
token: token.access_token,
|
|
986
|
+
});
|
|
987
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
988
|
+
writeCredentialFile(path, JSON.stringify(merged, null, 2) + "\n");
|
|
989
|
+
return {
|
|
990
|
+
target: opts.target,
|
|
991
|
+
token: token.access_token,
|
|
992
|
+
scope: token.scope,
|
|
993
|
+
expiresAt: tokenExpiresAt,
|
|
994
|
+
path,
|
|
995
|
+
wrote: true,
|
|
996
|
+
snippet: JSON.stringify(merged, null, 2),
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
if (opts.target === "hermes") {
|
|
1000
|
+
const directory = hermesDirectory;
|
|
1001
|
+
const path = hermesConfigPath;
|
|
1002
|
+
const credentialPath = join(directory, ".env");
|
|
1003
|
+
const existingConfig = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
1004
|
+
const existingEnv = existsSync(credentialPath)
|
|
1005
|
+
? readFileSync(credentialPath, "utf8")
|
|
1006
|
+
: "";
|
|
1007
|
+
// Build both outputs before touching either file. In particular, malformed
|
|
1008
|
+
// YAML must not leave a fresh secret behind beside an unchanged config.
|
|
1009
|
+
const config = buildHermesAuthConfig(existingConfig, url);
|
|
1010
|
+
const dotenv = mergeDotEnvCredential(existingEnv, HERMES_TOKEN_ENV_VAR, token.access_token);
|
|
1011
|
+
mkdirSync(directory, { recursive: true });
|
|
1012
|
+
writeCredentialFile(credentialPath, dotenv);
|
|
1013
|
+
writeCredentialFile(path, config);
|
|
1014
|
+
return {
|
|
1015
|
+
target: opts.target,
|
|
1016
|
+
token: token.access_token,
|
|
1017
|
+
scope: token.scope,
|
|
1018
|
+
expiresAt: tokenExpiresAt,
|
|
1019
|
+
path,
|
|
1020
|
+
credentialPath,
|
|
1021
|
+
wrote: true,
|
|
1022
|
+
snippet: config,
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
855
1025
|
return {
|
|
856
1026
|
target: opts.target,
|
|
857
1027
|
token: token.access_token,
|
|
@@ -914,7 +1084,10 @@ export function buildLoginOutput(result, opts = {}) {
|
|
|
914
1084
|
return [{ stream: "out", line: result.token }];
|
|
915
1085
|
const lines = [];
|
|
916
1086
|
if (result.wrote) {
|
|
917
|
-
|
|
1087
|
+
const written = [result.path, result.credentialPath]
|
|
1088
|
+
.filter((path) => Boolean(path))
|
|
1089
|
+
.join(" and ");
|
|
1090
|
+
lines.push({ stream: "err", line: `Connected. Wrote ${written}` });
|
|
918
1091
|
}
|
|
919
1092
|
else if (result.path) {
|
|
920
1093
|
lines.push({
|
|
@@ -1027,12 +1200,13 @@ export function parseCommandArgs(command, rest) {
|
|
|
1027
1200
|
}
|
|
1028
1201
|
return { ok: true, help, flags, values };
|
|
1029
1202
|
}
|
|
1030
|
-
function
|
|
1203
|
+
function parseLoginTarget(parsed, fallback) {
|
|
1031
1204
|
const value = parsed.values.get("--to");
|
|
1032
1205
|
if (value === undefined)
|
|
1033
1206
|
return fallback;
|
|
1034
|
-
if (!["claude-code", "codex", "stdout"].includes(value))
|
|
1207
|
+
if (!["claude-code", "codex", "openclaw", "hermes", "stdout"].includes(value)) {
|
|
1035
1208
|
return null;
|
|
1209
|
+
}
|
|
1036
1210
|
return value;
|
|
1037
1211
|
}
|
|
1038
1212
|
function parseLoginAgent(parsed) {
|
|
@@ -1096,14 +1270,14 @@ export async function runCli(argv, io = consoleIo, env = process.env) {
|
|
|
1096
1270
|
if (command === "login") {
|
|
1097
1271
|
// --to defaults to stdout: printing a snippet can never corrupt a config
|
|
1098
1272
|
// file the user did not ask us to touch.
|
|
1099
|
-
const target =
|
|
1273
|
+
const target = parseLoginTarget(parsed, "stdout");
|
|
1100
1274
|
if (!target) {
|
|
1101
|
-
io.err("login: --to must be claude-code, codex or stdout");
|
|
1275
|
+
io.err("login: --to must be claude-code, codex, openclaw, hermes or stdout");
|
|
1102
1276
|
return 2;
|
|
1103
1277
|
}
|
|
1104
1278
|
const agent = parseLoginAgent(parsed);
|
|
1105
1279
|
if (agent === null) {
|
|
1106
|
-
io.err("login: --agent must be claude-code, codex, cursor, openclaw or cline");
|
|
1280
|
+
io.err("login: --agent must be claude-code, codex, cursor, openclaw, hermes or cline");
|
|
1107
1281
|
return 2;
|
|
1108
1282
|
}
|
|
1109
1283
|
if (target !== "stdout" && agent !== undefined && agent !== target) {
|
package/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://showly.ai/schemas/skill-manifest-v1.json",
|
|
3
3
|
"name": "showly",
|
|
4
4
|
"displayName": "Showly",
|
|
5
|
-
"version": "0.4.
|
|
5
|
+
"version": "0.4.3",
|
|
6
6
|
"description": "Deploy and manage Showly sites from inside Claude Code / Codex.",
|
|
7
7
|
"homepage": "https://showly.ai/docs/mcp/overview",
|
|
8
8
|
"publisher": "Showly",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@showly/mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Connect Claude Code / Codex to the Showly MCP server — preview and deploy sites from your agent.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"claude-code-skill": {
|
|
54
54
|
"name": "showly",
|
|
55
|
-
"version": "0.4.
|
|
55
|
+
"version": "0.4.3",
|
|
56
56
|
"description": "Deploy and manage Showly sites from inside Claude Code.",
|
|
57
57
|
"mcp-server": {
|
|
58
58
|
"url-env": "SHOWLY_MCP_URL",
|
|
@@ -65,10 +65,13 @@
|
|
|
65
65
|
},
|
|
66
66
|
"codex-plugin": {
|
|
67
67
|
"name": "showly",
|
|
68
|
-
"version": "0.4.
|
|
68
|
+
"version": "0.4.3",
|
|
69
69
|
"type": "mcp-server",
|
|
70
70
|
"manifest": "manifest.json"
|
|
71
71
|
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"yaml": "^2.9.0"
|
|
74
|
+
},
|
|
72
75
|
"devDependencies": {
|
|
73
76
|
"@showly/eslint-config": "workspace:^",
|
|
74
77
|
"@types/node": "^26.2.0",
|