different-ai/openwork · error
MCP tool policy response was incomplete.
Error message
MCP tool policy response was incomplete.
What it means
useUpdateMcpConnectionToolPolicy PUTs a new tool policy for a connection and expects the response body (a record) to carry payload.policy parseable by parseExternalMcpToolPolicy. If the body is not a record or the policy fails to parse, this error is thrown even though the HTTP status was ok — the client cannot confirm what policy is now in effect.
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/mcp-connections-data.tsx:339
export function useUpdateMcpConnectionToolPolicy(connectionId: string) {
const queryClient = useQueryClient();
const { orgId } = useOrgDashboard();
return useMutation({
mutationFn: async (input: Pick<ExternalMcpToolPolicyView, "allDisabled" | "disabledTools">): Promise<ExternalMcpToolPolicyView> => {
const { response, payload } = await requestJson(
`/v1/mcp-connections/${encodeURIComponent(connectionId)}/tool-policy`,
{
method: "PUT",
headers: getOrgScopeHeaders(requireOrgId(orgId)),
body: JSON.stringify(input),
},
30000,
);
if (!response.ok) {
throw getRequestError(payload, response, `Failed to update MCP tool policy (${response.status}).`);
}
const policy = isRecord(payload) ? parseExternalMcpToolPolicy(payload.policy) : null;
if (!policy) throw new Error("MCP tool policy response was incomplete.");
return policy;
},
onSuccess: () => queryClient.invalidateQueries({ queryKey: mcpConnectionQueryKeys.tools(orgId, connectionId) }),
});
}
// The den-api tool run is bounded by its 150s MCP tool lifecycle deadline;
// give the request a little headroom so the server's structured failure
// arrives instead of a client-side timeout.
const RUN_TOOL_REQUEST_TIMEOUT_MS = 160000;
export function useRunMcpConnectionTool(connectionId: string) {
const { orgId } = useOrgDashboard();
return useMutation({
mutationFn: async (input: { toolName: string; arguments: Record<string, unknown> }): Promise<ExternalMcpToolRun> => {
const { response, payload } = await requestJson(
`/v1/mcp-connections/${encodeURIComponent(connectionId)}/tools/call`,
{View on GitHub (pinned to 2b7df46e8a)
Solutions
- Inspect the actual update response body and confirm it contains a parseable 'policy' object
- Fix the server route to echo the saved policy under payload.policy
- Extend parseExternalMcpToolPolicy to accept the current server policy shape
- Invalidate and refetch the tools query to read policy from the GET endpoint if the echo cannot be fixed
Example fix
// before
const policy = isRecord(payload) ? parseExternalMcpToolPolicy(payload.policy) : null;
if (!policy) throw new Error("MCP tool policy response was incomplete.");
// after
const rawPolicy = isRecord(payload) && isRecord(payload.policy) ? payload.policy : isRecord(payload) ? payload : null;
const policy = rawPolicy ? parseExternalMcpToolPolicy(rawPolicy) : null;
if (!policy) throw new Error("MCP tool policy response was incomplete."); Defensive patterns
Strategy: type-guard
Validate before calling
if (!isRecord(payload) || parseExternalMcpToolPolicy(payload.policy) === null) {
// fall back to refetching policy via the tools query instead of failing
} Type guard
function hasPolicy(v: unknown): v is { policy: Record<string, unknown> } {
return isRecord(v) && isRecord(v.policy);
} Try / catch
try {
await updatePolicy(connectionId, policy);
} catch (err) {
if (err.message === "MCP tool policy response was incomplete.") {
await queryClient.invalidateQueries(mcpConnectionQueryKeys.tools(orgId, connectionId)); // confirm via GET
}
} Prevention
- Server should echo the saved policy in the update response
- Test the policy PUT contract whenever the policy schema changes
- Fall back to refetching state rather than treating an unverifiable update as failed
When it happens
Trigger: Policy update returns 200 with empty body; response nests policy differently (e.g. {data:{policy}}); parseExternalMcpToolPolicy rejects the new policy object because required fields are missing or of wrong type.
Common situations: Server version without the policy echo in the update response; admin UI and API disagree on policy schema after a policy-format migration; proxy stripping response bodies.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- MCP tool catalog response was incomplete.
- MCP tool result was incomplete.
- Create MCP connection response was incomplete.
- invalid_mcp_token_payload
- Collection update response was incomplete.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/8ab1a0ad1a5cd8af.
Report an issue: GitHub.