@firfi/huly-mcp 0.49.6 → 0.49.7

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 +12 -0
  2. package/dist/index.cjs +102 -58
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -209,6 +209,18 @@ The `@latest` tag asks the package runner for the newest version. Some MCP clien
209
209
  | **Pi** | Run `/mcp reconnect huly`, then `/reload` if the registered direct-tool surface changed |
210
210
  | **npx (manual)** | `npx -y @firfi/huly-mcp@latest` — the `-y` flag auto-confirms install prompts |
211
211
 
212
+ ## Maintainer Production Release
213
+
214
+ Publish from a clean, current `master` checkout with the preferred certified Node.js runtime:
215
+
216
+ ```bash
217
+ mise exec node@24.15.0 -- pnpm local-release
218
+ ```
219
+
220
+ Use this exact command even when a newer Node.js version is active on the host. The release build accepts only the
221
+ exact Node.js versions certified by CI; this is intentionally narrower than the package's runtime requirement. See
222
+ the [production release guide](docs/NPM_PRODUCTION_RELEASE.md) for preflight checks, rerun behavior, and verification.
223
+
212
224
  ## HTTP Transport
213
225
 
214
226
  By default, the server uses stdio transport. For HTTP transport:
package/dist/index.cjs CHANGED
@@ -125061,7 +125061,7 @@ var init_unavailable_diagnostics = __esm({
125061
125061
  });
125062
125062
 
125063
125063
  // src/huly/errors-base.ts
