This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git


The following commit(s) were added to refs/heads/master by this push:
     new f5b188f8fa docs: MCP guide: GitHub links, modelcontextprotocol.io, 
clarify auth
f5b188f8fa is described below

commit f5b188f8fa5e8746bac070e456c9611bef41f744
Author: Robert Lazarski <[email protected]>
AuthorDate: Fri May 15 04:03:25 2026 -1000

    docs: MCP guide: GitHub links, modelcontextprotocol.io, clarify auth
    
    - Quick Start: replaced file paths with clickable GitHub links for
      both sample READMEs (Tomcat 11 and WildFly)
    - What is MCP: linked modelcontextprotocol.io and Wikipedia article
    - Two-Phase Bearer Token: clarified that the auth flow is implemented
      by the sample application's Spring Security configuration, not by
      Axis2 itself. Axis2 is a web services framework that does not
      impose any authentication mechanism.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 src/site/xdoc/docs/json-rpc-mcp-guide.xml | 274 +++++++++++++-----------------
 src/site/xdoc/docs/toc.xml                |   3 +-
 2 files changed, 122 insertions(+), 155 deletions(-)

diff --git a/src/site/xdoc/docs/json-rpc-mcp-guide.xml 
b/src/site/xdoc/docs/json-rpc-mcp-guide.xml
index a0f8b6d173..71f9903a99 100644
--- a/src/site/xdoc/docs/json-rpc-mcp-guide.xml
+++ b/src/site/xdoc/docs/json-rpc-mcp-guide.xml
@@ -35,8 +35,9 @@ catalog, the required envelope format, authentication flow, 
and current limitati
 
 <p><strong>Quick start:</strong> For step-by-step build, deploy, and test 
instructions
 (including curl commands for every endpoint), see the sample READMEs:
-<code>modules/samples/userguide/src/userguide/springbootdemo-tomcat11/README.md</code>
 (Tomcat 11)
-and 
<code>modules/samples/userguide/src/userguide/springbootdemo-wildfly/README.md</code>
+<a 
href="https://github.com/apache/axis-axis2-java-core/blob/master/modules/samples/userguide/src/userguide/springbootdemo-tomcat11/README.md";>springbootdemo-tomcat11
 README</a> (Tomcat 11)
+and
+<a 
href="https://github.com/apache/axis-axis2-java-core/blob/master/modules/samples/userguide/src/userguide/springbootdemo-wildfly/README.md";>springbootdemo-wildfly
 README</a>
 (WildFly 32/39).</p>
 
 <p><strong>In one sentence:</strong> Axis2 auto-generates an MCP tool catalog 
from its
@@ -47,10 +48,21 @@ deployed operation — no out-of-band documentation 
required.</p>
 <!-- ============================================================ -->
 <h2>What is MCP?</h2>
 
-<p><strong>MCP (Model Context Protocol)</strong> is an open standard published 
at
-<code>modelcontextprotocol.io</code> that defines how AI assistants (Claude, 
ChatGPT,
+<p><strong>MCP (<a 
href="https://en.wikipedia.org/wiki/Model_Context_Protocol";>Model Context
+Protocol</a>)</strong> is an open standard published at
+<a href="https://modelcontextprotocol.io/";>modelcontextprotocol.io</a>
+that defines how AI assistants (Claude, ChatGPT,
 Cursor, etc.) discover and call external tools.</p>
 
+<p><strong>Relationship to OpenAPI:</strong>
+<a href="https://en.wikipedia.org/wiki/OpenAPI_Specification";>OpenAPI</a>
+describes REST APIs for human developers and code generators. MCP describes
+the same services as <em>tools</em> for AI assistants. Axis2 generates both
+from the same deployed services — <code>/openapi.json</code> produces the
+OpenAPI spec, <code>/openapi-mcp.json</code> produces the MCP tool catalog.
+They are complementary: OpenAPI tells a developer how to call your API;
+MCP tells an AI assistant how to call it.</p>
+
 <p><strong>The core idea:</strong> An MCP server advertises a catalog of tools 
— each
 with a name, a natural-language description, and a JSON Schema describing its
 parameters. An AI assistant reads this catalog, decides which tool to call 
based on
@@ -127,10 +139,9 @@ parameters to each operation, and the MCP catalog appears 
automatically at
 <li><a href="#envelope">3. The Axis2 JSON-RPC Envelope (Critical)</a></li>
 <li><a href="#auth">4. Authentication: Two-Phase Bearer Token Flow</a></li>
 <li><a href="#error_handling">5. Error Handling: Correlation ID 
Pattern</a></li>
-<li><a href="#tested_features">6. Features Covered by Unit Tests</a></li>
-<li><a href="#not_implemented">7. Not Implemented / Limitations</a></li>
-<li><a href="#migration_path">8. Migration Path: JSON-RPC to REST</a></li>
-<li><a href="#python_compat">9. Python MCP Compatibility Notes</a></li>
+<li><a href="#not_implemented">6. Not Implemented / Limitations</a></li>
+<li><a href="#migration_path">7. Migration Path: JSON-RPC to REST</a></li>
+<li><a href="#python_compat">8. Python MCP Client Example</a></li>
 </ul>
 
 <!-- ============================================================ -->
@@ -179,7 +190,24 @@ constant across all services) and <code>tools</code> (one 
entry per deployed ope
     "axis2JsonRpcFormat": 
"{\"&lt;operationName&gt;\":[{\"arg0\":{&lt;params&gt;}}]}",
     "contentType":        "application/json",
     "authHeader":         "Authorization: Bearer &lt;token&gt;",
-    "tokenEndpoint":      "POST /services/loginService/doLogin"
+    "tokenEndpoint":      "POST /services/loginService/doLogin",
+    "errorContract": {
+      "schemaRef": "#/components/schemas/ErrorResponse",
+      "fields": {
+        "error":      "Error code: VALIDATION_ERROR | RATE_LIMITED | 
SERVICE_UNAVAILABLE | BAD_REQUEST | INTERNAL_ERROR",
+        "message":    "Human-readable error message",
+        "errorRef":   "UUID correlation ID — quote in support requests",
+        "timestamp":  "ISO 8601 when the error occurred",
+        "retryAfter": "Seconds to wait before retrying (429/503 only, null 
otherwise)"
+      },
+      "httpStatusMapping": {
+        "400": "BAD_REQUEST — malformed JSON or missing required fields",
+        "422": "VALIDATION_ERROR — valid JSON but fails business validation",
+        "429": "RATE_LIMITED — too many requests, check retryAfter",
+        "500": "INTERNAL_ERROR — server fault, errorRef logged server-side",
+        "503": "SERVICE_UNAVAILABLE — downstream dependency or overload"
+      }
+    }
   },
   ...
 }
@@ -195,6 +223,10 @@ before calling any tool:</p>
     <code>tokenEndpoint</code> — call <code>loginService/doLogin</code> first,
     then pass the returned token as a Bearer header.</li>
 <li><strong>What Content-Type?</strong> Always 
<code>application/json</code>.</li>
+<li><strong>What do errors look like?</strong> See <code>errorContract</code> —
+    structured JSON with error code, message, correlation ID 
(<code>errorRef</code>),
+    timestamp, and HTTP status mapping. Services throw
+    <code>JsonRpcFaultException</code> to produce these responses.</li>
 </ul>
 
 <h3>2.2 Per-Tool Fields</h3>
@@ -345,7 +377,15 @@ to see which format a specific service expects.</p>
 <a name="auth"/>
 <h2>4. Authentication: Two-Phase Bearer Token Flow</h2>
 
-<p>Axis2 services use a two-phase auth flow:</p>
+<p><strong>Note:</strong> Axis2 is a web services framework — it does not
+impose any specific authentication mechanism. The two-phase Bearer token
+flow described below is implemented by the
+<a 
href="https://github.com/apache/axis-axis2-java-core/tree/master/modules/samples/userguide/src/userguide/springbootdemo-tomcat11";>sample
 application</a>'s
