Python xmlrpc.client: Remote Calls

Published on: August 21, 2026
Reading time: 5 minutes
Server cables representing remote calls with Python xmlrpc.client

The xmlrpc.client module calls remote procedures exposed by an XML-RPC server. The protocol represents methods, parameters, and results as XML and uses HTTP or HTTPS for transport. It still appears in legacy systems, appliances, publishing platforms, and enterprise integrations that must be maintained without third-party dependencies.

XML-RPC is simple, but it is not a modern default for new public APIs. Python’s documentation warns that the client is not secure against maliciously constructed XML data. Use it only with authenticated, trusted endpoints, enable TLS, enforce timeouts and response limits, and keep an explicit allowlist of remote methods.

Your first ServerProxy call

from xmlrpc.client import ServerProxy

with ServerProxy(
    "https://rpc.example.com/RPC2",
    use_builtin_types=True,
) as proxy:
    result = proxy.calculator.add(7, 5)
    print(result)

ServerProxy creates a dynamic proxy. Accessing proxy.calculator.add does not make a request yet; the call happens when arguments are supplied. The complete dotted method name is sent to the server.

Use the proxy as a context manager so the transport is closed. Do not construct a method name directly from untrusted text, because that can expose operations the application did not intend to call.

Important options

In addition to the URI, ServerProxy accepts options such as:

  • allow_none=True to enable the common extension for None.
  • use_builtin_types=True to return dates as datetime and binary values as bytes.
  • headers for additional HTTP headers.
  • context for an ssl.SSLContext on HTTPS connections.
  • transport to customize connections, timeouts, proxies, or observability.

Not every server accepts None. Enable the extension only when the service contract explicitly supports it.

Supported data types

XML-RPC has a smaller type system than Python. Common values include booleans, bounded integers, floating-point numbers, strings, arrays, string-keyed structs, dates, and binary values.

payload = {
    "id": 42,
    "active": True,
    "tags": ["python", "rpc"],
    "price": 19.90,
}

with ServerProxy(URL, use_builtin_types=True) as proxy:
    response = proxy.catalog.create(payload)

Struct keys must be strings. Sets, generators, arbitrary complex objects, and many custom classes cannot be transmitted directly. Convert domain objects into a simple documented contract before calling the service.

Integer limits

Traditional XML-RPC integers are signed 32-bit values. Some implementations accept extensions such as i8 or biginteger, but interoperability varies. Large identifiers should be negotiated in the contract and are often safer as strings.

def rpc_id(value: int) -> str:
    if value < 0:
        raise ValueError("invalid identifier")
    return str(value)

Never assume that two XML-RPC products implement the same numeric extensions.

Dates and use_builtin_types

With use_builtin_types=True, received dates can become datetime.datetime objects. Without it, values may arrive as the module’s DateTime wrapper.

from datetime import datetime, timezone
from xmlrpc.client import ServerProxy

now = datetime.now(timezone.utc).replace(tzinfo=None)

with ServerProxy(URL, use_builtin_types=True) as proxy:
    proxy.events.record("backup", now)

XML-RPC does not carry rich timezone information. Define whether all timestamps are UTC and avoid ambiguous local times.

Binary data

Bytes are encoded as Base64. With use_builtin_types=True, returned data may be bytes. Otherwise, access Binary.data.

from xmlrpc.client import Binary, ServerProxy

content = b"binary data"

with ServerProxy(URL, use_builtin_types=True) as proxy:
    result = proxy.files.upload(Binary(content))

Base64 increases transfer size. Avoid moving large files through XML-RPC unless the service has strict limits and explicit support. A dedicated upload endpoint or object store is usually better.

Fault: a remote application error

When the server executes the request but returns an XML-RPC fault, the client raises Fault. It exposes faultCode and faultString.

from xmlrpc.client import Fault, ServerProxy

try:
    with ServerProxy(URL) as proxy:
        proxy.users.get(999)
except Fault as error:
    print("Remote code:", error.faultCode)
    print("Message:", error.faultString)

Do not render faultString directly as HTML or treat it as a structured trusted value. It may disclose internals or include externally influenced text.

ProtocolError: an HTTP-layer failure

ProtocolError represents HTTP or HTTPS problems such as 401, 403, 404, or 500 before a valid XML-RPC response is available. It includes the URL, status code, message, and headers.

from xmlrpc.client import ProtocolError

try:
    proxy.system.status()
except ProtocolError as error:
    print(error.errcode, error.errmsg)

A remote application fault and a transport response require different actions. Do not retry invalid credentials or a missing endpoint indefinitely. For the standard HTTP client’s hierarchy, read Python urllib.error.

Other transport failures

DNS, timeout, connection refusal, and TLS can surface as OSError, TimeoutError, ssl.SSLError, or transport-specific exceptions. Keep the try block small and preserve the original cause.

try:
    result = proxy.system.status()
except Fault:
    raise
except ProtocolError:
    raise
except OSError as error:
    raise RuntimeError("RPC service unavailable") from error

HTTPS certificate validation

For HTTPS URIs, current Python versions verify the certificate and hostname by default. Supply a context when using a corporate CA or an explicit minimum TLS version.

import ssl
from xmlrpc.client import ServerProxy

context = ssl.create_default_context(cafile="corporate-ca.pem")
context.minimum_version = ssl.TLSVersion.TLSv1_2

