@flomenco/claude-plugin-mcp 0.1.2 → 0.1.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/package.json +1 -1
- package/src/index.js +67 -5
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { spawn } from "node:child_process";
|
|
|
17
17
|
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
18
18
|
const OAUTH_WAIT_TIMEOUT_MS = 180_000;
|
|
19
19
|
const TOKEN_REFRESH_SKEW_SECONDS = 60;
|
|
20
|
+
const ASSET_ID_REGEX = /^[A-Za-z0-9._-]+$/;
|
|
20
21
|
const DEFAULT_TOKEN_CACHE_PATH = path.join(
|
|
21
22
|
os.homedir(),
|
|
22
23
|
".flo",
|
|
@@ -78,6 +79,17 @@ function defaultSettingsUrlForEnv() {
|
|
|
78
79
|
return "https://dev.floapp.co/settings/api";
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
function defaultWebAppUrlForEnv() {
|
|
83
|
+
const env = normalizedPluginEnv();
|
|
84
|
+
if (env === "prod") {
|
|
85
|
+
return "https://floapp.co";
|
|
86
|
+
}
|
|
87
|
+
if (env === "stg") {
|
|
88
|
+
return "https://stg.floapp.co";
|
|
89
|
+
}
|
|
90
|
+
return "https://dev.floapp.co";
|
|
91
|
+
}
|
|
92
|
+
|
|
81
93
|
function getInvocationUrl() {
|
|
82
94
|
const raw =
|
|
83
95
|
process.env.FLO_INTERFACE_AGENT_INVOCATION_URL ||
|
|
@@ -119,6 +131,8 @@ function getOAuthConfig(strict = false) {
|
|
|
119
131
|
process.env.FLO_OAUTH_CLIENT_ID_HELP_URL ||
|
|
120
132
|
defaultSettingsUrlForEnv()
|
|
121
133
|
).trim();
|
|
134
|
+
const rawAppLoginUrl = (process.env.FLO_OAUTH_APP_LOGIN_URL || "").trim();
|
|
135
|
+
const appLoginUrl = rawAppLoginUrl || `${defaultWebAppUrlForEnv()}/login`;
|
|
122
136
|
|
|
123
137
|
const ready = Boolean(authorizeUrl && tokenUrl && clientId);
|
|
124
138
|
if (strict && !ready) {
|
|
@@ -141,6 +155,7 @@ function getOAuthConfig(strict = false) {
|
|
|
141
155
|
userPoolName,
|
|
142
156
|
expectedClientName,
|
|
143
157
|
settingsUrl,
|
|
158
|
+
appLoginUrl,
|
|
144
159
|
};
|
|
145
160
|
}
|
|
146
161
|
|
|
@@ -643,6 +658,17 @@ function requireString(value, fieldName) {
|
|
|
643
658
|
return value.trim();
|
|
644
659
|
}
|
|
645
660
|
|
|
661
|
+
function requireAssetId(value, fieldName) {
|
|
662
|
+
const assetId = requireString(value, fieldName);
|
|
663
|
+
if (assetId.length > 128 || !ASSET_ID_REGEX.test(assetId)) {
|
|
664
|
+
throw new McpError(
|
|
665
|
+
ErrorCode.InvalidParams,
|
|
666
|
+
`\`${fieldName}\` must match ^[A-Za-z0-9._-]+$ and be <= 128 chars.`
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
return assetId;
|
|
670
|
+
}
|
|
671
|
+
|
|
646
672
|
function assertSearchPayload(payload) {
|
|
647
673
|
if (!payload || payload.status !== "ok" || !Array.isArray(payload.menuItems)) {
|
|
648
674
|
throw new McpError(
|
|
@@ -742,7 +768,7 @@ const tools = [
|
|
|
742
768
|
{
|
|
743
769
|
name: "flo_auth_login",
|
|
744
770
|
description:
|
|
745
|
-
"Start OAuth login (browser PKCE flow), cache token locally, and return auth status.",
|
|
771
|
+
"Start OAuth login (browser PKCE flow), cache token locally, and return auth status. If prompted by hosted login UI, first sign in via appLoginUrl.",
|
|
746
772
|
inputSchema: {
|
|
747
773
|
type: "object",
|
|
748
774
|
properties: {},
|
|
@@ -777,6 +803,28 @@ const tools = [
|
|
|
777
803
|
additionalProperties: false,
|
|
778
804
|
},
|
|
779
805
|
},
|
|
806
|
+
{
|
|
807
|
+
name: "flo_analyze",
|
|
808
|
+
description:
|
|
809
|
+
"Analyze an asset directly (friendly alias for /flo:analyze-image <assetId>).",
|
|
810
|
+
inputSchema: {
|
|
811
|
+
type: "object",
|
|
812
|
+
properties: {
|
|
813
|
+
assetId: {
|
|
814
|
+
type: "string",
|
|
815
|
+
minLength: 1,
|
|
816
|
+
maxLength: 128,
|
|
817
|
+
pattern: "^[A-Za-z0-9._-]+$",
|
|
818
|
+
},
|
|
819
|
+
authToken: {
|
|
820
|
+
type: "string",
|
|
821
|
+
description: "Optional bearer token override for this call only.",
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
required: ["assetId"],
|
|
825
|
+
additionalProperties: false,
|
|
826
|
+
},
|
|
827
|
+
},
|
|
780
828
|
{
|
|
781
829
|
name: "flo_search",
|
|
782
830
|
description:
|
|
@@ -814,11 +862,16 @@ const tools = [
|
|
|
814
862
|
{
|
|
815
863
|
name: "flo_skill_routing",
|
|
816
864
|
description:
|
|
817
|
-
"
|
|
865
|
+
"List available actions for an asset (what can I do with this file?).",
|
|
818
866
|
inputSchema: {
|
|
819
867
|
type: "object",
|
|
820
868
|
properties: {
|
|
821
|
-
assetId: {
|
|
869
|
+
assetId: {
|
|
870
|
+
type: "string",
|
|
871
|
+
minLength: 1,
|
|
872
|
+
maxLength: 128,
|
|
873
|
+
pattern: "^[A-Za-z0-9._-]+$",
|
|
874
|
+
},
|
|
822
875
|
authToken: {
|
|
823
876
|
type: "string",
|
|
824
877
|
description: "Optional bearer token override for this call only.",
|
|
@@ -960,6 +1013,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
960
1013
|
oauthUserPoolName: oauth.userPoolName,
|
|
961
1014
|
oauthUserPoolId: oauth.userPoolId || null,
|
|
962
1015
|
oauthSettingsUrl: oauth.settingsUrl,
|
|
1016
|
+
appLoginUrl: oauth.appLoginUrl,
|
|
963
1017
|
envTokenConfigured: envToken,
|
|
964
1018
|
cachePath: getTokenCachePath(),
|
|
965
1019
|
cachedTokenPresent: Boolean(cachedToken?.access_token),
|
|
@@ -982,11 +1036,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
982
1036
|
oauthUserPoolName: oauth.userPoolName,
|
|
983
1037
|
oauthUserPoolId: oauth.userPoolId || null,
|
|
984
1038
|
oauthSettingsUrl: oauth.settingsUrl,
|
|
1039
|
+
appLoginUrl: oauth.appLoginUrl,
|
|
985
1040
|
message:
|
|
986
|
-
"
|
|
1041
|
+
"If hosted login UI appears, sign in at appLoginUrl first, then run flo_auth_login again. Open oauthSettingsUrl to copy client id for oauthExpectedClientName into FLO_OAUTH_CLIENT_ID.",
|
|
987
1042
|
});
|
|
988
1043
|
}
|
|
989
1044
|
|
|
1045
|
+
if (name === "flo_analyze") {
|
|
1046
|
+
const assetId = requireAssetId(args.assetId, "assetId");
|
|
1047
|
+
const prompt = `/flo:analyze-image ${assetId}`;
|
|
1048
|
+
const bodyText = await invokeInterfaceAgent(prompt, args.authToken);
|
|
1049
|
+
return asTextResult(parseMaybeJson(bodyText) || bodyText);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
990
1052
|
if (name === "flo_auth_logout") {
|
|
991
1053
|
await clearCachedToken();
|
|
992
1054
|
return asTextResult({
|
|
@@ -1011,7 +1073,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1011
1073
|
}
|
|
1012
1074
|
|
|
1013
1075
|
if (name === "flo_skill_routing") {
|
|
1014
|
-
const assetId =
|
|
1076
|
+
const assetId = requireAssetId(args.assetId, "assetId");
|
|
1015
1077
|
const prompt = `/flo:skill-routing ${assetId}`;
|
|
1016
1078
|
const bodyText = await invokeInterfaceAgent(prompt, args.authToken);
|
|
1017
1079
|
return asTextResult(parseMaybeJson(bodyText) || bodyText);
|