Build interfaces · Lesson 05
Build an MCP image and let Ollama call pricing.total
This video joins four concrete components: the repository shop, Apizr's OCI plugin, a generated MCP container and a small Ollama bridge. Its result is a real tool request for 7 items at 19.5, returning 136.5.
By the end of this lesson
- Distinguish a repository MCP bundle from lesson 4's single-file bundle.
- Identify the explicit inputs and permission for an OCI image build.
- Follow a real Ollama request through the MCP client into the container.
Watch the lesson
English · 8:21 · Recorded with Apizr 0.4.3.
Chapters in this recording
| Time | Chapter |
|---|---|
| 00:00 | Generate the image. Let Ollama use the tool. |
| 00:22 | Four steps from Python to a model response. |
| 00:47 | Prepare the tools before recording the workflow. |
| 01:10 | Use a fixed GitHub release and inspect the source. |
| 01:44 | Install and activate the OCI plugin explicitly. |
| 02:20 | Select the public function and direct execution. |
| 02:56 | Generate the repository MCP bundle. |
| 03:32 | The image is built from explicit inputs. |
| 03:57 | Prepare the target runtime and build request. |
| 04:39 | Apizr generates the OCI service image. |
| 05:26 | Ollama tool calling meets MCP through a client. |
| 05:52 | Connect over container standard input and output. |
| 06:33 | Watch Ollama request the actual container tool. |
| 07:22 | Keep the machine-readable evidence. |
| 07:52 | Python → Apizr image → MCP → Ollama. |
Read the recording transcript and commands
This is the retained English narration, in the original chapter order. Commands keep the recorded version and prerequisites; setup additions in the lesson are labelled separately.
00:00 — Generate the image. Let Ollama use the tool.
Apizr can generate an O C I service image. In this tutorial, we will use its O C I plugin to build an image containing a generated MCP server. Then a local Ollama model will request a tool, and use the actual result returned by that container.
00:22 — Four steps from Python to a model response.
Our source is the shop example in the public Apizr repository. Apizr first generates a repository MCP bundle. Its O C I plugin turns that bundle into a container image. A small Python client connects the container to Ollama. The model chooses a tool call; the Python function runs inside the container.
00:47 — Prepare the tools before recording the workflow.
We use Apizr zero point four point three, Python three point fourteen, Docker with Buildx, and a running local Ollama server. The existing Qwen three Coder model supports tool calling. Plugin wheels and their hashes are already downloaded. Keep the plugin store outside the source checkout and outside the core environment.
01:10 — Use a fixed GitHub release and inspect the source.
Clone the recorded Apizr release into a source directory. The repository shop example contains a small price calculation with a fixed input contract. Read it, then inspect it with Apizr. We will expose only the total function. The example needs no additional business library inside the generated runtime.
git clone --depth 1 --branch v0.4.3 https://github.com/Alien6-Studio/outerspace-apizr.git source
git -C source rev-parse --short HEAD
cat source/examples/repository-shop/pricing.py
apizr inspect source/examples/repository-shop/pricing.py
01:44 — Install and activate the OCI plugin explicitly.
Use the downloaded wheel, its verified digest, and the complete dependency lock to install the O C I plugin into a separate store. Installation is offline. Now enable the installed version. Installing and activating the plugin do not grant permission to build an image. We will create that specific build grant after preparing the inputs.
plugin_sha=5b3f8905c1191f076379083a6c063cb2a9796eede40b277551a6e4acb478e27b
apizr plugins install plugin-wheels/outerspace_apizr_oci-0.4.3-py3-none-any.whl --sha256 "$plugin_sha" --requirements plugin.lock --wheelhouse plugin-wheels --plugins-dir "$PWD/plugins"
apizr plugins enable outerspace-apizr-oci --version 0.4.3 --plugins-dir "$PWD/plugins"
02:20 — Select the public function and direct execution.
Initialize the shop project to create its local analysis grant. The two prepared policies explicitly choose direct execution and select pricing total as the only public MCP capability. Direct execution means the service will run this reviewed Python code. Other functions in the shop project remain outside the tool interface.
apizr init source/examples/repository-shop
cat readiness.json
cat exposure.json
02:56 — Generate the repository MCP bundle.
Ask Apizr to build the MCP exposure from the shop directory, using the analysis grant and both policies. This repository bundle is the input required by the O C I plugin. A single file generation example from the earlier episode uses a different bundle format. Read the generated runtime requirements before preparing the image.
apizr expose build mcp source/examples/repository-shop --operator-policy source/examples/repository-shop/.apizr/operator.json --readiness-policy readiness.json --policy exposure.json --output-dir mcp-bundle
ls mcp-bundle
cat mcp-bundle/requirements.txt
03:32 — The image is built from explicit inputs.
The builder needs a Python base image pinned by digest, a target platform, and Linux wheels with exact hashes. The preparation helper downloads the generated server requirements using the target Python image. It writes the wheel lock, build request, and matching operator grant. The helper prepares inputs; Apizr performs the image build.
03:57 — Prepare the target runtime and build request.
Check the digest of our existing Python base image. Run the preparation helper. Package downloads happen here, before image construction. The helper records the complete wheel set for Linux ARM sixty four. It then writes the build request and a grant tied to this plugin, these input paths, this base image, and this local output tag.
docker image inspect python:3.14-slim --format '{{index .RepoDigests 0}}'
python prepare_build.py
python -c 'import json; d=json.load(open("build.json")); print({k:d[k] for k in ("interface","platform","tag")})'
python -c 'import json; g=json.load(open("build-operator.json"))["grants"][0]; print(g["operation"], g["permissions"]); print(g["plugin"]["name"], g["plugin"]["version"])'
04:39 — Apizr generates the OCI service image.
This is the image generation command: Apizr plugins run, outerspace Apizr O C I, build. Pass the prepared request, operator policy and plugin store. The plugin generates the Dockerfile and invokes the container builder. Save its complete response, then read the result fields. Published is false because this operation creates a local image.
apizr plugins run outerspace-apizr-oci build --arguments build.json --operator-policy build-operator.json --plugins-dir "$PWD/plugins" --timeout-ms 360000 > build-result.json
python -c 'import json; r=json.load(open("build-result.json"))["result"]; print(json.dumps({k:r[k] for k in ("tag","platform","image_id","published")}, indent=2))'
docker image inspect apizr-academy:05-shop-mcp --format 'User={{.Config.User}}'
05:26 — Ollama tool calling meets MCP through a client.
Ollama accepts function tool definitions through its chat API. Our client discovers the MCP tools and passes those schemas to the model. When the model requests pricing total, the client forwards the arguments through MCP, then returns the tool result to Ollama. This bridge is a small tutorial program, separate from Apizr image generation.
05:52 — Connect over container standard input and output.
Install the MCP Python client into its own environment. Read the server configuration: Docker runs the generated image with interactive standard input, without a terminal allocation. The MCP client starts and connects to the container. List the tools to verify that the generated image exposes pricing total and its input schema.
uv venv --python python3.14 client
uv pip install --python client/bin/python 'mcp==2.3.0'
sed -n '25,35p' ollama_mcp.py
client/bin/python ollama_mcp.py list
06:33 — Watch Ollama request the actual container tool.
Run the bridge with a question about seven items at nineteen point five each. Watch the model request pricing total with named arguments. The client sends that request to the generated MCP server inside the container. The server returns a successful result of one hundred thirty six point five. Ollama receives that result and writes the final sentence.
client/bin/python ollama_mcp.py
07:22 — Keep the machine-readable evidence.
The bridge also saves the real model responses and MCP results. Read that trace to verify the tool name, arguments and returned value. Compare the image identity in the Apizr build result with Docker inspection. These checks connect the generated artifact to the tool call that we just observed.
python -c 'import json; t=json.load(open("ollama-trace.json")); print(json.dumps(t["results"], indent=2)); print(t["answer"])'
python verify_image.py
07:52 — Python → Apizr image → MCP → Ollama.
You have generated an O C I image with Apizr, connected to its MCP server, and verified a real local model tool call. The example uses a small price function so the infrastructure is easy to understand. For your own project, begin with reviewed source, an explicit public selection, and the runtime dependencies that project actually needs.
1. Read the recorded setup
The recording uses Apizr and OCI plugin 0.4.3, Python 3.14, Apple Silicon, Docker Desktop with Buildx, a prepared Python base image and the local qwen3-coder:30b Ollama model. Plugin wheels, their hashes and the complete dependency lock are prepared before the filmed operations.
Download the original OCI/Ollama teaching files into a fresh workspace. They contain the original build helper, bridge, image verifier, recorded commands and the two policies. The helper retains the recording's Docker Desktop and ARM64 assumptions; review paths and target platform for your own machine. The OCI reference supplies the current preparation procedure as a separate setup reference.
2. Select the repository shop and build the image
The video clones Apizr's v0.4.3 source and selects python:pricing:total from source/examples/repository-shop. It explicitly installs and enables the OCI plugin in a separate plugin store. The recorded commands and required wheel digest appear in the transcript below.
apizr init source/examples/repository-shop
apizr expose build mcp source/examples/repository-shop --operator-policy source/examples/repository-shop/.apizr/operator.json --readiness-policy readiness.json --policy exposure.json --output-dir mcp-bundle
python prepare_build.py
apizr plugins run outerspace-apizr-oci build --arguments build.json --operator-policy build-operator.json --plugins-dir "$PWD/plugins" --timeout-ms 360000 > build-result.json
prepare_build.py downloads target-runtime wheels and writes their lock, the build request and a matching operator grant. The Apizr plugin generates the Dockerfile and performs the build. Its result has published: false: this is a local image, not a registry push.
3. Follow the model's actual tool call
The original bridge discovers the container's MCP schemas, passes them to Ollama's chat API, forwards the requested arguments through MCP and returns the tool result to Ollama. It starts the container with interactive stdin and no terminal allocation; no HTTP port is published.
uv venv --python python3.14 client
uv pip install --python client/bin/python 'mcp==2.3.0'
client/bin/python ollama_mcp.py list
client/bin/python ollama_mcp.py
python verify_image.py
The retained trace shows pricing.total called with quantity=7 and unit_price=19.5, followed by {"result": 136.5}. The bridge stores ollama-trace.json. The verifier compares the actual Docker image with the Apizr result, checks user 65532:65532, and checks that the image was not published.
Practice
Trace the four handoffs in the recording: reviewed source → repository MCP bundle → local image → Ollama/MCP call. Locate the tool arguments, returned value and image identity. Which component chooses the call, which executes Python, and which builds the image?
Check your reasoning
Ollama requests a tool; the Python bridge carries that request through MCP; the generated server runs pricing.total inside the container. Apizr and its OCI plugin produce the bundle and image. The observed result is 136.5. A model sentence alone would not establish that the tool ran; retain the actual request/result trace and matching image identity.