proxy = ServerProxy(
    "https://rpc.example.com/RPC2",
    context=context,
    use_builtin_types=True,
)

Never use an unverified context as a permanent workaround. The guide to Python ssl explains trust chains, hostname verification, and mTLS.

Authentication

The module accepts Basic Authentication credentials embedded in the URL, but that form can leak through logs, history, diagnostics, and monitoring. Prefer controlled headers or a custom transport and always use HTTPS.

headers = (("Authorization", "Bearer SHORT_LIVED_TOKEN"),)
proxy = ServerProxy(URL, headers=headers)

Do not hard-code tokens. Load secrets from the environment or a secret manager, rotate them, and redact the header everywhere.

Adding a timeout with a custom transport

ServerProxy has no direct timeout argument. A custom transport can create bounded connections.

import http.client
import xmlrpc.client

class TimeoutTransport(xmlrpc.client.SafeTransport):
    def __init__(self, timeout: float = 10.0, context=None):
        super().__init__(context=context)
        self.timeout = timeout

    def make_connection(self, host):
        return http.client.HTTPSConnection(
            host,
            timeout=self.timeout,
            context=self.context,
        )

Test custom transports against the exact Python version used in production because internal details can evolve. For low-level HTTP controls, read Python http.client.

Introspection

Some servers expose system.listMethods(), system.methodHelp(), and system.methodSignature().

with ServerProxy(URL) as proxy:
    methods = proxy.system.listMethods()
    for name in methods:
        print(name)

Introspection helps development and diagnostics, but it can reveal sensitive surface area. It is not authorization. The client should maintain its own allowlist.

MultiCall

MultiCall batches several calls into one system.multicall request when the server supports it.

from xmlrpc.client import MultiCall, ServerProxy

with ServerProxy(URL) as proxy:
    batch = MultiCall(proxy)
    batch.catalog.get(1)
    batch.catalog.get(2)
    results = list(batch())

Batching reduces network round trips but increases request cost and response size. Limit item count, define partial-failure behavior, and avoid grouping destructive operations without clear semantics.

XML security

The official documentation warns about malicious XML. Even a known endpoint can be compromised and return resource-intensive content. Enforce limits at a reverse proxy, set timeouts, authenticate both sides, and segment the network.

Never expose an XML-RPC client directly to an arbitrary URL supplied by a user. That combines SSRF, hostile XML, and credential-leakage risks.

Logging and observability

Log the logical method name, duration, summarized outcome, failure code, and correlation identifier. Do not log full parameters, binary results, passwords, tokens, or personal data.

Because proxy methods are dynamic, wrap them in explicit domain functions. This improves validation, metrics, and testability.

Test supported types, None enabled and disabled, out-of-range integers, dates, binary values, Fault, ProtocolError, timeout, invalid certificates, oversized responses, missing methods, partial multicall failures, and log redaction.

Run integration tests against a controlled local server. The companion guide to xmlrpc.server shows how to create one.

When not to use XML-RPC

For a new API, JSON over HTTP, gRPC, or another modern protocol usually offers a stronger ecosystem for authentication, schemas, streaming, and observability. XML-RPC mainly makes sense when interoperating with an existing system.

Conclusion

xmlrpc.client simplifies legacy XML-RPC integrations through ServerProxy. Use it safely by limiting methods and types, validating TLS, protecting credentials, configuring timeouts, separating Fault from ProtocolError, and treating all returned XML as untrusted.

Read the official xmlrpc.client documentation and the XML-RPC specification. For new systems, evaluate alternatives; for legacy systems, hide the protocol behind a well-tested domain adapter.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Error code over binary data representing failures handled with Python urllib.error
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python urllib.error: Handle HTTP Failures

    Learn Python urllib.error to handle URLError, HTTPError, incomplete downloads, selective retries, and clearer network diagnostics.

    Ler mais

    Tempo de leitura: 5 minutos
    21/08/2026
    HTML keycaps representing HTML entities with Python html.entities
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    html.entities: Convert HTML Entities

    Learn Python html.entities to inspect HTML entities, convert names and code points, and avoid confusing decoding with sanitization.

    Ler mais

    Tempo de leitura: 6 minutos
    21/08/2026
    Folder with files representing MIME types identified with Python mimetypes
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    mimetypes: Detect MIME Types for Files

    Learn Python mimetypes to identify file types, validate uploads, and set safer HTTP Content-Type headers.

    Ler mais

    Tempo de leitura: 6 minutos
    20/08/2026
    HTML code on a screen representing parsing with Python html.parser
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python html.parser: Parse HTML

    Learn Python html.parser to extract text, links, and metadata, process HTML incrementally, and avoid confusing parsing with sanitization.

    Ler mais

    Tempo de leitura: 5 minutos
    20/08/2026
    Server rack representing low-level HTTP connections with Python http.client
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python http.client: Low-Level HTTP

    Learn Python http.client for low-level HTTP and HTTPS connections, streaming, headers, TLS, connection reuse, size limits, and errors.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026
    HTML code on a screen representing responsible crawling with Python robotparser
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python robotparser: Read robots.txt

    Learn Python urllib.robotparser to respect robots.txt, crawl-delay, request-rate, sitemaps, caching, and responsible crawling limits.

    Ler mais

    Tempo de leitura: 4 minutos
    20/08/2026