chore: add project plan, research, evidence, and workflow artifacts

This commit is contained in:
2026-03-10 17:45:26 +00:00
parent 8fc6d7cbc0
commit 14c2a9f94c
17 changed files with 2015 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
# MCP Server Architecture — Research Findings
## Official SDK: @modelcontextprotocol/sdk
### Basic Server Pattern
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "my-server",
version: "1.0.0",
});
// Register a tool
server.tool(
"tool-name",
"Tool description for AI agent",
{ param: z.string() },
async ({ param }) => ({
content: [{ type: "text", text: `Result: ${param}` }],
}),
);
// Connect via stdio
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Transport Options
1. **stdio** — local process communication (Claude Desktop, Cursor)
2. **Streamable HTTP** — network transport (replaces deprecated HTTP+SSE)
- `NodeStreamableHTTPServerTransport` for stateful sessions
### Three MCP Primitives
1. **Tools** — Functions the AI can call (primary focus for ERP integration)
2. **Resources** — Data the AI can read (documentation, configs, schemas)
3. **Prompts** — Template conversations for common scenarios
## Production MCP Server Requirements
### What the spec covers:
- Capability negotiation (initialize)
- Tool listing/execution (tools/list, tools/call)
- Resource listing/reading (resources/list, resources/read)
- Transport: stdio and Streamable HTTP
### What production requires beyond spec:
- Authentication and authorization (OAuth2, JWT)
- Rate limiting per IP/token/tool
- Input schema validation before execution
- Concurrency control
- Backpressure when saturated
- Observability (Prometheus metrics, OpenTelemetry traces)
- CORS, CSP, max request body size
- Signal handling (SIGTERM, graceful shutdown)
- Error handling and retry patterns
## Tool Design Best Practices
### Schema Precision
```typescript
// BAD — vague schema
inputSchema: { type: "object" }
// GOOD — precise and documented
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "SQL SELECT query to execute",
},
limit: {
type: "number",
minimum: 1,
maximum: 100,
default: 10,
description: "Maximum number of rows to return",
},
},
required: ["query"],
additionalProperties: false,
}
```
### Tool Granularity for ERP
- **Fine-grained** tools: `get_invoice`, `search_customers`, `check_stock`
- Each tool has **clear purpose** and **precise schema**
- AI agent uses schema + description to decide when to call
### Resource Patterns for Documentation
```typescript
server.registerResource(
{
uri: "sage://help/invoicing",
name: "Invoice Help",
description: "Sage X3 invoicing documentation",
mimeType: "text/markdown",
},
async () => ({
text: "# Invoice Help\n...",
}),
);
```
## Existing ERP MCP Server: @casys/mcp-erpnext
- Connects AI agents to ERPNext (open-source ERP)
- Exposes invoices, purchase orders, stock levels, accounting data
- Good reference for design patterns:
- Focused scope per tool
- Strong input validation
- Read-only defaults with explicit write permissions
## Testing
- **mcp-inspector**: Official CLI testing tool
- **Programmatic testing**: Use SDK's Client class
```bash
npx @modelcontextprotocol/inspector
```
## Key Design Decisions for Sage X3 MCP Server
1. **Which API(s) to use**: GraphQL (newest, typed) vs REST vs SOAP (legacy but comprehensive)
2. **Tool granularity**: Domain-specific (get_invoice, search_orders) vs generic (query_graphql)
3. **Auth strategy**: How to manage Sage X3 credentials (env vars, config file)
4. **Resource layer**: Sage X3 documentation, schema info as resources
5. **Prompt templates**: Common troubleshooting scenarios
## IMPORTANT NOTE FOR AGENTS
When using `background_task` or similar functions, **timeouts are in MILLISECONDS not seconds**.
- 60 seconds = 60000 ms
- 120 seconds = 120000 ms
- Default timeout: 120000 ms (2 minutes)

View File

