@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.
@@ -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, t as i } from "./org-DsA8PUrd.js";
2
- import { serveStdio as a } from "@modelcontextprotocol/server/stdio";
3
- //#region src/cli.ts
4
- async function o() {
5
- let o = n(), s = new e(o);
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 s.request("GET", "/api/v1/me");
29
+ await n.request("GET", "/api/v1/me");
8
30
  } catch (e) {
9
- throw e instanceof t && e.status === 401 ? Error("FEATUREFLIP_TOKEN was rejected (401). Check the token in the Featureflip dashboard (Settings → API Tokens).") : e instanceof t && 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;
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
- let c = await i(s, o.org);
12
- a(() => r({
13
- api: s,
14
- org: c
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
- o().catch((e) => {
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
@@ -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,CAY3F"}
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, i as t, n, o as r, r as i, t as a } from "./org-DsA8PUrd.js";
2
- export { t as ApiError, e as FeatureflipApi, r as PKG_VERSION, i as createServer, n as loadConfig, a as resolveOrg };
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.4",
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.0.0"
35
+ zod: "^4.6.2"
35
36
  },
36
37
  devDependencies: {
37
38
  "@modelcontextprotocol/client": "2.0.0",
38
- "@types/node": "^26.2.0",
39
+ "@typescript/typescript6": "^6.0.2",
40
+ "@types/node": "^26.5.1",
39
41
  typescript: "^7.0.2",
40
- vite: "^8.2.2",
41
- "vite-plugin-dts": "^5.0.3",
42
- vitest: "^4.1.11"
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
- !a && !o || d.push({
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
- function j(e = process.env) {
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
- if (!t) throw Error("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
- 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 M(e, t) {
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, r as i, j as n, n as o, A as r, M as t };
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.4",
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.0.0"
40
+ "zod": "^4.6.2"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@modelcontextprotocol/client": "2.0.0",
43
- "@types/node": "^26.2.0",
44
+ "@typescript/typescript6": "^6.0.2",
45
+ "@types/node": "^26.5.1",
44
46
  "typescript": "^7.0.2",
45
- "vite": "^8.2.2",
46
- "vite-plugin-dts": "^5.0.3",
47
- "vitest": "^4.1.11"
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"