pipebrain-mcp 0.16.0 → 0.16.4

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.
Files changed (3) hide show
  1. package/README.md +14 -9
  2. package/dist/main.js +19 -13
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -9,16 +9,24 @@ This package is the **server only**. The command line tool is a separate package
9
9
 
10
10
  ## Install
11
11
 
12
- Register it with Claude Code (no install step — `npx` fetches it):
12
+ Register it with Claude Code (no install step — `npx` fetches it), at **user scope** so
13
+ every repo on the machine gets the tools:
13
14
 
14
15
  ```
15
- claude mcp add pipebrain -- npx -y pipebrain-mcp
16
+ claude mcp add pipebrain -s user -e PIPEBRAIN_API_URL=https://api.pipebrain.dev -e 'PIPEBRAIN_TOKEN=${PIPEBRAIN_TOKEN}' -- npx -y pipebrain-mcp@latest
16
17
  ```
17
18
 
18
- The server reads its configuration from the environment of the process that launches it,
19
- and refuses to start if either value is missing or malformed — including an unexpanded
20
- `${PIPEBRAIN_TOKEN}` placeholder, which is the failure that otherwise looks like a
21
- revoked token.
19
+ Both `-e` flags are required, not decoration. The server reads its configuration from the
20
+ environment of the process that launches it, and refuses to start if either value is
21
+ missing or malformed — including an unexpanded `${PIPEBRAIN_TOKEN}` placeholder, which is
22
+ the failure that otherwise looks like a revoked token. There is no default API URL (see
23
+ the table below), so a registration that passes neither flag produces a server that never
24
+ starts.
25
+
26
+ The single quotes around the token are load-bearing: they keep `${PIPEBRAIN_TOKEN}` a
27
+ literal *reference* in Claude's config instead of expanding it as you type, so the token
28
+ value itself never lands in a config file — the server resolves it from your environment
29
+ at each launch.
22
30
 
23
31
  ## Environment
24
32
 
@@ -27,9 +35,6 @@ revoked token.
27
35
  | `PIPEBRAIN_TOKEN` | Your `pbt_…` API token (Settings → Organization → API tokens). A pre-rename `plt_…` token still works. |
28
36
  | `PIPEBRAIN_API_URL` | API base URL, e.g. `https://api.pipebrain.dev`. Required — there is no default, so a session can always tell which environment it is bound to. |
29
37
 
30
- The pre-rename names `PIPELINE_TOKEN` and `PIPELINE_API_URL` are still honored as
31
- fallbacks, indefinitely. When both are set, `PIPEBRAIN_*` wins.
32
-
33
38
  Secret VALUES never cross this server: the secrets tools return metadata only, and there
34
39
  is deliberately no value-returning tool. Use `ppb secrets` (from `pipebrain-cli`) for the
35
40
  reveal plane.
