Go to file
Lucio Lelii 2217ea188a Let an LLM node call tools directly, bypassing the MCP bridge
The bridge coerces a tool argument from string to object whenever the string
happens to be valid JSON, even though the model emits it correctly and the
tool's own schema declares it as a string. The coercion happens inside the
bridge, between the model's response and the downstream MCP call: verified by
calling the model directly (arguments.content stays a string, byte for byte)
and by comparing a JSON-valid value (rejected) against a malformed or plain
text one (passed through untouched). The failing call never reaches the MCP
server, and the agent's retries under a different encoding are what turn an
unfinished operation into one that returns status: completed with the model's
last preamble as if it were the answer.

There is no fix available on our side for the bridge itself, so this removes
it from the path instead. An LLMBlock can now bind MCP servers straight from
the catalog and run its own tool-calling loop in this service:

- LLMProvider gains chatWithTools/supportsTools; only OllamaProtocolProvider
  implements it for now. Tool arguments stay JsonNode end to end - never a
  string, never re-parsed - which is the one change that actually closes the
  bridge's bug rather than working around it.
- A native streamable-http MCP client (mcp/client/) talks to a server without
  the bridge: initialize, tools/list, tools/call, session header handling,
  both response shapes the spec allows.
- MCPToolServerBinding is a narrower binding than MCPAgent's, restricted to
  catalog servers reachable over streamable-http - the ones this service can
  call directly, not the stdio ones the bridge still hosts a process for.
- LLMToolLoop runs the model/tool/model cycle with real budgets: a wall-clock
  deadline and iteration cap that fail the block explicitly rather than
  return a partial answer, and a character-based context budget that replaces
  older tool results with a placeholder once the conversation - plus the tool
  schemas sent on every call, which do not appear in the conversation but are
  not free either - grows past it. The iteration just completed is never
  pruned, and a result under ~500 characters is left alone: shrinking it would
  cost about as much as it saves.
- Ollama's done_reason now travels back as ToolChatResult.finishReason, so a
  turn that answers nothing can say whether the model chose silence or
  num_predict cut it off mid-thought - two different problems with two
  different fixes, previously indistinguishable from the error alone.
- A new skill, mcp-context-economy, carries the operating rules a real run
  against a 24-task plan exposed the hard way: write_file to create a file,
  apply_patch only to edit one that exists, and never read a file straight
  back after writing it or re-pull an already-inline document into the
  conversation - each halves the context a node needs for the same work.

MCPAgent and the bridge are untouched: this is a second path, not a
replacement, for the one transport (streamable-http) this service can reach
without it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 21:22:42 +02:00
.mvn/wrapper upgrade to springboot 4 2026-05-05 19:22:53 +02:00
src Let an LLM node call tools directly, bypassing the MCP bridge 2026-09-18 21:22:42 +02:00
.gitattributes first commit 2025-03-27 11:38:06 +01:00
.gitignore Improve assistant model routing and diagnostics 2026-05-20 12:27:09 +02:00
CITATION.cff Release under the AGPL with an attribution term 2026-09-16 12:10:26 +02:00
Dockerfile Harden Maven downloads in Docker build 2026-09-10 11:34:39 +02:00
LICENSE Release under the AGPL with an attribution term 2026-09-16 12:10:26 +02:00
LICENSE-ADDENDUM Release under the AGPL with an attribution term 2026-09-16 12:10:26 +02:00
NOTICE Release under the AGPL with an attribution term 2026-09-16 12:10:26 +02:00
README.md Release under the AGPL with an attribution term 2026-09-16 12:10:26 +02:00
mvnw first commit 2025-03-27 11:38:06 +01:00
mvnw.cmd first commit 2025-03-27 11:38:06 +01:00
ollama-preloaded-docker image for test with ollama added 2025-09-29 17:00:57 +02:00
pom.xml Release under the AGPL with an attribution term 2026-09-16 12:10:26 +02:00
run_service.sh Replace Flyway schema setup with JPA mappings 2026-09-09 12:20:36 +02:00

README.md

RUN LOCAL SERVICE

./run_service.sh

BUILD DOCKER IMAGE

docker buildx build –platform linux/amd64,linux/arm64 -t luciolelii/humainflow:latest . –push

HOST

lelii@build-host.internal

License

Copyright (C) 2025-2026 Lucio Lelii — ISTI-CNR.

HumAIn Flow is released under the GNU Affero General Public License v3.0 or later (LICENSE), with an additional attribution term under section 7(b) of that license (LICENSE-ADDENDUM).

In practice this means:

  • you may use, study, modify and redistribute it freely;

  • if you run a modified version as a network service, you must offer its source to the users of that service;

  • any work based on it must keep the attribution below, both in the source and where the interface shows its legal notices:

    Based on HumAIn Flow, originally developed by Lucio Lelii (ISTI-CNR) — https://github.com/luciolelii/humainflow-service

If you use HumAIn Flow in academic work, please cite it — see CITATION.cff.