Repository navigation
fix(hire): the hire flow grants MCP connectors that every bundled engine rejects at first turn, with no warning at creation time #314
Description
Preflight
- I searched open and closed issues for duplicates.
- I removed credentials, personal data, and private content from this report.
- This is not a security vulnerability.
Tracker sweep. Scanned all 116 issues (open + closed, GET /issues?state=all, pages 1–3) for mcp / connector / connection in the title. One hit: #89 ("hire flow has no way to grant MCP tools to a digital employee", blocked by upstream). Not a duplicate: #89 records the 2026-08 state where no grant path existed. Since #205 (2026-09-07, "promote RoleWeave workspace and branding to main") the grant path does exist — the hire UI ships an MCP connector picker and the AI proposal can bind servers — so the failure mode has changed from "cannot grant" to "grant succeeds, first turn always fails". This issue records that new state. Posted a cross-reference comment on #89.
Summary
The hire flow (v0.2.0) lets an operator bind MCP connectors to a new employee — via the CapabilityPicker UI or via an AI proposal — and the hire completes successfully with the binding written into the position package. But every bundled engine rejects employee-level MCP bindings before the first turn starts, so the employee's first task fails in under a second with qoder.mcp_binding_unsupported. Nothing at hire time warns that the granted capability is currently unusable.
Expected behavior
The hire flow should not let an operator grant a capability that the selected (or any) engine cannot honor — or should at least warn at binding/creation time that employee-level MCP is not yet supported by any engine.
Actual behavior
- In the hire drawer's CapabilityPicker, clicking an MCP server card (workspace-drive / issue-tracker / repository) binds it and shows "已绑定" — no warning.
- An AI hire proposal carrying
mcpServersis applied verbatim (applyProposal) — also no warning. - Hire submits, returns
status: "hired".buildPositionSkeletonFiles()writes the non-emptymcpServersintopermissions.json, generatesmcp.json, and attachesentrypoints.mcp+policy.mcpToolstoemployee.json. - First turn dispatch fails in <1 s:
当前 Qoder 适配器尚不支持员工 MCP 绑定;未加载全局 MCP 配置。(qoder.mcp_binding_unsupported,retryable: false). The user experience is "employee created fine, then instantly broken, with no hint that the MCP binding is the cause" — and re-hiring the next employee reproduces it.
Reproduction
Observed on a real install (Windows, v0.2.0, Qoder host bound):
- Hire a new employee with an MCP server selected in the CapabilityPicker (or accept an AI proposal that grants one).
- Hire succeeds; the position package on disk contains
"mcpServers": [{...}]inpermissions.json. - Dispatch any task to the employee → fails immediately with
qoder.mcp_binding_unsupported. - Manual workaround: edit the position's
permissions.json, setmcpServersto[]; the next turn spawns normally (verified).
Version or commit
| Artifact | Value |
|---|---|
| Upstream main used for source references | 5f2f6a880a2d9677263509fcb856ade36ccfa1b4 |
| Reporter's installed desktop build | v0.2.0 (latest release, E:\RoleWeave, renderer bundle index-DLsZG8bu.js contains the MCP picker copy; installed qoder-engine.mjs contains the L802 guard) |
| File @ main | blob |
|---|---|
apps/desktop/renderer/src/org/PermissionsEditor.tsx |
d14ed4d6e6816a4f841e07fa3a05d55aa6c7f160 |
apps/desktop/renderer/src/org/HireDrawer.tsx |
bb78d125b4fbe95d105eed90e7b7143bbd54e217 |
packages/shared/src/capabilities.ts |
79689f21e9ea06c367ee4fbedaeee822ed792905 |
packages/shared/src/hire.ts |
05fa12faed5e4f66f85989376fee32b192f16d22 |
apps/server/src/org/permission-artifacts.ts |
193990fa599f9507a6f308f1faa594d1830f364a |
apps/server/src/org/apply.ts |
999f03e07db3deed1f3f8c084531f169a5fa931e |
apps/server/src/routes/hire.ts |
78da422aac453aff9b3936afb7e38ea1a63322b4 |
apps/server/bin/qoder-engine.mjs |
276ac57bde84ad5c0146bec6d4c77ec59d94805e |
apps/server/src/agent-registry.ts |
421ed5fae7df514b029e3472874eae18e6084d52 |
Environment
- Windows 11 (10.0.26200), RoleWeave v0.2.0 desktop installer, engine control plane over WSL, Qoder host.
- Server-side behavior read from main
5f2f6a88; not run from a source checkout (see Not verified here).
Affected component
apps/desktop/renderer/src/org/PermissionsEditor.tsx(CapabilityPicker MCP section)apps/desktop/renderer/src/org/HireDrawer.tsx(proposal application)apps/server/src/routes/hire.ts+apps/server/src/org/apply.ts(creation-time gate)apps/server/bin/qoder-engine.mjs(the guard that fires at turn time)
Proposed severity
S2. A first-class hire-flow path completes "successfully" while producing an employee whose every turn fails until the operator manually edits permissions.json. The failure surfaces away from its cause (at turn time, not hire time), the error copy does not name the MCP binding as removable, and re-hiring reproduces it.
Current evidence level
E2 — source + live reproduction. Steps 1–4 of the Reproduction were executed on the reporter's machine (v0.2.0 install; screenshots and the on-disk package files inspected). Engine-side guard and hire-side code paths are read from main 5f2f6a88 at the listed blobs. Line numbers below are from those exact blobs.
Evidence
Grant side — no engine-capability gate anywhere before the package is staged:
PermissionsEditor.tsx:207-222— CapabilityPicker renders the "MCP 连接器" section fromhireMcpCatalog(capabilities.ts:51-70registersworkspace-drive,issue-tracker,repository);toggleMcpServerGrantbinds with one click; no warning copy.HireDrawer.tsx:196-200—applyProposalpersistsproposal.mcpServersverbatim viareplaceCapabilityRules; no warning.permission-artifacts.ts:58-111(derivePermissionArtifacts) validates only that the grant id exists inhireMcpCatalog; it cannot see engines.apply.ts:543-617—buildPositionSkeletonFileswritespermissions.jsonwith the grantedmcpServers(L617mcp.json; L571entrypoints.mcpwhenmcpToolsnon-empty; L582 assets list).routes/hire.ts(351 lines) contains zero occurrences ofmcp— the server-side hire contract imposes no engine-capability check on the grant.
Engine side — every host refuses the grant the hire flow just wrote:
qoder-engine.mjs:802—fail("qoder.mcp_binding_unsupported", "当前 Qoder 适配器尚不支持员工 MCP 绑定;未加载全局 MCP 配置。", false)wheneverpermissions.mcpServersis non-empty; the turn never starts.qoder-engine.mjs:839— the Qoder spawn hardcodes--strict-mcp-config --mcp-config '{"mcpServers":{}}' --setting-sources "";:1016shows the Claude branch doing the same.agent-registry.ts:103-123— all six host definitions declarecapabilities: ["turns", "streaming", "sessions", "groups", "approvals"]; no host declares MCP support, so "no engine can honor this" is currently a static fact, not a per-host check.
History context: #89 (blocked by upstream) predates #205; PR #91 was closed unmerged after review, and the MCP runtime itself is owned upstream (fullstack-ai-infra/digital-employee#219). The grant surface shipped regardless, which is what this issue is about.
Proposed fix / 未决决策
The engine-side MCP runtime is upstream's to build (#219); this issue only asks that the hire surface stop selling a capability no engine can honor. Options, in decreasing rigor:
- A (recommended): gate at hire time. In the hire contract (
routes/hire.ts) / org-apply staging, reject a request whosepermissions.mcpServersis non-empty with a clear error ("employee-level MCP is not yet supported by any engine; leave MCP connectors unbound"), and grey out the MCP section in CapabilityPicker with the same copy. When a host eventually declares MCP support (viaagent-registry.tscapabilities), the gate unlocks automatically. - B: warn only. Keep the binding creatable but show a persistent warning in the picker and at hire submit. Weaker: the failure still exists, just announced.
- C: leave as-is until upstream test(desktop): stabilize the group workspace navigation regression #219 lands. Every v0.2.0 user who tries the visible MCP section gets a silently broken employee.
Decision needed from the product owner: reject-at-hire (A) vs warn-and-allow (B). Either way the fix is small and entirely inside roleweave.
Non-goals
- Implementing the employee-level MCP runtime / spawn plumbing — owned by
fullstack-ai-infra/digital-employee#219; see also [blocked by upstream] hire flow has no way to grant MCP tools to a digital employee (requires MCP runtime + permission chain in digital-employee) #89. - Changing the position-package schema,
hireMcpCatalogcontents, or the permission-artifact validation rules. - Any change to already-created packages (the manual unbind workaround already works).
Acceptance criteria
- Hiring an employee with a non-empty
mcpServersgrant is either rejected at hire time with copy that names the limitation (A), or the picker/submit surfaces a persistent warning (B) — per the product owner's call. - The CapabilityPicker MCP section is rendered disabled (A) or annotated (B) while no host in
agent-registry.tsdeclares MCP support. - An employee hired without MCP grants behaves exactly as today (no regression in the default path).
- When a future host declares MCP support in
agent-registry.ts, the gate/warning no longer triggers for that host without further edits to the hire surface (the check reads the registry, not a hardcoded list).
Not verified here
- Whether engines outside the bundled set (if any runtime-resolved hosts exist) honor MCP grants — the check would read
agent-registry.ts, whose six built-ins are all I verified. - macOS/Linux packaged builds were not exercised; the reporter verified Windows only.
Activity
waterbro-8 commentedon Sep 17, 2026
Implementation PR: the hire/edit capability picker now shows a status warning as soon as any MCP connector is bound, naming
qoder.mcp_binding_unsupported. Grants are still saved (not silently dropped) so a later engine that honors MCP does not need a second hire.Tracking the PR opened from
fix/314-243-hire-mcp-and-engine-copies.fix(hire): reject employee-level MCP grants no bundled engine can honor
fix(hire): reject employee-level MCP grants no bundled engine can honor
fix(hire): warn when MCP grants cannot run on bundled engines
fix(hire): keep renderer turnStream off the shared Node barrel
fix(hire): reject employee-level MCP grants no bundled engine can honor
fix(hire): warn when MCP grants cannot run on bundled engines
fix(hire): keep renderer turnStream off the shared Node barrel
fix(hire): warn when MCP grants cannot run on bundled engines
fix(hire): keep renderer turnStream off the shared Node barrel
fix(server): treat only own Host catalog keys as known ids
fix(hire): reject employee-level MCP grants no bundled engine can hon…
test(server): fail-closed MCP gate on inherited Host ids
fix(hire): warn when MCP grants cannot run on bundled engines (#320)
waterbro-8 commentedon Sep 18, 2026
关闭:#319 拒绝 bundled engine 无法兑现的员工级 MCP;#320 在 hire/edit 能力选择器给出
qoder.mcp_binding_unsupported警告。两 PR 均已合入。waterbro-8 commentedon Sep 18, 2026
Reopen per 胡奕舟 18:27 口径:#314 保持 OPEN,picker 验收跟 #320,不以合入视为验收。#319/#320 已合(a131efc / d5e0284),closingIssuesReferences 为空;未获他确认前不关。
waterbro-8 commentedon Sep 20, 2026
平台组分工补派(冯浩然 / waterbro-8)
sun-970,仓库暂不能指派,以钉钉+本评论为准)waterbro-8 commentedon Sep 20, 2026
平台组群成员派活(冯浩然 / waterbro-8)
sun-970 commentedon Sep 20, 2026
Verified current
main(48fd61affdee41d863aa5ddedc44fec355370f70) against #314 AC. No new PR from this pass: engineering AC is already on main via #319 + #320, and the matching tests already exist. I am not closing the issue.What is on main
a131efc76de1319f8ac08409a8bdf7ebed7eda94— reject employee-level MCP grants no bundled engine can honord5e028472a64a39465ebcc2f0b3c8c262988cbe1— persistent warning in the hire/edit CapabilityPicker namingqoder.mcp_binding_unsupportedProduct as shipped: warn-and-allow in the picker (#320) plus fail-closed reject at hire/profile (#319). Both are still present. Gates read the agent registry (
HOST_DEFINITIONS[…].capabilities.includes("mcp")), not a hardcoded host list. Gemini CLI (#317) was added later; every catalog host still omits"mcp".mcpServersis rejected or persistently warnedPOST /hirereturns422 hire_mcp_unsupportedbefore staging; picker shows arole="status"warning as soon as a connector is boundapps/server/src/routes/hire.tsadf54a3ab5512fea01beff06cd270c80329ee517L259–268. Profile:apps/server/src/org/profile-edit.ts82e2ac686309176e66b3b77dacd89f3db4349730L103–104 (anyAgentHostSupportsEmployeeMcp()). Warn:apps/desktop/renderer/src/org/PermissionsEditor.tsx5e763c44985b797649db1666ef73646d92c92397L234–237 (hire.mcpUnsupportedHint). Drawer maps the failure code:HireDrawer.tsx6517de2e6b0ef1ec4c6de52096f2dd58f9a9c80fL30 →hire.errMcpCapability. Copy:packages/ui/src/locales/en.tsbd486c7e4a851bb010ac038fdc2f6aa436d5d2aeL474 / L548;zh.ts61f2926ef44df1bd2b67c0e24c4daef069d6a462L477 / L551PermissionsEditor.tsx. Wired fromHireDrawer.tsxL391 andEditEmployeeDrawer.tsxL150apps/server/test/hire.test.ts4904defb3eb0576d3c7783de78897949116fa372— default fixture has nomcpServers; asserts emptymcpTools, noentrypoints.mcp, persistedmcpServers: []apps/server/src/agent-registry.tsb0cfef3d4355bf6771d05dacebddac6ac98bdc51agentHostSupportsEmployeeMcp/anyAgentHostSupportsEmployeeMcpL338–349Tests already covering AC
hire.test.ts4904defb3eb0576d3c7783de78897949116fa372— non-empty grant →422 hire_mcp_unsupported, zero engine validator calls, no staged skeletonapps/server/test/position-profile.test.ts5f4d0beee6c66ddaf45a852a6a8eb49fa098fe39apps/server/test/agent-registry.test.tsda341cc3a604b1ea28d5486810f3b8c58bdb6736(“employee-MCP capability gate answers from the registry, not a list copy”)apps/desktop/renderer/test/capability-picker.test.tsx5fb1e97f641302507a656d8a0a5c416427df5e5dA second implementation PR would be a drive-by. Remaining work is human picker acceptance by 胡奕舟 / Bindy — merge of #320 is not that acceptance (18:27 口径). I cannot close #314.
@waterbro-8
waterbro-8 commentedon Sep 23, 2026
已完成:PR #319 在 hire/profile 入口按 registry fail-closed 拒绝无法兑现的 MCP grant;PR #320 增加持久警告。当前 main 的实现与回归测试已再次逐项核验。