@oisincoveney/pipeline 1.8.0 → 1.8.1

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/README.md CHANGED
@@ -37,11 +37,17 @@ Momokaya remote endpoint
37
37
 
38
38
  The default GitHub MCP registration uses GitHub's official container in
39
39
  read-only mode and reads `GITHUB_PERSONAL_ACCESS_TOKEN` from the environment.
40
- The Momokaya Qdrant endpoint is protected by Traefik HTTP Basic auth. Set either
41
- `MOMOKAYA_MCP_AUTHORIZATION` to the complete Authorization header value
42
- (`Basic <base64-user-colon-password>`) or `MEMORY_MCP_BASIC_AUTH` to only the
43
- base64 payload. `pipe init` resolves that value before registering the remote
44
- server with MCPM.
40
+ The Momokaya Qdrant endpoint is protected by Traefik HTTP Basic auth. Set
41
+ `MEMORY_MCP_BASIC_AUTH` to the base64 `user:password` payload before running
42
+ `pipe init` if you want init to register that remote server with MCPM:
43
+
44
+ ```shell
45
+ export MEMORY_MCP_BASIC_AUTH="$(printf '%s' 'user:password' | base64)"
46
+ ```
47
+
48
+ When `MEMORY_MCP_BASIC_AUTH` is not set, `pipe init` still writes the default
49
+ scaffold and keeps the generated `qdrant` MCP entry, but skips immediate MCPM
50
+ registration for that private endpoint.
45
51
 
46
52
  Check local prerequisites and config health:
47
53
 
@@ -78,12 +78,10 @@
78
78
  "name": "oisin-pipeline-qdrant",
79
79
  "transport": "remote",
80
80
  "url": "https://memory-mcp.momokaya.ee/mcp/",
81
+ "optionalRegistration": true,
81
82
  "headers": {
82
83
  "Authorization": {
83
- "sources": [
84
- { "env": "MOMOKAYA_MCP_AUTHORIZATION" },
85
- { "env": "MEMORY_MCP_BASIC_AUTH", "prefix": "Basic " }
86
- ]
84
+ "sources": [{ "env": "MEMORY_MCP_BASIC_AUTH", "prefix": "Basic " }]
87
85
  }
88
86
  }
89
87
  },
@@ -29,6 +29,18 @@ var PipelineMcpInstallError = class extends Error {
29
29
  this.name = "PipelineMcpInstallError";
30
30
  }
31
31
  };
