Skip to content

Make your first MCP and REST calls

Use stable Apizr 0.3.0 to expose two functions from the versioned examples/repository-shop example. You will call quote(unit_price=12.5, quantity=2) and get 25.0, then available(stock=10, requested=3) and get true.

Complete the shared preparation below, then choose MCP or REST. You only need to follow one interface path. For MCP, choose your usual client or the Python test without an AI account. No Docker, plugin, remote-Git adapter or development build is needed. The site also documents unreleased 0.4; this page uses only 0.3.0 commands.

Prepare an isolated workspace

Goal: install the stable compiler without changing your system Python. You need Python 3.11–3.14 with venv and pip, curl, an internet connection for downloads, and a POSIX shell on macOS or Linux. Run the following in a writable parent directory, using a new directory name. Keep the same terminal throughout.

mkdir apizr-quickstart
cd apizr-quickstart
python3 -m venv .venv
. .venv/bin/activate
python -m pip install outerspace-apizr==0.3.0
apizr --version

Observe: the last command reports 0.3.0. If venv or pip is unavailable, install those components for your Python before continuing. No Apizr checkout is needed. Generated files and client code will stay outside the directory analyzed below.

Get the example and choose its public functions

Goal: fetch all three source files from the stable tag, rather than copying an unversioned example from master.

mkdir shop
curl --fail --location https://raw.githubusercontent.com/Alien6-Studio/outerspace-apizr/v0.3.0/examples/repository-shop/api.py --output shop/api.py
curl --fail --location https://raw.githubusercontent.com/Alien6-Studio/outerspace-apizr/v0.3.0/examples/repository-shop/inventory.py --output shop/inventory.py
curl --fail --location https://raw.githubusercontent.com/Alien6-Studio/outerspace-apizr/v0.3.0/examples/repository-shop/pricing.py --output shop/pricing.py
ls shop

Observe: api.py, inventory.py and pricing.py are present. api.quote uses a private helper and pricing.total; only the two functions you select next will be public.

Readiness assesses whether the code evidence supports an interface. Its policy below permits the direct execution mode. An exposure policy names the public functions, interfaces and allowed modes. Create these two local JSON files:

cat > readiness-direct.json <<'JSON'
{"execution":{"modes":["direct"]}}
JSON
cat > exposure-direct.json <<'JSON'
{"selection":{"include":["python:api:quote","python:inventory:available"]},"interfaces":["rest","mcp"],"execution":{"allowed":["direct"]}}
JSON

Observe: both policy files exist beside shop, not inside it. Only python:api:quote and python:inventory:available are selected. Being ready does not automatically expose a function.

Choose your interface

The workspace, sources and policies above are shared. Continue with one path:

Use MCP Use REST

  • MCP: generate tools, then connect your usual client or test them with Python.
  • REST: generate an HTTP API and send two requests with curl. Skip the MCP sections.

Use MCP

Generate the MCP bundle

Goal: turn the selected functions into callable MCP tools. A bundle is the generated server, its contracts and the source it needs.

apizr expose build mcp shop --readiness-policy readiness-direct.json --policy exposure-direct.json --output-dir build/mcp

Observe: generation succeeds and build/mcp contains server.py, mcp-tools.json, requirements.txt and supporting artifacts. The tools are named api.quote and inventory.available. Helpers are packaged as support, not tools. Use a fresh output directory when generating again; do not edit generated files to bypass their integrity checks.

expose build performs the required scan, readiness assessment and exposure plan. Separate scan, graph, readiness and expose plan commands are optional ways to inspect these stages, not prerequisites. Generation does not execute the project. A conditional private helper does not prevent these two selected public functions from being generated.

Connect a client and make two calls

Goal: complete a real MCP exchange, not just start a process. Install the bundle's declared runtime dependencies into the active virtual environment:

python -m pip install -r build/mcp/requirements.txt

Observe: the MCP SDK and server requirements install successfully. Both client choices below use this same bundle and environment. Choose one; running the Python example is not required before connecting your usual client.

Calls execute trusted Python

This example uses direct mode: the functions execute inside the generated server with your user permissions. Analyze unfamiliar code before trusting it. A readiness result is not a security approval. For governed execution, an execution policy chooses a worker backend and its required limits; see the full journey.

This is a generated business-function MCP server. It is distinct from the Apizr analysis MCP server in development 0.4, which inspects repositories and plans exposure without executing their functions.

With your usual client

