Add wave-mcp/src/index.ts
This commit is contained in:
parent
f134b18bde
commit
6ac85284c2
1 changed files with 143 additions and 0 deletions
143
wave-mcp/src/index.ts
Normal file
143
wave-mcp/src/index.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Wave Finance MCP Server
|
||||||
|
*
|
||||||
|
* Provides tools for interacting with the Wave Finance GraphQL API,
|
||||||
|
* including businesses, customers, products, invoices, and accounting.
|
||||||
|
*
|
||||||
|
* Environment Variables:
|
||||||
|
* WAVE_ACCESS_TOKEN - Wave OAuth2 access token (required)
|
||||||
|
* TRANSPORT - 'http' or 'stdio' (default: 'stdio')
|
||||||
|
* PORT - HTTP port when TRANSPORT=http (default: 8300)
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 { WaveClient } from "./services/wave-client.js";
|
||||||
|
import { registerBusinessTools } from "./tools/businesses.js";
|
||||||
|
import { registerCustomerTools } from "./tools/customers.js";
|
||||||
|
import { registerProductTools } from "./tools/products.js";
|
||||||
|
import { registerInvoiceTools } from "./tools/invoices.js";
|
||||||
|
import { registerAccountingTools } from "./tools/accounting.js";
|
||||||
|
|
||||||
|
// ── Configuration ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function getConfig(): { accessToken: string } {
|
||||||
|
const accessToken = process.env.WAVE_ACCESS_TOKEN ?? "";
|
||||||
|
|
||||||
|
if (!accessToken) {
|
||||||
|
console.error(
|
||||||
|
"Missing required environment variable:\n" +
|
||||||
|
" WAVE_ACCESS_TOKEN - Wave OAuth2 access token\n\n" +
|
||||||
|
"To obtain a token, see the Wave Developer Portal:\n" +
|
||||||
|
" https://developer.waveapps.com"
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { accessToken };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Server Setup ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function createServer(): { server: McpServer; waveClient: WaveClient } {
|
||||||
|
const config = getConfig();
|
||||||
|
const waveClient = new WaveClient(config);
|
||||||
|
|
||||||
|
const server = new McpServer({
|
||||||
|
name: "wave-mcp-server",
|
||||||
|
version: "1.0.0",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register tool groups
|
||||||
|
registerAccountingTools(server, waveClient); // user, accounts, transactions, currencies, countries
|
||||||
|
registerBusinessTools(server, waveClient); // list_businesses, get_business
|
||||||
|
registerCustomerTools(server, waveClient); // list, get, create, update, delete customers
|
||||||
|
registerProductTools(server, waveClient); // list, create, update, archive products
|
||||||
|
registerInvoiceTools(server, waveClient); // list, get, create, approve, send, delete invoices
|
||||||
|
|
||||||
|
console.error("Wave MCP Server initialized with tools:");
|
||||||
|
console.error(" Accounting: wave_get_user, wave_list_accounts, wave_create_transaction, wave_list_currencies, wave_list_countries");
|
||||||
|
console.error(" Businesses: wave_list_businesses, wave_get_business");
|
||||||
|
console.error(" Customers: wave_list_customers, wave_get_customer, wave_create_customer, wave_update_customer, wave_delete_customer");
|
||||||
|
console.error(" Products: wave_list_products, wave_create_product, wave_update_product, wave_archive_product");
|
||||||
|
console.error(" Invoices: wave_list_invoices, wave_get_invoice, wave_create_invoice, wave_approve_invoice, wave_send_invoice, wave_delete_invoice");
|
||||||
|
|
||||||
|
return { server, waveClient };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Transport: stdio ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
async function runStdio(): Promise<void> {
|
||||||
|
const { server } = createServer();
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
await server.connect(transport);
|
||||||
|
console.error("Wave MCP Server running via stdio");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Transport: 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: "wave-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);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 ?? "8300", 10);
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.error(`Wave 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