+Spring Security configuration, not by Axis2 itself. Your application can
+use any auth mechanism (OAuth2, API keys, mTLS, etc.) by configuring
+Spring Security or your servlet container accordingly.</p>
+
+<p>The sample application uses the following two-phase flow:</p>
 
 <h3>Phase 1 — Obtain Token (no auth required)</h3>
 
@@ -396,14 +436,53 @@ without hardcoding the service path.</p>
 
 <!-- ============================================================ -->
 <a name="error_handling"/>
-<h2>5. Error Handling: Correlation ID Pattern</h2>
+<h2>5. Error Handling</h2>
+
+<p>Axis2 JSON-RPC services support two error formats depending on where the
+error originates:</p>
 
-<p>Malformed JSON-RPC bodies return a sanitized fault message containing only
-an opaque correlation ID. This is a deliberate security feature — the bare
-<code>Bad Request</code> message passes penetration testing with no structural
-information leakage.</p>
+<h3>5.1 Structured JSON Errors (service-level validation)</h3>
 
-<h3>5.1 What Clients Receive</h3>
+<p>Services that throw
+<a 
href="https://github.com/apache/axis-axis2-java-core/blob/master/modules/json/src/org/apache/axis2/json/gson/rpc/JsonRpcFaultException.java";><code>JsonRpcFaultException</code></a>
+produce structured JSON error responses with proper HTTP status codes:</p>
+
+<pre>
+HTTP 422
+Content-Type: application/json
+
+{
+  "response": {
+    "status":     "FAILED",
+    "error":      "VALIDATION_ERROR",
+    "message":    "initialValue must be > 0 (GBM is undefined for non-positive 
starting values).",
+    "errorRef":   "a3f2c1d0-7b4e-4a2f-9c8d-1e6f3b5a2d7c",
+    "timestamp":  "2026-05-15T14:30:00Z",
+    "retryAfter": null
+  }
+}
+</pre>
+
+<p>The HTTP status codes map to error categories:</p>
+<table border="1">
+<tr><th>HTTP Status</th><th>Error Code</th><th>Meaning</th></tr>
+<tr><td>400</td><td>BAD_REQUEST</td><td>Malformed JSON or missing required 
fields</td></tr>
+<tr><td>422</td><td>VALIDATION_ERROR</td><td>Valid JSON but fails business 
validation</td></tr>
+<tr><td>429</td><td>RATE_LIMITED</td><td>Too many requests; check 
<code>retryAfter</code></td></tr>
+<tr><td>500</td><td>INTERNAL_ERROR</td><td>Server fault; <code>errorRef</code> 
logged server-side</td></tr>
+<tr><td>503</td><td>SERVICE_UNAVAILABLE</td><td>Downstream dependency or 
overload</td></tr>
+</table>
+
+<p>The <code>errorRef</code> UUID is logged server-side with full context 
(operation
+name, exception message, stack trace). Clients should surface the UUID in
+their error displays so users can quote it in support requests.</p>
+
+<h3>5.2 SOAP Fault Fallback (parse-level errors)</h3>
+
+<p>Requests that fail before reaching the service method (malformed JSON,
+wrong operation name, missing array wrapper) produce a legacy SOAP fault
+with a sanitized <code>Bad Request</code> message. This is a deliberate
+security feature — no structural information leakage:</p>
 
 <pre>
 HTTP 500
@@ -413,10 +492,6 @@ HTTP 500
 &lt;/soapenv:Fault&gt;
 </pre>
 
-<p>The <code>errorRef</code> UUID is logged server-side with full context 
(operation
-name, exception message, stack trace). Developers grep the UUID; the client 
response
-contains no class names, field paths, or stack trace elements.</p>
-
 <h3>5.2 What Triggers This</h3>
 
 <table border="1">
@@ -446,114 +521,9 @@ class ErrorResponse:
 </pre>
 
 <!-- ============================================================ -->
