public_mcp_key_bindings.key_id cannot be a foreign key — the key records live in the secret vault,
not Postgres (migrations/0033_public_mcp_keys.sql:54-60) — and nothing compensates in the
application layer. agent_id has no existence check either. Validation is nonEmptyString only
(publicMcpKeyBindingsAdmin.ts:142-159), and the UI's canSave only checks for non-empty strings.
So an operator who typos one character gets 201 Created, a row in the list, and a
fully-configured-looking binding — while the integration reaches zero tools forever, because the
endpoint verifies the key and then looks up a row that does not exist. A typo is visually
indistinguishable from a working binding.
agentId is the cheap half: the agent registry is available in-process. keyId needs the key lister
that #438/#439 never shipped a UI for (see the separate issue), so the honest interim is a warning
when the pasted id matches no vault record rather than a hard rejection.
Not fixed in PR #550 because it needs a lister that does not exist yet.
Filed as a follow-up from PR #550 (MCP 2026-07-28 cluster, wave 4–6).
public_mcp_key_bindings.key_idcannot be a foreign key — the key records live in the secret vault,not Postgres (
migrations/0033_public_mcp_keys.sql:54-60) — and nothing compensates in theapplication layer.
agent_idhas no existence check either. Validation isnonEmptyStringonly(
publicMcpKeyBindingsAdmin.ts:142-159), and the UI'scanSaveonly checks for non-empty strings.So an operator who typos one character gets
201 Created, a row in the list, and afully-configured-looking binding — while the integration reaches zero tools forever, because the
endpoint verifies the key and then looks up a row that does not exist. A typo is visually
indistinguishable from a working binding.
agentIdis the cheap half: the agent registry is available in-process.keyIdneeds the key listerthat #438/#439 never shipped a UI for (see the separate issue), so the honest interim is a warning
when the pasted id matches no vault record rather than a hard rejection.
Not fixed in PR #550 because it needs a lister that does not exist yet.
Filed as a follow-up from PR #550 (MCP 2026-07-28 cluster, wave 4–6).