Add erpnext-mcp/src/index.ts
This commit is contained in:
parent
72bfac437b
commit
bba62faf23
1 changed files with 148 additions and 0 deletions
148
erpnext-mcp/src/index.ts
Normal file
148
erpnext-mcp/src/index.ts
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import express from "express";
|
||||
|
||||
import { ERPNextClient } from "./services/erpnext-client.js";
|
||||
import { registerCoreTools } from "./tools/core.js";
|
||||
import { registerAccountingTools } from "./tools/accounting.js";
|
||||
import { registerSellingTools } from "./tools/selling.js";
|
||||
import { registerBuyingTools } from "./tools/buying.js";
|
||||
import { registerStockTools } from "./tools/stock.js";
|
||||
import {
|
||||
registerManufacturingTools,
|
||||
registerHRTools,
|
||||
registerCRMTools,
|
||||
registerProjectTools,
|
||||
registerSupportTools,
|
||||
registerSetupTools,
|
||||
} from "./tools/domains.js";
|
||||
import { registerFrappeTools } from "./tools/frappe.js";
|
||||
|
||||
// ── Configuration ───────────────────────────────────────
|
||||
|
||||
function getConfig() {
|
||||
const baseUrl = process.env.ERPNEXT_URL || process.env.ERPNEXT_BASE_URL || "";
|
||||
const apiKey = process.env.ERPNEXT_API_KEY || "";
|
||||
const apiSecret = process.env.ERPNEXT_API_SECRET || "";
|
||||
|
||||
if (!baseUrl || !apiKey || !apiSecret) {
|
||||
console.error(
|
||||
"Missing required environment variables:\n" +
|
||||
" ERPNEXT_URL - ERPNext instance URL (e.g. https://erp.example.com)\n" +
|
||||
" ERPNEXT_API_KEY - API Key from ERPNext user settings\n" +
|
||||
" ERPNEXT_API_SECRET - API Secret from ERPNext user settings"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
return { baseUrl, apiKey, apiSecret };
|
||||
}
|
||||
|
||||
// ── Server Setup ────────────────────────────────────────
|
||||
|
||||
function createServer(): { server: McpServer; client: ERPNextClient } {
|
||||
const config = getConfig();
|
||||
const client = new ERPNextClient(config);
|
||||
|
||||
const server = new McpServer({
|
||||
name: "erpnext-mcp-server",
|
||||
version: "1.0.0",
|
||||
});
|
||||
|
||||
// Register all tool categories
|
||||
registerCoreTools(server, client); // 1-15: Generic CRUD, search, reports, meta, bulk ops
|
||||
registerAccountingTools(server, client); // 16-22: GL balance, exchange rate, journal entries, payments
|
||||
registerSellingTools(server, client); // 23-30: Quotations, sales orders, invoices, delivery notes
|
||||
registerBuyingTools(server, client); // 31-36: Purchase orders, receipts, RFQ, supplier quotations
|
||||
registerStockTools(server, client); // 37-50: Stock balance, entries, batches, barcodes, bins
|
||||
registerManufacturingTools(server, client);// 51-53: Work orders, BOMs
|
||||
registerHRTools(server, client); // 54-57: Employees, departments, org chart
|
||||
registerCRMTools(server, client); // 58-60: Leads, opportunities, pipeline
|
||||
registerProjectTools(server, client); // 61-63: Projects, tasks
|
||||
registerSupportTools(server, client); // 64-66: Issues, SLA
|
||||
registerSetupTools(server, client); // 67-70: Company, addresses, holidays, T&C
|
||||
registerFrappeTools(server, client); // 71-100+: Get/set value, assignments, comments, tags,
|
||||
// leaderboards, notifications, todos, activity,
|
||||
// linked docs, print formats, warehouse tree,
|
||||
// returns, material request ops, rename, etc.
|
||||
|
||||
console.error(
|
||||
`ERPNext MCP Server initialized\n` +
|
||||
` Instance: ${config.baseUrl}\n` +
|
||||
` Tools registered: 100+`
|
||||
);
|
||||
|
||||
return { server, client };
|
||||
}
|
||||
|
||||
// ── Transport: stdio ────────────────────────────────────
|
||||
|
||||
async function runStdio(): Promise<void> {
|
||||
const { server } = createServer();
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error("ERPNext MCP Server running on stdio");
|
||||
}
|
||||
|
||||
// ── Transport: Streamable HTTP ──────────────────────────
|
||||
|
||||
async function runHTTP(): Promise<void> {
|
||||
const { server } = createServer();
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Health check
|
||||
app.get("/health", (_req, res) => {
|
||||
res.json({ status: "ok", server: "erpnext-mcp-server", version: "1.0.0" });
|
||||
});
|
||||
|
||||
// MCP endpoint
|
||||
app.post("/mcp", async (req, res) => {
|
||||
const transport = new StreamableHTTPServerTransport({
|
||||
sessionIdGenerator: undefined,
|
||||
enableJsonResponse: true,
|
||||
});
|
||||
res.on("close", () => transport.close());
|
||||
await server.connect(transport);
|
||||
await transport.handleRequest(req, res, req.body);
|
||||
});
|
||||
|
||||
// Handle GET and DELETE for MCP protocol compliance
|
||||
app.get("/mcp", async (_req, res) => {
|
||||
res.writeHead(405).end(JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
error: { code: -32000, message: "Method not allowed. Use POST for MCP requests." },
|
||||
id: null,
|
||||
}));
|
||||
});
|
||||
|
||||
app.delete("/mcp", async (_req, res) => {
|
||||
res.writeHead(405).end(JSON.stringify({
|
||||
jsonrpc: "2.0",
|
||||
error: { code: -32000, message: "Method not allowed." },
|
||||
id: null,
|
||||
}));
|
||||
});
|
||||
|
||||
const port = parseInt(process.env.PORT || "32802", 10);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.error(`ERPNext MCP Server running on http://0.0.0.0:${port}/mcp`);
|
||||
});
|
||||
}
|
||||
|
||||
// ── Entrypoint ──────────────────────────────────────────
|
||||
|
||||
const transport = process.env.TRANSPORT || "stdio";
|
||||
if (transport === "http") {
|
||||
runHTTP().catch((error) => {
|
||||
console.error("Server error:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
runStdio().catch((error) => {
|
||||
console.error("Server error:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue