fix: MCP server entrypoint not found in packaged builds
In packaged Electron apps process.cwd() does not point to the app directory so the mcp-server bundle was never found. Additionally the mcp-server dist was not included in the package at all. Changes: - Bundle mcp-server into a single self-contained ESM file (tsup noExternal + createRequire banner for CJS compat) - Ship mcp-server/dist/index.js and package.json via extraResources - Resolve entry via process.resourcesPath when app.isPackaged is true - Build controller + mcp-server in prebuild so dist exists before electron-builder runs - Add mcp-server/dist/index.js to CI verify steps on all platforms - Improve error message to list checked paths for easier debugging
This commit is contained in:
parent
24a398bccf
commit
1d15f5f4d9
4 changed files with 72 additions and 4 deletions
3
.github/workflows/release.yml
vendored
3
.github/workflows/release.yml
vendored
|
|
@ -113,6 +113,7 @@ jobs:
|
|||
test -f dist-electron/main/index.cjs
|
||||
test -f dist-electron/preload/index.js
|
||||
test -f out/renderer/index.html
|
||||
test -f mcp-server/dist/index.js
|
||||
|
||||
- name: Package (macOS ${{ matrix.arch }})
|
||||
env:
|
||||
|
|
@ -180,6 +181,7 @@ jobs:
|
|||
test -f dist-electron/main/index.cjs
|
||||
test -f dist-electron/preload/index.js
|
||||
test -f out/renderer/index.html
|
||||
test -f mcp-server/dist/index.js
|
||||
|
||||
- name: Package (Windows)
|
||||
env:
|
||||
|
|
@ -246,6 +248,7 @@ jobs:
|
|||
test -f dist-electron/main/index.cjs
|
||||
test -f dist-electron/preload/index.js
|
||||
test -f out/renderer/index.html
|
||||
test -f mcp-server/dist/index.js
|
||||
|
||||
- name: Package (Linux)
|
||||
env:
|
||||
|
|
|
|||
|
|
@ -4,8 +4,28 @@ export default defineConfig({
|
|||
entry: ['src/index.ts'],
|
||||
format: ['esm'],
|
||||
target: 'node20',
|
||||
platform: 'node',
|
||||
outDir: 'dist',
|
||||
clean: true,
|
||||
sourcemap: true,
|
||||
dts: false,
|
||||
// Bundle all dependencies into a single self-contained file so the packaged
|
||||
// Electron app can run the MCP server without a node_modules tree.
|
||||
noExternal: [/.*/],
|
||||
splitting: false,
|
||||
// Provide a real `require` function for CJS dependencies (e.g. undici)
|
||||
// that use require() for Node built-in modules.
|
||||
banner: {
|
||||
js: `import { createRequire as __bundled_createRequire } from 'module';\nconst require = __bundled_createRequire(import.meta.url);`,
|
||||
},
|
||||
esbuildOptions(options) {
|
||||
// Optional peer deps of xsschema (pulled in by fastmcp) — we only use zod.
|
||||
// Mark as external at the esbuild level to avoid resolution errors.
|
||||
options.external = [
|
||||
...(options.external ?? []),
|
||||
'sury',
|
||||
'@valibot/to-json-schema',
|
||||
'effect',
|
||||
];
|
||||
},
|
||||
});
|
||||
|
|
|
|||
10
package.json
10
package.json
|
|
@ -20,7 +20,7 @@
|
|||
"scripts": {
|
||||
"dev": "electron-vite dev",
|
||||
"dev:kill": "node bin/kill-dev.js",
|
||||
"prebuild": "tsx scripts/fetch-pricing-data.ts",
|
||||
"prebuild": "tsx scripts/fetch-pricing-data.ts && pnpm --filter agent-teams-controller build && pnpm --filter agent-teams-mcp build",
|
||||
"build": "electron-vite build",
|
||||
"dist": "electron-builder --mac --win --linux",
|
||||
"dist:mac": "electron-builder --mac",
|
||||
|
|
@ -223,6 +223,14 @@
|
|||
{
|
||||
"from": "resources/pricing.json",
|
||||
"to": "pricing.json"
|
||||
},
|
||||
{
|
||||
"from": "mcp-server/dist/index.js",
|
||||
"to": "mcp-server/index.js"
|
||||
},
|
||||
{
|
||||
"from": "mcp-server/package.json",
|
||||
"to": "mcp-server/package.json"
|
||||
}
|
||||
],
|
||||
"npmRebuild": false,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,24 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|||
return !!value && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function isPackagedApp(): boolean {
|
||||
try {
|
||||
const { app } = require('electron') as typeof import('electron');
|
||||
return app.isPackaged;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In a packaged Electron build the mcp-server bundle lives under
|
||||
* `process.resourcesPath/mcp-server/index.js` (copied via extraResources).
|
||||
* In dev mode we resolve relative to the workspace root (process.cwd()).
|
||||
*/
|
||||
function getPackagedServerEntry(): string {
|
||||
return path.join(process.resourcesPath, 'mcp-server', 'index.js');
|
||||
}
|
||||
|
||||
function getWorkspaceRoot(): string {
|
||||
return process.cwd();
|
||||
}
|
||||
|
|
@ -82,17 +100,34 @@ async function resolveNodePath(): Promise<string> {
|
|||
}
|
||||
|
||||
async function resolveMcpLaunchSpec(): Promise<McpLaunchSpec> {
|
||||
const checked: string[] = [];
|
||||
|
||||
// 1. Packaged Electron app — use extraResources bundle
|
||||
if (isPackagedApp()) {
|
||||
const packagedEntry = getPackagedServerEntry();
|
||||
checked.push(packagedEntry);
|
||||
if (await pathExists(packagedEntry)) {
|
||||
return {
|
||||
command: await resolveNodePath(),
|
||||
args: [packagedEntry],
|
||||
};
|
||||
}
|
||||
logger.warn(`Packaged MCP entry not found at ${packagedEntry}, falling back to workspace`);
|
||||
}
|
||||
|
||||
// 2. Dev mode — prefer source for hot changes
|
||||
const sourceEntry = getSourceServerEntry();
|
||||
checked.push(sourceEntry);
|
||||
if (await pathExists(sourceEntry)) {
|
||||
// Prefer source in workspace/dev runs so newly added MCP tools are available
|
||||
// immediately and we do not accidentally serve a stale built dist bundle.
|
||||
return {
|
||||
command: 'pnpm',
|
||||
args: ['--dir', getMcpServerDir(), 'exec', 'tsx', sourceEntry],
|
||||
};
|
||||
}
|
||||
|
||||
// 3. Dev mode — built dist
|
||||
const builtEntry = getBuiltServerEntry();
|
||||
checked.push(builtEntry);
|
||||
if (await pathExists(builtEntry)) {
|
||||
return {
|
||||
command: await resolveNodePath(),
|
||||
|
|
@ -100,7 +135,9 @@ async function resolveMcpLaunchSpec(): Promise<McpLaunchSpec> {
|
|||
};
|
||||
}
|
||||
|
||||
throw new Error('agent-teams-mcp entrypoint not found in mcp-server package');
|
||||
throw new Error(
|
||||
`agent-teams-mcp entrypoint not found. Checked paths:\n${checked.map((p) => ` - ${p}`).join('\n')}`
|
||||
);
|
||||
}
|
||||
|
||||
export class TeamMcpConfigBuilder {
|
||||
|
|
|
|||
Loading…
Reference in a new issue