@fruggr/zendesk-mcp-server 2.17.0 → 2.17.1
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/index.js +74 -71
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { homedir, release } from "node:os";
|
|
|
6
6
|
import open from "open";
|
|
7
7
|
import { dirname, join } from "node:path";
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
9
|
+
import { parseArgs } from "node:util";
|
|
9
10
|
import * as z from "zod/v4";
|
|
10
11
|
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
12
|
import * as cheerio from "cheerio";
|
|
@@ -706,97 +707,99 @@ const parsePort = (raw, label) => {
|
|
|
706
707
|
if (!DIGITS_ONLY.test(raw)) throw new Error(`Invalid ${label} value. Expected an integer 0-65535.`);
|
|
707
708
|
return Number(raw);
|
|
708
709
|
};
|
|
709
|
-
const parsePortEnv = (raw, label) => raw === void 0
|
|
710
|
-
const
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
};
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
710
|
+
const parsePortEnv = (raw, label) => raw === void 0 ? void 0 : parsePort(raw, label);
|
|
711
|
+
const requireNonEmptyEnv = (name) => {
|
|
712
|
+
const raw = process.env[name];
|
|
713
|
+
if (raw === "") throw new Error(`Empty ${name}. Set it to a value, or unset it entirely.`);
|
|
714
|
+
return raw;
|
|
715
|
+
};
|
|
716
|
+
const CLI_OPTIONS = {
|
|
717
|
+
mode: { type: "string" },
|
|
718
|
+
namespace: {
|
|
719
|
+
type: "string",
|
|
720
|
+
multiple: true
|
|
721
|
+
},
|
|
722
|
+
tool: {
|
|
723
|
+
type: "string",
|
|
724
|
+
multiple: true
|
|
725
|
+
},
|
|
726
|
+
"log-level": { type: "string" },
|
|
727
|
+
"hc-resource-scheme": { type: "string" },
|
|
728
|
+
transport: { type: "string" },
|
|
729
|
+
host: { type: "string" },
|
|
730
|
+
port: { type: "string" },
|
|
731
|
+
"public-url": { type: "string" },
|
|
732
|
+
"cors-origin": {
|
|
733
|
+
type: "string",
|
|
734
|
+
multiple: true
|
|
735
|
+
},
|
|
736
|
+
"callback-port": { type: "string" },
|
|
737
|
+
"read-only": { type: "boolean" },
|
|
738
|
+
"no-topology": { type: "boolean" },
|
|
739
|
+
"no-promoted-articles": { type: "boolean" },
|
|
740
|
+
dev: { type: "boolean" }
|
|
741
|
+
};
|
|
742
|
+
new Set(Object.entries(CLI_OPTIONS).filter(([, spec]) => spec.type === "string").map(([name]) => `--${name}`));
|
|
743
|
+
const FIELD_BY_FLAG = /* @__PURE__ */ new Map([
|
|
744
|
+
["mode", "mode"],
|
|
745
|
+
["namespace", "namespaces"],
|
|
746
|
+
["tool", "tools"],
|
|
747
|
+
["log-level", "logLevel"],
|
|
748
|
+
["hc-resource-scheme", "hcResourceScheme"],
|
|
749
|
+
["transport", "transport"],
|
|
750
|
+
["host", "host"],
|
|
751
|
+
["public-url", "publicUrl"],
|
|
752
|
+
["cors-origin", "corsOrigins"]
|
|
728
753
|
]);
|
|
729
|
-
const
|
|
730
|
-
["
|
|
731
|
-
|
|
732
|
-
}],
|
|
733
|
-
["
|
|
734
|
-
result.hcResourceScheme = value;
|
|
735
|
-
}],
|
|
736
|
-
["--log-level", (result, value) => {
|
|
737
|
-
result.logLevel = value;
|
|
738
|
-
}],
|
|
739
|
-
["--transport", (result, value) => {
|
|
740
|
-
result.transport = value;
|
|
741
|
-
}],
|
|
742
|
-
["--host", (result, value) => {
|
|
743
|
-
result.host = value;
|
|
744
|
-
}],
|
|
745
|
-
["--public-url", (result, value) => {
|
|
746
|
-
result.publicUrl = value;
|
|
747
|
-
}],
|
|
748
|
-
["--port", (result, value) => {
|
|
749
|
-
result.port = parsePort(value, "--port");
|
|
750
|
-
}],
|
|
751
|
-
["--callback-port", (result, value) => {
|
|
752
|
-
result.callbackPort = parsePort(value, "--callback-port");
|
|
753
|
-
}],
|
|
754
|
-
["--namespace", appendTo("namespaces")],
|
|
755
|
-
["--tool", appendTo("tools")],
|
|
756
|
-
["--cors-origin", appendTo("corsOrigins")]
|
|
754
|
+
const STANDALONE_EFFECTS = /* @__PURE__ */ new Map([
|
|
755
|
+
["read-only", { readOnly: true }],
|
|
756
|
+
["no-topology", { topology: false }],
|
|
757
|
+
["no-promoted-articles", { promotedArticles: false }],
|
|
758
|
+
["dev", { dev: true }]
|
|
757
759
|
]);
|
|
758
760
|
const parseCliArgs = (args) => {
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
}
|
|
768
|
-
const
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
valued(result, next);
|
|
772
|
-
i++;
|
|
761
|
+
const { values, positionals } = parseArgs({
|
|
762
|
+
args,
|
|
763
|
+
options: CLI_OPTIONS,
|
|
764
|
+
allowPositionals: true
|
|
765
|
+
});
|
|
766
|
+
if (positionals.length > 1) throw new Error(`Expected one positional argument (the subdomain), got ${positionals.length}. A repeatable flag has to be repeated (--namespace tickets --namespace help_center); it does not take a space-separated list.`);
|
|
767
|
+
const result = { subdomain: positionals[0] };
|
|
768
|
+
for (const [flag, value] of Object.entries(values)) {
|
|
769
|
+
if (Array.isArray(value) ? value.includes("") : value === "") throw new Error(`Empty value for --${flag}. Provide a value, or omit the flag.`);
|
|
770
|
+
const effect = STANDALONE_EFFECTS.get(flag);
|
|
771
|
+
if (effect) {
|
|
772
|
+
Object.assign(result, effect);
|
|
773
773
|
continue;
|
|
774
774
|
}
|
|
775
|
-
|
|
775
|
+
const field = FIELD_BY_FLAG.get(flag);
|
|
776
|
+
if (field) Object.assign(result, { [field]: value });
|
|
776
777
|
}
|
|
778
|
+
if (values.port !== void 0) result.port = parsePort(values.port, "--port");
|
|
779
|
+
if (values["callback-port"] !== void 0) result.callbackPort = parsePort(values["callback-port"], "--callback-port");
|
|
777
780
|
return result;
|
|
778
781
|
};
|
|
779
782
|
const resolveTransportSettings = (cli) => {
|
|
780
783
|
const corsFromEnv = (process.env["CORS_ORIGIN"] ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
781
784
|
return {
|
|
782
|
-
transport: cli.transport ??
|
|
783
|
-
host: cli.host ??
|
|
784
|
-
port: cli.port ?? parsePortEnv(
|
|
785
|
-
publicUrl: cli.publicUrl ??
|
|
785
|
+
transport: cli.transport ?? requireNonEmptyEnv("TRANSPORT") ?? "stdio",
|
|
786
|
+
host: cli.host ?? requireNonEmptyEnv("HOST") ?? "0.0.0.0",
|
|
787
|
+
port: cli.port ?? parsePortEnv(requireNonEmptyEnv("PORT"), "PORT") ?? 3e3,
|
|
788
|
+
publicUrl: cli.publicUrl ?? requireNonEmptyEnv("PUBLIC_URL"),
|
|
786
789
|
corsOrigins: [...cli.corsOrigins ?? [], ...corsFromEnv]
|
|
787
790
|
};
|
|
788
791
|
};
|
|
789
792
|
const loadConfig = (argv = process.argv.slice(2)) => {
|
|
790
793
|
const cli = parseCliArgs(argv);
|
|
791
|
-
const subdomain = cli.subdomain ??
|
|
792
|
-
const oauthClientId =
|
|
794
|
+
const subdomain = cli.subdomain ?? requireNonEmptyEnv("ZENDESK_SUBDOMAIN") ?? "";
|
|
795
|
+
const oauthClientId = requireNonEmptyEnv("ZENDESK_OAUTH_CLIENT_ID") ?? `${subdomain}_zendesk`;
|
|
793
796
|
const mode = cli.tools?.length ? "all" : cli.mode ?? "namespace";
|
|
794
|
-
const callbackPort = cli.callbackPort ?? parsePortEnv(
|
|
795
|
-
const hcResourceScheme = cli.hcResourceScheme ?? (
|
|
797
|
+
const callbackPort = cli.callbackPort ?? parsePortEnv(requireNonEmptyEnv("ZENDESK_OAUTH_CALLBACK_PORT"), "ZENDESK_OAUTH_CALLBACK_PORT");
|
|
798
|
+
const hcResourceScheme = cli.hcResourceScheme ?? requireNonEmptyEnv("HC_RESOURCE_SCHEME");
|
|
796
799
|
return ConfigSchema.parse({
|
|
797
800
|
subdomain,
|
|
798
801
|
oauthClientId,
|
|
799
|
-
logLevel: cli.logLevel ??
|
|
802
|
+
logLevel: cli.logLevel ?? requireNonEmptyEnv("LOG_LEVEL") ?? "info",
|
|
800
803
|
mode,
|
|
801
804
|
readOnly: cli.readOnly ?? false,
|
|
802
805
|
namespaces: cli.namespaces,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fruggr/zendesk-mcp-server",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.1",
|
|
4
4
|
"mcpName": "io.github.fruggr/zendesk-mcp-server",
|
|
5
5
|
"description": "Deep Zendesk MCP server for your AI assistant: search, draft, update and translate Help Center articles and manage Support tickets end to end — comments, triage and image attachments.",
|
|
6
6
|
"type": "module",
|