AI Use Cases & Business Automation Examples | RAAS Impact

Building an AI Agent for NetSuite: When "It Just Works" Doesn't (Part 1)

Written by Lino Moretto | Mar 18, 2026 6:43:30 PM

 

A technical deep-dive into connecting Google's Agent Development Kit with NetSuite's ERP — the authentication challenges nobody talks about, and the research journey that led to a working solution.

The Promise

"Build AI agents that connect to any system in minutes."

That's what Google's Agent Development Kit (ADK) promised. Combine it with the Model Context Protocol (MCP), and suddenly your AI agent can talk to databases, APIs, and enterprise systems like NetSuite.

The official ADK documentation made it look straightforward — a few lines of Python, point your agent at an MCP server's SSE endpoint, and you're done.

I needed exactly this. As someone working with NetSuite daily, I wanted an AI agent that could answer natural language questions about our ERP data. "What were last quarter's top-selling products?" "Show me pending purchase orders." "Run this report and cross-check the results on HubSpot." Simple questions that normally require navigating NetSuite's complex UI.

Google's ADK seemed perfect. NetSuite released their "AI Connector" last August — an MCP endpoint. Everything should just… work.

Spoiler: it didn't. And the reason reveals something fundamental about enterprise AI integrations that the tutorials conveniently skip over: authentication.

The Reality: It's All About Authentication

Here's what the tutorials don't tell you. When you connect AI agents to enterprise systems, you're not just making API calls to a public endpoint. You're dealing with something much more complex: user-authenticated, session-bound access to business-critical data.

Think about it:

  • Your AI agent needs to access NetSuite data
  • That data belongs to a specific user with specific permissions
  • The user's credentials must be securely managed
  • The authentication must persist across the agent's session
  • All of this must happen without hardcoding credentials in your agent code

This is fundamentally different from connecting to a public API or a database with service account credentials. This is enterprise-grade, user-context-aware authentication — and it's an essential part of building production AI agents.

That simple SSE connection example from the docs? It assumes your MCP server is either publicly accessible with no authentication, or using simple API keys you can pass in headers. But NetSuite requires OAuth 2.0 — real OAuth, with authorisation flows, access tokens, refresh tokens, and user consent. The kind of authentication that makes enterprise systems secure — and integration complex.

The Research Journey

Discovery 1: NetSuite Has an MCP Server

My starting point was NetSuite's official documentation about their "NetSuite AI Connector" — their implementation of an MCP server.

The docs explained that NetSuite exposes an MCP endpoint, supports OAuth 2.0 authentication, and provides tools for querying records and running saved searches. Great — but light on implementation details. How do I actually authenticate? How do I manage tokens? How does this integrate with ADK?

Discovery 2: Someone Already Built Something Like This

After digging through GitHub, I found an excellent guide by Caleb Moore showing a working NetSuite MCP implementation. Real code, real patterns, actual working examples. Gold.

The guide showed you need NetSuite integration credentials (Client ID and Secret), proper OAuth scope configuration, and careful handling of NetSuite's account ID format. But it used a different architecture than ADK. I needed to figure out how to adapt this pattern to Google's Agent Development Kit.

Discovery 3: ADK's Built-in OAuth Is… Not Simple

ADK's authentication documentation explains you can add OAuth to MCP connections, but it requires implementing a fair amount of infrastructure: defining an AuthConfig, implementing token storage and refresh logic, handling the OAuth callback flow, managing session-bound credentials, and more.

For a proof-of-concept to validate the architecture? Massive overkill.

This is where I hit the wall. I wanted to validate that ADK + NetSuite MCP actually works and build a working demo quickly — then worry about production authentication. But ADK's approach required building the production authentication system first. There was no "simple mode" for OAuth-protected MCP servers.

Discovery 4: The mcp-remote Breakthrough

That's when I found an article by Claude Chaikin about breaking open the NetSuite AI Connector Service. The key insight:

The mcp-remote tool can act as a proxy, handling OAuth authentication behind the scenes and presenting the remote MCP server as if it were local.

This changed everything. mcp-remote connects to remote MCP servers via HTTP/SSE, handles OAuth automatically, and exposes the remote server via stdio (standard input/output), making it look like a "local" MCP server to your application.

The architecture becomes clean and simple:

My Agent (Python)
↓ stdio (simple!)
mcp-remote (Node.js) ← Handles ALL OAuth complexity
↓ HTTPS + OAuth NetSuite MCP Server

Instead of my agent needing to implement OAuth, run a callback server, manage token storage, and handle refresh logic — all of that is isolated in mcp-remote. My agent code stays simple. Token management is automatic. Easy to debug. No callback server needed.

The Implementation (Then Reality Hit Again)

Armed with this research, I started implementing. The setup was straightforward — configure McpToolset with StdioConnectionParams pointing at the local patched mcp-remote, pass the NetSuite credentials, run adk run netsuite_agent with a simple query and...

Error: Invalid token response from OAuth provider Expected 'expires_in' to be a number, received string 

Hours of research. Clear architecture. Clean code. And it still doesn't work.

This is where most tutorials end. "Just use the standard OAuth flow!" they say. But enterprise systems don't always follow standards.

I added debug logging to mcp-remote and found the culprit. NetSuite's token response returns expires_in as a string ("3600") instead of a number (3600). According to the OAuth 2.0 specification (RFC 6749), expires_in should be a number representing seconds. But NetSuite returns a string. This seemingly minor difference breaks the entire MCP SDK authentication flow.

The MCP SDK uses Zod for schema validation, and NetSuite's string value fails validation. The connection dies before it even starts.

The Solution: One Word

The fix lives deep in the dependency chain — in @modelcontextprotocol/sdk, specifically in the OAuthTokensSchema. The change is surprisingly simple:

// Before (strict validation)
expires_in: z.number().optional()

// After (coerce strings to numbers)
expires_in: z.coerce.number().optional()

That single word — coerce — makes Zod automatically convert "3600" to 3600 before validation.

I created a local patched version of mcp-remote, placed it in .node/mcp-remote in the project, and modified the code to use the local version instead of the npm package.

Update: This has since been fixed in the TypeScript SDK.

What This Taught Us

Authentication is the hard part of enterprise AI. Not the AI. Not the prompting. Not the agent framework. The secure, user-context-aware connection to business-critical data — that's where the real work lives.

Research first, code second. Read official docs. Find working examples. Understand available approaches. Make informed architectural decisions. The hours I spent researching before writing a single line of code saved days of going down the wrong path.

Enterprise APIs are different. Expect quirks and non-standard implementations. Debug with proper tools. Be willing to patch when necessary. And document everything — because the next person hitting this wall deserves a shorter path.

The right tool for the job:

  • ADK native OAuth → production multi-tenant apps
  • mcp-remote → prototyping and single-tenant deployments
  • Service accounts → internal tools with trusted users

Coming Up in Part 2

We've solved the authentication challenge — the hardest part of enterprise AI integrations. In the next article, we'll build the complete AI agent on top of this foundation: full code implementation, handling tool calls and responses, real-world examples of the agent querying NetSuite, and the lessons learned when the LLM meets real ERP complexity.

Read Part 2: From Working Auth to Working Agent →

Resources

Originally published on Medium.

At RAAS Impact, we help businesses navigate exactly these kinds of enterprise AI integration challenges — from proof of concept to production. Let's talk if you're exploring AI agents for your ERP or business systems.