-<a name="tested_features"/>
-<h2>6. Features Covered by Unit Tests</h2>
-
-<p>The following capabilities are covered by unit and integration tests. Use 
this as a
-conformance checklist when extending the catalog or adding new MCP client 
code.</p>
-
-<h3>6.1 MCP Catalog Generator — McpCatalogGeneratorTest (50+ tests)</h3>
-
-<table border="1">
-<tr><th>Test</th><th>Feature Verified</th></tr>
-<tr><td><code>testCatalogIsValidJson</code></td><td>Catalog output is 
parseable JSON</td></tr>
-<tr><td><code>testCatalogRootHasToolsArray</code></td><td>Root has "tools" 
array key</td></tr>
-<tr><td><code>testEmptyConfigurationProducesEmptyToolsArray</code></td><td>No 
services → empty tools array (no crash)</td></tr>
-<tr><td><code>testToolNameMatchesOperationName</code></td><td>tool.name equals 
Axis2 operation name</td></tr>
-<tr><td><code>testToolDescriptionContainsServiceAndOperationName</code></td><td>Description
 is "ServiceName: operationName"</td></tr>
-<tr><td><code>testToolEndpointFormat</code></td><td>Endpoint is "POST 
/services/ServiceName/operationName"</td></tr>
-<tr><td><code>testInputSchemaTypeIsObject</code></td><td>inputSchema.type = 
"object"</td></tr>
-<tr><td><code>testInputSchemaHasPropertiesField</code></td><td>inputSchema.properties
 field present</td></tr>
-<tr><td><code>testInputSchemaHasRequiredField</code></td><td>inputSchema.required
 array present</td></tr>
-<tr><td><code>testTwoServicesEachWithOneOperationProduceTwoTools</code></td><td>Tool
 count matches deployed operations</td></tr>
-<tr><td><code>testOperationNameWithQuoteIsEscaped</code></td><td>Special 
characters are JSON-escaped in all fields</td></tr>
-<tr><td><code>testGenerateMcpCatalogWithNullRequestDoesNotThrow</code></td><td>null
 HttpServletRequest → graceful empty catalog</td></tr>
-<tr><td><code>testCatalogHasMetaObject</code></td><td>_meta object present at 
catalog root</td></tr>
-<tr><td><code>testMetaHasAxis2JsonRpcFormat</code></td><td>_meta.axis2JsonRpcFormat
 contains "operationName" and "arg0" placeholders</td></tr>
-<tr><td><code>testMetaHasContentType</code></td><td>_meta.contentType = 
"application/json"</td></tr>
-<tr><td><code>testMetaHasAuthHeaderField</code></td><td>_meta.authHeader 
describes Bearer scheme</td></tr>
-<tr><td><code>testMetaHasTokenEndpoint</code></td><td>_meta.tokenEndpoint 
references loginService, starts with "POST "</td></tr>
-<tr><td><code>testToolHasPayloadTemplateField</code></td><td>x-axis2-payloadTemplate
 present on every tool</td></tr>
-<tr><td><code>testPayloadTemplateIsValidJson</code></td><td>Template string is 
parseable JSON</td></tr>
-<tr><td><code>testPayloadTemplateOperationNameIsTopLevelKey</code></td><td>Template
 has {operationName: ...} at root</td></tr>
-<tr><td><code>testPayloadTemplateValueIsArray</code></td><td>Template value is 
an array</td></tr>
-<tr><td><code>testPayloadTemplateArrayHasArg0Object</code></td><td>Array 
element has "arg0" key</td></tr>
-<tr><td><code>testPayloadTemplatesDistinctAcrossOperations</code></td><td>Each 
operation has a unique template</td></tr>
-<tr><td><code>testNonLoginServiceRequiresAuth</code></td><td>Regular services 
have x-requiresAuth: true</td></tr>
-<tr><td><code>testLoginServiceDoesNotRequireAuth</code></td><td>loginService 
has x-requiresAuth: false</td></tr>
-<tr><td><code>testLoginServiceCaseInsensitive</code></td><td>"LoginService" 
(capital L) also no-auth</td></tr>
-<tr><td><code>testToolHasAnnotationsField</code></td><td>annotations object 
present on every tool</td></tr>
-<tr><td><code>testAnnotationsHasReadOnlyHint</code></td><td>readOnlyHint 
boolean present</td></tr>
-<tr><td><code>testAllAnnotationHintsAreBooleans</code></td><td>All MCP 
2025-03-26 hints are booleans, not strings</td></tr>
-<tr><td><code>testMcpToolsMatchOpenApiPaths</code></td><td>Every MCP tool 
endpoint has a matching OpenAPI path</td></tr>
-<tr><td><code>testTickerResolveEndpointPresentWhenConfigured</code></td><td>_meta.tickerResolveEndpoint
 appears when mcpTickerResolveService global param is set</td></tr>
