@topline-build/harness-mcp 0.5.1 → 0.5.2

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable customer-visible Build MCP changes are recorded here. A source chang
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.5.2 - 2026-09-26
8
+
9
+ - Report rejected bearer credentials as `authorization_required`, with scoped cache-clearing and browser reconnect guidance instead of input-correction advice.
10
+ - Guide connection-specific cache cleanup and recovery of existing deployment progress before a write is retried.
11
+ - Report native client certification timeouts as failures even when partial output mentions authentication; a timed-out process is not proof of a missing provider session.
12
+
7
13
  ## 0.5.1 - 2026-09-18
8
14
 
9
15
  - Harden the bundled Claude certification script with strict tool isolation, effective-runtime proof, and noninteractive JSONL validation.
package/README.md CHANGED
@@ -22,6 +22,8 @@ npx -y @topline-build/harness-mcp
22
22
 
23
23
  Run `npx -y @topline-build/harness-mcp --help` for every supported flag and environment variable. `TOPLINE_MCP_TOKEN` is an advanced manual-token fallback; browser-approved OAuth is preferred.
24
24
 
25
+ If a tool returns `authorization_required`, clear only that connection's OAuth cache and reconnect through browser sign-in. Replace an expired or revoked manual token if using the fallback. Inspect existing artifact/deployment progress before retrying a write; the helper does not silently replay the rejected request.
26
+
25
27
  ## Typical workflow
26
28
 
27
29
  1. Use `platform_init_artifact_app` to create a starter, or point at an existing artifact app.
