Skip to content

Commit d5af731

Browse files
committed
Use Smithery fork and pre-pack bundled resources
1 parent e251d20 commit d5af731

File tree

12 files changed

+160
-54
lines changed

12 files changed

+160
-54
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ jobs:
2626
- name: Install dependencies
2727
run: npm ci
2828

29+
- name: Use forked Smithery CLI (stdio prepack)
30+
run: npm install --no-save --no-package-lock @smithery/cli@github:cameroncooke/cli#stdio-prepack-hook
31+
2932
- name: Bundle AXe artifacts
3033
run: npm run bundle:axe
3134

.github/workflows/release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ jobs:
4242
rm -rf node_modules package-lock.json
4343
npm install --ignore-scripts
4444
45+
- name: Use forked Smithery CLI (stdio prepack)
46+
run: npm install --no-save --no-package-lock @smithery/cli@github:cameroncooke/cli#stdio-prepack-hook
47+
4548
- name: Check formatting
4649
run: npm run format:check
4750

@@ -104,6 +107,17 @@ jobs:
104107
echo "📦 Publishing to NPM with tag: $NPM_TAG"
105108
npm publish --access public --tag "$NPM_TAG"
106109
110+
- name: Deploy to Smithery (production releases only)
111+
if: github.event_name == 'push'
112+
env:
113+
SMITHERY_TOKEN: ${{ secrets.SMITHERY_TOKEN }}
114+
run: |
115+
if [ -z "$SMITHERY_TOKEN" ]; then
116+
echo "Missing SMITHERY_TOKEN secret for Smithery deploy."
117+
exit 1
118+
fi
119+
npx smithery deploy --transport stdio
120+
107121
- name: Create GitHub Release (production releases only)
108122
if: github.event_name == 'push'
109123
uses: softprops/action-gh-release@v1
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Smithery stdio packaging: problem domain and handoff
2+
3+
## Audience
4+
This document is for a new AI agent with no context about the prior investigation.
5+
6+
## Original problem
7+
XcodeBuildMCP is a **local stdio** MCP server deployed via the Smithery CLI. The server depends on bundled non-code assets (e.g., `bundled/` with an `axe` binary and frameworks). When deploying with the Smithery CLI, the resulting `.mcpb` bundle **does not include** these bundled assets, so the installed server lacks required resources at runtime.
8+
9+
## Key facts about the current Smithery CLI (v3.x)
10+
The Smithery CLI now builds and packs local stdio servers by:
11+
1) Building the stdio bundle into an output directory (default `.smithery/stdio`).
12+
2) Packing only that output directory into `server.mcpb` using `@anthropic-ai/mcpb`.
13+
3) Uploading the `server.mcpb` in `smithery deploy --transport stdio`.
14+
15+
Important constraints:
16+
- The CLI **does not read `smithery.config.js`** or run any custom build hooks for asset staging.
17+
- The CLI only reads `smithery.yaml` for metadata (e.g., name/target), not for a prepack step.
18+
- The pack step includes only what is inside `.smithery/stdio`.
19+
20+
## What we did
21+
1) Confirmed the repository uses `@smithery/cli` v3.x and targets a local stdio server.
22+
2) Verified that `smithery build --transport stdio` produces `.smithery/stdio/server.mcpb` **without** `bundled/`.
23+
3) Confirmed that the previous `smithery.config.js` copy approach is obsolete because the CLI no longer loads that config.
24+
4) Opened a Smithery CLI issue to request an official asset-staging hook:
25+
- https://github.com/smithery-ai/cli/issues/524
26+
27+
## How to reproduce the missing-assets behavior
28+
From the XcodeBuildMCP repo:
29+
1) `npx smithery build --transport stdio -o .smithery/stdio`
30+
2) `unzip -l .smithery/stdio/server.mcpb`
31+
- The bundle contains the compiled entrypoint and manifests only.
32+
- `bundled/` is missing.
33+
34+
## Workaround (local validation only)
35+
This is **not** compatible with `smithery deploy`, but it proves the bundle can contain assets:
36+
1) Build the stdio bundle:
37+
- `npx smithery build --transport stdio -o .smithery/stdio`
38+
2) Copy assets into the stdio output directory:
39+
- `cp -R bundled .smithery/stdio/bundled`
40+
3) Temporarily replace `manifest.json` with `mcpb-manifest.json` for packing:
41+
- `cp .smithery/stdio/manifest.json .smithery/stdio/manifest.payload.json`
42+
- `cp .smithery/stdio/mcpb-manifest.json .smithery/stdio/manifest.json`
43+
4) Re-pack using the official `mcpb` CLI:
44+
- `npx @anthropic-ai/mcpb pack .smithery/stdio .smithery/stdio/server.mcpb`
45+
5) Restore the original manifest:
46+
- `mv .smithery/stdio/manifest.payload.json .smithery/stdio/manifest.json`
47+
48+
Result: `server.mcpb` now contains `bundled/` and its frameworks.
49+
50+
## Why the workaround cannot be used for deployment
51+
`smithery deploy --transport stdio` rebuilds and repacks in its own flow, and provides no prepack hook to stage assets. As a result, there is no official way to inject `bundled/` into the `.mcpb` during deploy.
52+
53+
## How we likely want to proceed
54+
### Option A: Upstream fix (recommended)
55+
Add an official asset staging hook or prepack command in the Smithery CLI:
56+
- Example: `smithery.yaml` fields like `build.assets` or `build.prepackCommand`.
57+
- The hook should run before `packExtension()` in `src/lib/bundle/stdio.ts`.
58+
- This would allow asset copying into `.smithery/stdio` during `smithery deploy`.
59+
60+
Issue to track:
61+
- https://github.com/smithery-ai/cli/issues/524
62+
63+
### Option B: Fork the CLI
64+
If the upstream fix is slow, fork `smithery-ai/cli` and add:
65+
- A prepack hook (env var or `smithery.yaml` field).
66+
- A deterministic asset staging step inside `buildStdioBundle` before the pack step.
67+
Then consume the fork in CI:
68+
- Publish the fork under a scoped npm package, or
69+
- Install the fork from GitHub release in the release workflow.
70+
71+
Current implementation (forked CLI):
72+
- Added `build.prepackCommand` support in `smithery.yaml` (plus env var overrides).
73+
- CI/release workflows install the forked CLI before `smithery build`.
74+
- This repo wires `smithery.yaml` to `scripts/smithery-prepack.sh` to bundle/copy assets.
75+
76+
## Current repo state that matters
77+
- `smithery.config.js` exists but is **ignored** by v3.x CLI.
78+
- Any asset copy logic in this file does not run in deploy.
79+
- Release workflow currently publishes npm and MCP registry, but **does not** run Smithery deploy.
80+
- `npm run build` uses Smithery’s default transport (shttp) unless explicit `--transport stdio` is used.
81+
82+
## Summary
83+
The problem is not an outdated CLI version. The CLI is current, but the integration strategy is obsolete because v3.x no longer honors `smithery.config.js`. The deploy flow packs only `.smithery/stdio`. Until Smithery adds an official prepack/assets hook (or a fork is used), correct bundling for local stdio deployments is not achievable via `smithery deploy`.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"xcodebuildmcp-doctor": "build/doctor-cli.js"
1616
},
1717
"scripts": {
18-
"build": "npm run build:tsup && npx smithery build",
18+
"build": "npm run build:tsup && npx smithery build --transport stdio",
1919
"dev": "npm run generate:version && npm run generate:loaders && npx smithery dev",
2020
"build:tsup": "npm run generate:version && npm run generate:loaders && tsup",
2121
"dev:tsup": "npm run build:tsup && tsup --watch",

scripts/smithery-prepack.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
3+
set -euo pipefail
4+
5+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
7+
OUT_DIR="${SMITHERY_STDIO_OUT_DIR:-$PROJECT_ROOT/.smithery/stdio}"
8+
BUNDLED_DIR="$PROJECT_ROOT/bundled"
9+
DEST_DIR="$OUT_DIR/bundled"
10+
11+
if [ ! -d "$OUT_DIR" ]; then
12+
mkdir -p "$OUT_DIR"
13+
fi
14+
15+
if [ ! -f "$BUNDLED_DIR/axe" ]; then
16+
echo "Bundled AXe artifacts missing; running bundle:axe..."
17+
npm run bundle:axe
18+
else
19+
echo "Bundled AXe artifacts already present."
20+
fi
21+
22+
if [ ! -f "$BUNDLED_DIR/axe" ]; then
23+
echo "Bundled AXe artifacts are still missing after bundle:axe"
24+
exit 1
25+
fi
26+
27+
if [ -d "$DEST_DIR" ]; then
28+
rm -r "$DEST_DIR"
29+
fi
30+
31+
cp -R "$BUNDLED_DIR" "$OUT_DIR/"
32+
33+
echo "Copied bundled artifacts to $DEST_DIR"

scripts/verify-smithery-bundle.sh

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,44 @@
33
set -euo pipefail
44

55
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
6-
BUNDLE_DIR="$PROJECT_ROOT/.smithery/bundled"
6+
SMITHERY_DIR="$PROJECT_ROOT/.smithery"
7+
STDIO_DIR="$SMITHERY_DIR/stdio"
8+
BUNDLE_DIR="$STDIO_DIR/bundled"
9+
10+
if [ ! -f "$BUNDLE_DIR/axe" ]; then
11+
echo "Missing bundled AXe artifacts under $STDIO_DIR"
12+
if [ -d "$SMITHERY_DIR" ]; then
13+
echo ".smithery contents:"
14+
ls -la "$SMITHERY_DIR"
15+
fi
16+
exit 1
17+
fi
718
AXE_BIN="$BUNDLE_DIR/axe"
819
FRAMEWORK_DIR="$BUNDLE_DIR/Frameworks"
920

1021
if [ ! -f "$AXE_BIN" ]; then
11-
echo "Missing AXe binary at $AXE_BIN"
22+
echo "Missing AXe binary at $AXE_BIN"
1223
if [ -d "$PROJECT_ROOT/.smithery" ]; then
13-
echo "🔍 .smithery contents:"
24+
echo ".smithery contents:"
1425
ls -la "$PROJECT_ROOT/.smithery"
1526
fi
1627
exit 1
1728
fi
1829

1930
if [ ! -d "$FRAMEWORK_DIR" ]; then
20-
echo "Missing Frameworks directory at $FRAMEWORK_DIR"
31+
echo "Missing Frameworks directory at $FRAMEWORK_DIR"
2132
if [ -d "$BUNDLE_DIR" ]; then
22-
echo "🔍 bundled contents:"
33+
echo "bundled contents:"
2334
ls -la "$BUNDLE_DIR"
2435
fi
2536
exit 1
2637
fi
2738

2839
FRAMEWORK_COUNT="$(find "$FRAMEWORK_DIR" -maxdepth 2 -type d -name "*.framework" | wc -l | tr -d ' ')"
2940
if [ "$FRAMEWORK_COUNT" -eq 0 ]; then
30-
echo "No frameworks found in $FRAMEWORK_DIR"
41+
echo "No frameworks found in $FRAMEWORK_DIR"
3142
find "$FRAMEWORK_DIR" -maxdepth 2 -type d | head -n 50
3243
exit 1
3344
fi
3445

35-
echo "Smithery bundle includes AXe binary and $FRAMEWORK_COUNT frameworks"
46+
echo "Smithery bundle includes AXe binary and $FRAMEWORK_COUNT frameworks"

smithery.config.js

Lines changed: 0 additions & 39 deletions
This file was deleted.

smithery.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
# Smithery configuration file: https://smithery.ai/docs/build/project-config
2-
runtime: "typescript"
3-
target: "local"
1+
runtime: typescript
2+
target: local
3+
build:
4+
prepackCommand: "bash scripts/smithery-prepack.sh"

src/doctor-cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ async function runDoctor(): Promise<void> {
2424
// Output the doctor information
2525
if (result.content && result.content.length > 0) {
2626
const textContent = result.content.find((item) => item.type === 'text');
27-
if (textContent && textContent.type === 'text') {
27+
if (textContent?.type === 'text') {
2828
// eslint-disable-next-line no-console
2929
console.log(textContent.text);
3030
} else {

src/mcp/tools/swift-package/swift_package_build.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export async function swift_package_buildLogic(
2929
const resolvedPath = path.resolve(params.packagePath);
3030
const swiftArgs = ['build', '--package-path', resolvedPath];
3131

32-
if (params.configuration && params.configuration.toLowerCase() === 'release') {
32+
if (params.configuration?.toLowerCase() === 'release') {
3333
swiftArgs.push('-c', 'release');
3434
}
3535

0 commit comments

Comments
 (0)