Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
# This file:
#     http://anggtwu.net/JSONRPC/quickstart-server.py.html
#     http://anggtwu.net/JSONRPC/quickstart-server.py
#            (find-angg "JSONRPC/quickstart-server.py")
#       See: (find-angg "JSONRPC/quickstart-client.py")
#  Code from: https://json-rpc.readthedocs.io/en/latest/quickstart.html
# Adapted by: Eduardo Ochs <eduardoochs@gmail.com>
#      Needs: (find-pip3-links "json-rpc")
#             (find-pip3-links "werkzeug")

from werkzeug.wrappers import Request, Response
from werkzeug.serving  import run_simple
from jsonrpc           import JSONRPCResponseManager, dispatcher

@dispatcher.add_method
def foobar(**kwargs):
    return kwargs["foo"] + kwargs["bar"]

@Request.application
def application(request):
    # Dispatcher is dictionary {<method_name>: callable}
    dispatcher["echo"] = lambda s: s
    dispatcher["add"]  = lambda a, b: a + b
    response = JSONRPCResponseManager.handle(
        request.data, dispatcher)
    return Response(response.json, mimetype='application/json')

if __name__ == '__main__':
    run_simple('localhost', 4000, application)


"""
** Based on:
** (find-angg "JSONRPC/quickstart-client.py")
* (find-3EE '(eepitch-python) '(eepitch-shell2))
* (eepitch-shell2)
  python3 quickstart-server.py
* (eepitch-python)
import requests
import json
url      = "http://localhost:4000/jsonrpc"
headers  = {'content-type': 'application/json'}
payload1 = {"jsonrpc":"2.0", "id":0, "method":"echo", "params":["echome!"]}
response = requests.post(url, data=json.dumps(payload1), headers=headers).json()
response


(require 'jsonrpc)
(setq myid 0)
(setq mymethod "add")
(setq myparams [1 2])
(setq myjson0 `((method . ,mymethod) (jsonrpc . "2.0") (id . ,myid) (params . ,myparams)))
(setq myjson1 (json-serialize myjson0))
(setq myextraheaders
      `(("Content-Type" . "application/json")
	("Connection" . "Keep-Alive")
	("Content-Length" . ,(number-to-string (string-bytes myjson1)))))

"""