DEV Community

Cover image for Connect Your Business APIs Once, Share Them with Every Agent Client via MCP
rebornace
rebornace

Posted on

Connect Your Business APIs Once, Share Them with Every Agent Client via MCP

Project: Baize — a team-facing AI assistant runtime (Go 1.25+, MIT)
Repo: https://github.com/rebornace/baize

1. A very real pain point

When a team rolls out AI, one thing you can't avoid: everyone uses a different Agent client.

One person codes in Cursor, another uses Claude Desktop, another uses something else. Business API docs, login credentials, callback URLs — if you reconfigure them in every client, you end up wiring the same legacy system once in Cursor, then again in Claude Desktop, with credentials scattered everywhere. The day that legacy system changes its auth, you have to go fix each one.

Baize sits on the "wired up the business system" side of this problem. The OpenAPI doc is imported into Baize once, login is completed in Baize's console once, and write-approval is audited in Baize once. The remaining question is: how do you let the Agent clients your team already uses reuse this wired-up capability, instead of reconfiguring it all over again?

That's what MCP server export is for.

2. Where the decision happens, and where it doesn't

One thing to get out of the way: once Baize exports the tools, the decision is not on Baize's side.

The Cursor model in Cursor, Claude in Claude Desktop — they still decide for themselves "which tool to call this turn, with what arguments." What Baize exports is only two things: a tool catalog (name, description, parameter schema), and an execution channel for when those tools are called. Baize's own main model, ReAct loop, decision layer, memory, and context compression are all not involved in this export path.

The payoff is direct: the decision layer stays free to pick on the client side — whichever model you use in Cursor is none of Baize's business — while the execution layer stays centralized in Baize. Business API integration, auth, and approval are maintained in exactly one place.

3. Transport and auth

The export channel runs over the standard MCP Streamable HTTP, stateless. When a client connects, it sends a Bearer key in the request header.

On the server side:

  • Wrong key, or missing key → 401.
  • Keys are stored as hashes only, never in plaintext.
  • Each key maps to a separate export identity (e.g. "the one for Cursor" and "the one for Claude Desktop" are two different keys).
  • Keys can be revoked at any time; revoking one immediately disconnects that client.
  • The whole export feature has a master toggle; when off, all requests return 503.

"One key per identity" isn't ceremony — it's what makes the later login-state and isolation behavior possible.

4. "Read-only" isn't a slogan — it's four layers of hard constraints

The most common objection to exposing business tools to external clients is: what about writes? Baize doesn't just say "read-only" in marketing copy. It stacks four layers in the export policy:

Layer 1: HTTP tools only expose GET/HEAD by default. Before a tool is exported, Baize looks at its HTTP method. Anything that isn't GET or HEAD isn't exported, unless the tool is explicitly marked force_allow.

Layer 2: MCP-sourced write tools are hard-rejected. Baize itself also connects to external MCP servers as a client. Tools coming out of those servers — if their name or description contains insert, update, delete, drop, truncate, execute_write, and similar — are never exported, even if someone tries to force_allow them.

Layer 3: Tools that require approval are not exported. Write operations flagged in Baize as "need human confirmation before calling" (e.g. creating a record) simply don't appear on the export surface — because the export channel has no approval card, and exposing one would mean bypassing human review.

Layer 4: Policy is re-checked at call time. Tools pass policy once when they're registered into the MCP catalog, and again when they're actually invoked. That means if you disable or un-export a tool in Baize's backend, the next external client call fails immediately — no "catalog still lists it but it's already off" gap.

5. How login state is handled

This is the subtlest part of the export path. Legacy APIs require login. Credentials are configured in Baize's console, but when an external client (say, Cursor) calls a tool, whose login state does the call go out with?

Baize's approach: each export identity is bridged to a separate internal identity. It has its own session namespace (prefixed with mcp-export-id: plus the export identity ID), and every call is forced through that identity. Concretely:

  • You log in once inside Baize for the "Cursor identity" and configure its credentials.
  • When Cursor calls any tool with that key, Baize uses that identity to reach the legacy system.
  • The "Claude Desktop key" goes through a different identity, a different login state — the two never cross.

The user inside Cursor never sees the legacy system's login page; credentials are already maintained on Baize's side.

6. The actual usage path

Three steps:

  1. Wire up the business system in Baize's console (OpenAPI doc import, login done, approval rules configured).
  2. Create an export identity in the export settings and generate a key.
  3. Plug Baize's MCP Streamable HTTP endpoint and the Bearer key into your Agent client (Cursor, Claude Desktop — any MCP-supporting client works the same way).

After that, say something in the client; the client model picks which already-wired Baize tool to call, and Baize handles execution and returns the result.

7. How this relates to the previous article

In the earlier post ("How I wired a ten-year-old Java legacy system into AI with zero changes"), MCP only got a short paragraph — the focus was how to bring a legacy system in without touching it. This article zooms in on the MCP server side: Baize doesn't just turn legacy systems into its own tools, it can also share those tools with whatever Agent clients the team already uses.

Putting bidirectional MCP together, Baize's position in the ecosystem is clear: on the way in, it can connect to external MCP tool servers and pull others' tools in; on the way out, it can expose its own wired catalog over MCP so the team doesn't reconfigure anything twice.

8. Closing

"Wire the business API once, let every Agent client on the team use it" sounds like just "sharing a tool catalog." Doing it for real means a pile of concrete questions: how to block writes, how to manage keys, how to isolate login state, how to make config changes take effect immediately. Baize converges those into three areas: export policy, key management, and identity bridging. The default is conservative (read-only, approval-gated things stay hidden, revocable); opening anything up takes an explicit action at each step.

This export capability is still evolving, and different clients support MCP at different depths. Try it out and open an issue — or tell me in the comments how your team connects business tools to your own clients. I'll keep iterating.

GitHub: https://github.com/rebornace/baize

Top comments (2)

Collapse
 
autenai profile image
Auten •

The call-time re-check (layer 4) is the part most export layers skip, nice to see it. Two places I'd expect the other layers to leak with real legacy systems:

  • Layer 1 trusts the HTTP verb. Older internal APIs are full of GET /orders/approve?id=... or GET /export/run that change state. An OpenAPI import can't tell you that, so a per-operation "this GET has side effects" flag (default off for anything with a verb in the path) is cheaper than finding out from an audit log.
  • Layer 2 matches words in names and descriptions, but upstream MCP servers name writes archive_record, set_status, send, sync. Recent servers also declare readOnlyHint / destructiveHint annotations, which help, but they are self-reported by the server you're trying to guard against. Default-deny plus an explicit allowlist per export key holds up better than a denylist of words.

One more thing worth spelling out in the doc: whether the bridged identity's session can expire mid-call and what the client sees then. Cursor and Claude Desktop both surface a tool error to the model, and the model will happily retry or "work around" it unless the error text says plainly that a human has to re-login in Baize.

The systems that never got an OpenAPI doc at all (old desktop apps, admin panels) are the slice we work on at Auten, driving the screen instead. Where an API exists, a centralized layer like this is the better path.

Collapse
 
suppdevbot profile image
DEV SUPPORTS •

You need to verify your account.

Enter fullscreen mode Exit fullscreen mode

tr.ee/dev-to