@@ -0,0 +1,134 @@
# Sage X3 API Landscape — Research Findings
## Overview: Three API Types
Sage X3 exposes **three distinct API layers**, each suited to different integration scenarios:
### 1. GraphQL API (Newest — V12+, via Sage X3 Builder)
**Architecture**: Syracuse server → GraphQL endpoint → Node-based schema
**Auth**: OAuth2 (Authorization Code flow)
**Best for**: Modern integrations, complex queries, typed schema
**Key Concepts**:
- **Nodes**: Data models published as GraphQL types (e.g., `SalesInvoice`, `PurchaseOrder`, `Customer`)
- **Operations/Mutations**: GraphQL mutations linked to X3 functions (subprograms, windows, classes, import templates)
- **Node Bindings**: Customization of API nodes and properties
- **Packages**: Organizational units for nodes in the GraphQL schema
**Example Query (Purchasing)**:
```graphql
{
x3Purchasing {
purchaseOrder {
query(filter: "{purchaseSite: 'FR011', orderFromSupplier: 'FR053', isClosed: {_ne: 'yes'}}") {
edges {
node {
id
purchaseSite { code }
receiptSite { code }
orderFromSupplier { code { code } }
isClosed
receiptStatus
signatureStatus
purchaseOrderLines { query { edges { node { orderedQuantity } } } }
}
}
}
}
}
}
```
**Modules Available**: x3Sales, x3Purchasing, x3Financials, x3CommonData, x3Manufacturing, x3Stock
**Authorization Flow** (OAuth2):
1. GET `https://api.myregion-sagex3.com/v1/token/authorise` with client_id, scope, redirect_uri
2. User approves in Sage X3 UI, selects folder(s)
3. App receives callback with authorization code
4. Exchange code for access token + refresh token
### 2. REST Web Services (V7+ style — Syracuse/SData)
**Architecture**: Syracuse server → REST endpoints → Classes + Representations
**Auth**: Basic, Client Certificate (on-prem), OAuth2 (cloud)
**Best for**: Standard CRUD operations on business objects
**URL Pattern**:
```
http://SERVER:PORT/api1/x3/erp/ENDPOINT/CLASS?representation=REPR.$query
```
**Parameters**:
- `count=N` — pagination (default 20)
- `startRecord=N` — pagination offset
- `orderBy=field asc|desc` — sorting
- `where=condition` — filtering
**Example**: Query customers
```
GET http://server:8124/api1/x3/erp/X3/BPCUSTOMER?representation=BPCUSTOMER.$query&count=50
```
**Key Entities**: BPCUSTOMER, SINVOICE (sales invoice), SORDER (sales order), PORDER (purchase order), etc.
### 3. SOAP Web Services (Legacy V6 style)
**Architecture**: Syracuse server → SOAP pool → X3 classic programs/subprograms
**Auth**: Basic (username/password in request), Bearer Token
**Best for**: Legacy integrations, subprogram calls, complex object manipulation
**WSDL Endpoint**:
```
http://SERVER:PORT/soap-wsdl/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC?wsdl
```
**Operations**: read, save, delete, query, run (subprogram), getDescription
**Call Context**:
```xml
<callContext xsi:type="wss:CAdxCallContext">
<codeLang xsi:type="xsd:string">ENG</codeLang>
<poolAlias xsi:type="xsd:string">POOL_NAME</poolAlias>
<poolId xsi:type="xsd:string"></poolId>
<requestConfig xsi:type="xsd:string">adxwss.optreturn=JSON&adxwss.beautify=true</requestConfig>
</callContext>
```
**Response Format**: XML or JSON (configurable via `adxwss.optreturn`)
**SIH (Sales Invoice) Example Description**:
- Fields: SALFCY (Sales site), SIVTYP (Type), NUM (Invoice no.), BPCINV (Bill-to customer), CUR (Currency), INVDAT (Date)
- Methods: READ, CREATE, MODIFY, DELETE, LIST
- Read key: NUM (Invoice number)
## Authentication Summary
| API Type | On-Premise | Cloud |
|----------|-----------|-------|
| GraphQL | OAuth2 | OAuth2 |
| REST | Basic, Client Cert, OAuth2 | OAuth2 |
| SOAP | Basic Auth, Bearer Token | OAuth2 |
## Key Business Objects (Common Names)
| Object Code | Description | SOAP Public Name |
|-------------|-------------|-----------------|
| SIH | Sales Invoice Header | SIH / WSIH |
| SIV | Sales Invoice | WSIV |
| SOH | Sales Order Header | SOH |
| SOQ | Sales Quote | SOQ |
| POH | Purchase Order Header | POH |
| BPC | Business Partner Customer | WSBPC |
| BPS | Business Partner Supplier | WSBPS |
| ITM | Item/Product | WITM |
| STK | Stock | — |
## Integration Architecture Notes
- **Syracuse Server** is the middleware layer for all APIs
- SOAP uses connection **pools** with configurable channels
- REST uses **representations** (views of data) and **classes** (business objects)
- GraphQL uses **nodes** (data models) with **operations** (mutations)
- **Licensing** controls data volume for SOAP (WSSIZELIMIT per period)
- On-premise vs Cloud affects auth options and file/DB integration access