UNPKG

@suiteinsider/netsuite-mcp

Version:

NetSuite MCP server with OAuth 2.0 PKCE authentication. Works seamlessly with Claude Code, Cursor IDE, and other MCP clients.

421 lines (320 loc) 12.9 kB
# NetSuite MCP Server A Model Context Protocol (MCP) server providing access to NetSuite data through OAuth 2.0 with PKCE authentication. Works seamlessly with any MCP-compatible client including Claude Code, Cursor IDE, and Gemini CLI. ## Features -**OAuth 2.0 with PKCE** - Secure authentication without client secrets -**Automatic Token Refresh** - Tokens refresh automatically before expiration -**Environment Variable Support** - Configure credentials once in your MCP config -**Session Persistence** - Authentication survives server restarts -**Universal MCP Integration** - Works with Claude Code, Cursor IDE, Gemini CLI, and other MCP clients -**NetSuite MCP Tools** - Access to all NetSuite MCP capabilities (SuiteQL, Reports, Saved Searches, etc.) -**Modular Architecture** - Clean, maintainable codebase following single-responsibility principle ## Quick Start ### 1. NetSuite Setup #### Step 1: Install NetSuite AI Connector SuiteApp Before creating the integration record, you must install and configure the NetSuite AI Connector SuiteApp: **Important**: The NetSuite AI Connector SuiteApp is required for MCP functionality. Without it, the MCP tools will not be available even after authentication. #### Step 2: Create OAuth Integration Record After installing the SuiteApp, create an integration record: 1. Navigate to **Setup > Integration > Manage Integrations > New** 2. Fill in the details: - **Name**: "MCP Server Integration" - **OAuth 2.0**: Checked Authorization Code Grant Checked Public Client - **Redirect URI**: `http://localhost:8080/callback` (or your custom port) 3. Save and copy the **Client ID** (consumer key) **Note**: we dont need client secret (since this is public client and Authorization Code Grant with pkce) <img width="1891" height="410" alt="image" src="https://github.com/user-attachments/assets/1779d97e-77e2-4968-8a59-d814e99a8492" /> ### 2. MCP Client Configuration Add to your MCP client's configuration file: **Claude Code**: `~/.claude.json` **Cursor IDE**: `.cursor/mcp.json` **Gemini CLI**: Per Gemini's MCP setup #### Option A: Using npx (Recommended - No Installation Required) ```json { "mcpServers": { "netsuite": { "command": "npx", "args": ["@suiteinsider/netsuite-mcp@latest"], "env": { "NETSUITE_ACCOUNT_ID": "your-account-id", "NETSUITE_CLIENT_ID": "your-client-id", "OAUTH_CALLBACK_PORT": "8080" } } } } ``` **Benefits**: - No manual installation required - Always uses the latest version with `@latest` - Clean, simple configuration - Works immediately after MCP client restart **Optional Environment Variables**: - `OAUTH_CALLBACK_PORT` - OAuth callback port (default: 8080) #### Option B: Local Development Setup For contributing or local development: ```bash # Clone the repository git clone https://github.com/dsvantien/netsuite-mcp-server.git cd netsuite-mcp-server # Install dependencies npm install # Test locally with npm link npm link ``` Then configure with absolute path: ```json { "mcpServers": { "netsuite": { "command": "node", "args": ["/absolute/path/to/netsuite-mcp-server/src/index.js"], "env": { "NETSUITE_ACCOUNT_ID": "your-account-id", "NETSUITE_CLIENT_ID": "your-client-id", "OAUTH_CALLBACK_PORT": "8080" } } } } ``` #### Option C: Without Environment Variables ```json { "mcpServers": { "netsuite": { "command": "npx", "args": ["@suiteinsider/netsuite-mcp@latest"] } } } ``` **Note**: You'll need to provide credentials when calling `netsuite_authenticate` ### 3. Authenticate & Use Start your MCP client and authenticate: ``` Authenticate with NetSuite ``` A browser window opens → Login to NetSuite → Authentication complete! **Important**: After authentication, you'll need to restart your chat or reconnect the MCP server to see NetSuite tools. This is normal MCP behavior. Once authenticated, use natural language queries: ``` Show me all customers List available saved searches Run a SuiteQL query to get sales orders from last month Execute the "Monthly Revenue" report ``` ## Architecture ``` MCP Client (Claude Code, Cursor, Gemini, etc.) │ │ stdio (JSON-RPC) ▼ ┌──────────────────────────────┐ │ MCP Server (Node.js) │ │ │ │ ┌────────────────────────┐ │ │ │ OAuth Manager │ │ │ │ - PKCE generation │ │ │ │ - Local HTTP server │ │ │ │ (port 8080 default) │ │ │ │ - Token storage │ │ │ └────────────────────────┘ │ │ │ │ ┌────────────────────────┐ │ │ │ MCP Tools │ │ │ │ - ns_runCustomSuiteQL │ │ │ │ - ns_runReport │ │ │ │ - ns_listSavedSearches │ │ │ └────────────────────────┘ │ └──────────────────────────────┘ │ │ HTTPS + Bearer Token ▼ ┌──────────────────────────────┐ │ NetSuite MCP REST API │ └──────────────────────────────┘ ``` ## Project Structure ``` netsuite-mcp-server/ ├── src/ │ ├── index.js # Main MCP server entry point │ ├── oauth/ │ │ ├── manager.js # OAuth flow orchestrator │ │ ├── pkce.js # PKCE challenge/verifier generation │ │ ├── callbackServer.js # HTTP callback server with CSRF protection │ │ ├── sessionStorage.js # Session file management │ │ └── tokenExchange.js # Token exchange & refresh operations │ ├── mcp/ │ │ └── tools.js # NetSuite MCP API client │ └── utils/ │ └── browserLauncher.js # Cross-platform browser launcher ├── sessions/ # OAuth tokens (gitignored) ├── authenticate.js # Standalone CLI authentication utility ├── package.json ├── .gitignore └── README.md ``` ### Modular Design Benefits The codebase follows the single-responsibility principle: - **pkce.js** - PKCE utilities (base64 encoding, challenge generation) - **callbackServer.js** - HTTP callback handling (CSRF protection, HTML pages, timeouts) - **sessionStorage.js** - Session persistence (save, load, clear, isAuthenticated) - **tokenExchange.js** - NetSuite OAuth API communication (token exchange/refresh) - **browserLauncher.js** - Cross-platform URL opening (macOS, Windows, Linux) This modular structure enables: - ✅ Independent testing of each module - ✅ Easy maintenance and debugging - ✅ Reusability in other projects - ✅ Clear separation of concerns ## Environment Variable Configuration ### Configuration Example **Recommended npx setup:** ```json { "mcpServers": { "netsuite": { "command": "npx", "args": ["@suiteinsider/netsuite-mcp@latest"], "env": { "NETSUITE_ACCOUNT_ID": "123456-sb1", "NETSUITE_CLIENT_ID": "your-client-id-here", "OAUTH_CALLBACK_PORT": "8080" } } } } ``` **Local development setup:** ```json { "mcpServers": { "netsuite": { "command": "node", "args": ["path/to/src/index.js"], "env": { "NETSUITE_ACCOUNT_ID": "123456-sb1", "NETSUITE_CLIENT_ID": "your-client-id-here", "OAUTH_CALLBACK_PORT": "8080" } } } } ``` ### Environment Variables - **NETSUITE_ACCOUNT_ID** - Your NetSuite account ID (required) - **NETSUITE_CLIENT_ID** - Your OAuth client ID (required) - **OAUTH_CALLBACK_PORT** - OAuth callback port (optional, default: 8080) ### Resolution Order 1. **Check arguments first**: If `accountId` or `clientId` provided as arguments, use them 2. **Fallback to environment variables**: If no arguments, use env vars 3. **Validation**: If neither source provides credentials, show error with instructions ### Security Best Practices 1. **File Permissions**: Ensure config file has restrictive permissions ```bash chmod 600 ~/.claude.json ``` 2. **No Secrets**: Client secrets not required (PKCE authentication) 3. **Local Token Storage**: OAuth tokens stored in `sessions/` directory 4. **Never Commit**: Don't commit config files with credentials to git ## Available NetSuite MCP Tools Once authenticated, you'll have access to NetSuite's native MCP tools: - `ns_runCustomSuiteQL` - Execute SuiteQL queries - `ns_listAllReports` - List available financial reports - `ns_runReport` - Execute a specific report - `ns_listSavedSearches` - List saved searches - `ns_runSavedSearch` - Execute a saved search - `ns_getRecord` - Retrieve a specific record - `ns_createRecord` - Create a new record - `ns_updateRecord` - Update an existing record - And more... The exact tools available depend on your NetSuite account configuration. ## OAuth Flow 1. **Initiation**: User calls `netsuite_authenticate` with credentials 2. **PKCE Generation**: Server generates code verifier and SHA-256 challenge 3. **Authorization URL**: Server generates NetSuite OAuth URL and starts local callback server 4. **User Login**: Browser opens NetSuite login page 5. **Authorization**: User approves access 6. **Callback**: NetSuite redirects to `http://localhost:8080/callback` with authorization code 7. **Token Exchange**: Server exchanges code for access/refresh tokens (public client pattern) 8. **Session Storage**: Tokens stored in `sessions/session.json` (persists across restarts) 9. **Auto-Refresh**: Tokens automatically refresh when expiring (5-minute buffer) ## Troubleshooting now uses absolute paths based on script location ### Issue: "Port already in use" **Cause**: Another application using the OAuth callback port **Solution**: ```bash # Check what's using the port (example for port 8080) lsof -i :8080 # Option 1: Kill the process # Option 2: Change port via environment variable ``` Set custom port in your MCP config: ```json { "env": { "OAUTH_CALLBACK_PORT": "9000" } } ``` **Remember to update the redirect URI in your NetSuite integration to match the new port!** ### Issue: Tools not appearing after authentication **Cause**: MCP clients cache tool list at session start **Solution**: - **Restart chat** - Open new conversation - **Reconnect MCP** - Use `/mcp` command (Claude Code) - **Restart app** - Close and reopen your IDE This is normal MCP behavior - tool lists are fetched once per session. ## Development ### Standalone Authentication Test authentication without MCP client: ```bash node authenticate.js <accountId> <clientId> ``` ### Clearing Session ```bash rm -rf sessions/ ``` Or use the `netsuite_logout` tool in your MCP client. ### Viewing Logs All server logs output to stderr. When running in MCP clients, these logs appear in the client's console/logs. ## Technical Details ### PKCE Implementation - **Code Verifier**: 32 random bytes, base64url encoded - **Code Challenge**: SHA-256 hash of verifier, base64url encoded - **Challenge Method**: S256 (required by NetSuite) ### Token Exchange (Public Client Pattern) ```http POST https://{accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code={authorization_code} &redirect_uri=http://localhost:8080/callback &client_id={client_id} &code_verifier={verifier} ``` **Important**: No `Authorization` header (public client). ### Token Refresh Tokens automatically refresh when expiring in < 5 minutes: ```http POST https://{accountId}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token Content-Type: application/x-www-form-urlencoded grant_type=refresh_token &refresh_token={refresh_token} &client_id={client_id} ``` ## Prerequisites - **Node.js** 18.0.0 or higher - **NetSuite Account** with MCP access - **NetSuite AI Connector SuiteApp** (Bundle ID: 522506) installed and configured - **NetSuite Integration Record** with OAuth 2.0 and PKCE enabled - **MCP Client** - Any MCP-compatible client (Claude Code, Cursor IDE, Gemini CLI, etc.) ## License MIT ## References - [Model Context Protocol Documentation](https://modelcontextprotocol.io/) - [NetSuite OAuth 2.0 Documentation](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_158081952044.html) - [PKCE Specification (RFC 7636)](https://datatracker.ietf.org/doc/html/rfc7636)