@elitedcs/ghl-mcp 3.27.1 → 3.28.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/CHANGELOG.md +54 -0
- package/LICENSE +19 -17
- package/README.md +39 -0
- package/dist/index.js +135 -18
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,59 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.28.0 — Tool allowlist (issue #1): cut context cost on big installs
|
|
4
|
+
|
|
5
|
+
Two new optional env vars let you gate which tools register at startup so
|
|
6
|
+
unused schemas never load into context. Closes [issue #1](https://github.com/drjerryrelth/ghl-command-feedback/issues/1).
|
|
7
|
+
|
|
8
|
+
**New env vars (both optional, both default-empty):**
|
|
9
|
+
|
|
10
|
+
- `GHL_ENABLED_MODULES` — comma-separated module names to register
|
|
11
|
+
(e.g. `contacts,conversations,locations,custom-objects`).
|
|
12
|
+
- `GHL_ENABLED_TOOLS` — comma-separated tool names to register
|
|
13
|
+
(e.g. `search_contacts,get_contact,update_custom_value`).
|
|
14
|
+
|
|
15
|
+
**Filter precedence:**
|
|
16
|
+
|
|
17
|
+
- Neither set → every tool registers (backward compatible).
|
|
18
|
+
- Modules only → tools in those modules register.
|
|
19
|
+
- Tools only → those exact tool names register.
|
|
20
|
+
- Both set → UNION (a tool registers if its module is enabled OR its
|
|
21
|
+
name is explicitly listed).
|
|
22
|
+
|
|
23
|
+
**Always-on tools** never get filtered out, so setup and recovery still
|
|
24
|
+
work even with a heavily-restricted allowlist:
|
|
25
|
+
`setup_ghl_mcp`, `request_license`, `get_mcp_version`,
|
|
26
|
+
`auto_capture_firebase_script`, `enable_workflow_builder`, `health_check`.
|
|
27
|
+
|
|
28
|
+
**Validation + logging:**
|
|
29
|
+
|
|
30
|
+
- Whitespace and commas both work as separators. Matching is case-insensitive.
|
|
31
|
+
- Unrecognized names log a one-line WARNING to stderr and are ignored
|
|
32
|
+
(startup never aborts).
|
|
33
|
+
- When the allowlist is active, startup logs one summary:
|
|
34
|
+
`Tool allowlist active: registered N of M tools (modules=[...]; explicit-tools=[...])`.
|
|
35
|
+
- When unset, zero extra noise — existing logs are unchanged.
|
|
36
|
+
|
|
37
|
+
**Motivation (from the issue):** running 25+ registered locations with
|
|
38
|
+
all 212 tools registered burned tokens on every message in chats that
|
|
39
|
+
didn't need GHL. Now buyers can restrict the surface to the modules
|
|
40
|
+
they actually use.
|
|
41
|
+
|
|
42
|
+
## 3.27.2 — Fix license metadata: MIT → Proprietary
|
|
43
|
+
|
|
44
|
+
Metadata-only release. Corrects the npm package's stated license, which
|
|
45
|
+
was wrongly set to MIT and contradicted the paid/proprietary nature of
|
|
46
|
+
the product.
|
|
47
|
+
|
|
48
|
+
- `package.json` `license` field: `"MIT"` → `"SEE LICENSE IN LICENSE"`
|
|
49
|
+
- `LICENSE` file replaced with the actual proprietary commercial license
|
|
50
|
+
(Copyright Elite DCs, LLC; usage requires a paid license from
|
|
51
|
+
elitedcs.com/ghl-mcp-server; no redistribution, no reverse engineering,
|
|
52
|
+
no license-gate circumvention).
|
|
53
|
+
|
|
54
|
+
No code changes. Same 212-tool surface as 3.27.1. The runtime license-key
|
|
55
|
+
validation flow is unchanged.
|
|
56
|
+
|
|
3
57
|
## 3.27.1 — README: real buyer testimonials + 30-day guarantee
|
|
4
58
|
|
|
5
59
|
Documentation-only release. Surfaces four real, verbatim buyer replies on the npm package README:
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
GHL Command - Proprietary Software License
|
|
2
|
+
Copyright (c) 2026 Elite DCs, LLC. All rights reserved.
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
1. Overview
|
|
5
|
+
GHL Command (the "Software") is commercial, proprietary software owned by Elite DCs, LLC (the "Licensor"). The Software is licensed, not sold. Use of the Software requires a valid paid license obtained from https://elitedcs.com/ghl-mcp-server.
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
of
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
7
|
+
2. License Grant
|
|
8
|
+
Subject to payment of the applicable fee and ongoing compliance with the Licensor's then-current commercial terms, Licensor grants the purchaser a non-exclusive, non-transferable, revocable license to install and use the Software on the number of machines specified at purchase. No other rights are granted.
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
3. Restrictions
|
|
11
|
+
Except as expressly permitted by the commercial terms or by applicable law, you may not: (a) copy, modify, or create derivative works of the Software; (b) distribute, sublicense, sell, rent, lease, or otherwise transfer the Software; (c) reverse engineer, decompile, or disassemble the Software, or attempt to derive its source code; (d) remove or alter any proprietary notices; or (e) circumvent or disable any license-validation or activation mechanism.
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
4. Ownership
|
|
14
|
+
The Software and all intellectual property rights therein are and remain the exclusive property of Elite DCs, LLC. This license does not transfer any ownership interest.
|
|
15
|
+
|
|
16
|
+
5. No Warranty
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
|
|
18
|
+
|
|
19
|
+
6. Limitation of Liability
|
|
20
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL ELITE DCS, LLC BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
7. Contact
|
|
23
|
+
Elite DCs, LLC - https://elitedcs.com/ghl-mcp-server
|
package/README.md
CHANGED
|
@@ -709,9 +709,48 @@ Source repo is private. Contributors need an invitation from `drjerryrelth`. The
|
|
|
709
709
|
| `GHL_USER_ID` | No* | Your GHL user ID. Required for workflow builder tools. |
|
|
710
710
|
| `GHL_FIREBASE_API_KEY` | No* | Firebase API key from GHL's auth system. Required for workflow builder tools. |
|
|
711
711
|
| `GHL_FIREBASE_REFRESH_TOKEN` | No* | Firebase refresh token. Required for workflow builder tools. May rotate periodically. |
|
|
712
|
+
| `GHL_ENABLED_MODULES` | No | Comma-separated module names to limit which tool groups register at startup (e.g. `contacts,conversations,locations`). Unset = every module registers (default). See "Reducing context / token usage" below. |
|
|
713
|
+
| `GHL_ENABLED_TOOLS` | No | Comma-separated individual tool names to register (e.g. `search_contacts,get_contact,update_custom_value`). Set alongside `GHL_ENABLED_MODULES` to add specific tools on top of whole-module enables. |
|
|
712
714
|
|
|
713
715
|
*Required only for the workflow builder (internal API) tools. The standard API tools work without these.
|
|
714
716
|
|
|
717
|
+
### Reducing context / token usage
|
|
718
|
+
|
|
719
|
+
Every registered MCP tool's schema is shipped to the model on every message. With 212 tools that's a meaningful per-message context cost even in chats that never touch GHL. If you only use a slice of GHL Command, restrict the tool surface with `GHL_ENABLED_MODULES` and/or `GHL_ENABLED_TOOLS`:
|
|
720
|
+
|
|
721
|
+
```jsonc
|
|
722
|
+
// Claude Desktop config — enable whole modules
|
|
723
|
+
"env": {
|
|
724
|
+
"GHL_API_KEY": "pit-...",
|
|
725
|
+
"GHL_LOCATION_ID": "...",
|
|
726
|
+
"GHL_ENABLED_MODULES": "contacts,conversations,locations,custom-objects"
|
|
727
|
+
}
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
```jsonc
|
|
731
|
+
// Or pin to individual tools
|
|
732
|
+
"env": {
|
|
733
|
+
"GHL_API_KEY": "pit-...",
|
|
734
|
+
"GHL_LOCATION_ID": "...",
|
|
735
|
+
"GHL_ENABLED_TOOLS": "search_contacts,get_contact,update_custom_value"
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
Rules of the road:
|
|
740
|
+
|
|
741
|
+
- **Neither set → every tool registers** (default, backward compatible — your existing config keeps working unchanged).
|
|
742
|
+
- **`GHL_ENABLED_MODULES` only** → register tools in those modules.
|
|
743
|
+
- **`GHL_ENABLED_TOOLS` only** → register only those exact tool names.
|
|
744
|
+
- **Both set** → register the **union**: a tool registers if its module is in `GHL_ENABLED_MODULES` OR its name is in `GHL_ENABLED_TOOLS`. (Whole modules plus a few extra tools.)
|
|
745
|
+
- Whitespace and commas both work as separators. Matching is case-insensitive.
|
|
746
|
+
- Always-on tools register regardless of the allowlist so setup and recovery still work: `setup_ghl_mcp`, `request_license`, `get_mcp_version`, `auto_capture_firebase_script`, `enable_workflow_builder`, `health_check`.
|
|
747
|
+
- Unrecognized module/tool names log a one-line WARNING to stderr and are ignored. Startup never aborts.
|
|
748
|
+
- On startup with the allowlist active, the server logs one summary line: `Tool allowlist active: registered N of M tools (...)`.
|
|
749
|
+
|
|
750
|
+
**Valid module names** (use these in `GHL_ENABLED_MODULES`):
|
|
751
|
+
|
|
752
|
+
`contacts`, `conversations`, `opportunities`, `calendars`, `locations`, `workflows`, `funnels`, `forms`, `surveys`, `payments`, `products`, `invoices`, `campaigns`, `users`, `media`, `social-planner`, `courses`, `businesses`, `blogs`, `emails`, `trigger-links`, `custom-objects`, `associations`, `estimates`, `coupons`, `webhooks`, `documents`, `bulk-operations`, `account-export`, `template-deployer`, `workflow-builder`, `funnel-builder`, `form-builder`, `pipeline-builder`, `workflow-cloner`, `smart-lists`, `reputation`, `email-campaigns`, `email-builder`, `memberships`, `validators`, `diagnostics`, `location-switcher`
|
|
753
|
+
|
|
715
754
|
---
|
|
716
755
|
|
|
717
756
|
## Troubleshooting
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@elitedcs/ghl-mcp",
|
|
34
|
-
version: "3.
|
|
34
|
+
version: "3.28.0",
|
|
35
35
|
mcpName: "io.github.drjerryrelth/ghl-command",
|
|
36
36
|
description: "GoHighLevel MCP Server for Claude. 212 tools \u2014 full CRM, automation, marketing control, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
37
37
|
main: "dist/index.js",
|
|
@@ -71,7 +71,7 @@ var require_package = __commonJS({
|
|
|
71
71
|
"agency"
|
|
72
72
|
],
|
|
73
73
|
author: "Elite DCs, LLC",
|
|
74
|
-
license: "
|
|
74
|
+
license: "SEE LICENSE IN LICENSE",
|
|
75
75
|
homepage: "https://elitedcs.com/ghl-mcp-server",
|
|
76
76
|
repository: {
|
|
77
77
|
type: "git",
|
|
@@ -1776,6 +1776,89 @@ ${errorBody}`
|
|
|
1776
1776
|
}
|
|
1777
1777
|
};
|
|
1778
1778
|
|
|
1779
|
+
// src/tools/tool-filter.ts
|
|
1780
|
+
var ALWAYS_ON_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
1781
|
+
"setup_ghl_mcp",
|
|
1782
|
+
"request_license",
|
|
1783
|
+
"get_mcp_version",
|
|
1784
|
+
"auto_capture_firebase_script",
|
|
1785
|
+
"enable_workflow_builder",
|
|
1786
|
+
"health_check"
|
|
1787
|
+
]);
|
|
1788
|
+
function parseList(raw) {
|
|
1789
|
+
if (raw === void 0) return null;
|
|
1790
|
+
const items = raw.split(/[,\s]+/).map((x) => x.trim().toLowerCase()).filter((x) => x.length > 0);
|
|
1791
|
+
return items.length > 0 ? items : null;
|
|
1792
|
+
}
|
|
1793
|
+
function parseAllowlist(env) {
|
|
1794
|
+
const moduleList = parseList(env.GHL_ENABLED_MODULES);
|
|
1795
|
+
const toolList = parseList(env.GHL_ENABLED_TOOLS);
|
|
1796
|
+
return {
|
|
1797
|
+
enabledModules: moduleList ? new Set(moduleList) : null,
|
|
1798
|
+
enabledTools: toolList ? new Set(toolList) : null,
|
|
1799
|
+
rawModuleInput: moduleList,
|
|
1800
|
+
rawToolInput: toolList
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1803
|
+
function isAllowlistActive(config3) {
|
|
1804
|
+
return config3.enabledModules !== null || config3.enabledTools !== null;
|
|
1805
|
+
}
|
|
1806
|
+
function shouldRegister(toolName, moduleName, config3) {
|
|
1807
|
+
if (ALWAYS_ON_TOOL_NAMES.has(toolName)) return true;
|
|
1808
|
+
if (!isAllowlistActive(config3)) return true;
|
|
1809
|
+
const toolLower = toolName.toLowerCase();
|
|
1810
|
+
const moduleLower = moduleName.toLowerCase();
|
|
1811
|
+
const moduleEnabled = config3.enabledModules?.has(moduleLower) ?? false;
|
|
1812
|
+
const toolEnabled = config3.enabledTools?.has(toolLower) ?? false;
|
|
1813
|
+
return moduleEnabled || toolEnabled;
|
|
1814
|
+
}
|
|
1815
|
+
function wrapServerForModule(realServer, moduleName, config3, attemptedTools, registeredTools) {
|
|
1816
|
+
return new Proxy(realServer, {
|
|
1817
|
+
get(target, prop, receiver) {
|
|
1818
|
+
if (prop === "tool") {
|
|
1819
|
+
return (name, ...rest) => {
|
|
1820
|
+
attemptedTools.add(name);
|
|
1821
|
+
if (!shouldRegister(name, moduleName, config3)) {
|
|
1822
|
+
return void 0;
|
|
1823
|
+
}
|
|
1824
|
+
registeredTools.add(name);
|
|
1825
|
+
return target.tool(name, ...rest);
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
return Reflect.get(target, prop, receiver);
|
|
1829
|
+
}
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
function validateAndLog(config3, knownModules, attemptedTools, registeredTools, log = (m) => process.stderr.write(m)) {
|
|
1833
|
+
if (!isAllowlistActive(config3)) return;
|
|
1834
|
+
if (config3.rawModuleInput) {
|
|
1835
|
+
const knownLower = new Set([...knownModules].map((m) => m.toLowerCase()));
|
|
1836
|
+
const unknown = config3.rawModuleInput.filter((m) => !knownLower.has(m));
|
|
1837
|
+
if (unknown.length > 0) {
|
|
1838
|
+
log(
|
|
1839
|
+
`[ghl-mcp] WARNING: GHL_ENABLED_MODULES has unrecognized name(s): ${unknown.join(", ")}. Known modules: ${[...knownModules].sort().join(", ")}.
|
|
1840
|
+
`
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
if (config3.rawToolInput) {
|
|
1845
|
+
const attemptedLower = new Set([...attemptedTools].map((t) => t.toLowerCase()));
|
|
1846
|
+
const unknown = config3.rawToolInput.filter((t) => !attemptedLower.has(t));
|
|
1847
|
+
if (unknown.length > 0) {
|
|
1848
|
+
log(
|
|
1849
|
+
`[ghl-mcp] WARNING: GHL_ENABLED_TOOLS has unrecognized name(s): ${unknown.join(", ")}.
|
|
1850
|
+
`
|
|
1851
|
+
);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
const moduleSummary = config3.enabledModules && config3.enabledModules.size > 0 ? `modules=[${[...config3.enabledModules].sort().join(",")}]` : "modules=(none)";
|
|
1855
|
+
const toolSummary = config3.enabledTools && config3.enabledTools.size > 0 ? `explicit-tools=[${[...config3.enabledTools].sort().join(",")}]` : "explicit-tools=(none)";
|
|
1856
|
+
log(
|
|
1857
|
+
`[ghl-mcp] Tool allowlist active: registered ${registeredTools.size} of ${attemptedTools.size} tools (${moduleSummary}; ${toolSummary}).
|
|
1858
|
+
`
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1779
1862
|
// src/tools/contacts.ts
|
|
1780
1863
|
var import_zod6 = require("zod");
|
|
1781
1864
|
|
|
@@ -8602,24 +8685,58 @@ var publicApiTools = [
|
|
|
8602
8685
|
[registerAccountExportTools, "account-export"],
|
|
8603
8686
|
[registerTemplateDeployerTools, "template-deployer"]
|
|
8604
8687
|
];
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8688
|
+
var internalApiTools = [
|
|
8689
|
+
[registerWorkflowBuilderTools, "workflow-builder"],
|
|
8690
|
+
[registerFunnelBuilderTools, "funnel-builder"],
|
|
8691
|
+
[registerFormBuilderTools, "form-builder"],
|
|
8692
|
+
[registerPipelineBuilderTools, "pipeline-builder"],
|
|
8693
|
+
[registerWorkflowClonerTools, "workflow-cloner"],
|
|
8694
|
+
[registerSmartListTools, "smart-lists"],
|
|
8695
|
+
[registerReputationTools, "reputation"],
|
|
8696
|
+
[registerEmailCampaignTools, "email-campaigns"],
|
|
8697
|
+
[registerEmailBuilderInternalTools, "email-builder"],
|
|
8698
|
+
[registerMembershipTools, "memberships"]
|
|
8699
|
+
];
|
|
8700
|
+
var VALIDATORS_MODULE = "validators";
|
|
8701
|
+
var DIAGNOSTICS_MODULE = "diagnostics";
|
|
8702
|
+
var LOCATION_SWITCHER_MODULE = "location-switcher";
|
|
8703
|
+
var KNOWN_MODULES = /* @__PURE__ */ new Set([
|
|
8704
|
+
...publicApiTools.map(([, label]) => label),
|
|
8705
|
+
...internalApiTools.map(([, label]) => label),
|
|
8706
|
+
VALIDATORS_MODULE,
|
|
8707
|
+
DIAGNOSTICS_MODULE,
|
|
8708
|
+
LOCATION_SWITCHER_MODULE
|
|
8709
|
+
]);
|
|
8710
|
+
function registerAllTools(server2, client, registry2, mcpVersion, env = process.env) {
|
|
8711
|
+
const config3 = parseAllowlist(env);
|
|
8712
|
+
const attemptedTools = /* @__PURE__ */ new Set();
|
|
8713
|
+
const registeredTools = /* @__PURE__ */ new Set();
|
|
8714
|
+
const wrap = (moduleName) => wrapServerForModule(server2, moduleName, config3, attemptedTools, registeredTools);
|
|
8715
|
+
for (const [register, moduleName] of publicApiTools) {
|
|
8716
|
+
register(wrap(moduleName), client);
|
|
8608
8717
|
}
|
|
8609
8718
|
const builderClient = WorkflowBuilderClient.fromEnv(registry2) ?? WorkflowBuilderClient.fromFirstCompany(registry2);
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8719
|
+
for (const [register, moduleName] of internalApiTools) {
|
|
8720
|
+
register(wrap(moduleName), builderClient);
|
|
8721
|
+
}
|
|
8722
|
+
registerValidatorTools(wrap(VALIDATORS_MODULE), client, builderClient);
|
|
8723
|
+
registerDiagnosticTools(
|
|
8724
|
+
wrap(DIAGNOSTICS_MODULE),
|
|
8725
|
+
mcpVersion ?? "unknown",
|
|
8726
|
+
client,
|
|
8727
|
+
builderClient,
|
|
8728
|
+
registry2 ?? null
|
|
8729
|
+
);
|
|
8730
|
+
registerLocationSwitcherTools(
|
|
8731
|
+
wrap(LOCATION_SWITCHER_MODULE),
|
|
8732
|
+
client,
|
|
8733
|
+
builderClient,
|
|
8734
|
+
registry2,
|
|
8735
|
+
mcpVersion
|
|
8736
|
+
);
|
|
8737
|
+
if (isAllowlistActive(config3)) {
|
|
8738
|
+
validateAndLog(config3, KNOWN_MODULES, attemptedTools, registeredTools);
|
|
8739
|
+
}
|
|
8623
8740
|
}
|
|
8624
8741
|
|
|
8625
8742
|
// src/attestation.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elitedcs/ghl-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.28.0",
|
|
4
4
|
"mcpName": "io.github.drjerryrelth/ghl-command",
|
|
5
5
|
"description": "GoHighLevel MCP Server for Claude. 212 tools — full CRM, automation, marketing control, and the only programmatic GHL workflow builder, now multi-tenant across client accounts.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"agency"
|
|
41
41
|
],
|
|
42
42
|
"author": "Elite DCs, LLC",
|
|
43
|
-
"license": "
|
|
43
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
44
44
|
"homepage": "https://elitedcs.com/ghl-mcp-server",
|
|
45
45
|
"repository": {
|
|
46
46
|
"type": "git",
|