-<tr><td><code>testTickerResolveEndpointAbsentWhenNotConfigured</code></td><td>tickerResolveEndpoint
 absent from _meta when param not set (no misleading field)</td></tr>
-<tr><td><code>testOperationLevelMcpDescriptionOverridesDefault</code></td><td>mcpDescription
 on AxisOperation replaces auto-generated "ServiceName: opName"</td></tr>
-<tr><td><code>testServiceLevelMcpDescriptionUsedWhenNoOperationLevel</code></td><td>Service-level
 mcpDescription used as fallback when operation has none</td></tr>
-<tr><td><code>testOperationLevelMcpDescriptionTakesPrecedenceOverServiceLevel</code></td><td>Operation-level
 wins over service-level when both set</td></tr>
-<tr><td><code>testDescriptionFallsBackToAutoGeneratedWhenNoMcpDescriptionParam</code></td><td>Auto-generated
 fallback still produced when no mcpDescription param present</td></tr>
-<tr><td><code>testServiceLevelMcpReadOnlySetsTrueOnAnnotation</code></td><td>mcpReadOnly=true
 on service → readOnlyHint: true on all its tools</td></tr>
-<tr><td><code>testOperationLevelMcpReadOnlyOverridesServiceLevel</code></td><td>Operation-level
 mcpReadOnly takes precedence over service-level</td></tr>
-<tr><td><code>testMcpIdempotentParamSetsIdempotentHint</code></td><td>mcpIdempotent=true
 → idempotentHint: true</td></tr>
-<tr><td><code>testMcpDestructiveParamSetsDestructiveHint</code></td><td>mcpDestructive=true
 → destructiveHint: true</td></tr>
-<tr><td><code>testAnnotationDefaultsAreConservativeWhenNoParamsSet</code></td><td>All
 four hints remain false when no MCP params set (no regression)</td></tr>
-</table>
-
-<h3>6.2 Catalog HTTP Handler — McpCatalogHandlerTest (17 tests)</h3>
-
-<table border="1">
-<tr><th>Test</th><th>Feature Verified</th></tr>
-<tr><td><code>testMcpCatalogReturnsHttp200</code></td><td>Endpoint responds 
successfully</td></tr>
-<tr><td><code>testMcpCatalogContentTypeIsJson</code></td><td>application/json 
Content-Type</td></tr>
-<tr><td><code>testMcpCatalogContentTypeIncludesUtf8</code></td><td>UTF-8 
charset declared</td></tr>
-<tr><td><code>testMcpCatalogHasCorsOriginHeader</code></td><td>Access-Control-Allow-Origin:
 *</td></tr>
-<tr><td><code>testMcpCatalogHasCacheControlNoCache</code></td><td>Cache-Control
 contains no-cache or no-store</td></tr>
-<tr><td><code>testMcpCatalogHasXContentTypeOptionsNoSniff</code></td><td>X-Content-Type-Options:
 nosniff</td></tr>
-<tr><td><code>testMcpCatalogCorsMethodsIncludesGet</code></td><td>CORS allows 
GET (catalog is read-only)</td></tr>
-<tr><td><code>testMcpCatalogReflectsRegisteredService</code></td><td>Deployed 
services appear in tools array</td></tr>
-<tr><td><code>testMcpCatalogBodyHasMetaObject</code></td><td>_meta present in 
handler response</td></tr>
-<tr><td><code>testMcpCatalogMetaDocumentsAxis2Format</code></td><td>_meta.axis2JsonRpcFormat
 contains "arg0"</td></tr>
