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":
"{\"<operationName>\":[{\"arg0\":{<params>}}]}",
"contentType": "application/json",
"authHeader": "Authorization: Bearer <token>",
- "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
</soapenv:Fault>
</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) ->
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>