@cloudgrid-io/mcp 0.4.4 → 0.4.5
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/package.json +3 -2
- package/src/tools.js +59 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudgrid-io/mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "MCP server for CloudGrid. Two editions: a local stdio server (full toolset) and a hosted web server (light, CLI-free toolset) over MCP Streamable HTTP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"smoke:web": "node test/smoke-web.mjs",
|
|
23
23
|
"smoke:redrop": "node test/smoke-redrop.mjs",
|
|
24
24
|
"smoke:oauth": "node test/smoke-oauth.mjs",
|
|
25
|
-
"test:auth": "node test/auth.test.mjs"
|
|
25
|
+
"test:auth": "node test/auth.test.mjs",
|
|
26
|
+
"build:mcpb": "node scripts/build-mcpb.mjs"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
28
29
|
"@cloudgrid-io/cli": "^0.9.20",
|
package/src/tools.js
CHANGED
|
@@ -601,6 +601,7 @@ export function registerTools(server, ctx) {
|
|
|
601
601
|
slug: z.string().describe("Org slug to pass as the org parameter."),
|
|
602
602
|
name: z.string().describe("Human-readable org name."),
|
|
603
603
|
role: z.string().describe("User's role in the org."),
|
|
604
|
+
is_active: z.boolean().optional().describe("True if this is the user's currently active org."),
|
|
604
605
|
})).optional().describe("The user's orgs, when org choice is needed."),
|
|
605
606
|
needs_sign_in: z.boolean().optional().describe("True when sign-in is needed before dropping."),
|
|
606
607
|
login_url: z.string().optional().describe("Sign-in URL when authentication is needed."),
|
|
@@ -634,11 +635,16 @@ export function registerTools(server, ctx) {
|
|
|
634
635
|
structured: { needs_sign_in: true, login_url: url },
|
|
635
636
|
});
|
|
636
637
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// Stateless org disambiguation — both editions, when authenticated.
|
|
641
|
+
// No dependency on prior-call state so it works even when the client
|
|
642
|
+
// reconnects on every tool call (ChatGPT Apps SDK behaviour).
|
|
643
|
+
if (input?.anonymous !== true) {
|
|
644
|
+
const token = await ctx.getToken();
|
|
645
|
+
if (token) {
|
|
641
646
|
const orgs = await fetchUserOrgs(token);
|
|
647
|
+
const activeOrg = await ctx.getActiveOrg();
|
|
642
648
|
const suppliedOrg = input?.org;
|
|
643
649
|
const validOrg = suppliedOrg && orgs.some((o) => o.slug === suppliedOrg);
|
|
644
650
|
if (validOrg) {
|
|
@@ -646,13 +652,22 @@ export function registerTools(server, ctx) {
|
|
|
646
652
|
input = { ...(input || {}), org: suppliedOrg };
|
|
647
653
|
} else if (orgs.length > 1) {
|
|
648
654
|
// No valid org supplied and multiple orgs — ask once.
|
|
655
|
+
// Mark the active org so the agent can offer it as the default.
|
|
656
|
+
const annotated = orgs.map((o) => ({
|
|
657
|
+
...o,
|
|
658
|
+
is_active: o.slug === activeOrg,
|
|
659
|
+
}));
|
|
660
|
+
annotated.sort((a, b) => (b.is_active ? 1 : 0) - (a.is_active ? 1 : 0));
|
|
649
661
|
const lines = ["Which org should this be published to?"];
|
|
650
|
-
for (const o of
|
|
662
|
+
for (const o of annotated) {
|
|
663
|
+
const tag = o.is_active ? " (your active org)" : "";
|
|
664
|
+
lines.push(` ${o.slug} — ${o.name} (${o.role})${tag}`);
|
|
665
|
+
}
|
|
651
666
|
lines.push("Pass the org slug in the org parameter to publish.");
|
|
652
667
|
return okResult({
|
|
653
668
|
text: lines.join("\n"),
|
|
654
|
-
structured: { needs_org: true, orgs },
|
|
655
|
-
meta: { "openai/outputTemplate": ORG_PICKER_URI },
|
|
669
|
+
structured: { needs_org: true, orgs: annotated },
|
|
670
|
+
...(ctx.edition === "web" ? { meta: { "openai/outputTemplate": ORG_PICKER_URI } } : {}),
|
|
656
671
|
});
|
|
657
672
|
} else if (orgs.length === 1) {
|
|
658
673
|
// Single org — publish to it silently.
|
|
@@ -791,36 +806,44 @@ export function registerTools(server, ctx) {
|
|
|
791
806
|
},
|
|
792
807
|
);
|
|
793
808
|
|
|
794
|
-
// Org listing —
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
},
|
|
808
|
-
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
809
|
-
},
|
|
810
|
-
async () => {
|
|
811
|
-
const token = await ctx.getToken();
|
|
812
|
-
if (!token) {
|
|
813
|
-
return fail("You are not signed in. Run cloudgrid_login first.");
|
|
814
|
-
}
|
|
815
|
-
const orgs = await fetchUserOrgs(token);
|
|
816
|
-
if (orgs.length === 0) {
|
|
817
|
-
return okResult({ text: "No organizations found.", structured: { orgs: [] } });
|
|
818
|
-
}
|
|
819
|
-
const lines = orgs.map((o) => `${o.slug} — ${o.name} (${o.role})`);
|
|
820
|
-
return okResult({ text: lines.join("\n"), structured: { orgs } });
|
|
809
|
+
// Org listing — both editions.
|
|
810
|
+
server.registerTool(
|
|
811
|
+
"cloudgrid_orgs",
|
|
812
|
+
{
|
|
813
|
+
description: "List the signed-in user's organizations. Returns each org's slug, name, and the user's role. Use to discover which org to publish to. Requires sign-in.",
|
|
814
|
+
inputSchema: {},
|
|
815
|
+
outputSchema: {
|
|
816
|
+
orgs: z.array(z.object({
|
|
817
|
+
slug: z.string().describe("Org slug."),
|
|
818
|
+
name: z.string().describe("Human-readable org name."),
|
|
819
|
+
role: z.string().describe("User's role in the org."),
|
|
820
|
+
is_active: z.boolean().optional().describe("True if this is the user's currently active org."),
|
|
821
|
+
})).describe("The user's org memberships."),
|
|
821
822
|
},
|
|
822
|
-
|
|
823
|
-
|
|
823
|
+
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true },
|
|
824
|
+
},
|
|
825
|
+
async () => {
|
|
826
|
+
const token = await ctx.getToken();
|
|
827
|
+
if (!token) {
|
|
828
|
+
return fail("You are not signed in. Run cloudgrid_login first.");
|
|
829
|
+
}
|
|
830
|
+
const orgs = await fetchUserOrgs(token);
|
|
831
|
+
if (orgs.length === 0) {
|
|
832
|
+
return okResult({ text: "No organizations found.", structured: { orgs: [] } });
|
|
833
|
+
}
|
|
834
|
+
const activeOrg = await ctx.getActiveOrg();
|
|
835
|
+
const annotated = orgs.map((o) => ({
|
|
836
|
+
...o,
|
|
837
|
+
is_active: o.slug === activeOrg,
|
|
838
|
+
}));
|
|
839
|
+
annotated.sort((a, b) => (b.is_active ? 1 : 0) - (a.is_active ? 1 : 0));
|
|
840
|
+
const lines = annotated.map((o) => {
|
|
841
|
+
const tag = o.is_active ? " (your active org)" : "";
|
|
842
|
+
return `${o.slug} — ${o.name} (${o.role})${tag}`;
|
|
843
|
+
});
|
|
844
|
+
return okResult({ text: lines.join("\n"), structured: { orgs: annotated } });
|
|
845
|
+
},
|
|
846
|
+
);
|
|
824
847
|
|
|
825
848
|
if (ctx.edition !== "local") return; // web edition stops here — no CLI tools
|
|
826
849
|
|