-<tr><td><code>testMcpCatalogToolsHavePayloadTemplateAndAuth</code></td><td>Tools
 carry x-axis2-payloadTemplate, x-requiresAuth, annotations end-to-end</td></tr>
-</table>
-
-<h3>6.3 Axis2 JSON-RPC Payload — McpAxis2PayloadTest (30 tests)</h3>
-
-<table border="1">
-<tr><th>Test</th><th>Feature Verified</th></tr>
-<tr><td><code>testPayloadTemplateHasSingleTopLevelKey</code></td><td>Template 
has exactly one root key</td></tr>
-<tr><td><code>testPayloadTemplateValueIsArray</code></td><td>Root value is 
array (not object)</td></tr>
-<tr><td><code>testPayloadTemplateArrayHasExactlyOneElement</code></td><td>Array
 has exactly one element</td></tr>
-<tr><td><code>testPayloadTemplateArrayElementHasArg0Key</code></td><td>Element 
has "arg0" key</td></tr>
-<tr><td><code>testPayloadTemplateArg0IsEmptyObject</code></td><td>arg0 is 
<code>{}</code> in template (params substituted by caller)</td></tr>
-<tr><td><code>testLoginServicePayloadTemplateHasDoLoginKey</code></td><td>loginService
 template has "doLogin" as root key</td></tr>
-<tr><td><code>testLoginServicePayloadTemplateCompatibleWithExpectedFormat</code></td><td>Template
 structure matches expected client-side login payload format</td></tr>
-<tr><td><code>testTwoPhaseAuthFlowDocumentedInCatalog</code></td><td>loginService
 is public; all others require auth; both have templates</td></tr>
-<tr><td><code>testAllToolPayloadTemplatesMatchToolName</code></td><td>Every 
template's root key equals the tool's name field</td></tr>
-<tr><td><code>testAllNonLoginToolsRequireAuth</code></td><td>No service 
accidentally marked public</td></tr>
-<tr><td><code>testAllToolsHaveAnnotations</code></td><td>MCP 2025 annotations 
present on every tool</td></tr>
-<tr><td><code>testMetaTokenEndpointPointsToLoginService</code></td><td>_meta.tokenEndpoint
 contains "loginService"</td></tr>
-<tr><td><code>testMetaAxis2FormatHintContainsArg0</code></td><td>Format hint 
is instructive (contains "arg0")</td></tr>
-<tr><td><code>testMetaAuthHeaderDocumentsBearerScheme</code></td><td>authHeader
 contains "Bearer"</td></tr>
-</table>
-
-<h3>6.4 JSON-RPC Error Hardening — Gson JSONRPCIntegrationTest (9 tests)</h3>
-
-<table border="1">
-<tr><th>Test</th><th>Feature Verified</th></tr>
-<tr><td><code>testJsonRpcMessageReceiver</code></td><td>Correct envelope → 
successful round-trip response</td></tr>
-<tr><td><code>testJsonInOnlyRPCMessageReceiver</code></td><td>Fire-and-forget 
(InOnly) receives empty response on success</td></tr>
-<tr><td><code>testMalformedJsonBodyReturnsBadRequest</code></td><td>Non-JSON 
body returns "Bad Request" (no exception class leaked)</td></tr>
-<tr><td><code>testMalformedJsonBodyIncludesCorrelationId</code></td><td>Fault 
contains "errorRef=" UUID</td></tr>
-<tr><td><code>testMalformedJsonBodyCorrelationIdIsUuid</code></td><td>errorRef 
matches 8-4-4-4-12 hex UUID format</td></tr>
-<tr><td><code>testMissingOuterArrayReturnsBadRequestWithCorrelationId</code></td><td>Valid
 JSON but wrong envelope structure → correlated Bad Request</td></tr>