package/dist/main.js CHANGED
@@ -16753,7 +16753,7 @@ ${general}`;
16753
16753
  }
16754
16754
 
16755
16755
  // ../../libs/mcp-server/dist/server.js
16756
- var SUCCESSOR_NOTICE = "NOTICE \u2014 this server is the FINAL release of the `@fvcsolutions/pipeline-mcp` package. The server moved to `pipebrain-mcp` on npmjs.org (public, no registry auth), and the CLI moved to `pipebrain-cli`, which provides the `ppb` command in place of `pipeline`. Re-register through the team bootstrap, or: `claude mcp add pipebrain -- npx -y pipebrain-mcp`. Tell the operator; this build still works and will not be updated again.\n\n";
16756
+ var SUCCESSOR_NOTICE = "NOTICE \u2014 this server is the FINAL release of the `@fvcsolutions/pipeline-mcp` package. The server moved to `pipebrain-mcp` on npmjs.org (public, no registry auth), and the CLI moved to `pipebrain-cli`, which provides the `ppb` command in place of `pipeline`. Re-register through the team bootstrap, or: `claude mcp add pipebrain -s user -e PIPEBRAIN_API_URL=https://api.pipebrain.dev -e 'PIPEBRAIN_TOKEN=${PIPEBRAIN_TOKEN}' -- npx -y pipebrain-mcp@latest`. Tell the operator; this build still works and will not be updated again.\n\n";
16757
16757
  function successorNotice() {
16758
16758
  const armed = process.env.PIPELINE_MCP_SUCCESSOR_NOTICE;
16759
16759
  return armed === void 0 || armed === "" ? "" : SUCCESSOR_NOTICE;
@@ -16809,6 +16809,7 @@ async function resolveDeliverableTargetId(client2, projectKey, ref) {
16809
16809
  return match.id;
16810
16810
  }
16811
16811
  function createMcpServer(client2, apiBaseUrl, orgInstructions2 = /* @__PURE__ */ new Map(), opts = {}) {
16812
+ const surface = opts.surface ?? "local";
16812
16813
  const server2 = new McpServer({ name: "pipebrain", version: opts.version ?? DEFAULT_VERSION }, {
16813
16814
  instructions: withGeneralInstructions(successorNotice() + `Pipebrain MCP server, bound to the ${apiBindingLabel(apiBaseUrl)} API at ${apiBaseUrl}. Every tool reads and writes THAT environment \u2014 confirm it is the one you intend (a local dev API vs production) before mutating. Tools are namespaced by this server's registration name in .mcp.json (e.g. pipebrain-local:* vs pipebrain:*).`, orgInstructions2)
16814
16815
  });
@@ -17077,21 +17078,23 @@ function createMcpServer(client2, apiBaseUrl, orgInstructions2 = /* @__PURE__ */
17077
17078
  }
17078
17079
  }, ({ deliverable, ...fields }) => run(() => client2.promoteDeliverable(deliverable, fields)));
17079
17080
  registerTool("list_assets", {
17080
- description: "List project assets (S3-backed files of any type) filtered by project, status (pending/active/rejected), category (image/video/document), and filename text, sorted by date or size (asc/desc): id, filename, contentType, size, sha256, status, hasThumbnail, and linkCount (live references). Metadata only \u2014 the bytes move by path (upload_asset/download_asset), never through this result.",
17081
+ description: "List project assets (S3-backed files of any type) filtered by project, status (pending/active/rejected), category (image/video/document), and filename text, sorted by date or size (asc/desc): id, filename, contentType, size, sha256, status, hasThumbnail, and linkCount (live references). Metadata only \u2014 the bytes move by path, never through this result.",
17081
17082
  inputSchema: listAssetsFilterSchema.shape
17082
17083
  }, (args) => run(() => client2.listAssets(args)));
17083
17084
  registerTool("get_asset", {
17084
- description: "Get an asset\u2019s metadata by uuid: filename, contentType, size, sha256 (client-computed, server-verified by read-back), status, hasThumbnail, linkCount (live references), and timestamps. Metadata only \u2014 no value/URL is returned over MCP; use download_asset to write the bytes to a local file.",
17085
+ description: "Get an asset\u2019s metadata by uuid: filename, contentType, size, sha256 (client-computed, server-verified by read-back), status, hasThumbnail, linkCount (live references), and timestamps. Metadata only \u2014 no value/URL is returned over MCP. To get the bytes, use download_asset (a LOCAL server only \u2014 it writes to a path on the machine running the server) or `ppb assets download`.",
17085
17086
  inputSchema: { asset: uuidSchema }
17086
17087
  }, (args) => run(() => client2.getAsset(args.asset)));
