@fruggr/zendesk-mcp-server 2.14.2 → 2.15.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 +3 -0
- package/dist/index.js +40 -8
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -174,6 +174,9 @@ disabled together with `--no-topology`):
|
|
|
174
174
|
|
|
175
175
|
Clients that don't consume `instructions` or `resources` simply ignore them —
|
|
176
176
|
the feature degrades silently. Use `--no-topology` to turn both off server-wide.
|
|
177
|
+
The `zendesk-hc://` URI scheme is the default; a deployer can brand it with
|
|
178
|
+
[`--hc-resource-scheme` / `HC_RESOURCE_SCHEME`](docs/configuration.md#hc_resource_scheme)
|
|
179
|
+
(e.g. `wiki` → `wiki://topology`).
|
|
177
180
|
|
|
178
181
|
## Prerequisites
|
|
179
182
|
|
package/dist/index.js
CHANGED
|
@@ -595,13 +595,34 @@ const ConfigSchema = z.object({
|
|
|
595
595
|
tools: z.array(z.string()).optional(),
|
|
596
596
|
/**
|
|
597
597
|
* Whether to expose the Help Center structural context (the `instructions`
|
|
598
|
-
* blob + the `zendesk-hc://topology`
|
|
598
|
+
* blob + the topology resource, default `zendesk-hc://topology`). On by
|
|
599
|
+
* default; an operator
|
|
599
600
|
* disables it server-wide with `--no-topology` (e.g. on a very large Help
|
|
600
601
|
* Center, or when the context is unwanted). Only ever active when the
|
|
601
602
|
* `help_center` namespace itself is active.
|
|
602
603
|
*/
|
|
603
604
|
topology: z.boolean().default(true),
|
|
604
605
|
/**
|
|
606
|
+
* URI scheme of the Help Center MCP resources (today the topology resource,
|
|
607
|
+
* `<scheme>://topology`). Defaults to `zendesk-hc`; a deployer can brand it
|
|
608
|
+
* (`--hc-resource-scheme wiki` / `HC_RESOURCE_SCHEME=wiki`). Strictly a bare
|
|
609
|
+
* RFC 3986 scheme — clients parse resource URIs with WHATWG `URL`, so a
|
|
610
|
+
* non-conformant scheme would surface as a broken resource at runtime;
|
|
611
|
+
* reject it at config parse time instead. ASCII-only message, value not
|
|
612
|
+
* echoed (same policy as parsePort below).
|
|
613
|
+
*/
|
|
614
|
+
hcResourceScheme: z.string().regex(/^[a-z][a-z0-9+.-]*$/, {
|
|
615
|
+
message: "Invalid HC_RESOURCE_SCHEME / --hc-resource-scheme value. Expected a bare RFC 3986 scheme: a lowercase letter followed by lowercase letters, digits, \"+\", \"-\" or \".\" (no \"://\").",
|
|
616
|
+
abort: true
|
|
617
|
+
}).refine((scheme) => {
|
|
618
|
+
const uri = `${scheme}://topology`;
|
|
619
|
+
try {
|
|
620
|
+
return new URL(uri).toString() === uri;
|
|
621
|
+
} catch {
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
}, { message: "Invalid HC_RESOURCE_SCHEME / --hc-resource-scheme value. WHATWG-special schemes (http, https, ws, wss, ftp, file) do not survive URL normalization and would make the resource unreadable; pick a custom scheme such as \"wiki\"." }).default("zendesk-hc"),
|
|
625
|
+
/**
|
|
605
626
|
* Dev-only (stdio): expose the `reload_tools` tool, which re-imports the tool
|
|
606
627
|
* modules from source and re-registers them on the live session on demand, so
|
|
607
628
|
* tool code edited during a dev cycle takes effect without a restart. CLI-only
|
|
@@ -640,7 +661,10 @@ const parseCliArgs = (args) => {
|
|
|
640
661
|
i++;
|
|
641
662
|
} else if (arg === "--read-only") result.readOnly = true;
|
|
642
663
|
else if (arg === "--no-topology") result.topology = false;
|
|
643
|
-
else if (arg === "--
|
|
664
|
+
else if (arg === "--hc-resource-scheme" && next) {
|
|
665
|
+
result.hcResourceScheme = next;
|
|
666
|
+
i++;
|
|
667
|
+
} else if (arg === "--dev") result.dev = true;
|
|
644
668
|
else if (arg === "--namespace" && next) {
|
|
645
669
|
result.namespaces = result.namespaces ?? [];
|
|
646
670
|
result.namespaces.push(next);
|
|
@@ -690,6 +714,7 @@ const loadConfig = (argv = process.argv.slice(2)) => {
|
|
|
690
714
|
const corsFromEnv = (process.env["CORS_ORIGIN"] ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
691
715
|
const corsOrigins = [...cli.corsOrigins ?? [], ...corsFromEnv];
|
|
692
716
|
const callbackPort = cli.callbackPort ?? parsePortEnv(process.env["ZENDESK_OAUTH_CALLBACK_PORT"], "ZENDESK_OAUTH_CALLBACK_PORT");
|
|
717
|
+
const hcResourceScheme = cli.hcResourceScheme ?? (process.env["HC_RESOURCE_SCHEME"] || void 0);
|
|
693
718
|
return ConfigSchema.parse({
|
|
694
719
|
subdomain,
|
|
695
720
|
oauthClientId,
|
|
@@ -699,6 +724,7 @@ const loadConfig = (argv = process.argv.slice(2)) => {
|
|
|
699
724
|
namespaces: cli.namespaces,
|
|
700
725
|
tools: cli.tools,
|
|
701
726
|
topology: cli.topology ?? true,
|
|
727
|
+
hcResourceScheme,
|
|
702
728
|
dev: cli.dev ?? false,
|
|
703
729
|
transport,
|
|
704
730
|
host,
|
|
@@ -847,11 +873,17 @@ const helpCenterUpload = async (subdomain, token, path, formData) => {
|
|
|
847
873
|
};
|
|
848
874
|
//#endregion
|
|
849
875
|
//#region src/guidance/instructions.ts
|
|
850
|
-
/**
|
|
851
|
-
|
|
876
|
+
/**
|
|
877
|
+
* URI of the dynamic Help Center topology resource. Single source of truth for
|
|
878
|
+
* every place that cites it (resource registration, `instructions` blob): the
|
|
879
|
+
* scheme comes from the config (`--hc-resource-scheme`, default `zendesk-hc`),
|
|
880
|
+
* the path is fixed. Any future Help Center resource should build its URI the
|
|
881
|
+
* same way so the whole surface follows the configured scheme.
|
|
882
|
+
*/
|
|
883
|
+
const topologyResourceUri = (config) => `${config.hcResourceScheme}://topology`;
|
|
852
884
|
/**
|
|
853
885
|
* Whether the Help Center structural context (init instructions + the
|
|
854
|
-
* `zendesk-hc://topology`
|
|
886
|
+
* topology resource, default `zendesk-hc://topology`) should be exposed. True only when the
|
|
855
887
|
* feature is enabled (`--no-topology` not set) AND the `help_center` namespace
|
|
856
888
|
* is active (no `--namespace` filter, or one that includes it). Shared by the
|
|
857
889
|
* instructions builder and the resource registration in `server.ts` so both
|
|
@@ -862,14 +894,14 @@ const helpCenterContextEnabled = (config) => config.topology && (!config.namespa
|
|
|
862
894
|
* The static `instructions` blob sent on `initialize`. Deliberately short and
|
|
863
895
|
* I/O-free: it must not trigger the lazy OAuth/PKCE flow just to connect, and
|
|
864
896
|
* it stays within a tight token budget. The rich, dynamic topology lives in the
|
|
865
|
-
* pull-only `zendesk-hc://topology`
|
|
897
|
+
* pull-only topology resource (default `zendesk-hc://topology`) referenced here.
|
|
866
898
|
*/
|
|
867
899
|
const buildInstructions = (config) => {
|
|
868
900
|
if (!helpCenterContextEnabled(config)) return void 0;
|
|
869
901
|
return [
|
|
870
902
|
`This MCP server is connected to the Zendesk Help Center of "${config.subdomain}".`,
|
|
871
903
|
"",
|
|
872
|
-
`When creating or editing Help Center content, the resource ${
|
|
904
|
+
`When creating or editing Help Center content, the resource ${topologyResourceUri(config)} is useful context:`,
|
|
873
905
|
"it lists the active locales (and the default one), the category → section tree with IDs,",
|
|
874
906
|
"the visibility user segments, the permission groups, and your current role.",
|
|
875
907
|
"Prefer its IDs (section_id, permission_group_id, user_segment_id, locale) over guessing from names.",
|
|
@@ -3534,7 +3566,7 @@ const registerToolset = (server, { config, getToken, onUnauthorized, logger = si
|
|
|
3534
3566
|
}
|
|
3535
3567
|
if (helpCenterContextEnabled(config)) {
|
|
3536
3568
|
const topology = createTopologyProvider(getToken, config.subdomain, onUnauthorized);
|
|
3537
|
-
registered.push(server.registerResource("help-center-topology",
|
|
3569
|
+
registered.push(server.registerResource("help-center-topology", topologyResourceUri(config), {
|
|
3538
3570
|
title: "Zendesk Help Center topology",
|
|
3539
3571
|
description: "Active locales, category → section tree, visibility segments, permission groups, and your role. Useful context when creating or editing content; admin-only sections (permission groups, user segments) are marked unavailable rather than empty when your role lacks Guide-admin rights.",
|
|
3540
3572
|
mimeType: "text/markdown"
|