createAgent (the ReAct prebuilt, running on LangGraph) —
it runs the model, calls your tools, persists state, and loops until the job is done.
What LangGraph doesn’t ship is a way for those agents to act as a real account — sign
up for a SaaS tool, hold a funded card, or spend within a budget you control, per end-user.
That’s the half Naive adds. You keep LangGraph’s orchestration; Naive gives each agent a
tenant identity, a virtual card,
1,000+ third-party connections, and an
Account Kit that bounds exactly what the agent can do —
enforced server-side, with human approval on the
sensitive actions.
How the pairing works
The Naive SDK exposes a small, drop-in toolset viaagentTools(). Instead of dumping
thousands of schemas on the model, it’s a discover-then-run meta-toolset (search
apps/primitives, then run them). Each Naive tool ships an Anthropic-style input_schema
(plain JSON Schema), which LangChain’s tool() accepts directly — so the adapter is a few
lines, and every call stays gated by the user’s Account Kit:
Tested against:
@usenaive-sdk/server (Naive API v2), LangChain v1 — langchain
1.x (createAgent, humanInTheLoopMiddleware), @langchain/core 1.x (tool),
@langchain/langgraph 1.x (runtime), @langchain/anthropic 1.x
(ChatAnthropic), and @langchain/mcp-adapters 1.1.x (MultiServerMCPClient, for the
MCP extension), on Node ≥ 20.Passing a raw JSON Schema to tool() (instead of Zod) is supported on current
@langchain/core 1.x. On pre-v1 LangGraph (@langchain/langgraph 0.x),
swap createAgent from langchain for createReactAgent from
@langchain/langgraph/prebuilt (use llm: instead of model: and prompt: instead of
systemPrompt:). Pin your versions and adjust the model id to a provider/model you have
access to.Prerequisites
- A Naive API key (
nv_sk_...) — get one from the dashboard. - A model provider key for whichever model runs the graph (this guide uses Anthropic via
ANTHROPIC_API_KEY). - Node ≥ 20.
Minimal viable integration
The shortest path to a LangGraph agent that can actually transact: define a policy, provision a user, adapt Naive’s tools, and run the graph.Define the policy, then provision a user
An Account Kit is the spend/capability policy. Here a tenant
user gets a card (capped at $500, approval required), the vault, and an allowlist of apps.
Everything the agent does is bounded by this kit — server-side.
Adapt Naive's tools into LangChain tools
client.agentTools() returns tools as JSON-schema definitions plus a handle(name, input)
dispatcher. LangChain’s tool() accepts a JSON Schema directly in its schema field, so
the adapter just maps each Naive tool’s input_schema and routes the executor through
handle:naive_search_apps, naive_connect_app,
naive_run_capability, naive_search_primitives, naive_run_primitive, …) — a handful of
tools that reach every app and primitive the kit allows, instead of thousands of schemas.LangChain doesn’t runtime-validate JSON-Schema tool inputs (only Zod schemas are
validated), but Naive re-validates every call server-side against the Account Kit, so
the model can’t smuggle out-of-policy arguments past the graph.
Build the graph — and let it transact
Hand the adapted tools to The model discovers GitHub, returns a connect link for Alice to authorize, and attempts to
issue the card — a real card on Alice’s account, capped by her kit. The whole graph is
LangGraph’s; the real-world actions are Naive’s.
createAgent. It compiles a LangGraph ReAct graph (model node →
tool node → loop) and runs the multi-step loop for you (call tool → feed result back →
continue):createAgent graph that would otherwise just
describe spending money now issues a policy-bounded card on a specific user’s account.
Extension: human-in-the-loop spend (two gates)
Because the kit setcards.requiresApproval: true, the agent cannot silently spend.
You get two complementary layers — pair them for defense in depth:
- In the graph — LangChain’s
humanInTheLoopMiddlewareinterrupts before a sensitive tool runs, so the graph pauses and surfaces the call for review. - On the server — even if a call gets through, Naive freezes it and returns a pending
approval (HTTP
202) instead of a live card. This holds no matter what runtime calls it.
202 / isPendingApproval payload uses action; approval records from
approvals.list() or approvals.get() use action_type.
Your app then resolves it out of band — and on approval, Naive replays the frozen action
server-side:
isPendingApproval(res), or
poll a single approval to completion with client.approvals.wait(approvalId). See
Approvals for the full lifecycle (pending → executed / failed / denied).
Approvals are only enforced for agent (API-key / MCP) calls on real tenant users. A human
acting in your dashboard, and agent calls on the operator’s own default user, bypass the
gate — so end-user agents stay governed while your own automation isn’t slowed down.
Alternative: hand a scoped MCP session to the graph
If the agent runs somewhere you don’t fully trust (an edge runtime, a third-party host), don’t ship it your API key. Mint a short-lived, per-user MCP session and connect to it with@langchain/mcp-adapters — the bearer lives only in the session headers
and expires. getTools() auto-discovers Naive’s tools as LangChain tools:
client.sessions.revoke(session.id).
What stays enforced
No matter which path you choose, the policy is enforced where it matters — on Naive’s servers, not in your prompt or your graph:- Identity — every action runs as a specific tenant user, fully isolated from your other users.
- Capability bounds — the Account Kit decides which
primitives and which apps the agent can touch (
allowlist/blocklist/ per-tool). - Scoped spend — virtual cards are capped per card and per user; the model can’t raise its own limit.
- Human-in-the-loop — sensitive actions (cards, domains, KYC, formation, connecting an app) freeze as approvals until a human says yes.
Next steps
- SDK overview — the full Naive client surface
- Agent tools — what
agentTools()exposes and howhandle()works - Account Kits — author spend/capability policy
- Approvals — the human-in-the-loop lifecycle
- Sessions — per-user MCP sessions for untrusted runtimes
- Vercel AI SDK — the same pairing, AI SDK flavor