17087
- registerTool("upload_asset", {
17088
- description: "Upload a LOCAL FILE (by path) as a project asset and activate it: reads and SHA-256-hashes the file locally, registers the asset, PUTs the bytes directly to storage, and completes (server verifies the digest by read-back). Returns the asset metadata (status active on success). Only the file PATH crosses the wire \u2014 the bytes never do; do NOT pass base64 or file contents. contentType is guessed from the extension when omitted. Then use link_asset to attach the returned asset to a deliverable revision or a content draft.",
17089
- inputSchema: uploadAssetInputSchema.shape
17090
- }, (args) => run(() => uploadAssetFromPath(client2, apiBaseUrl, args)));
17091
- registerTool("download_asset", {
17092
- description: "Download an ACTIVE asset\u2019s bytes to a LOCAL FILE at `path` (created/overwritten), so you can read or view an uploaded image, mockup, or document. The bytes are written to disk and re-verified against the recorded sha256; the RESULT is metadata + the written path \u2014 never the bytes or a URL. Addressed by asset uuid (from list_assets, get_asset, or get_content).",
17093
- inputSchema: downloadAssetInputSchema.shape
17094
- }, (args) => run(() => downloadAssetToPath(client2, args)));
17088
+ if (surface === "local") {
17089
+ registerTool("upload_asset", {
17090
+ description: "Upload a LOCAL FILE (by path) as a project asset and activate it: reads and SHA-256-hashes the file locally, registers the asset, PUTs the bytes directly to storage, and completes (server verifies the digest by read-back). Returns the asset metadata (status active on success). Only the file PATH crosses the wire \u2014 the bytes never do; do NOT pass base64 or file contents. contentType is guessed from the extension when omitted. Then use link_asset to attach the returned asset to a deliverable revision or a content draft.",
17091
+ inputSchema: uploadAssetInputSchema.shape
17092
+ }, (args) => run(() => uploadAssetFromPath(client2, apiBaseUrl, args)));
17093
+ registerTool("download_asset", {
17094
+ description: "Download an ACTIVE asset\u2019s bytes to a LOCAL FILE at `path` (created/overwritten), so you can read or view an uploaded image, mockup, or document. The bytes are written to disk and re-verified against the recorded sha256; the RESULT is metadata + the written path \u2014 never the bytes or a URL. Addressed by asset uuid (from list_assets, get_asset, or get_content).",
17095
+ inputSchema: downloadAssetInputSchema.shape
17096
+ }, (args) => run(() => downloadAssetToPath(client2, args)));
17097
+ }
17095
17098
  registerTool("link_asset", {
17096
17099
  description: "Reference an active asset FROM a target. Two targets are wired: `deliverable_revision` (targetId is a content_deliverable_revision uuid, e.g. from get_content) and `content_draft` (targetId is a content_draft uuid \u2014 the asset attaches to the topic doc and is snapshot-copied onto deliverables when they are created). Rejects a non-active asset or a cross-project link.",
17097
17100
  inputSchema: linkAssetInputSchema.shape
@@ -17232,7 +17235,7 @@ function loadMcpConfig() {
17232
17235
  }
17233
17236
 
17234
17237
  // src/version.ts
17235
- var VERSION = "0.16.0";
17238
+ var VERSION = "0.16.4";
17236
17239
 
17237
17240
  // src/main.ts
17238
17241
  var config2 = loadMcpConfig();
@@ -17241,7 +17244,10 @@ var client = new ApiClient({
17241
17244
  auth: { bearer: config2.token }
17242
17245
  });
17243
17246
  var orgInstructions = await fetchOrgInstructionsSafe(client);
17244
- var server = createMcpServer(client, config2.apiUrl, orgInstructions, { version: VERSION });
17247
+ var server = createMcpServer(client, config2.apiUrl, orgInstructions, {
17248
+ version: VERSION,
17249
+ surface: "local"
17250
+ });
17245
17251
  var transport = new StdioServerTransport();
17246
17252
  await server.connect(transport);
17247
17253
  var notice = successorNotice();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pipebrain-mcp",
3
- "version": "0.16.0",
3
+ "version": "0.16.4",
4
4
  "description": "Pipebrain MCP server for Claude Code and Claude Desktop — issues, requirements, content, assets, and metadata-only secrets over the Pipebrain API.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -13,7 +13,7 @@
13
13
  ],
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/fvcsolutions/pipeline.git",
16
+ "url": "git+https://github.com/fvcsolutions/pipebrain.git",
17
17
  "directory": "apps/mcp"
18
18
  },
19
19
  "publishConfig": {
@@ -26,7 +26,7 @@
26
26
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
27
27
  "build": "node build.mjs",
28
28
  "build:mcpb": "nx build pipebrain-mcp && node mcpb/build-mcpb.mjs",
29
- "prepack": "npx nx build pipebrain-mcp"
29
+ "prepack": "npx nx build pipebrain-mcp && node ../../scripts/check-publishable.mjs"
30
30
  },
31
31
  "dependencies": {
32
32
  "@modelcontextprotocol/sdk": "1.29.0"