| # MCP Examples: Financial Services on Axis2/Java | |
| **Summary**: Apache Axis2/Java serves the same financial calculations as Axis2/C — | |
| portfolio variance, Monte Carlo VaR (GBM and Merton jump-diffusion), scenario | |
| analysis — over JSON on WildFly 32/39 and Tomcat 11 with Spring Security JWT | |
| authentication. This document shows the same live demos as the Axis2/C | |
| `MCP_EXAMPLES.md`, run against the Java implementation, with head-to-head | |
| performance numbers. | |
| The financial results are identical (same algorithms, same inputs, same outputs). | |
| The implementations compete only on performance. | |
| --- | |
| ## Transport and Timing Note | |
| Both Axis2/C and Axis2/Java support **HTTPS/HTTP2**. Axis2/C runs over | |
| Apache httpd with mod_h2; Axis2/Java runs over WildFly or Tomcat with | |
| ALPN-negotiated HTTP/2 on port 8443. Verified on WildFly 32, WildFly 39, | |
| and Tomcat 11 — all negotiate `h2` via ALPN when accessed over TLS. | |
| All timings in this document use the **server-reported `calcTimeUs` field** | |
| — wall-clock time measured inside the service handler, after request | |
| parsing and before response serialization. Transport overhead (TLS, HTTP/2 | |
| framing) is excluded. The computation comparison is apples-to-apples. | |
| --- | |
| ## Authentication | |
| All examples use **HTTPS/HTTP2 on port 8443**. WildFly uses a self-signed certificate, | |
| so `-k` skips certificate verification. Tomcat uses mTLS with CA-signed client certs | |
| (see `mcp-architecture.md` for PKI details). | |
| Axis2/Java requires JWT authentication via Spring Security. All financial service | |
| calls need a `Bearer` token obtained from the login endpoint: | |
| ```bash | |
| TOKEN=$(curl -s --http2 -k https://localhost:8443/axis2-json-api/services/loginService \ | |
| -H 'Content-Type: application/json' \ | |
| -d '{"doLogin":[{"arg0":{"email":"java-dev@axis.apache.org","credentials":"userguide"}}]}' \ | |
| | python3 -c "import sys,json; print(json.load(sys.stdin)['response']['token'])") | |
| ``` | |
| All subsequent examples assume `$TOKEN` is set. | |
| --- | |
| ## API Differences: Java vs C | |
| The financial calculations are identical. The wire format differs: | |
| | | Axis2/C | Axis2/Java | | |
| |---|---|---| | |
| | URL pattern | `.../portfolioVariance` | `.../FinancialBenchmarkService` | | |
| | Request format | `{"n_assets": 5, ...}` | `{"portfolioVariance":[{"arg0":{...}}]}` | | |
| | Response format | `{"status": "SUCCESS", ...}` | `{"response": {"status": "SUCCESS", ...}}` | | |
| | Field naming | `snake_case` | `camelCase` | | |
| | Authentication | None (HTTP/2 + TLS) | JWT Bearer token | | |
| | Memory field | `memory_used_kb` (KB) | `memoryUsedMb` (MB) | | |
| | Covariance input | Flat array (row-major) | 2D array `[[...],[...]]` | | |
| --- | |
| ## MCP Bridge | |
| Axis2/Java exposes MCP via `axis2-mcp-bridge`, a stdio JAR that reads | |
| `/openapi-mcp.json` and proxies `tools/call` to the Axis2 service. The | |
| bridge handles authentication (mTLS on Tomcat, JWT on WildFly) so the AI | |
| client sees only standard MCP JSON-RPC. | |
| **Claude Desktop configuration** (WildFly, JWT auth): | |
| ```json | |
| { | |
| "mcpServers": { | |
| "axis2-java-finbench": { | |
| "command": "java", | |
| "args": ["-jar", "/path/to/axis2-mcp-bridge-2.0.1-SNAPSHOT-exe.jar", | |
| "--base-url", "https://localhost:8443/axis2-json-api"] | |
| } | |
| } | |
| } | |
| ``` | |
| **MCP stdio call format** (what the bridge sends/receives): | |
| ```bash | |
| echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{ | |
| "name":"portfolioVariance","arguments":{...}}}' \ | |
| | java -jar axis2-mcp-bridge-2.0.1-SNAPSHOT-exe.jar \ | |
| --base-url https://localhost:8443/axis2-json-api | |
| ``` | |
| All curl examples below include paired MCP stdio equivalents. | |
| --- | |
| ## Live Examples (Tested on WildFly 32/39 and Tomcat 11) | |
| ### Portfolio Variance — 5 assets | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{ | |
| "nAssets": 5, | |
| "weights": [0.25, 0.25, 0.20, 0.15, 0.15], | |
| "covarianceMatrix": [ | |
| [0.0691, 0.0313, 0.0457, 0.0272, -0.0035], | |
| [0.0313, 0.0976, 0.0591, 0.0408, 0.0058], | |
| [0.0457, 0.0591, 0.1207, 0.0437, -0.0086], | |
| [0.0272, 0.0408, 0.0437, 0.0638, 0.0015], | |
| [-0.0035, 0.0058,-0.0086, 0.0015, 0.0303] | |
| ], | |
| "normalizeWeights": true | |
| }}]}' | |
| ``` | |
| ```json | |
| { | |
| "response": { | |
| "status": "SUCCESS", | |
| "portfolioVariance": 0.0392, | |
| "portfolioVolatility": 0.198, | |
| "annualizedVolatility": 3.143, | |
| "calcTimeUs": 1, | |
| "matrixOperations": 25, | |
| "memoryUsedMb": 198, | |
| "runtimeInfo": "Java (JVM heap tier: < 2 GB)" | |
| } | |
| } | |
| ``` | |
| **MCP stdio equivalent:** | |
| ```bash | |
| echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"portfolioVariance","arguments":{"nAssets":5,"weights":[0.25,0.25,0.20,0.15,0.15],"covarianceMatrix":[[0.0691,0.0313,0.0457,0.0272,-0.0035],[0.0313,0.0976,0.0591,0.0408,0.0058],[0.0457,0.0591,0.1207,0.0437,-0.0086],[0.0272,0.0408,0.0437,0.0638,0.0015],[-0.0035,0.0058,-0.0086,0.0015,0.0303]],"normalizeWeights":true}}}' \ | |
| | java -jar axis2-mcp-bridge-2.0.1-SNAPSHOT-exe.jar --base-url https://localhost:8443/axis2-json-api | |
| ``` | |
| ### Portfolio Variance — 500 assets | |
| ```bash | |
| # Generate 500-asset test data | |
| python3 -c " | |
| import json | |
| n=500; w=[1.0/n]*n; c=[] | |
| for i in range(n): | |
| row=[] | |
| for j in range(n): | |
| if i==j: row.append(0.04) | |
| else: row.append(0.01*max(0,1.0-abs(i-j)/50.0)) | |
| c.append(row) | |
| print(json.dumps({'portfolioVariance':[{'arg0':{'nAssets':n,'weights':w,'covarianceMatrix':c}}]}))" \ | |
| > /tmp/pv500.json | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d @/tmp/pv500.json | |
| ``` | |
| ```json | |
| { | |
| "response": { | |
| "status": "SUCCESS", | |
| "portfolioVariance": 0.001027, | |
| "portfolioVolatility": 0.0320, | |
| "calcTimeUs": 660, | |
| "matrixOperations": 250000, | |
| "memoryUsedMb": 229 | |
| } | |
| } | |
| ``` | |
| (MCP equivalent omitted for 500-asset — the arguments object is identical, | |
| just wrapped in `tools/call` JSON-RPC as shown above.) | |
| ### Monte Carlo VaR — 100K simulations | |
| Monte Carlo Value at Risk estimates portfolio loss at a given confidence | |
| level by simulating thousands of random price paths. The default model is | |
| Geometric Brownian Motion (GBM): `S(t+dt) = S(t) × exp((μ − σ²/2)·dt + σ·√dt·Z)` | |
| where Z ~ N(0,1). A Merton jump-diffusion model is also available | |
| (`"model":"merton"`) which adds Poisson-distributed jumps for fat-tailed | |
| scenarios — configurable via `jumpIntensity`, `jumpMean`, and `jumpVol` | |
| parameters. Run 100,000 paths, sort the terminal values, read off the | |
| 1st percentile loss — that's your 99% VaR. Production risk systems run | |
| this nightly for regulatory capital calculations. | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"monteCarlo":[{"arg0":{ | |
| "nSimulations": 100000, | |
| "nPeriods": 252, | |
| "initialValue": 1000000, | |
| "expectedReturn": 0.10, | |
| "volatility": 0.198, | |
| "nPeriodsPerYear": 252 | |
| }}]}' | |
| ``` | |
| ```json | |
| { | |
| "response": { | |
| "status": "SUCCESS", | |
| "meanFinalValue": 1104699.76, | |
| "var95": 219309.63, | |
| "var99": 317526.89, | |
| "cvar95": 279538.64, | |
| "maxDrawdown": 0.567, | |
| "probProfit": 0.657, | |
| "calcTimeUs": 1380378, | |
| "simulationsPerSecond": 72443, | |
| "memoryUsedMb": 142 | |
| } | |
| } | |
| ``` | |
| **MCP stdio equivalent:** | |
| ```bash | |
| echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"nSimulations":100000,"nPeriods":252,"initialValue":1000000,"expectedReturn":0.10,"volatility":0.198,"nPeriodsPerYear":252}}}' \ | |
| | java -jar axis2-mcp-bridge-2.0.1-SNAPSHOT-exe.jar --base-url https://localhost:8443/axis2-json-api | |
| ``` | |
| --- | |
| ## Demo 1: Stress-test — "What if correlations spike?" | |
| Same test as Axis2/C `MCP_EXAMPLES.md` Demo 1. Baseline portfolio at real | |
| market correlations, then stressed to ρ = 0.8, then Monte Carlo on the | |
| stressed portfolio. | |
| Each curl below has an MCP equivalent — same `tools/call` pattern as | |
| the Live Examples above, with the arguments object matching the `arg0` | |
| payload. The bridge handles the Axis2 JSON-RPC wrapping transparently. | |
| **Step 1 — Baseline:** | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{ | |
| "nAssets": 5, | |
| "weights": [0.25, 0.25, 0.20, 0.15, 0.15], | |
| "covarianceMatrix": [ | |
| [0.0691, 0.0313, 0.0457, 0.0272, -0.0035], | |
| [0.0313, 0.0976, 0.0591, 0.0408, 0.0058], | |
| [0.0457, 0.0591, 0.1207, 0.0437, -0.0086], | |
| [0.0272, 0.0408, 0.0437, 0.0638, 0.0015], | |
| [-0.0035, 0.0058,-0.0086, 0.0015, 0.0303] | |
| ], | |
| "normalizeWeights": true | |
| }}]}' | |
| ``` | |
| ```json | |
| { | |
| "response": { | |
| "status": "SUCCESS", | |
| "portfolioVariance": 0.0392, | |
| "portfolioVolatility": 0.198, | |
| "calcTimeUs": 1, | |
| "memoryUsedMb": 198 | |
| } | |
| } | |
| ``` | |
| **Step 2 — Stressed (all pairwise correlations → 0.8):** | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{ | |
| "nAssets": 5, | |
| "weights": [0.25, 0.25, 0.20, 0.15, 0.15], | |
| "covarianceMatrix": [ | |
| [0.0691, 0.0656, 0.0730, 0.0530, 0.0366], | |
| [0.0656, 0.0974, 0.0866, 0.0629, 0.0434], | |
| [0.0730, 0.0866, 0.1204, 0.0699, 0.0483], | |
| [0.0530, 0.0629, 0.0699, 0.0635, 0.0351], | |
| [0.0366, 0.0434, 0.0483, 0.0351, 0.0303] | |
| ], | |
| "normalizeWeights": true | |
| }}]}' | |
| ``` | |
| ```json | |
| { | |
| "response": { | |
| "status": "SUCCESS", | |
| "portfolioVariance": 0.0649, | |
| "portfolioVolatility": 0.2547, | |
| "calcTimeUs": 1, | |
| "memoryUsedMb": 198 | |
| } | |
| } | |
| ``` | |
| **Step 3 — Monte Carlo on stressed portfolio (100K paths):** | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"monteCarlo":[{"arg0":{ | |
| "nSimulations": 100000, | |
| "nPeriods": 252, | |
| "initialValue": 1000000, | |
| "expectedReturn": 0.10, | |
| "volatility": 0.255, | |
| "nPeriodsPerYear": 252 | |
| }}]}' | |
| ``` | |
| ```json | |
| { | |
| "response": { | |
| "status": "SUCCESS", | |
| "meanFinalValue": 1104718.26, | |
| "var95": 296582.35, | |
| "var99": 409644.96, | |
| "cvar95": 364494.42, | |
| "maxDrawdown": 0.668, | |
| "probProfit": 0.602, | |
| "calcTimeUs": 1437421, | |
| "simulationsPerSecond": 69569 | |
| } | |
| } | |
| ``` | |
| **MCP stdio equivalent (stressed MC):** | |
| ```bash | |
| echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"nSimulations":100000,"nPeriods":252,"initialValue":1000000,"expectedReturn":0.10,"volatility":0.255,"nPeriodsPerYear":252}}}' \ | |
| | java -jar axis2-mcp-bridge-2.0.1-SNAPSHOT-exe.jar --base-url https://localhost:8443/axis2-json-api | |
| ``` | |
| **Comparison — Axis2/C vs Axis2/Java (same inputs, same day):** | |
| | Metric | Normal ρ | Stressed ρ = 0.8 | Change | | |
| |--------|----------|-------------------|--------| | |
| | Portfolio vol | 19.8% | 25.5% | **+29%** | | |
| | 95% VaR (1yr, $1M) | $219K | $297K | **+$78K** | | |
| | 99% VaR | $318K | $410K | **+$92K** | | |
| | Prob of profit | 65.7% | 60.2% | -5.5pp | | |
| | Timing | Axis2/C | Axis2/Java | Ratio | | |
| |--------|---------|------------|-------| | |
| | `portfolioVariance` (×2) | < 1 μs each | 1 μs each | ~1x | | |
| | `monteCarlo` (100K) | 727 ms | 1,437 ms | **2.0x** | | |
| | Total compute | ~0.73 sec | ~1.44 sec | 2.0x | | |
| Both produce the same financial results. Java's Monte Carlo is ~2x slower | |
| on this run; the JIT-warmed steady state is typically 1.3-1.5x (see | |
| convergence section below). | |
| --- | |
| ## Demo 2: Pre-trade risk — "Should I add this name?" | |
| Same test as Axis2/C Demo 2. Two candidate 6-asset portfolios: European | |
| semiconductor (high correlation to existing tech) vs Japanese peer (low | |
| correlation). All calls have MCP equivalents via the bridge (same pattern | |
| as Live Examples). | |
| **Candidate A — European semi (vol 44%, ρ = 0.68 to tech):** | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{ | |
| "nAssets": 6, | |
| "weights": [0.2425, 0.2425, 0.194, 0.1455, 0.1455, 0.03], | |
| "covarianceMatrix": [ | |
| [0.0691, 0.0313, 0.0457, 0.0272,-0.0035, 0.0787], | |
| [0.0313, 0.0976, 0.0591, 0.0408, 0.0058, 0.0934], | |
| [0.0457, 0.0591, 0.1207, 0.0437,-0.0086, 0.1039], | |
| [0.0272, 0.0408, 0.0437, 0.0638, 0.0015, 0.0610], | |
| [-0.0035, 0.0058,-0.0086, 0.0015, 0.0303, 0.0115], | |
| [0.0787, 0.0934, 0.1039, 0.0610, 0.0115, 0.1936] | |
| ], | |
| "normalizeWeights": true | |
| }}]}' | |
| ``` | |
| ```json | |
| {"response": {"status": "SUCCESS", "portfolioVolatility": 0.2035, "calcTimeUs": 1}} | |
| ``` | |
| **Candidate B — Japanese peer (vol 38%, ρ = 0.31 to US tech):** | |
| ```bash | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{ | |
| "nAssets": 6, | |
| "weights": [0.2425, 0.2425, 0.194, 0.1455, 0.1455, 0.03], | |
| "covarianceMatrix": [ | |
| [0.0691, 0.0313, 0.0457, 0.0272,-0.0035, 0.0310], | |
| [0.0313, 0.0976, 0.0591, 0.0408, 0.0058, 0.0368], | |
| [0.0457, 0.0591, 0.1207, 0.0437,-0.0086, 0.0409], | |
| [0.0272, 0.0408, 0.0437, 0.0638, 0.0015, 0.0239], | |
| [-0.0035, 0.0058,-0.0086, 0.0015, 0.0303, 0.0066], | |
| [0.0310, 0.0368, 0.0409, 0.0239, 0.0066, 0.1444] | |
| ], | |
| "normalizeWeights": true | |
| }}]}' | |
| ``` | |
| ```json | |
| {"response": {"status": "SUCCESS", "portfolioVolatility": 0.1968, "calcTimeUs": 1}} | |
| ``` | |
| **Head-to-head Monte Carlo (100K paths each):** | |
| ```bash | |
| # European candidate (vol 21.1%) | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"monteCarlo":[{"arg0":{"nSimulations":100000,"nPeriods":252, | |
| "initialValue":1000000,"expectedReturn":0.10,"volatility":0.211, | |
| "nPeriodsPerYear":252}}]}' | |
| # Japanese candidate (vol 20.1%) | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"monteCarlo":[{"arg0":{"nSimulations":100000,"nPeriods":252, | |
| "initialValue":1000000,"expectedReturn":0.10,"volatility":0.201, | |
| "nPeriodsPerYear":252}}]}' | |
| ``` | |
| **European candidate response:** | |
| ```json | |
| {"response": {"var95": 237481, "var99": 340245, "cvar95": 300412, "probProfit": 0.643, "maxDrawdown": 0.610, "calcTimeUs": 1360351}} | |
| ``` | |
| **Japanese candidate response:** | |
| ```json | |
| {"response": {"var95": 221367, "var99": 322087, "cvar95": 282371, "probProfit": 0.656, "maxDrawdown": 0.555, "calcTimeUs": 1364834}} | |
| ``` | |
| **Results summary (2026-04-08):** | |
| | | Before (5 names) | + European semi | + Japanese peer | | |
| |---|---|---|---| | |
| | Portfolio vol | 19.8% | **20.3%** (+55bp) | **19.7%** (-13bp) | | |
| | 95% VaR ($1M) | $219K | $237K | $221K | | |
| | 99% VaR | $318K | $340K | $322K | | |
| | CVaR 95% | $280K | $300K | $282K | | |
| | Prob of profit | 65.7% | 64.3% | 65.6% | | |
| **Timing comparison:** | |
| | Call | Axis2/C | Axis2/Java | Ratio | | |
| |------|---------|------------|-------| | |
| | `portfolioVariance` (×4) | < 1 μs each | 1 μs each | ~1x | | |
| | `monteCarlo` European | 716 ms | 1,360 ms | 1.9x | | |
| | `monteCarlo` Japanese | 672 ms | 1,365 ms | 2.0x | | |
| | Total compute | ~1.4 sec | ~2.7 sec | 1.9x | | |
| Financial conclusions are identical — the Japanese name provides genuine | |
| diversification. Java takes roughly twice as long for the Monte Carlo | |
| simulations. | |
| --- | |
| ## Demo 3: Convergence — "How much compute do I actually need?" | |
| Run `monteCarlo` at 1K, 10K, 100K, and 1M paths: | |
| ```bash | |
| for N in 1000 10000 100000 1000000; do | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d "{\"monteCarlo\":[{\"arg0\":{\"nSimulations\":$N,\"nPeriods\":252, | |
| \"initialValue\":1000000,\"expectedReturn\":0.10,\"volatility\":0.198, | |
| \"nPeriodsPerYear\":252}}]}" | |
| done | |
| ``` | |
| **MCP stdio equivalent (example for 100K):** | |
| ```bash | |
| echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"monteCarlo","arguments":{"nSimulations":100000,"nPeriods":252,"initialValue":1000000,"expectedReturn":0.10,"volatility":0.198,"nPeriodsPerYear":252}}}' \ | |
| | java -jar axis2-mcp-bridge-2.0.1-SNAPSHOT-exe.jar --base-url https://localhost:8443/axis2-json-api | |
| ``` | |
| **Axis2/Java results (2026-04-08):** | |
| | Simulations | 95% VaR | 99% VaR | Calc time | Sims/sec | | |
| |-------------|---------|---------|-----------|----------| | |
| | 1,000 | $221,665 | $325,340 | **13 ms** | 77,863 | | |
| | 10,000 | $216,407 | $312,895 | **136 ms** | 73,378 | | |
| | 100,000 | $218,868 | $315,163 | **1.37 sec** | 73,211 | | |
| | 1,000,000 | $217,286 | $315,700 | **13.8 sec** | 72,710 | | |
| **Head-to-head with Axis2/C (same inputs, same machine):** | |
| | Simulations | C time | Java time | Ratio | C sims/sec | Java sims/sec | | |
| |-------------|--------|-----------|-------|------------|---------------| | |
| | 1,000 | 6 ms | 13 ms | 2.1x | 164,295 | 77,863 | | |
| | 10,000 | 66 ms | 136 ms | 2.1x | 152,423 | 73,378 | | |
| | 100,000 | 716 ms | 1,370 ms | 1.9x | 139,650 | 73,211 | | |
| | 1,000,000 | 6.6 sec | 13.8 sec | 2.1x | 150,773 | 72,710 | | |
| The ratio is a consistent **~2x** across all simulation counts. C processes | |
| ~150K simulations/sec vs Java's ~73K sims/sec. | |
| **Production capacity math (Java)**: at 1.37 sec per 100K-path run, a single | |
| core processes **44 funds per minute**. A 500-fund universe completes in | |
| ~11.4 minutes on one core, or **~69 seconds on a 10-core node**. | |
| For comparison, Axis2/C: 500 funds in 6 minutes on one core, 36 seconds | |
| on 10 cores. | |
| --- | |
| ## 500-Asset Portfolio Variance — The Big Comparison | |
| This is where the gap widens. O(n^2) matrix math at n=500 means 250,000 | |
| multiply-accumulate operations on a flat array (C) vs a 2D Java array | |
| with bounds checking. | |
| **Axis2/C:** | |
| ```json | |
| {"portfolio_volatility": 0.0320, "calc_time_us": 232, "matrix_operations": 250000} | |
| ``` | |
| **Axis2/Java:** | |
| ```json | |
| {"portfolioVolatility": 0.0320, "calcTimeUs": 660, "matrixOperations": 250000} | |
| ``` | |
| | | Axis2/C | Axis2/Java | Ratio | | |
| |---|---|---|---| | |
| | Calc time | **232 μs** | **660 μs** | 2.8x | | |
| | Memory | ~193 MB RSS | 229 MB heap | 1.2x | | |
| | Result | 0.0320 | 0.0320 | identical | | |
| At 500 assets Java is 2.8x slower — the JVM's array bounds checking and | |
| object overhead becomes measurable at O(n^2). Both are still sub-millisecond, | |
| which is fast enough for interactive use. | |
| --- | |
| ## Full Performance Summary | |
| All measurements from 2026-04-08, same machine (Linux, 32 GB RAM). | |
| Timings are server-reported `calcTimeUs` — pure computation time, no | |
| transport overhead. Monte Carlo timings vary ±5% across runs due to JIT | |
| warmup and GC; values below are from the Demo 3 convergence runs (JIT-warm | |
| steady state). | |
| | Benchmark | Axis2/C | Axis2/Java | Ratio | | |
| |-----------|---------|------------|-------| | |
| | portfolioVariance (5 assets) | < 1 μs | 1 μs | ~1x | | |
| | portfolioVariance (500 assets) | 232 μs | 660 μs | 2.8x | | |
| | monteCarlo (1K × 252) | 6 ms | 13 ms | 2.1x | | |
| | monteCarlo (10K × 252) | 66 ms | 136 ms | 2.1x | | |
| | monteCarlo (100K × 252) | 716 ms | 1,366 ms | 1.9x | | |
| | monteCarlo (1M × 252) | 6.6 sec | 13.8 sec | 2.1x | | |
| | MC throughput (sims/sec) | ~150K | ~73K | 2.1x | | |
| | Peak memory (500-asset PV) | ~193 MB | 229 MB | 1.2x | | |
| | Peak memory (100K MC) | ~44 MB | 142 MB | 3.2x | | |
| | Startup | instant | ~7 sec (WildFly) | N/A | | |
| ### When to use which | |
| - **Axis2/C**: Edge devices, Android (1-2 GB RAM), IoT gateways, latency-critical | |
| paths, environments where a JVM cannot run or its memory overhead is unacceptable. | |
| Sub-millisecond portfolio variance at 500 assets. Startup in milliseconds. | |
| - **Axis2/Java**: Standard Java EE/Jakarta EE deployment on WildFly or Tomcat, | |
| teams with existing Java infrastructure, environments requiring Spring Security | |
| (JWT/mTLS), or integration with Java-based data providers. 2x slower on Monte | |
| Carlo but still interactive (1.4 sec for 100K paths). Deploys as a standard WAR | |
| with OpenAPI/Swagger UI and MCP bridge included. | |
| Both implement the same MCP tool schemas. An AI assistant configured with | |
| either backend gets the same financial capabilities — the same questions | |
| produce the same answers. The choice is deployment context, not functionality. | |
| --- | |
| ## MCP Tool Discovery | |
| Axis2/Java exposes an MCP tool catalog at: | |
| ``` | |
| GET https://localhost:8443/axis2-json-api/openapi-mcp.json | |
| ``` | |
| This endpoint returns the same tool schema structure that Claude Desktop | |
| and other MCP clients consume. The catalog includes `doLogin`, | |
| `portfolioVariance`, `monteCarlo`, and `scenarioAnalysis` — each with full | |
| input schemas, parameter types, constraints, and defaults. The three | |
| financial tools are identical in capability to the Axis2/C MCP stdio server. | |
| --- | |
| ## Container/JDK Testing Matrix | |
| MCP bridge and OpenAPI endpoints need validation across all supported containers | |
| and JDK versions before the 2.0.1 release: | |
| | Container | JDK | MCP Bridge | OpenAPI/Swagger UI | Status | | |
| |-----------|-----|------------|-------------------|--------| | |
| | WildFly 32 | OpenJDK 21 | ✅ Tested | ✅ Tested | Validated | | |
| | WildFly 39 | OpenJDK 25 | ✅ Tested | ✅ Tested | Validated | | |
| | Tomcat 11 | OpenJDK 21 | ✅ Tested | ✅ Tested | Validated | | |
| | Tomcat 11 | OpenJDK 25 | ✅ Tested | ✅ Tested | Validated | | |
| All four container/JDK combinations negotiate HTTP/2 via ALPN over TLS. | |
| --- | |
| ## Build and Deploy | |
| ### WildFly | |
| Full build, deploy, and test instructions are in | |
| `modules/samples/userguide/src/userguide/springbootdemo-wildfly/README.md`. | |
| Quick start: | |
| ```bash | |
| cd modules/samples/userguide/src/userguide/springbootdemo-wildfly | |
| mvn -Dmaven.test.skip.exec clean install | |
| # Deploy exploded WAR to WildFly | |
| rsync -a --delete target/deploy/axis2-json-api/ ~/wildfly/standalone/deployments/axis2-json-api.war/ | |
| touch ~/wildfly/standalone/deployments/axis2-json-api.war.dodeploy | |
| ``` | |
| ### Tomcat 11 | |
| Full build, deploy, and test instructions are in | |
| `modules/samples/userguide/src/userguide/springbootdemo-tomcat11/README.md`. | |
| Quick start: | |
| ```bash | |
| cd modules/samples/userguide/src/userguide/springbootdemo-tomcat11 | |
| mvn -Dmaven.test.skip.exec clean install | |
| # Deploy exploded WAR to Tomcat | |
| cp -r target/deploy/axis2-json-api /path/to/tomcat/webapps/ | |
| ``` | |
| ### Verify all endpoints after deploy | |
| **Tomcat 11** (HTTPS/HTTP2 on port 8443 with mTLS): | |
| ```bash | |
| CERTS=/path/to/axis-axis2-java-core/certs | |
| CURL_MTLS="curl -s --http2 --cert $CERTS/client.crt --key $CERTS/client.key --cacert $CERTS/ca.crt" | |
| # OpenAPI and MCP (no auth required, but mTLS handshake still needed) | |
| $CURL_MTLS https://localhost:8443/axis2-json-api/openapi.json | |
| $CURL_MTLS https://localhost:8443/axis2-json-api/openapi.yaml | |
| $CURL_MTLS https://localhost:8443/axis2-json-api/openapi-mcp.json | |
| $CURL_MTLS https://localhost:8443/axis2-json-api/swagger-ui | |
| # Login | |
| TOKEN=$($CURL_MTLS -X POST https://localhost:8443/axis2-json-api/services/loginService \ | |
| -H 'Content-Type: application/json' \ | |
| -d '{"doLogin":[{"arg0":{"email":"java-dev@axis.apache.org","credentials":"userguide"}}]}' \ | |
| | python3 -c "import sys,json; print(json.load(sys.stdin)['response']['token'])") | |
| # Financial benchmark | |
| $CURL_MTLS -X POST https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{"nAssets":2,"weights":[0.6,0.4],"covarianceMatrix":[[0.04,0.006],[0.006,0.09]]}}]}' | |
| ``` | |
| **WildFly 32/39** (HTTPS/HTTP2 on port 8443 with self-signed cert, JWT auth): | |
| ```bash | |
| # OpenAPI and MCP | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/openapi.json | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/openapi-mcp.json | |
| # Login + financial benchmark | |
| TOKEN=$(curl -s --http2 -k https://localhost:8443/axis2-json-api/services/loginService \ | |
| -H 'Content-Type: application/json' \ | |
| -d '{"doLogin":[{"arg0":{"email":"java-dev@axis.apache.org","credentials":"userguide"}}]}' \ | |
| | python3 -c "import sys,json; print(json.load(sys.stdin)['response']['token'])") | |
| curl -s --http2 -k https://localhost:8443/axis2-json-api/services/FinancialBenchmarkService \ | |
| -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" \ | |
| -d '{"portfolioVariance":[{"arg0":{"nAssets":2,"weights":[0.6,0.4],"covarianceMatrix":[[0.04,0.006],[0.006,0.09]]}}]}' | |
| ``` | |
| See the sample READMEs for the complete test flow covering all services. | |
| --- | |
| ## WildFly Deployment Notes | |
| See `WILDFLY32_DEPLOY_STATE.md` in the Axis2/C repo for the full deployment | |
| walkthrough. Key points (apply to both WildFly 32 and WildFly 39): | |
| - WildFly 32.0.1.Final or WildFly 39 with `--add-modules=java.se` in `standalone.conf` | |
| - `jboss-deployment-structure.xml` from production deployment template (includes `jdk.net` module dependency) | |
| - `beans.xml` with `bean-discovery-mode="none"` (satisfies Weld without CDI scanning) | |
| - Spring Boot 3.4.3 starts in ~0.9 seconds inside WildFly | |
| - WAR: `axis2-json-api-0.0.1-SNAPSHOT.war` |