- What LlamaIndex ships —
FunctionAgent/AgentWorkfloworchestration, tool-calling, multi-agent handoff,Context-based state, typedoutput_clsresults, and first-class MCP client support viallama-index-tools-mcp. - What it doesn’t ship — 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.
How the pairing works
- LlamaIndex turns any MCP server into a list of
FunctionTools — point aBasicMCPClientat the server, wrap it in anMcpToolSpec, andto_tool_list_async()returns tools you hand straight to aFunctionAgent. - Naive ships a hosted MCP server and mints per-user sessions — short-lived, revocable SSE endpoints whose tool list is the fused native + third-party toolset, already filtered by that user’s Account Kit.
- So the integration is: mint a session for one user → build a
BasicMCPClientagainst its SSE URL + scoped bearer → load the tools into aFunctionAgent→ every tool call runs as that user, gated server-side.
Tested against: Naive API v2 (hosted MCP server over SSE, per-user sessions),
llama-index / llama-index-core 0.14.x (llama_index.core.agent.workflow.FunctionAgentAgentWorkflow,output_cls),llama-index-tools-mcp0.4.x (BasicMCPClientwithheaders,McpToolSpec),llama-index-llms-openai0.7.x, and themcpPython package 1.x, on Python 3.10–3.13.
/mcp/sse/…, so BasicMCPClient auto-selects SSE transport
(it switches on /sse/ in the path); the scoped bearer is passed via its headers argument,
never the URL. There is no Naive Python SDK today — provision the control plane over the REST API, the
dashboard, the CLI, or the Node SDK (@usenaive-sdk/server).
Pin your versions and
set the model to one you have access to.Prerequisites
- A Naive API key (
nv_sk_...) — get one from the dashboard. - A model provider key for the model that runs the agent (this guide uses OpenAI via
OPENAI_API_KEY). - Python 3.10–3.13.
Minimal viable integration
The shortest path to a LlamaIndex agent that can actually transact: define a policy, provision a user (control plane, once), then at runtime mint a per-user MCP session and load its tools into aFunctionAgent.
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. These are one-time
control-plane calls:
Mint a per-user MCP session
At runtime, mint a short-lived session scoped to one user. It
returns an SSE URL plus a scoped bearer that lives only in the headers — never in the URL —
and expires (default 15 min, max 24h):
Load the tools — and let the agent transact
Build a The agent discovers GitHub (
BasicMCPClient against the session, turn it into a tool list, and hand it to a
FunctionAgent. LlamaIndex discovers Naive’s tools automatically and runs the agent loop for
you. Because it’s LlamaIndex, you can also pin a typed output_cls so the run returns a
validated object, not a blob of text:naive_connections_connect), returns a connect link for Alice
to authorize, and attempts to issue the card (naive_cards_create) — a real card on
Alice’s account, capped by her kit. The whole agent loop is LlamaIndex’s; the real-world
actions are Naive’s.SetupReport back.
The session’s tool list is already filtered by Alice’s kit — the agent never sees a tool the
policy forbids. To narrow further per agent, pass
allowed_tools=[...] to McpToolSpec
(or BasicMCPClient). To swap the session per request, build a fresh BasicMCPClient and
reload the tool list before each agent.run(...).Extension: human-in-the-loop spend
Because the kit setcards.requiresApproval: true, the agent cannot silently spend. When
it calls the card-issuing tool, Naive freezes the request and the tool result comes back as a
pending approval (HTTP 202) instead of a live card:
202 response uses action; approval records from the approvals API use
action_type.
The agent relays the pending status (card_status: "pending_approval" in the typed report)
instead of claiming success. Your app then resolves it out of band — and on approval, Naive
replays the frozen action server-side:
pending → executed / failed / denied).
To detect the pending state inside the run, stream the workflow with
agent.run(...).stream_events() and inspect each ToolCallResult — you can spot a
pending_approval payload, tag it, and shape how the agent reports it. The server-side gate
holds regardless of what the handler does.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: a multi-agent workflow on one account
LlamaIndex’s strength is multi-agent handoff. The same Naive session can back an entireAgentWorkflow — a planner that hands off to a specialist — and every agent in the graph
inherits the same per-user, policy-bounded toolset:
ops transacts. Naive still enforces identity, capability bounds,
and approvals server-side — the handoff doesn’t widen what either agent may do.
What stays enforced
No matter how the agent is wired, the policy is enforced where it matters — on Naive’s servers, not in your prompt or your agent config:- 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.
- Scoped, expiring access — the agent holds a per-user session bearer, not your API key;
it expires (default 15 min) and you can
DELETE /v1/users/:user_id/sessions/:idto revoke it early.
Next steps
- MCP server — the hosted SSE server and its full tool list
- Sessions — per-user MCP sessions, TTL, and revocation
- Account Kits — author spend/capability policy
- Approvals — the human-in-the-loop lifecycle
- Pydantic AI · CrewAI — the same MCP-session pairing for other Python stacks