The generated MCP server can also be launched by a compatible AI client. On macOS, for example, the official local-server guide for Claude Desktop documents Settings → Developer → Edit Config, the mcpServers structure, absolute paths and a full restart after saving. Install Claude Desktop separately if you choose this client; the optional Python test does not require it.

Run pwd in apizr-quickstart to obtain its absolute path. Add this entry to the existing mcpServers object, preserving any other servers. Replace both /absolute/path/apizr-quickstart prefixes with that real path; do not use ~ or shell variables in this JSON:

{
  "mcpServers": {
    "repository-shop": {
      "command": "/absolute/path/apizr-quickstart/.venv/bin/python",
      "args": [
        "/absolute/path/apizr-quickstart/build/mcp/server.py",
        "--transport",
        "stdio"
      ]
    }
  }
}

After restarting the client, inspect the server's available tools. Ask it to call api.quote with unit_price=12.5, quantity=2, then inventory.available with stock=10, requested=3. Approve only those intended calls and inspect the tool results (25.0 and true), not just the assistant's prose answer.

This configuration follows the official client documentation. Apizr's documented automated proof uses the Python client in the other choice; it does not claim a graphical Claude Desktop session was exercised. Other MCP clients can use the same stdio command and arguments according to their own configuration format.

Test with Python — no AI account

This bundle uses the SDK's v2 client API; follow the official Python client documentation and stdio transport configuration. The small client below starts the generated server with that same Python, completes the protocol handshake, lists its tools and calls them. No AI account is required.

Run this from apizr-quickstart, still with .venv active:

python - <<'PY'
import asyncio
import json
import sys
from pathlib import Path

from mcp import Client, StdioServerParameters


async def main():
    server = StdioServerParameters(
        command=sys.executable,
        args=[str(Path("build/mcp/server.py").resolve()), "--transport", "stdio"],
    )
    async with Client(server, read_timeout_seconds=10) as client:
        names = sorted(tool.name for tool in (await client.list_tools()).tools)
        assert names == ["api.quote", "inventory.available"], names
        print("tools:", ", ".join(names))
        quote = await client.call_tool("api.quote", {"unit_price": 12.5, "quantity": 2})
        available = await client.call_tool("inventory.available", {"stock": 10, "requested": 3})
        assert not quote.is_error and not available.is_error
        assert quote.structured_content == 25.0
        assert available.structured_content is True
        print("quote:", json.dumps(quote.structured_content))
        print("available:", json.dumps(available.structured_content))


asyncio.run(main())
PY

Observe: the client prints these results, then closes the server connection:

tools: api.quote, inventory.available
quote: 25.0
available: true

The server may also log diagnostic messages to stderr. Running python build/mcp/server.py --transport stdio alone waits for an MCP client; it is not evidence that any tool has been called. Do not type chat messages into its protocol stream.

After your two successful calls, continue with your own code. You can finish here without following the REST path.

Use REST

Goal: expose the same two functions as HTTP endpoints. After the workspace, source and policy steps, you can choose REST directly; the MCP steps are not required. Keep the same active .venv and run:

apizr expose build rest shop --readiness-policy readiness-direct.json --policy exposure-direct.json --output-dir build/rest
python -m pip install -r build/rest/requirements.txt

Observe: build/rest contains app.py, openapi.json, requirements.txt and supporting artifacts. Starting this server executes trusted source inside its process with your user permissions (direct mode). Readiness is not a security approval. For governed workers and their limits, see execution policies. Use an available local port; this example uses 8000 and binds only to your machine:

uvicorn app:app --app-dir build/rest --host 127.0.0.1 --port 8000

Observe: Uvicorn reports that the server is running. Keep that terminal open. In a second terminal with curl available, send the two requests:

curl --fail --silent --show-error http://127.0.0.1:8000/capabilities/api.quote --header 'Content-Type: application/json' --data '{"unit_price":12.5,"quantity":2}'
curl --fail --silent --show-error http://127.0.0.1:8000/capabilities/inventory.available --header 'Content-Type: application/json' --data '{"stock":10,"requested":3}'

Observe: the response bodies are 25.0 and true respectively (curl does not append a newline). Open http://127.0.0.1:8000/docs for the generated API contract. Stop the server with Ctrl+C in its terminal when finished.

Continue with your own code

Follow The full journey to inspect each compiler stage, understand policy decisions and choose direct or governed execution. For your own repository, replace shop with its local source root and explicitly choose its capability IDs in your exposure policy. Use apizr scan /path/to/source to discover those IDs; review the source and application dependencies before executing a generated bundle. The exposure guide covers refusals and worker policies.