@featureflip/mcp 0.1.4 → 0.1.6
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/bootstrap.d.ts +12 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/cli.mjs +44 -13
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{org-DsA8PUrd.js → org-BixGfyQ6.js} +21 -14
- package/dist/unconfigured.d.ts +11 -0
- package/dist/unconfigured.d.ts.map +1 -0
- package/package.json +9 -7
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToolContext } from './tools/context.js';
|
|
2
|
+
/**
|
|
3
|
+
* Decides what the server serves before it starts.
|
|
4
|
+
*
|
|
5
|
+
* A configured token still preflights and still fails fast on a bad one — the
|
|
6
|
+
* startup error is unchanged. No token at all is a different situation: nobody
|
|
7
|
+
* has wired this up yet, and the caller may only be enumerating the tool surface,
|
|
8
|
+
* so we hand back a context that serves definitions and errors on use. Exiting
|
|
9
|
+
* there made the server indistinguishable from one with no tools.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveContext(env?: Record<string, string | undefined>, fetchImpl?: typeof fetch): Promise<ToolContext>;
|
|
12
|
+
//# sourceMappingURL=bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAyBtD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,EACrD,SAAS,CAAC,EAAE,OAAO,KAAK,GACvB,OAAO,CAAC,WAAW,CAAC,CAGtB"}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,20 +1,51 @@
|
|
|
1
|
-
import { a as e, i as t, n, r,
|
|
2
|
-
import { serveStdio as
|
|
3
|
-
//#region src/
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { a as e, i as t, n, o as r, s as i, t as a } from "./org-BixGfyQ6.js";
|
|
2
|
+
import { serveStdio as o } from "@modelcontextprotocol/server/stdio";
|
|
3
|
+
//#region src/unconfigured.ts
|
|
4
|
+
var s = class extends i {
|
|
5
|
+
constructor() {
|
|
6
|
+
super({
|
|
7
|
+
token: "",
|
|
8
|
+
baseUrl: "https://api.featureflip.io"
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
request() {
|
|
12
|
+
return Promise.reject(Error(n));
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
function c() {
|
|
16
|
+
return {
|
|
17
|
+
api: new s(),
|
|
18
|
+
org: ""
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/bootstrap.ts
|
|
23
|
+
async function l(e, t) {
|
|
24
|
+
let n = new i({
|
|
25
|
+
...e,
|
|
26
|
+
fetchImpl: t
|
|
27
|
+
});
|
|
6
28
|
try {
|
|
7
|
-
await
|
|
29
|
+
await n.request("GET", "/api/v1/me");
|
|
8
30
|
} catch (e) {
|
|
9
|
-
throw e instanceof
|
|
31
|
+
throw e instanceof r && e.status === 401 ? Error("FEATUREFLIP_TOKEN was rejected (401). Check the token in the Featureflip dashboard (Settings → API Tokens).") : e instanceof r && e.status === 404 ? Error("The public Management API returned 404 for /api/v1/me. This usually means the public API is not enabled for your organization yet — contact Featureflip support.") : e;
|
|
10
32
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
33
|
+
return {
|
|
34
|
+
api: n,
|
|
35
|
+
org: await a(n, e.org)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function u(e = process.env, n) {
|
|
39
|
+
let r = t(e);
|
|
40
|
+
return r ? l(r, n) : Promise.resolve(c());
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/cli.ts
|
|
44
|
+
async function d() {
|
|
45
|
+
let t = await u();
|
|
46
|
+
o(() => e(t));
|
|
16
47
|
}
|
|
17
|
-
|
|
48
|
+
d().catch((e) => {
|
|
18
49
|
console.error(`[featureflip-mcp] ${e instanceof Error ? e.message : String(e)}`), process.exit(1);
|
|
19
50
|
});
|
|
20
51
|
//#endregion
|
package/dist/config.d.ts
CHANGED
|
@@ -3,5 +3,12 @@ export interface McpConfig {
|
|
|
3
3
|
baseUrl: string;
|
|
4
4
|
org?: string;
|
|
5
5
|
}
|
|
6
|
+
export declare const MISSING_TOKEN_MESSAGE: string;
|
|
7
|
+
/**
|
|
8
|
+
* Returns null instead of throwing when no token is configured, so the server can
|
|
9
|
+
* still start and advertise its tool definitions to a client that is only
|
|
10
|
+
* inspecting the surface (registries, `tools/list` probes, first-run editors).
|
|
11
|
+
*/
|
|
12
|
+
export declare function tryLoadConfig(env?: Record<string, string | undefined>): McpConfig | null;
|
|
6
13
|
export declare function loadConfig(env?: Record<string, string | undefined>): McpConfig;
|
|
7
14
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,qBAAqB,QAGO,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,SAAS,GAAG,IAAI,CAMrG;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,SAAS,CAI3F"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as e,
|
|
2
|
-
export {
|
|
1
|
+
import { a as e, c as t, o as n, r, s as i, t as a } from "./org-BixGfyQ6.js";
|
|
2
|
+
export { n as ApiError, i as FeatureflipApi, t as PKG_VERSION, e as createServer, r as loadConfig, a as resolveOrg };
|
|
@@ -4,7 +4,7 @@ import * as t from "zod/v4";
|
|
|
4
4
|
//#region src/version.ts
|
|
5
5
|
var n = {
|
|
6
6
|
name: "@featureflip/mcp",
|
|
7
|
-
version: "0.1.
|
|
7
|
+
version: "0.1.6",
|
|
8
8
|
mcpName: "io.github.canopy-labs/featureflip",
|
|
9
9
|
description: "MCP server for managing Featureflip feature flags from AI agents and editors",
|
|
10
10
|
license: "Apache-2.0",
|
|
@@ -27,19 +27,21 @@ var n = {
|
|
|
27
27
|
typecheck: "tsc --noEmit -p tsconfig.json",
|
|
28
28
|
"generate:api": "npx --yes openapi-typescript@7.13.0 ../../apps/management-api/public-v1-openapi.json -o src/generated/api-types.ts",
|
|
29
29
|
test: "vitest run",
|
|
30
|
-
"test:watch": "vitest"
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"smoke:docker": "node scripts/docker-smoke.mjs"
|
|
31
32
|
},
|
|
32
33
|
dependencies: {
|
|
33
34
|
"@modelcontextprotocol/server": "2.0.0",
|
|
34
|
-
zod: "^4.
|
|
35
|
+
zod: "^4.6.2"
|
|
35
36
|
},
|
|
36
37
|
devDependencies: {
|
|
37
38
|
"@modelcontextprotocol/client": "2.0.0",
|
|
38
|
-
"@
|
|
39
|
+
"@typescript/typescript6": "^6.0.2",
|
|
40
|
+
"@types/node": "^26.5.1",
|
|
39
41
|
typescript: "^7.0.2",
|
|
40
|
-
vite: "^8.
|
|
41
|
-
"vite-plugin-dts": "^5.0
|
|
42
|
-
vitest: "^
|
|
42
|
+
vite: "^8.3.0",
|
|
43
|
+
"vite-plugin-dts": "^5.1.0",
|
|
44
|
+
vitest: "^5.0.0"
|
|
43
45
|
},
|
|
44
46
|
engines: { node: ">=20.19.0" }
|
|
45
47
|
}.version, r = class extends Error {
|
|
@@ -460,7 +462,7 @@ function S(e, n) {
|
|
|
460
462
|
let t = await n.api.request("GET", `${r}/${i(e.key)}/environments`);
|
|
461
463
|
if (t.length === 0) continue;
|
|
462
464
|
let a = t.every((e) => e.isEnabled), o = t.every((e) => !e.isEnabled);
|
|
463
|
-
|
|
465
|
+
(a || o) && d.push({
|
|
464
466
|
key: e.key,
|
|
465
467
|
name: e.name,
|
|
466
468
|
updatedAt: e.updatedAt,
|
|
@@ -704,18 +706,23 @@ function A(t) {
|
|
|
704
706
|
}
|
|
705
707
|
//#endregion
|
|
706
708
|
//#region src/config.ts
|
|
707
|
-
|
|
709
|
+
var j = "FEATUREFLIP_TOKEN is required. Create one in the Featureflip dashboard — Settings → API Tokens (personal token, ffp_...) or Organization Settings → Service Tokens (ffs_...) — and set it in your MCP client config.";
|
|
710
|
+
function M(e = process.env) {
|
|
708
711
|
let t = e.FEATUREFLIP_TOKEN?.trim();
|
|
709
|
-
|
|
710
|
-
return {
|
|
712
|
+
return t ? {
|
|
711
713
|
token: t,
|
|
712
714
|
baseUrl: (e.FEATUREFLIP_API_URL?.trim() || "https://api.featureflip.io").replace(/\/+$/, ""),
|
|
713
715
|
org: e.FEATUREFLIP_ORG?.trim() || void 0
|
|
714
|
-
};
|
|
716
|
+
} : null;
|
|
717
|
+
}
|
|
718
|
+
function N(e = process.env) {
|
|
719
|
+
let t = M(e);
|
|
720
|
+
if (!t) throw Error(j);
|
|
721
|
+
return t;
|
|
715
722
|
}
|
|
716
723
|
//#endregion
|
|
717
724
|
//#region src/org.ts
|
|
718
|
-
async function
|
|
725
|
+
async function P(e, t) {
|
|
719
726
|
if (t) return t;
|
|
720
727
|
let n = (await e.request("GET", "/api/v1/orgs", { query: { limit: 100 } })).items ?? [];
|
|
721
728
|
if (n.length === 1) {
|
|
@@ -726,4 +733,4 @@ async function M(e, t) {
|
|
|
726
733
|
throw n.length === 0 ? Error("The token can see no organizations. Check the token in the Featureflip dashboard.") : Error(`The token can see ${n.length} organizations — set FEATUREFLIP_ORG to one of: ` + n.map((e) => e.slug ?? "?").join(", "));
|
|
727
734
|
}
|
|
728
735
|
//#endregion
|
|
729
|
-
export { a,
|
|
736
|
+
export { A as a, n as c, M as i, j as n, r as o, N as r, a as s, P as t };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ToolContext } from './tools/context.js';
|
|
2
|
+
/**
|
|
3
|
+
* A context that serves tool *definitions* but no data.
|
|
4
|
+
*
|
|
5
|
+
* `tools/list` is how a client discovers what this server can do, and registries
|
|
6
|
+
* (Glama among them) enumerate it before anyone has wired a token. Exiting at
|
|
7
|
+
* startup made the server look like it had no tools at all — so with no token we
|
|
8
|
+
* start anyway and fail at call time instead.
|
|
9
|
+
*/
|
|
10
|
+
export declare function unconfiguredContext(): ToolContext;
|
|
11
|
+
//# sourceMappingURL=unconfigured.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unconfigured.d.ts","sourceRoot":"","sources":["../src/unconfigured.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAkBtD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,CAEjD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featureflip/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"mcpName": "io.github.canopy-labs/featureflip",
|
|
5
5
|
"description": "MCP server for managing Featureflip feature flags from AI agents and editors",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,19 +32,21 @@
|
|
|
32
32
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
33
33
|
"generate:api": "npx --yes openapi-typescript@7.13.0 ../../apps/management-api/public-v1-openapi.json -o src/generated/api-types.ts",
|
|
34
34
|
"test": "vitest run",
|
|
35
|
-
"test:watch": "vitest"
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"smoke:docker": "node scripts/docker-smoke.mjs"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@modelcontextprotocol/server": "2.0.0",
|
|
39
|
-
"zod": "^4.
|
|
40
|
+
"zod": "^4.6.2"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"@modelcontextprotocol/client": "2.0.0",
|
|
43
|
-
"@
|
|
44
|
+
"@typescript/typescript6": "^6.0.2",
|
|
45
|
+
"@types/node": "^26.5.1",
|
|
44
46
|
"typescript": "^7.0.2",
|
|
45
|
-
"vite": "^8.
|
|
46
|
-
"vite-plugin-dts": "^5.0
|
|
47
|
-
"vitest": "^
|
|
47
|
+
"vite": "^8.3.0",
|
|
48
|
+
"vite-plugin-dts": "^5.1.0",
|
|
49
|
+
"vitest": "^5.0.0"
|
|
48
50
|
},
|
|
49
51
|
"engines": {
|
|
50
52
|
"node": ">=20.19.0"
|