Supporting Agentic Workloads #3644
Replies: 2 comments 1 reply
|
This split feels right to me: make services callable as tools, but leave the agent loop, memory, and durable workflow engine outside the web framework. The piece I would add to the
That does not mean GoFr needs to become an agent runtime. I would keep the core interface small: schema exposure plus pre-invocation and post-invocation hooks. Then separate modules can implement policy, human approval, redaction, tracing, or receipts without pulling those dependencies into A useful first version might be: default every exported MCP handler to read-only metadata unless the developer explicitly marks side effects, and emit a per-call receipt with tool name, schema hash, caller/session id, policy decision, and result class. That gives Claude Code or any MCP client a clean tool surface while giving production teams a way to debug and audit agent-triggered service calls. Disclosure: I work on Armorer Labs. |
Uh oh!
There was an error while loading. Please reload this page.
Right now if someone wants to wire up Claude or any other AI agent to call their GoFr service, they have to write a bunch of glue code manually. The idea here is simple — make that a one-liner.
With this shipped, a developer adds app.EnableMCP() and their existing handlers are immediately callable by Claude Code, Claude Desktop, or any MCP-compatible agent. No changes to the handlers themselves. The schema for each tool gets derived automatically from the request struct they already wrote.go
import _ "gofr.dev/pkg/gofr/ai/anthropic"
app.EnableMCP()
app.AddLLM(ai.Anthropic(ai.AnthropicConfigs{}))
app.Run()
That's the entire opt-in. Everything else — health checks, traces, metrics — comes for free the same way it does for every other GoFr feature.
The one rule we can't break
Nothing new lands in the core gofr.dev module's dependencies.
Same way we handle Cassandra, Mongo, S3 etc. — the interface lives in core, the actual SDK dependency lives in a separate module that users pull in via blank import. Every PR here needs to run go mod tidy on the root module and confirm go.sum hasn't grown.
Module split:gofr.dev ← core, zero new deps
ai.Model interface
app.EnableMCP() / app.AddLLM()
ctx.LLM() / ctx.MCPTools()
pkg/gofr/ai/mcp/ go.mod ← MCP server + schema extraction
pkg/gofr/ai/anthropic/ go.mod ← Anthropic SDK
pkg/gofr/ai/openai/ go.mod ← OpenAI SDK
pkg/gofr/sync/ go.mod ← distributed lock + leader election
pkg/gofr/secrets/ go.mod ← secrets provider interface + impls
What we're not doing and why
These aren't gaps we'll fill later — they're deliberate decisions. Worth writing down so we have something to point at when PRs come in for them.
Agent loop / multi-turn runtime — GoFr's job is to make services callable as tools. What the agent does with those tools — how many turns, when to stop, how to handle streaming — varies wildly per use case. If we bake in one loop, we're making that choice for everyone. We provide ctx.LLM() and ctx.MCPTools() as primitives; the loop itself stays in userland.
Agent memory and plan/delegate — Same reasoning. Memory backend, serialization format, TTL, persistence across restarts — these are application-level concerns. GoFr already has a store interface if someone wants to build this on top of it.
Built-in service registry / client-side load balancing — Once you're on Kubernetes, your registry is K8s DNS and your load balancer is the service mesh. Baking one into the framework just means two systems that need to agree, and yours is always the one people stop trusting. We complement the platform, we don't replace it.
Workflow / durable execution engine — Checkpointed, resumable multi-step workflows are a hard problem. Temporal solves it well. We're not going to do a worse version of Temporal inside GoFr.
Bundled ORM — Already a stated GoFr principle. ORMs leak abstractions and pull in large dependency trees. Plain SQL via ctx.SQL() works, and people can add sqlc or gorm themselves if they want it.
All reactions