package/dist/index.d.ts CHANGED
@@ -32,7 +32,7 @@ export interface PackedArtifactAppBundle {
32
32
  type ToolProgressReporter = (progress: number, message: string) => void | Promise<void>;
33
33
  export declare const DEFAULT_MCP_PROTOCOL_VERSION = "2025-11-25";
34
34
  export declare const BUILD_MCP_SERVER_NAME = "topline-build-stdio";
35
- export declare const HARNESS_MCP_VERSION = "0.5.1";
35
+ export declare const HARNESS_MCP_VERSION = "0.5.2";
36
36
  export declare const DEFAULT_OAUTH_SCOPES: readonly string[];
37
37
  export interface BuildMcpSetupOption {
38
38
  readonly flag: string;
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError } fr
13
13
  export const DEFAULT_MCP_PROTOCOL_VERSION = "2025-11-25";
14
14
  const DEFAULT_TIMEOUT_MS = 120_000;
15
15
  export const BUILD_MCP_SERVER_NAME = "topline-build-stdio";
16
- export const HARNESS_MCP_VERSION = "0.5.1";
16
+ export const HARNESS_MCP_VERSION = "0.5.2";
17
17
  export const DEFAULT_OAUTH_SCOPES = Object.freeze(["harness:artifact:read", "harness:artifact:write", "harness:artifact:deploy", "harness:artifact:delete"]);
18
18
  export const BUILD_MCP_SETUP_OPTIONS = Object.freeze([
19
19
  { flag: "--url", env: "TOPLINE_API_URL", aliases: ["PLATFORM_API_URL", "OVERSITE_API_URL"], required: true, description: "Topline tenant base URL. HTTPS is required except for loopback development." },
@@ -1063,6 +1063,7 @@ function toolError(message) {
1063
1063
  return structuredToolError(message);
1064
1064
  }
1065
1065
  const BUILD_MCP_RECOVERY_ERROR_VALUES = {
1066
+ authorization_required: { retryable: false, recoveryAction: "Clear only this connection's cached OAuth credentials, then reconnect the Build MCP through browser sign-in. If using a manual bearer token, replace the expired or revoked token. Recover existing artifact/deployment progress before retrying a write." },
1066
1067
  platform_harness_timeout: { retryable: true, recoveryAction: "Retry the call. For a deployment, use platform_list_artifact_drafts to recover the artifact and platform_wait_artifact_deploy to resume progress." },
1067
1068
  platform_mcp_tool_error: { retryable: false, recoveryAction: "Read the returned error code, correct the request or OAuth scopes, then retry." },
1068
1069
  artifact_deploy_wait_timeout: { retryable: true, recoveryAction: "Call platform_wait_artifact_deploy again with the same artifactId and operationId." },
@@ -1087,6 +1088,8 @@ function structuredToolError(message) {
1087
1088
  };
1088
1089
  }
1089
1090
  function recoveryErrorCode(message) {
1091
+ if (/^platform_harness_http_error:401(?::|$)/.test(message))
1092
+ return "authorization_required";
1090
1093
  const known = [
1091
1094
  "artifact_delete_plan_stale",
1092
1095
  "artifact_deploy_wait_timeout",
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "package": {
4
4
  "name": "@topline-build/harness-mcp",
5
- "version": "0.5.1",
5
+ "version": "0.5.2",
6
6
  "bin": {
7
7
  "topline-mcp": "dist/cli.js"
8
8
  }
@@ -12,7 +12,7 @@
12
12
  "defaultVersion": "2025-11-25",
13
13
  "server": {
14
14
  "name": "topline-build-stdio",
15
- "version": "0.5.1"
15
+ "version": "0.5.2"
16
16
  }
17
17
  },
18
18
  "generatedFrom": {
@@ -171,6 +171,11 @@
171
171
  "recoveryAction": "Inspect the code and message, correct the input if needed, then retry the same tool."
172
172
  },
173
173
  "catalog": [
174
+ {
175
+ "code": "authorization_required",
176
+ "retryable": false,
177
+ "recoveryAction": "Clear only this connection's cached OAuth credentials, then reconnect the Build MCP through browser sign-in. If using a manual bearer token, replace the expired or revoked token. Recover existing artifact/deployment progress before retrying a write."
178
+ },
174
179
  {
175
180
  "code": "platform_harness_timeout",
176
181
  "retryable": true,
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Generated from `src/index.ts#BUILD_MCP_TOOLS`. Do not edit this file by hand.
4
4
 
5
- Package: `@topline-build/harness-mcp@0.5.1`
5
+ Package: `@topline-build/harness-mcp@0.5.2`
6
6
  Transport: `stdio`
7
7
  Default protocol: `2025-11-25`
8
8
  Canonical guide: https://topline.build/docs/build-mcp-guide
@@ -32,6 +32,7 @@ The first authenticated tool call normally opens browser approval. Set `TOPLINE_
32
32
 
33
33
  Tool failures set `isError: true` and return `structuredContent.error` with `code`, `message`, `retryable`, and `recoveryAction`.
34
34
 
35
+ - `authorization_required` (not automatically retryable): Clear only this connection's cached OAuth credentials, then reconnect the Build MCP through browser sign-in. If using a manual bearer token, replace the expired or revoked token. Recover existing artifact/deployment progress before retrying a write.
35
36
  - `platform_harness_timeout` (retryable): Retry the call. For a deployment, use platform_list_artifact_drafts to recover the artifact and platform_wait_artifact_deploy to resume progress.
36
37
  - `platform_mcp_tool_error` (not automatically retryable): Read the returned error code, correct the request or OAuth scopes, then retry.
37
38
  - `artifact_deploy_wait_timeout` (retryable): Call platform_wait_artifact_deploy again with the same artifactId and operationId.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topline-build/harness-mcp",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Topline Build MCP for creating and deploying artifact app drafts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -218,9 +218,7 @@ async function agentMediatedRead(name, command, scratch, apiUrl, appDir, workspa
218
218
  "-p", "--verbose", "--output-format", "stream-json", prompt
219
219
  ], scratch, 180000, strictAgentEnvironment(process.env));
220
220
  if (!result.ok) {
221
- return authUnavailable(result.output)
222
- ? skipped("provider_credentials_or_client_session_unavailable")
223
- : failed("client_mediated_read_failed", result.exitCode);
221
+ return clientMediatedFailure(result);
224
222
  }
225
223
  const usedTool = hasToolCallEvidence(result.output, "platform_inspect_artifact_app");
226
224
  const certified = hasAssistantCertificationEvidence(result.output);
@@ -344,6 +342,12 @@ async function certifyProtocol({ apiUrl, token, appDir, workspaceRoot }) {
344
342
  }
345
343
 
346
344
  function selfTestReport() {
345
+ const timedOutProbe = run({ executable: process.execPath, prefix: [] }, ["-e", "console.log('api key authentication required'); setInterval(() => {}, 1000)"], process.cwd(), 1000);
346
+ const timedOutFailure = clientMediatedFailure(timedOutProbe);
347
+ if (!timedOutProbe.timedOut || !authUnavailable(timedOutProbe.output) || timedOutFailure.status !== "failed" || timedOutFailure.reason !== "client_mediated_read_timed_out"
348
+ || clientMediatedFailure({ timedOut: false, output: "not logged in", exitCode: 1 }).status !== "skipped") {
349
+ throw new Error("client_timeout_classification_self_test_failed");
350
+ }
347
351
  const toolName = "platform_inspect_artifact_app";
348
352
  const promptOnly = JSON.stringify({ type: "user", content: `Call ${toolName} and print TOPLINE_CLIENT_READ_CERTIFIED.` });
349
353
  const toolEvent = JSON.stringify({ type: "item.completed", item: { type: "mcp_tool_call", tool: toolName } });
@@ -477,12 +481,20 @@ function run(command, commandArgs, cwd, timeout = 30000, env = clientProbeEnviro
477
481
  return {
478
482
  ok: result.status === 0,
479
483
  missing: result.error?.code === "ENOENT",
484
+ timedOut: result.error?.code === "ETIMEDOUT",
480
485
  exitCode: result.status,
481
486
  stdout: result.stdout || "",
482
487
  output: `${result.stdout || ""}\n${result.stderr || ""}`
483
488
  };
484
489
  }
485
490
 
491
+ function clientMediatedFailure(result) {
492
+ if (result.timedOut) return failed("client_mediated_read_timed_out", result.exitCode);
493
+ return authUnavailable(result.output)
494
+ ? skipped("provider_credentials_or_client_session_unavailable")
495
+ : failed("client_mediated_read_failed", result.exitCode);
496
+ }
497
+
486
498
  function authUnavailable(output) {
487
499
  return /not logged in|not authenticated|authentication required|api key|login required|please login|sign in|unable to locate credentials|security token|AccessDeniedException|UnrecognizedClientException/i.test(output);
488
500
  }