125064
- var HulyError, NoUpdateFieldsError, HulyConnectionError, HulyDataInvalidError, HulyUnavailableError, HulyAuthError, HulyModelNameSchema, HulyModelFieldSchema, HulyModelMetadataError;
125064
+ var HulyError, NoUpdateFieldsError, HulyConnectionOperation, HulyHttpStatus, HulyConnectionDiagnostic, HulyConnectionError, HTTP_ERROR_STATUS_PATTERN, hulyHttpStatusFromCause, makeOperationConnectionError, HulyDataInvalidError, HulyUnavailableError, HulyAuthError, HulyModelNameSchema, HulyModelFieldSchema, HulyModelMetadataError;
125065
125065
  var init_errors_base = __esm({
125066
125066
  "src/huly/errors-base.ts"() {
125067
125067
  "use strict";
@@ -125080,11 +125080,67 @@ var init_errors_base = __esm({
125080
125080
  return `${this.operation} requires at least one update field: ${this.fields.join(", ")}`;
125081
125081
  }
125082
125082
  };
125083
+ HulyConnectionOperation = Schema_exports.Literals([
125084
+ "findAll",
125085
+ "findOne",
125086
+ "findAllInModel",
125087
+ "createDoc",
125088
+ "conditionalCreateDoc",
125089
+ "updateDoc",
125090
+ "conditionalUpdateDoc",
125091
+ "addCollection",
125092
+ "updateCollection",
125093
+ "removeCollection",
125094
+ "removeDoc",
125095
+ "conditionalRemoveDoc",
125096
+ "createMixin",
125097
+ "updateMixin",
125098
+ "uploadMarkup",
125099
+ "fetchMarkup",
125100
+ "updateMarkup",
125101
+ "searchFulltext",
125102
+ "getWorkspaceMembers",
125103
+ "getPersonInfo",
125104
+ "updateWorkspaceRole",
125105
+ "getWorkspaceInfo",
125106
+ "getUserWorkspaces",
125107
+ "createWorkspace",
125108
+ "deleteWorkspace",
125109
+ "getUserProfile",
125110
+ "setMyProfile",
125111
+ "createAccessLink",
125112
+ "updateAllowReadOnlyGuests",
125113
+ "updateAllowGuestSignUp",
125114
+ "getRegionInfo"
125115
+ ]);
125116
+ HulyHttpStatus = Schema_exports.Int.check(Schema_exports.isBetween({ minimum: 100, maximum: 599 })).pipe(
125117
+ Schema_exports.brand("HulyHttpStatus")
125118
+ );
125119
+ HulyConnectionDiagnostic = Schema_exports.Struct({
125120
+ operation: HulyConnectionOperation,
125121
+ httpStatus: Schema_exports.optionalKey(HulyHttpStatus)
125122
+ });
125083
125123
  HulyConnectionError = class extends Schema_exports.TaggedError()("HulyConnectionError", {
125084
125124
  message: Schema_exports.String,
125085
- cause: Schema_exports.optional(Schema_exports.Defect())
125125
+ cause: Schema_exports.optional(Schema_exports.Defect()),
125126
+ diagnostic: Schema_exports.optionalKey(HulyConnectionDiagnostic)
125086
125127
  }) {
125087
125128
  };
125129
+ HTTP_ERROR_STATUS_PATTERN = /\bHTTP(?: error)?\s+(?<status>[1-5]\d{2})\b/i;
125130
+ hulyHttpStatusFromCause = (cause) => {
125131
+ if (!(cause instanceof Error)) return void 0;
125132
+ const statusText = HTTP_ERROR_STATUS_PATTERN.exec(cause.message)?.groups?.status;
125133
+ if (statusText === void 0) return void 0;
125134
+ return HulyHttpStatus.make(Number(statusText));
125135
+ };
125136
+ makeOperationConnectionError = (operation, cause) => {
125137
+ const httpStatus = hulyHttpStatusFromCause(cause);
125138
+ const message = `${operation} failed${httpStatus === void 0 ? "" : ` with HTTP ${httpStatus}`}`;
125139
+ return new HulyConnectionError({
125140
+ message,
125141
+ diagnostic: { operation, ...httpStatus === void 0 ? {} : { httpStatus } }
125142
+ });
125143
+ };
125088
125144
  HulyDataInvalidError = class extends Schema_exports.TaggedError()("HulyDataInvalidError", {
125089
125145
  operation: Schema_exports.String,
125090
125146
  entity: Schema_exports.String,
@@ -125144,7 +125200,7 @@ var VERSION;
125144
125200
  var init_version = __esm({
125145
125201
  "src/version.ts"() {
125146
125202
  "use strict";
125147
- VERSION = true ? "0.49.6" : "0.0.0-dev";
125203
+ VERSION = true ? "0.49.7" : "0.0.0-dev";
125148
125204
  }
125149
125205
  });
125150
125206
 
@@ -128260,7 +128316,7 @@ var init_tool_responses = __esm({
128260
128316
  });
128261
128317
 
128262
128318
  // src/mcp/error-mapping.ts
128263
- var INVALID_PARAMS_TAGS, INTERNAL_ERROR_PREFIX, hulyUnavailableMessage, mapDomainErrorToMcp, isClientResolutionError, clientResolutionFailure, mapClientResolutionErrorToMcp, mapClientResolutionCauseToMcp, clientResolutionErrorMessage, clientResolutionCauseMessage, mapParseErrorToMcp, mapParseCauseToMcp, mapDomainCauseToMcp;
128319
+ var INVALID_PARAMS_TAGS, INTERNAL_ERROR_PREFIX, CONNECTION_ERROR_GUIDANCE, hulyConnectionMessage, hulyUnavailableMessage, mapDomainErrorToMcp, isClientResolutionError, clientResolutionFailure, redactResolutionDetail, mapClientResolutionErrorToMcp, mapClientResolutionCauseToMcp, clientResolutionErrorMessage, clientResolutionCauseMessage, mapParseErrorToMcp, mapParseCauseToMcp, mapDomainCauseToMcp;
128264
128320
  var init_error_mapping = __esm({
128265
128321
  "src/mcp/error-mapping.ts"() {
128266
128322
  "use strict";
@@ -128472,9 +128528,13 @@ var init_error_mapping = __esm({
128472
128528
  INTERNAL_ERROR_PREFIX = {
128473
128529
  FileUploadError: "File upload error",
128474
128530
  HulyStorageConfigError: "Storage configuration error",
128475
- HulyConnectionError: "Connection error",
128476
128531
  HulyAuthError: "Authentication error"
128477
128532
  };
128533
+ CONNECTION_ERROR_GUIDANCE = "Verify HULY_URL, workspace, and network connectivity before retrying.";
128534
+ hulyConnectionMessage = (error3) => {
128535
+ const diagnostic = error3.diagnostic;
128536
+ return diagnostic === void 0 ? `Connection error while communicating with Huly. ${CONNECTION_ERROR_GUIDANCE}` : `Connection error while communicating with Huly: ${diagnostic.operation} failed${diagnostic.httpStatus === void 0 ? "" : ` with HTTP ${diagnostic.httpStatus}`}. ${CONNECTION_ERROR_GUIDANCE}`;
128537
+ };
128478
128538
  hulyUnavailableMessage = (error3) => {
128479
128539
  const failureGuidance = error3.failureKind === "timeout" ? " The request timed out; verify HULY_CONNECTION_TIMEOUT before retrying." : error3.failureKind === "dns" || error3.failureKind === "tls" ? " Verify the hostname, certificate, DNS, and proxy configuration before retrying." : "";
128480
128540
  if (isDefaultHulyCloudOrigin(error3.endpointOrigin)) {
@@ -128487,12 +128547,7 @@ var init_error_mapping = __esm({
128487
128547
  return createErrorResponse(hulyUnavailableMessage(error3), McpErrorCode.InternalError, error3._tag, warnings);
128488
128548
  }
128489
128549
  if (error3 instanceof HulyConnectionError) {
128490
- return createErrorResponse(
128491
- "Connection error while communicating with Huly. Verify HULY_URL, workspace, and network connectivity before retrying.",
128492
- McpErrorCode.InternalError,
128493
- error3._tag,
128494
- warnings
128495
- );
128550
+ return createErrorResponse(hulyConnectionMessage(error3), McpErrorCode.InternalError, error3._tag, warnings);
128496
128551
  }
128497
128552
  if (INVALID_PARAMS_TAGS.has(error3._tag)) {
128498
128553
  return createErrorResponse(error3.message, McpErrorCode.InvalidParams, error3._tag, warnings);
@@ -128507,9 +128562,10 @@ var init_error_mapping = __esm({
128507
128562
  if (!Cause_exports.isCause(error3)) return void 0;
128508
128563
  return findRecoverableCauseFailure(error3, isClientResolutionError);
128509
128564
  };
128565
+ redactResolutionDetail = (failure) => failure instanceof HulyConnectionError ? new HulyConnectionError({ message: "" }) : failure;
128510
128566
  mapClientResolutionErrorToMcp = (error3) => {
128511
128567
  const failure = clientResolutionFailure(error3);
128512
- return failure === void 0 ? mapDomainErrorToMcp(new HulyError({ message: "Failed to initialize Huly clients" })) : mapDomainErrorToMcp(failure);
128568
+ return failure === void 0 ? mapDomainErrorToMcp(new HulyError({ message: "Failed to initialize Huly clients" })) : mapDomainErrorToMcp(redactResolutionDetail(failure));
128513
128569
  };
128514
128570
  mapClientResolutionCauseToMcp = (cause) => mapClientResolutionErrorToMcp(cause);
128515
128571
  clientResolutionErrorMessage = (error3) => mapClientResolutionErrorToMcp(error3).content[0].text;
@@ -178671,39 +178727,36 @@ var init_client = __esm({
178671
178727
  );
178672
178728
  const markupUrlConfig = { refUrl: UrlString.make(refUrl), imageUrl: UrlString.make(imageUrl) };
178673
178729
  const workbenchUrlConfig = { baseUrl: UrlString.make(config2.url), workspaceUrlSlug };
178674
- const withClient = (op, errorMsg) => Effect_exports.tryPromise({
178675
- try: () => op(client),
178676
- catch: (e) => new HulyConnectionError({ message: `${errorMsg}: ${String(e)}`, cause: e })
178677
- });
178730
+ const withClient = (op, operation) => Effect_exports.tryPromise({ try: () => op(client), catch: (error3) => makeOperationConnectionError(operation, error3) });
178678
178731
  const operations = {
178679
178732
  getAccountUuid: () => accountUuid,
178680
178733
  getPrimarySocialId: () => primarySocialId,
178681
178734
  getSocialIds: () => socialIds,
178682
178735
  workbenchUrlConfig,
178683
178736
  markupUrlConfig,
178684
- findAll: (_class, query, options) => withClient((client2) => client2.findAll(_class, query, options), "findAll failed"),
178685
- findOne: (_class, query, options) => withClient((client2) => client2.findOne(_class, query, options), "findOne failed"),
178737
+ findAll: (_class, query, options) => withClient((client2) => client2.findAll(_class, query, options), "findAll"),
178738
+ findOne: (_class, query, options) => withClient((client2) => client2.findOne(_class, query, options), "findOne"),
178686
178739
  findAllInModel: (_class, query, options) => withClient(
178687
178740
  (client2) => Promise.resolve(client2.getModel().findAllSync(_class, query, options)),
178688
- "findAllInModel failed"
178741
+ "findAllInModel"
178689
178742
  ),
178690
- createDoc: (_class, space, attributes, id2) => withClient((client2) => client2.createDoc(_class, space, attributes, id2), "createDoc failed"),
178743
+ createDoc: (_class, space, attributes, id2) => withClient((client2) => client2.createDoc(_class, space, attributes, id2), "createDoc"),
178691
178744
  createDocIfNotMatched: (_class, space, attributes, id2, matchClass, matchQuery, scope3) => withClient(async (client2) => {
178692
178745
  const apply2 = client2.apply(scope3);
178693
178746
  apply2.notMatch(matchClass, matchQuery);
178694
178747
  await apply2.createDoc(_class, space, attributes, id2);
178695
178748
  return (await apply2.commit()).result ? "applied" : "condition-not-met";
178696
- }, "conditional createDoc failed"),
178697
- updateDoc: (_class, space, objectId, ops, retrieve) => withClient((client2) => client2.updateDoc(_class, space, objectId, ops, retrieve), "updateDoc failed"),
178749
+ }, "conditionalCreateDoc"),
178750
+ updateDoc: (_class, space, objectId, ops, retrieve) => withClient((client2) => client2.updateDoc(_class, space, objectId, ops, retrieve), "updateDoc"),
178698
178751
  updateDocIfMatched: (_class, space, objectId, matchQuery, operations2, scope3) => withClient(async (client2) => {
178699
178752
  const apply2 = client2.apply(scope3);
178700
178753
  apply2.match(_class, matchQuery);
178701
178754
  await apply2.updateDoc(_class, space, objectId, operations2);
178702
178755
  return (await apply2.commit()).result ? "applied" : "condition-not-met";
178703
- }, "conditional updateDoc failed"),
178756
+ }, "conditionalUpdateDoc"),
178704
178757
  addCollection: (_class, space, attachedTo, attachedToClass, collection, attributes, id2) => withClient(
178705
178758
  (client2) => client2.addCollection(_class, space, attachedTo, attachedToClass, collection, attributes, id2),
178706
- "addCollection failed"
178759
+ "addCollection"
178707
178760
  ),
178708
178761
  updateCollection: (_class, space, objectId, attachedTo, attachedToClass, collection, operations2, retrieve) => withClient(
178709
178762
  (client2) => client2.updateCollection(
@@ -178716,40 +178769,40 @@ var init_client = __esm({
178716
178769
  operations2,
178717
178770
  retrieve
178718
178771
  ),
178719
- "updateCollection failed"
178772
+ "updateCollection"
178720
178773
  ),
178721
178774
  removeCollection: (_class, space, objectId, attachedTo, attachedToClass, collection) => withClient(
178722
178775
  (client2) => client2.removeCollection(_class, space, objectId, attachedTo, attachedToClass, collection),
178723
- "removeCollection failed"
178776
+ "removeCollection"
178724
178777
  ),
178725
- removeDoc: (_class, space, objectId) => withClient((client2) => client2.removeDoc(_class, space, objectId), "removeDoc failed"),
178778
+ removeDoc: (_class, space, objectId) => withClient((client2) => client2.removeDoc(_class, space, objectId), "removeDoc"),
178726
178779
  removeDocIfMatched: (_class, space, objectId, matchQuery, scope3) => withClient(async (client2) => {
178727
178780
  const apply2 = client2.apply(scope3);
178728
178781
  apply2.match(_class, matchQuery);
178729
178782
  await apply2.removeDoc(_class, space, objectId);
178730
178783
  return (await apply2.commit()).result ? "applied" : "condition-not-met";
178731
- }, "conditional removeDoc failed"),
178784
+ }, "conditionalRemoveDoc"),
178732
178785
  createMixin: (objectId, objectClass, objectSpace, mixin, attributes) => withClient(
178733
178786
  (client2) => client2.createMixin(objectId, objectClass, objectSpace, mixin, attributes),
178734
- "createMixin failed"
178787
+ "createMixin"
178735
178788
  ),
178736
178789
  updateMixin: (objectId, objectClass, objectSpace, mixin, attributes) => withClient(
178737
178790
  (client2) => client2.updateMixin(objectId, objectClass, objectSpace, mixin, attributes),
178738
- "updateMixin failed"
178791
+ "updateMixin"
178739
178792
  ),
178740
178793
  uploadMarkup: (objectClass, objectId, objectAttr, markup, format5) => Effect_exports.tryPromise({
178741
178794
  try: () => markupOps.uploadMarkup(objectClass, objectId, objectAttr, markup, format5),
178742
- catch: (e) => new HulyConnectionError({ message: `uploadMarkup failed: ${String(e)}`, cause: e })
178795
+ catch: (error3) => makeOperationConnectionError("uploadMarkup", error3)
178743
178796
  }),
178744
178797
  fetchMarkup: (objectClass, objectId, objectAttr, id2, format5) => Effect_exports.tryPromise({
178745
178798
  try: () => markupOps.fetchMarkup(objectClass, objectId, objectAttr, id2, format5),
178746
- catch: (e) => new HulyConnectionError({ message: `fetchMarkup failed: ${String(e)}`, cause: e })
178799
+ catch: (error3) => makeOperationConnectionError("fetchMarkup", error3)
178747
178800
  }),
178748
178801
  updateMarkup: (objectClass, objectId, objectAttr, markup, format5) => Effect_exports.tryPromise({
178749
178802
  try: () => markupOps.updateMarkup(objectClass, objectId, objectAttr, markup, format5),
178750
- catch: (e) => new HulyConnectionError({ message: `updateMarkup failed: ${String(e)}`, cause: e })
178803
+ catch: (error3) => makeOperationConnectionError("updateMarkup", error3)
178751
178804
  }),
178752
- searchFulltext: (query, options) => withClient((client2) => client2.searchFulltext(query, options), "searchFulltext failed")
178805
+ searchFulltext: (query, options) => withClient((client2) => client2.searchFulltext(query, options), "searchFulltext")
178753
178806
  };
178754
178807
  return operations;
178755
178808
  })
@@ -183437,10 +183490,7 @@ var init_workspace_client = __esm({
183437
183490
  { url: config2.url, auth: config2.auth, workspace: config2.workspace },
183438
183491
  sdk
183439
183492
  );
183440
- const withClient = (op, errorMsg) => Effect_exports.tryPromise({
183441
- try: () => op(client),
183442
- catch: (e) => new HulyConnectionError({ message: `${errorMsg}: ${String(e)}`, cause: e })
183443
- });
183493
+ const withClient = (op, operation) => Effect_exports.tryPromise({ try: () => op(client), catch: (error3) => makeOperationConnectionError(operation, error3) });
183444
183494
  const accessLinkIdentityOptions = (options) => ({
183445
183495
  ...options.firstName !== void 0 ? { firstName: options.firstName } : {},
183446
183496
  ...options.lastName !== void 0 ? { lastName: options.lastName } : {},
@@ -183454,25 +183504,19 @@ var init_workspace_client = __esm({
183454
183504
  });
183455
183505
  const toAccountClientAccessLinkOptions = (options) => options === void 0 ? void 0 : { ...accessLinkIdentityOptions(options), ...accessLinkTimingOptions(options) };
183456
183506
  const operations = {
183457
- getWorkspaceMembers: () => withClient((c) => c.getWorkspaceMembers(), "Failed to get workspace members"),
183458
- getPersonInfo: (account) => withClient((c) => c.getPersonInfo(account), "Failed to get person info"),
183459
- updateWorkspaceRole: (account, role) => withClient((c) => c.updateWorkspaceRole(account, role), "Failed to update workspace role"),
183460
- getWorkspaceInfo: (updateLastVisit) => withClient((c) => c.getWorkspaceInfo(updateLastVisit), "Failed to get workspace info"),
183461
- getUserWorkspaces: () => withClient((c) => c.getUserWorkspaces(), "Failed to get user workspaces"),
183462
- createWorkspace: (name, region) => withClient((c) => c.createWorkspace(name, region), "Failed to create workspace"),
183463
- deleteWorkspace: () => withClient((c) => c.deleteWorkspace(), "Failed to delete workspace"),
183464
- getUserProfile: (personUuid) => withClient((c) => c.getUserProfile(personUuid), "Failed to get user profile"),
183465
- setMyProfile: (profile) => withClient((c) => c.setMyProfile(profile), "Failed to set my profile"),
183466
- createAccessLink: (role, options) => withClient(
183467
- (c) => c.createAccessLink(role, toAccountClientAccessLinkOptions(options)),
183468
- "Failed to create access link"
183469
- ),
183470
- updateAllowReadOnlyGuests: (readOnlyGuestsAllowed) => withClient(
183471
- (c) => c.updateAllowReadOnlyGuests(readOnlyGuestsAllowed),
183472
- "Failed to update read-only guest setting"
183473
- ),
183474
- updateAllowGuestSignUp: (guestSignUpAllowed) => withClient((c) => c.updateAllowGuestSignUp(guestSignUpAllowed), "Failed to update guest sign-up setting"),
183475
- getRegionInfo: () => withClient((c) => c.getRegionInfo(), "Failed to get region info")
183507
+ getWorkspaceMembers: () => withClient((c) => c.getWorkspaceMembers(), "getWorkspaceMembers"),
183508
+ getPersonInfo: (account) => withClient((c) => c.getPersonInfo(account), "getPersonInfo"),
183509
+ updateWorkspaceRole: (account, role) => withClient((c) => c.updateWorkspaceRole(account, role), "updateWorkspaceRole"),
183510
+ getWorkspaceInfo: (updateLastVisit) => withClient((c) => c.getWorkspaceInfo(updateLastVisit), "getWorkspaceInfo"),
183511
+ getUserWorkspaces: () => withClient((c) => c.getUserWorkspaces(), "getUserWorkspaces"),
183512
+ createWorkspace: (name, region) => withClient((c) => c.createWorkspace(name, region), "createWorkspace"),
183513
+ deleteWorkspace: () => withClient((c) => c.deleteWorkspace(), "deleteWorkspace"),
183514
+ getUserProfile: (personUuid) => withClient((c) => c.getUserProfile(personUuid), "getUserProfile"),
183515
+ setMyProfile: (profile) => withClient((c) => c.setMyProfile(profile), "setMyProfile"),
183516
+ createAccessLink: (role, options) => withClient((c) => c.createAccessLink(role, toAccountClientAccessLinkOptions(options)), "createAccessLink"),
183517
+ updateAllowReadOnlyGuests: (readOnlyGuestsAllowed) => withClient((c) => c.updateAllowReadOnlyGuests(readOnlyGuestsAllowed), "updateAllowReadOnlyGuests"),
183518
+ updateAllowGuestSignUp: (guestSignUpAllowed) => withClient((c) => c.updateAllowGuestSignUp(guestSignUpAllowed), "updateAllowGuestSignUp"),
183519
+ getRegionInfo: () => withClient((c) => c.getRegionInfo(), "getRegionInfo")
183476
183520
  };
183477
183521
  return operations;
183478
183522
  })
@@ -223136,7 +223180,7 @@ if (unsupportedRuntime) {
223136
223180
  detectedNodeVersion: process.versions.node,
223137
223181
  executable: process.execPath,
223138
223182
  requiredNodeVersion: nodeEngineRequirement,
223139
- serverVersion: "0.49.6"
223183
+ serverVersion: "0.49.7"
223140
223184
  });
223141
223185
  startUnsupportedNodeMcp(config2);
223142
223186
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firfi/huly-mcp",
3
- "version": "0.49.6",
3
+ "version": "0.49.7",
4
4
  "description": "Huly MCP: feature-complete MCP server for Huly integration",
5
5
  "mcpName": "io.github.dearlordylord/huly-mcp",
6
6
  "type": "module",