-<tr><td><code>testMalformedJsonBodyDoesNotLeakExceptionClassName</code></td><td>No
 "MalformedJsonException", "IOException", or "at org.apache" in 
response</td></tr>
-<tr><td><code>testInOnlyMalformedJsonBodyDoesNotLeakExceptionDetails</code></td><td>InOnly
 receiver returns empty body on fault (MEP semantics); no exception class name 
or stack trace leaked in response</td></tr>
-</table>
-
-
 <!-- ============================================================ -->
 <a name="not_implemented"/>
-<h2>7. Not Implemented / Limitations</h2>
+<h2>6. Not Implemented / Limitations</h2>
 
 <p>The following capabilities are <strong>not present</strong> in the Axis2 
MCP catalog.
 Each item notes whether the gap is architectural (won't be added to Axis2) or 
deferred
@@ -609,9 +579,12 @@ Each item notes whether the gap is architectural (won't be 
added to Axis2) or de
     Cursor-based pagination is not implemented (offset/limit maps directly to 
JPA/Hibernate DAO patterns).</td>
 </tr>
 <tr>
-  <td>RFC 7807 Problem Details error format</td>
-  <td>Not implemented — architectural gap</td>
-  <td>Axis2 returns SOAP faults (XML envelope) even for JSON-RPC errors. A 
REST layer could return RFC 7807 JSON problem details with per-field validation 
errors. The correlation ID in Axis2 faults is the only structured information 
in the error response.</td>
+  <td>Structured error responses</td>
+  <td><strong>Implemented</strong> — see <a href="#error_handling">Section 
5</a></td>
+  <td>Services throw <code>JsonRpcFaultException</code> to produce structured 
JSON errors
+    with HTTP status codes (422/429/503), error codes, correlation IDs, and 
timestamps.
+    Parse-level errors still produce legacy SOAP faults. Not RFC 7807 format, 
but
+    provides equivalent structured error information.</td>
 </tr>
 <tr>
   <td>API key management</td>
@@ -627,7 +600,7 @@ Each item notes whether the gap is architectural (won't be 
added to Axis2) or de
 
 <!-- ============================================================ -->
 <a name="migration_path"/>
-<h2>8. Migration Path: JSON-RPC to REST</h2>
+<h2>7. Migration Path: JSON-RPC to REST</h2>
 
 <p>Organizations that deploy both Axis2 JSON-RPC services and a modern REST 
API layer
 will have two different MCP transport paths. Understanding which path a given 
MCP tool
@@ -639,7 +612,7 @@ uses determines what limitations apply:</p>
 <tr><td>Tool definitions</td><td>Auto-generated from deployed Axis2 
services</td><td>Auto-generated from OpenAPI 3.1 (e.g., via 
springdoc-openapi)</td></tr>
 <tr><td>Auth</td><td>email + password → Bearer token 
(loginService)</td><td>API key + secret → scoped JWT</td></tr>
 <tr><td>Query semantics</td><td>Per-operation parameters in 
arg0</td><td>Uniform filter/sort/fields on every resource</td></tr>
-<tr><td>Error format</td><td>SOAP fault with correlation ID UUID</td><td>RFC 
7807 Problem Details (JSON, per-field)</td></tr>
+<tr><td>Error format</td><td>Structured JSON (JsonRpcFaultException) with 
correlation ID, HTTP status codes</td><td>RFC 7807 Problem Details (JSON, 
per-field)</td></tr>
 <tr><td>Pagination</td><td>Offset/limit (<a 
href="json-pagination.html">PaginatedResponse</a>)</td><td>Cursor-based</td></tr>
 <tr><td>inputSchema</td><td>Full JSON Schema via <code>mcpInputSchema</code> 
in services.xml (hand-authored)</td><td>Full JSON Schema from OpenAPI 
annotations (auto-generated)</td></tr>
 </table>
@@ -651,25 +624,12 @@ tool discovery during the transition period.</p>
 
 <!-- ============================================================ -->
 <a name="python_compat"/>
-<h2>9. Python MCP Compatibility Notes</h2>
+<h2>8. Python MCP Client Example</h2>
 
-<p>When building a Python MCP server that targets Axis2 services, keep these 
points in mind:</p>
-
-<ul>
-<li>When <code>mcpInputSchema</code> is set in services.xml, the catalog 
provides full
-    JSON Schema for each tool. For services without 
<code>mcpInputSchema</code>, define
-    Pydantic <code>inputSchema</code> per tool in your Python MCP server 
layer.</li>
-<li>Use curated natural language descriptions in your MCP server rather than 
relying on
-    the auto-generated "ServiceName: opName" default (or set 
<code>mcpDescription</code>
-    in services.xml).</li>
-<li>The catalog's <code>_meta.axis2JsonRpcFormat</code> documents the exact 
envelope format
-    your HTTP client must send.</li>
-<li>A recommended response pattern for MCP tools wrapping Axis2:
-    <code>ToolResponse(success, data, metadata, message)</code> and
-    <code>ErrorResponse(error, error_type, suggestions)</code>.</li>
-</ul>
-
-<h3>Minimal Axis2-Aware MCP Server Template</h3>
+<p>The most common MCP integration path is a Python bridge — AI assistants
+like Claude and ChatGPT use Python-based MCP servers to call external tools.
+The template below shows how to authenticate, discover tools from the
+Axis2 MCP catalog, and call services using the correct JSON-RPC envelope.</p>
 
 <pre>
 import httpx
@@ -717,10 +677,18 @@ async def call_tool(name: str, arguments: dict) -&gt; 
list[TextContent]:
     ...
 </pre>
 
-<p><strong>Note on catalog-driven tool lists:</strong> Fetching the catalog at
-<code>list_tools()</code> time is correct because the catalog has
-<code>Cache-Control: no-cache</code>. The tool list is always current without 
requiring
-an MCP server restart on Axis2 redeployment.</p>
+<p><strong>Key points:</strong></p>
+<ul>
+<li>The catalog at <code>/openapi-mcp.json</code> has
+    <code>Cache-Control: no-cache</code>, so fetching it at
+    <code>list_tools()</code> time is correct — the tool list stays
+    current without restarting the MCP server.</li>
+<li>When <code>mcpInputSchema</code> is set in <code>services.xml</code>,
+    the catalog provides full JSON Schema for each tool. For services
+    without it, define the schema in your Python MCP server.</li>
+<li>The <code>_meta.axis2JsonRpcFormat</code> field documents the exact
+    envelope format your HTTP client must send.</li>
+</ul>
 
 </body>
 </html>
diff --git a/src/site/xdoc/docs/toc.xml b/src/site/xdoc/docs/toc.xml
index 29f6c60e11..8c67825a02 100644
--- a/src/site/xdoc/docs/toc.xml
+++ b/src/site/xdoc/docs/toc.xml
@@ -168,10 +168,9 @@ Support</a></li>
         <li><a href="json-rpc-mcp-guide.html#envelope">Axis2 JSON-RPC Envelope 
Format</a></li>
         <li><a href="json-rpc-mcp-guide.html#auth">Two-Phase Bearer Token 
Authentication</a></li>
         <li><a href="json-rpc-mcp-guide.html#error_handling">Error Handling: 
Correlation ID Pattern</a></li>
-        <li><a href="json-rpc-mcp-guide.html#tested_features">Unit Test 
Feature Coverage</a></li>
         <li><a href="json-rpc-mcp-guide.html#not_implemented">Not Implemented 
/ Limitations</a></li>
         <li><a href="json-streaming-formatter.html">Streaming Formatter for 
Large MCP Tool Responses</a></li>
-        <li><a href="json-rpc-mcp-guide.html#python_compat">Python MCP 
Compatibility Notes</a></li>
+        <li><a href="json-rpc-mcp-guide.html#python_compat">Python MCP Client 
Example</a></li>
     </ul>
     </li>
     <li><strong>23.5 <a href="mcp-architecture.html">MCP Architecture — 
Multi-Protocol Design</a></strong>

Reply via email to