Netsuite Mcp Server — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Netsuite Mcp Server (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Serveur MCP (Model Context Protocol) qui expose l'API REST NetSuite pour orchestrer les flux d'intégration Spendesk × NetSuite.
Ce projet suit la même architecture que le serveur MCP Spendesk (mcp-poc) en production :
stdio : pour Cursor, Claude DesktopHTTP Streamable : pour Dust, ChatGPT, déploiement cloudnode --version # v20+Tu dois créer une Integration et un Access Token dans ton compte sandbox NetSuite :
#### Créer l'Integration
Spendesk MCP ServerEnabled#### Créer l'Access Token
Spendesk MCP Server# Clone le repo
cd netsuite-mcp-server
# Installe les dépendances
npm install
# Configure les credentials
cp .env.example .env
# puis édite .env avec tes vraies credentials.env# NetSuite Sandbox credentials
NETSUITE_ACCOUNT_ID=TSTDRV1234567 # ton account ID sandbox
NETSUITE_CONSUMER_KEY=xxx
NETSUITE_CONSUMER_SECRET=xxx
NETSUITE_TOKEN_ID=xxx
NETSUITE_TOKEN_SECRET=xxx
# HTTP server (pour mode HTTP Streamable)
PORT=3001
HOST=0.0.0.0
ALLOWED_HOSTS=localhost⚠️ Sécurité : .env est dans .gitignore, ne committe jamais tes vrais credentials.
# Build
npm run build
# Lancer le serveur stdio
npm start#### Configuration Cursor
Ajoute dans ton MCP config (~/.cursor/mcp.json ou équivalent) :
{
"mcpServers": {
"netsuite": {
"command": "node",
"args": ["/chemin/absolu/vers/netsuite-mcp-server/dist/index.js"],
"env": {
"NETSUITE_ACCOUNT_ID": "TSTDRV1234567",
"NETSUITE_CONSUMER_KEY": "xxx",
"NETSUITE_CONSUMER_SECRET": "xxx",
"NETSUITE_TOKEN_ID": "xxx",
"NETSUITE_TOKEN_SECRET": "xxx"
}
}
}
}# Build
npm run build
# Lancer le serveur HTTP
npm run start:httpLe serveur écoute sur http://0.0.0.0:3001 par défaut.
Endpoints :
GET / : health checkPOST /mcp : endpoint MCP Streamable HTTP (JSON-RPC + SSE)#### Test du serveur HTTP
# Dans un terminal, lance le serveur :
npm run start:http
# Dans un autre terminal, teste :
npm run test:httpLe serveur expose 25 tools pour orchestrer les flows Spendesk × NetSuite :
department, location, class)department, location, class)Les trois dimensions analytiques NetSuite (department, location, class) sont supportées dans tous les tools de création (vendor bills, journal entries, expense reports, vendor credits).
Exemples de requêtes SuiteQL :
-- Trouver un vendor par externalId
SELECT id, companyName, email FROM vendor WHERE externalId = 'spk_supplier_xxx'
-- Lister les vendor bills non approuvées
SELECT id, tranId, entity, amount, status FROM transaction
WHERE type = 'VendBill' AND status = 'VendBill:B'
-- Mapping account par numéro
SELECT id, acctNumber, acctName, type FROM account WHERE acctNumber LIKE '6%'# Test de connexion NetSuite (liste 5 vendors)
npm run test:vendors
# Test du serveur HTTP MCP complet
npm run test:http
# Test de tous les 25 tools MCP
npm run test:allPour les guides complets et les rapports métier, voir le dossier docs/ :
docs/deploy/ (Quickstart, checklist, guide complet Railway/Dust)docs/setup/docs/testing/docs/suiteql/docs/overview/, docs/vendors/, docs/bill-payments/Un Dockerfile est prévu (à créer si besoin, inspiré du mcp-poc) :
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY dist ./dist
EXPOSE 3001
CMD ["node", "dist/server-http.js"]npm run buildnpm run start:http3001src/
├── index.ts # Entry point stdio
├── server-http.ts # Entry point HTTP Streamable (Hono)
├── netsuite-client.ts # Client REST NetSuite (OAuth 1.0a)
├── tools/
│ ├── index.ts # Enregistre tous les tools
│ ├── vendors.ts # Tools vendors
│ ├── vendor-bills.ts # Tools vendor bills (+ location, class)
│ ├── journal-entries.ts # Tools journal entries (+ location, class)
│ ├── employees.ts # Tools employees (NEW)
│ ├── expense-reports.ts # Tools expense reports (NEW)
│ ├── payments.ts # Tools bill payments (NEW)
│ ├── vendor-credits.ts # Tools vendor credits (NEW)
│ ├── analytics.ts # Tools locations + classifications (NEW)
│ ├── file-cabinet.ts # Tools file upload + attach (NEW)
│ ├── reference.ts # Tools référentiel
│ └── suiteql.ts # Tool SuiteQL
└── utils/
├── oauth1.ts # Génération header OAuth 1.0a HMAC-SHA256
└── pagination.ts # Helper pagination NetSuiteLe client utilise OAuth 1.0a avec signature HMAC-SHA256, implémenté from scratch (pas de lib externe) dans utils/oauth1.ts.
Chaque requête inclut un header Authorization: OAuth ... avec :
oauth_consumer_key, oauth_tokenoauth_signature_method=HMAC-SHA256oauth_timestamp, oauth_nonceoauth_signature (HMAC-SHA256 de la Signature Base String)Tous les tools MCP catchent les erreurs NetSuite et retournent des messages clairs, ex :
NetSuite 401: Invalid credentials. Check NETSUITE_TOKEN_ID and NETSUITE_TOKEN_SECRET.
NetSuite 400: Bad RequestLes tools de création acceptent un paramètre externalId (ex: spendesk_supplier_id, spendesk_payable_id) pour éviter les doublons si l'agent rejoue un flow.
Les logs sont sur stderr (pas stdout, qui est réservé au protocole stdio MCP).
Exemple :
Starting NetSuite MCP HTTP server on 0.0.0.0:3001
Health check: http://0.0.0.0:3001/
MCP endpoint: http://0.0.0.0:3001/mcpVérifie que :
Certains endpoints référentiels (/account, /department, etc.) peuvent ne pas exister ou nécessiter une syntaxe différente selon la version NetSuite. Utilise SuiteQL comme alternative :
SELECT id, acctNumber, acctName FROM account LIMIT 10Vérifie que le port 3001 est libre :
lsof -ti:3001 # Si un PID apparaît, kill-le
npm run start:httpMIT
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.