32
+ var PipelineMcpMissingCredentialError = class extends PipelineMcpInstallError {
33
+ headerName;
34
+ missingEnv;
35
+ serverName;
36
+ constructor(serverName, headerName, missingEnv) {
37
+ super([`MCP server ${serverName} requires ${headerName} credentials before it can be registered.`, `Set ${missingEnv.join(" or ")} and re-run pipeline init.`].join("\n"));
38
+ this.name = "PipelineMcpMissingCredentialError";
39
+ this.serverName = serverName;
40
+ this.headerName = headerName;
41
+ this.missingEnv = missingEnv;
42
+ }
43
+ };
32
44
  var PipelineDefaultManifestError = class extends Error {
33
45
  constructor(message) {
34
46
  super(message);
@@ -58,6 +70,7 @@ const pipelineMcpInstallSpecSchema = z.object({
58
70
  env: z.record(z.string(), z.string()).optional(),
59
71
  headers: z.record(z.string(), pipelineMcpHeaderValueSchema).optional(),
60
72
  name: z.string().min(1),
73
+ optionalRegistration: z.boolean().optional(),
61
74
  transport: z.enum(["remote", "stdio"]),
62
75
  url: z.string().url().optional()
63
76
  }).strict().superRefine((spec, ctx) => {
@@ -824,8 +837,13 @@ async function installDefaultSkillsWithCli(specs, cwd) {
824
837
  }
825
838
  }
826
839
  async function installDefaultMcpsWithCli(specs, cwd) {
840
+ const skipped = [];
827
841
  for (const spec of specs) {
828
842
  const install = mcpInstallArgs(spec);
843
+ if ("skipped" in install) {
844
+ skipped.push(install.skipped);
845
+ continue;
846
+ }
829
847
  try {
830
848
  await execa("uvx", [...DEFAULT_MCPM_ARGS, ...install.args], {
831
849
  cwd,
@@ -848,6 +866,7 @@ async function installDefaultMcpsWithCli(specs, cwd) {
848
866
  ].filter(Boolean).join("\n"));
849
867
  }
850
868
  }
869
+ return { skipped };
851
870
  }
852
871
  function mcpInstallArgs(spec) {
853
872
  if (spec.catalog) return {
@@ -870,19 +889,29 @@ function mcpInstallArgs(spec) {
870
889
  if (spec.transport === "remote") {
871
890
  if (!spec.url) throw new PipelineMcpInstallError(`MCP server ${spec.name} is remote but has no url.`);
872
891
  const redactions = [];
873
- return {
874
- args: [
875
- ...args,
876
- "--url",
877
- spec.url,
878
- ...Object.entries(spec.headers ?? {}).flatMap(([key, value]) => {
879
- const headerValue = resolveMcpHeaderValue(spec.name, key, value);
880
- redactions.push(headerValue);
881
- return ["--headers", `${key}=${headerValue}`];
882
- })
883
- ],
884
- redactions
885
- };
892
+ try {
893
+ const headers = Object.entries(spec.headers ?? {}).flatMap(([key, value]) => {
894
+ const headerValue = resolveMcpHeaderValue(spec.name, key, value);
895
+ redactions.push(headerValue);
896
+ return ["--headers", `${key}=${headerValue}`];
897
+ });
898
+ return {
899
+ args: [
900
+ ...args,
901
+ "--url",
902
+ spec.url,
903
+ ...headers
904
+ ],
905
+ redactions
906
+ };
907
+ } catch (err) {
908
+ if (spec.optionalRegistration && err instanceof PipelineMcpMissingCredentialError) return { skipped: {
909
+ missingEnv: err.missingEnv,
910
+ name: spec.name,
911
+ reason: `missing ${err.headerName} credentials`
912
+ } };
913
+ throw err;
914
+ }
886
915
  }
887
916
  if (!spec.command) throw new PipelineMcpInstallError(`MCP server ${spec.name} is stdio but has no command.`);
888
917
  return {
@@ -914,8 +943,7 @@ function resolveMcpHeaderValue(serverName, headerName, header) {
914
943
  const rawValue = process.env[source.env];
915
944
  if (rawValue && rawValue.trim().length > 0) return `${source.prefix ?? ""}${rawValue}${source.suffix ?? ""}`;
916
945
  }
917
- const envNames = header.sources.map((source) => source.env).join(" or ");
918
- throw new PipelineMcpInstallError([`MCP server ${serverName} requires ${headerName} credentials before it can be registered.`, `Set ${envNames} and re-run pipeline init.`].join("\n"));
946
+ throw new PipelineMcpMissingCredentialError(serverName, headerName, header.sources.map((source) => source.env));
919
947
  }
920
948
  function assertDefaultSkillsInstalled(cwd) {
921
949
  const paths = defaultSkillPaths();
@@ -935,7 +963,7 @@ async function initPipelineProject(options = {}) {
935
963
  const paths = Object.keys(files);
936
964
  const conflicts = paths.filter((path) => existsSync(join(cwd, path)));
937
965
  if (conflicts.length > 0 && !options.overwrite) throw new PipelineInitError(conflicts);
938
- await (options.mcpInstaller ?? installDefaultMcpsWithCli)(DEFAULT_MCP_INSTALLS, cwd);
966
+ const mcpInstallResult = await (options.mcpInstaller ?? installDefaultMcpsWithCli)(DEFAULT_MCP_INSTALLS, cwd);
939
967
  await (options.skillInstaller ?? installDefaultSkillsWithCli)(DEFAULT_SKILL_INSTALLS, cwd);
940
968
  const skillPaths = assertDefaultSkillsInstalled(cwd);
941
969
  for (const [path, content] of Object.entries(files)) {
@@ -949,10 +977,18 @@ async function initPipelineProject(options = {}) {
949
977
  ...existsSync(join(cwd, "skills-lock.json")) ? ["skills-lock.json"] : []
950
978
  ];
951
979
  loadPipelineConfig(cwd);
952
- return { files: generatedPaths };
980
+ return {
981
+ files: generatedPaths,
982
+ skippedMcps: mcpInstallResult?.skipped ?? []
983
+ };
953
984
  }
954
985
  function formatPipelineInitResult(result) {
955
- return ["Initialized pipeline scaffold:", ...result.files.map((path) => `create ${path}`)].join("\n");
986
+ const skippedMcps = result.skippedMcps ?? [];
987
+ return [
988
+ "Initialized pipeline scaffold:",
989
+ ...result.files.map((path) => `create ${path}`),
990
+ ...skippedMcps.flatMap((skip) => [`Skipped MCPM registration for ${skip.name}: ${skip.reason}.`, `Set ${skip.missingEnv.join(" or ")} before retrying MCPM registration. The generated MCP entry remains in .mcp.json.`])
991
+ ].join("\n");
956
992
  }
957
993
  function hostResourceInput(host) {
958
994
  return [
package/package.json CHANGED
@@ -82,7 +82,7 @@
82
82
  "prepack": "bun run build:cli"
83
83
  },
84
84
  "type": "module",
85
- "version": "1.8.0",
85
+ "version": "1.8.1",
86
86
  "description": "Config-driven multi-agent pipeline runner for repository work",
87
87
  "main": "./dist/index.js",
88
88
  "types": "./dist/index.d.ts",