MCP
In the previous module, you deployed the backend databases, REST APIs and MCP servers. This module demonstrates how to register the MCP servers with Llama Stack, how to programmatically interact with Llama Stack and MCP tools using Python - the primary language for AI application development.
You’ll explore 2 distinct approaches to building agents that consume MCP tools:
-
Llama Stack Client: The native Python SDK for Llama Stack, providing direct access to tool invocation
-
LangGraph: A popular third-party agentic framework that uses Llama Stack as its inference backend
Both approaches demonstrate important patterns for agent development, from simple tool invocation to complex multi-step reasoning.
Two approaches to agent development
Llama Stack’s flexible architecture supports multiple development patterns:
- Direct tool invocation (Llama Stack Client)
-
Best for: Orchestrating tool calls programmatically when you control the logic
-
You decide which tools to call and when
-
Useful for deterministic workflows, testing, and integration scenarios
-
Full control over tool invocation, parameter passing, and result handling
-
- Agent-driven invocation (LangGraph + Llama Stack)
-
Best for: Building autonomous agents that reason about tool usage
-
The agent decides which tools to call based on user intent
-
Useful for conversational interfaces, customer support, and complex problem-solving
-
Agent handles tool selection, parameter extraction, and result synthesis
-
This module demonstrates both patterns so you can choose the right approach for your use case.
Setup
Make sure you are in the correct base directory
cd $HOME/fantaco-redhat-one-2026/
pwd
/home/lab-user/fantaco-redhat-one-2026
Check that you have set key env variables
export LLAMA_STACK_BASE_URL=http://llamastack-distribution-vllm-service.agentic-{user}.svc:8321
export INFERENCE_MODEL=vllm/qwen3-14b
echo "LLAMA_STACK_BASE_URL="$LLAMA_STACK_BASE_URL
echo "INFERENCE_MODEL="$INFERENCE_MODEL
LLAMA_STACK_BASE_URL=http://llamastack-distribution-vllm-service.agentic-{user}.svc:8321
INFERENCE_MODEL=vllm/qwen3-14b
If needed, create a Python virtual environment (venv)
python -m venv .venv
or you can look for an existing .venv folder
ls .venv
The following response indicates you need to create your Python venv
ls: cannot access '.venv': No such file or directory
and
echo $VIRTUAL_ENV
/home/lab-user/fantaco-redhat-one-2026/.venv
Set environment
source .venv/bin/activate
And if you use Terminal 2 you wish to make sure all the env vars are set up there as well.
The execution of the source command will change the prompt itself to look like the following:
((.venv) ) [lab-user: ~/fantaco-redhat-one-2026]
Change to the correct sub-directory
cd mcp-examples/
pwd
/home/lab-user/fantaco-redhat-one-2026/mcp-examples/
Python Setup
You should have access to python and pip
python -V
Python 3.12.11
pip -V
pip 23.2.1 from /usr/lib/python3.12/site-packages/pip (python 3.12)
which python
~/fantaco-redhat-one-2026/.venv/bin/python
Install dependencies
pip install -r requirements.txt
This installs the required Python packages:
-
llamastack-client: Official Python SDK for Llama Stack -
langgraph: Graph-based agent framework -
langchain-openai: OpenAI-compatible LangChain integration -
Supporting libraries for HTTP requests and JSON processing
Register MCP Servers
Verify that you have connectivity to the MCP Servers which in turn have connectivity to the REST endpoints.
export CUSTOMER_MCP_SERVER_URL=https://$(oc get routes -l app=mcp-customer -o jsonpath="{range .items[*]}{.status.ingress[0].host}{end}")/mcp
export FINANCE_MCP_SERVER_URL=https://$(oc get routes -l app=mcp-finance -o jsonpath="{range .items[*]}{.status.ingress[0].host}{end}")/mcp
echo $CUSTOMER_MCP_SERVER_URL
echo $FINANCE_MCP_SERVER_URL
https://mcp-customer-route-default.apps.cluster-frcqw.dynamic.redhatworkshops.io/mcp
https://mcp-finance-route-default.apps.cluster-frcqw.dynamic.redhatworkshops.io/mcp
Register Customer MCP with Llama Stack
echo "LLAMA_STACK_BASE_URL: ${LLAMA_STACK_BASE_URL}"
echo "CUSTOMER_MCP_SERVER_URL: ${CUSTOMER_MCP_SERVER_URL}"
curl -w "\nHTTP Status: %{http_code}\n" -X POST "${LLAMA_STACK_BASE_URL}/v1/toolgroups" \
-H "Content-Type: application/json" \
-d '{
"toolgroup_id": "customer_mcp",
"provider_id": "model-context-protocol",
"mcp_endpoint": { "uri": "'"${CUSTOMER_MCP_SERVER_URL}"'" }
}'
LLAMA_STACK_BASE_URL: http://localhost:8321
CUSTOMER_MCP_SERVER_URL: https://mcp-customer-route-default.apps.cluster-frcqw.dynamic.redhatworkshops.io/mcp
null
HTTP Status: 200
Note: If you feel that your registration failed, perhaps the wrong URL, then there Python and shell scripts to help you unregister the tool.
See that the new toolgroup is registered
curl -sS -H "Content-Type: application/json" $LLAMA_STACK_BASE_URL/v1/toolgroups | jq
{
"data": [
{
"identifier": "builtin::rag",
"provider_resource_id": "builtin::rag",
"provider_id": "rag-runtime",
"type": "tool_group",
"mcp_endpoint": null,
"args": null
},
{
"identifier": "builtin::websearch",
"provider_resource_id": "builtin::websearch",
"provider_id": "tavily-search",
"type": "tool_group",
"mcp_endpoint": null,
"args": null
},
{
"identifier": "customer_mcp",
"provider_resource_id": "customer_mcp",
"provider_id": "model-context-protocol",
"type": "tool_group",
"mcp_endpoint": {
"uri": "https://mcp-customer-route-agentic-user1.apps.cluster-b8h97.dynamic.redhatworkshops.io/mcp"
},
"args": null
}
]
}
Register Finance MCP with Llama Stack
echo "LLAMA_STACK_BASE_URL: ${LLAMA_STACK_BASE_URL}"
echo "FINANCE_MCP_SERVER_URL: ${FINANCE_MCP_SERVER_URL}"
curl -w "\nHTTP Status: %{http_code}\n" -X POST "${LLAMA_STACK_BASE_URL}/v1/toolgroups" \
-H "Content-Type: application/json" \
-d '{
"toolgroup_id": "finance_mcp",
"provider_id": "model-context-protocol",
"mcp_endpoint": { "uri": "'"${FINANCE_MCP_SERVER_URL}"'" }
}'
LLAMA_STACK_BASE_URL: http://localhost:8321
FINANCE_MCP_SERVER_URL: https://mcp-finance-route-default.apps.cluster-frcqw.dynamic.redhatworkshops.io/mcp
null
HTTP Status: 200
See if both the Customer and Finance MCP servers are registered
curl -sS -H "Content-Type: application/json" \
"$LLAMA_STACK_BASE_URL/v1/toolgroups" \
| jq -r '.data[] | select(.provider_id == "model-context-protocol") | .identifier'
customer_mcp
finance_mcp
|
What just happened? You registered two MCP servers as tool groups with Llama Stack. Llama Stack now knows where to find them and will query them for available tools at runtime. Notice the |
List Customer Tools
curl -sS -L -H "Content-Type: application/json" \
"$LLAMA_STACK_BASE_URL/v1/tool-runtime/list-tools?tool_group_id=customer_mcp" \
| jq -r '.data[] | "Tool: \(.name)\nDescription: \(.description | split("\n")[0])\n"'
Tool: search_customers
Description: Search for customers by various fields with partial matching
Tool: get_customer
Description: Get customer by ID
List Finance Tools
curl -sS -L -H "Content-Type: application/json" \
"$LLAMA_STACK_BASE_URL/v1/tool-runtime/list-tools?tool_group_id=finance_mcp" \
| jq -r '.data[] | "Tool: \(.name)\nDescription: \(.description | split("\n")[0])\n"'
Tool: fetch_order_history
Description: Get order history for a customer.
Tool: fetch_invoice_history
Description: Get invoice history for a customer.
Tool discovery and inspection
Before building agents, you need to understand what tools are available. Llama Stack provides APIs for discovering registered tool groups and inspecting individual tools. This dynamic discovery is a key feature of MCP - agents can adapt to available capabilities without hardcoded dependencies.
The sample code includes Python scripts for: - Listing all registered tool groups - Inspecting tools in each MCP server - Invoking tools directly (Llama Stack Client approach) - Building autonomous agents (LangGraph approach)
Available Tools
python 2_list_tools.py
==================================================
Registered Toolgroups
==================================================
Toolgroup ID: builtin::rag
Provider ID: rag-runtime
--------------------------------------------------
Toolgroup ID: builtin::websearch
Provider ID: tavily-search
--------------------------------------------------
Toolgroup ID: customer_mcp
Provider ID: model-context-protocol
MCP Endpoint: https://mcp-customer-route-agentic-user1.apps.cluster-b8h97.dynamic.redhatworkshops.io/mcp
--------------------------------------------------
Toolgroup ID: finance_mcp
Provider ID: model-context-protocol
MCP Endpoint: https://mcp-finance-route-agentic-user1.apps.cluster-b8h97.dynamic.redhatworkshops.io/mcp
--------------------------------------------------
Total toolgroups: 4
==================================================
Customer MCP Tools
python 3_list_customer_tools.py
==================================================
Customer MCP Server Tools
==================================================
MCP Server URL: https://mcp-customer-route-showroom-27qxd-1-user1.apps.cluster-27qxd.dynamic.redhatworkshops.io/mcp
Tool Name: search_customers
Description: Search for customers by various fields with partial matching
Args:
company_name: Filter by company name (partial matching, optional)
contact_name: Filter by contact person name (partial matching, optional)
contact_email: Filter by contact email address (partial matching, optional)
phone: Filter by phone number (partial matching, optional)
Returns:
List of customers matching the search criteria
--------------------------------------------------
Tool Name: get_customer
Description: Get customer by ID
Retrieves a single customer record by its unique identifier
Args:
customer_id: The unique 5-character identifier of the customer
Returns:
Customer details including customerId, companyName, contactName, contactTitle,
address, city, region, postalCode, country, phone, fax, contactEmail,
createdAt, and updatedAt
--------------------------------------------------
Total tools: 2
==================================================
Finance MCP tools
python 3_list_finance_tools.py
==================================================
Finance MCP Server Tools
==================================================
MCP Server URL: https://mcp-finance-route-showroom-27qxd-1-user1.apps.cluster-27qxd.dynamic.redhatworkshops.io/mcp
Tool Name: fetch_order_history
Description: Get order history for a customer.
Retrieves the order history for a specific customer with optional date filtering and pagination.
Args:
customer_id: Unique identifier for the customer (e.g., "CUST-12345")
start_date: Start date for filtering orders in ISO 8601 format (e.g., "2024-01-15T10:30:00")
end_date: End date for filtering orders in ISO 8601 format (e.g., "2024-01-31T23:59:59")
limit: Maximum number of orders to return (default: 50)
Returns:
Dictionary containing:
- success: Boolean indicating if the request was successful
- message: Description of the result
- data: List of order objects with details (id, orderNumber, customerId, totalAmount, status, orderDate, etc.)
- count: Number of orders returned
--------------------------------------------------
Tool Name: fetch_invoice_history
Description: Get invoice history for a customer.
Retrieves the invoice history for a specific customer with optional date filtering and pagination.
Args:
customer_id: Unique identifier for the customer (e.g., "CUST-12345")
start_date: Start date for filtering invoices in ISO 8601 format (e.g., "2024-01-15T10:30:00")
end_date: End date for filtering invoices in ISO 8601 format (e.g., "2024-01-31T23:59:59")
limit: Maximum number of invoices to return (default: 50)
Returns:
Dictionary containing:
- success: Boolean indicating if the request was successful
- message: Description of the result
- data: List of invoice objects with details (id, invoiceNumber, orderId, customerId, amount, status, invoiceDate, dueDate, paidDate, etc.)
- count: Number of invoices returned
--------------------------------------------------
Total tools: 2
==================================================
Notice the rich tool descriptions returned by the MCP servers. Each tool includes: - Name: Unique identifier for the tool - Description: Explains what the tool does and when to use it - Args: Detailed parameter specifications with types and requirements - Returns: Description of the expected result structure
This metadata enables agents to understand how to use tools without prior knowledge of the backend systems. The agent can read these descriptions and determine which tool to call for a given user request.
Approach 1: Llama Stack Client (direct tool invocation)
The Llama Stack Client SDK provides a programmatic interface to all Llama Stack capabilities. When you use this approach, your Python code explicitly decides which tools to invoke and when - you’re orchestrating the tool calls rather than letting an agent reason about them.
This approach is useful when: - You have deterministic workflows with known tool sequences - You’re testing tool connectivity and responses - You’re building integrations where tool selection is rule-based - You need fine-grained control over error handling and retries
Llama Stack Client: Customer
The key elements of code to pay attention to in the Llama Stack Client for Customer are creation of the Client
client = Client(
base_url=BASE_URL,
api_key=API_KEY
)
And the invocation of the tool.
result = client.tool_runtime.invoke_tool(
tool_name="search_customers",
kwargs={"contact_email": email}
)
Run the script
python 4_llamastack_client_customer.py
Base URL: http://llamastack-distribution-vllm-service:8321
Model: vllm/qwen3-14b
==================================================
Searching for customer: thomashardy@example.com
==================================================
==================================================
CUSTOMER SEARCH RESULT
==================================================
{
"results": [
{
"customerId": "AROUT",
"companyName": "Around the Horn",
"contactName": "Thomas Hardy",
"contactTitle": "Sales Representative",
"address": "120 Hanover Sq.",
"city": "London",
"region": null,
"postalCode": "WA1 1DP",
"country": "UK",
"phone": "(171) 555-7788",
"fax": "(171) 555-6750",
"contactEmail": "thomashardy@example.com",
"createdAt": "2026-01-02T18:21:35.131298",
"updatedAt": "2026-01-02T18:21:35.131298"
}
]
}
==================================================
|
Direct invocation = no LLM involved. This approach calls the MCP tool directly through |
Llama Stack Client: Finance
Also run the Llama Stack Client for Finance
python 4_llamastack_client_finance.py
Base URL: http://llamastack-distribution-vllm-service:8321
Model: vllm/qwen3-14b
==================================================
Fetching order history for customer: AROUT
==================================================
==================================================
ORDER HISTORY FOR CUSTOMER: AROUT
==================================================
Order #1:
Order ID: 8
Order Number: ORD-008
Order Date: 2024-01-30T15:20:00
Status: PENDING
Total Amount: $59.99
Order #2:
Order ID: 3
Order Number: ORD-003
Order Date: 2024-01-25T09:45:00
Status: PENDING
Total Amount: $89.99
Order #3:
Order ID: 4
Order Number: ORD-004
Order Date: 2024-01-10T16:20:00
Status: DELIVERED
Total Amount: $199.99
==================================================
Total Orders Found: 3
==================================================
The Llama Stack Client approach demonstrates direct tool invocation where you control the workflow. Notice that:
- Your code explicitly calls client.tool_runtime.invoke_tool()
- You specify the exact tool name and parameters
- You receive structured ToolInvocationResult objects
- No LLM reasoning is involved - this is pure tool execution
This pattern is efficient for known workflows but doesn’t leverage the agent’s ability to reason about which tools to use based on natural language input.
Approach 2: LangGraph with Llama Stack (agent-driven invocation)
LangGraph is a framework for building stateful, multi-agent applications using a graph-based execution model. When integrated with Llama Stack, LangGraph uses Llama Stack’s Response API (or ChatCompletion API) for inference while adding sophisticated agent orchestration capabilities.
Why use LangGraph with Llama Stack?
- LangGraph adds agent capabilities
-
-
Autonomous tool selection: Agent decides which tools to call based on user intent
-
Natural language understanding: Extract tool parameters from conversational input
-
Multi-step reasoning: Chain multiple tool calls together to answer complex questions
-
State management: Maintain conversation context across turns
-
- Llama Stack provides the inference layer
-
-
Model serving: vLLM handles the heavy lifting of model inference
-
Tool runtime: MCP servers are invoked through Llama Stack’s tool execution
-
Unified API: LangGraph uses standard OpenAI-compatible endpoints
-
- Together, they enable production agentic applications
-
-
LangGraph orchestrates the agent workflow (what to do)
-
Llama Stack executes the operations (how to do it)
-
MCP servers connect to business systems (where to get data)
-
Response API participant Model as vLLM Model participant MCP as MCP Server User->>LG: "Find customer with email
thomashardy@example.com" LG->>LLS: POST /v1/responses
(user message) LLS->>Model: Inference request Model->>Model: Analyze intent
Generate tool call Model-->>LLS: "Call search_customers
with email parameter" LLS->>MCP: Invoke search_customers MCP-->>LLS: Customer data LLS-->>LG: Tool result LG->>LLS: POST /v1/responses
(with tool result) LLS->>Model: Generate response Model-->>LLS: Natural language answer LLS-->>LG: Final response LG-->>User: "Found customer:
Thomas Hardy at
Around the Horn..." Note over User,MCP: Agent reasons about tools,
Llama Stack executes them
LangGraph integration with Llama Stack
LangGraph connects to Llama Stack through OpenAI-compatible APIs, making it easy to swap between different inference providers. The key integration points are:
- OpenAI-compatible endpoints
-
Llama Stack exposes
/v1/chat/completionsand/v1/responsesendpoints that follow OpenAI’s API specification. LangGraph uses these endpoints as if it were talking to OpenAI’s GPT models. - Response API usage
-
The code uses
use_responses_api=Trueto leverage Llama Stack’s native Response API instead of ChatCompletion. This provides better integration with Llama Stack’s tool runtime. - MCP tool binding
-
Tools are bound to the LLM using MCP server references. LangGraph tells Llama Stack which MCP servers to make available to the agent.
Since Llama Stack’s OpenAI-compatible endpoints don’t require real authentication (when using local vLLM), you can set a placeholder API key.
Setup
Many frameworks assume that you need an OpenAI API key but in the case of using vLLM via MaaS and/or via Llama Stack, we simply need to set a "not-applicable" value.
export API_KEY="not-applicable"
LangGraph Client: Customer
The key elements in the code include:
llm = ChatOpenAI(
model=INFERENCE_MODEL,
openai_api_key=API_KEY,
base_url=f"{BASE_URL}/v1",
use_responses_api=True
)
# MCP tool binding using OpenAI Responses API format
llm_with_tools = llm.bind(
tools=[
{
"type": "mcp",
"server_label": "customer_mcp",
"server_url": os.getenv("CUSTOMER_MCP_SERVER_URL"),
"require_approval": "never",
},
])
response = graph.invoke(
{"messages": [{"role": "user", "content": "Search for customer with email thomashardy@example.com"}]})
Execute it
python 5_langgraph_client_customer.py
Base URL: http://localhost:8321
Model: vllm/qwen3-14b
Testing LLM connectivity...
LLM connectivity OK
==================================================
Searching for customer: thomashardy@example.com
==================================================
==================================================
CUSTOMER SEARCH RESULTS
==================================================
Customer ID: AROUT
Company Name: Around the Horn
Contact Name: Thomas Hardy
Contact Email: thomashardy@example.com
==================================================
Assistant:
Here is the customer information matching the email **thomashardy@example.com**:
**Customer ID:** AROUT
**Company:** Around the Horn
**Contact Name:** Thomas Hardy
**Title:** Sales Representative
**Address:** 120 Hanover Sq.
**City:** London
**Postal Code:** WA1 1DP
**Country:** UK
**Phone:** (171) 555-7788
**Fax:** (171) 555-6750
**Email:** thomashardy@example.com
**Created At:** 2026-01-02 18:21:35
**Updated At:** 2026-01-02 18:21:35
Let me know if you'd like to view more details or perform any actions for this customer!
LangGraph Client: Finance
python 5_langgraph_client_finance.py
Base URL: http://localhost:8321
Model: vllm/qwen3-14b
Testing LLM connectivity...
LLM connectivity OK
==================================================
Fetching order history for customer: AROUT
==================================================
==================================================
ORDER HISTORY RESULTS
==================================================
Order #1:
Order ID: 8
Order Number: ORD-008
Order Date: 2024-01-30T15:20:00
Status: PENDING
Total Amount: $59.99
Order #2:
Order ID: 3
Order Number: ORD-003
Order Date: 2024-01-25T09:45:00
Status: PENDING
Total Amount: $89.99
Order #3:
Order ID: 4
Order Number: ORD-004
Order Date: 2024-01-10T16:20:00
Status: DELIVERED
Total Amount: $199.99
==================================================
Total Orders: 3
==================================================
Assistant:
Here is the order history for customer AROUT:
**Order History (3 orders total):**
1. **ORD-008**
- Total: $59.99
- Status: PENDING
- Date: January 30, 2024, 3:20 PM
2. **ORD-003**
- Total: $89.99
- Status: PENDING
- Date: January 25, 2024, 9:45 AM
3. **ORD-004**
- Total: $199.99
- Status: DELIVERED
- Date: January 10, 2024, 4:20 PM
Let me know if you'd like to investigate any specific order or need further assistance!
LangGraph Client: Customer + Finance
The real power is seen when combining a natural language query that works across BOTH the customer and finance tools.
Find all orders for franwilson@example.com
Where the use of the contact email address first requires a search of the customers to find the correct customer id which is then used to retrieve the orders from the finance tool.
python 6_langgraph_client_list_orders_for_franwilson.py
Base URL: http://llamastack-distribution-vllm-service:8321
Model: vllm/qwen3-14b
Testing LLM connectivity...
LLM connectivity OK
==================================================
Finding orders for: franwilson@example.com
==================================================
==================================================
CUSTOMER INFORMATION
==================================================
Customer ID: LONEP
Company Name: Lonesome Pine Restaurant
Contact Name: Fran Wilson
Contact Email: franwilson@example.com
==================================================
==================================================
ORDER HISTORY
==================================================
Order #1:
Order ID: 2
Order Number: ORD-002
Order Date: 2024-01-20T14:15:00
Status: SHIPPED
Total Amount: $149.5
Order #2:
Order ID: 1
Order Number: ORD-001
Order Date: 2024-01-15T10:30:00
Status: DELIVERED
Total Amount: $299.99
Order #3:
Order ID: 6
Order Number: ORD-006
Order Date: 2024-01-05T08:30:00
Status: DELIVERED
Total Amount: $399.99
==================================================
Total Orders: 3
==================================================
Assistant:
Here are all the orders for Fran Wilson (LONEP):
1. **Order #ORD-001**
- Date: January 15, 2024
- Status: DELIVERED
- Total: $299.99
2. **Order #ORD-006**
- Date: January 5, 2024
- Status: DELIVERED
- Total: $399.99
3. **Order #ORD-002**
- Date: January 20, 2024
- Status: SHIPPED
- Total: $149.50
Let me know if you need details about a specific order!
|
Multi-step reasoning in action: The agent received a single request ("Find all orders for franwilson@example.com") and autonomously executed two tool calls: first |
python 7_langgraph_client_list_orders_any_customer.py liuwong@example.com
Base URL: http://llamastack-distribution-vllm-service:8321
Model: vllm/qwen3-14b
Testing LLM connectivity...
LLM connectivity OK
==================================================
Finding orders for: liuwong@example.com
==================================================
==================================================
CUSTOMER INFORMATION
==================================================
Customer ID: THECR
Company Name: The Cracker Box
Contact Name: Liu Wong
Contact Email: liuwong@example.com
==================================================
==================================================
ORDER HISTORY
==================================================
Order #1:
Order ID: 7
Order Number: ORD-007
Order Date: 2024-01-28T13:45:00
Status: SHIPPED
Total Amount: $129.99
Order #2:
Order ID: 5
Order Number: ORD-005
Order Date: 2024-01-22T11:10:00
Status: CANCELLED
Total Amount: $79.99
==================================================
Total Orders: 2
==================================================
Assistant:
Here are the orders for liuwong@example.com (customer ID THECR):
1. **Order #ORD-007**
- Date: January 28, 2024
- Status: ✅ SHIPPED
- Total: $129.99
2. **Order #ORD-005**
- Date: January 22, 2024
- Status: ❌ CANCELLED
- Total: $79.99
Let me know if you need details about a specific order!
python 8_langgraph_client_list_invoices_any_customer.py liuwong@example.com
Base URL: http://llamastack-distribution-vllm-service:8321
Model: vllm/qwen3-14b
Testing LLM connectivity...
LLM connectivity OK
==================================================
Finding invoices for: liuwong@example.com
==================================================
==================================================
CUSTOMER INFORMATION
==================================================
Customer ID: THECR
Company Name: The Cracker Box
Contact Name: Liu Wong
Contact Email: liuwong@example.com
==================================================
==================================================
INVOICE HISTORY
==================================================
Invoice #1:
Invoice ID: 7
Invoice Number: INV-007
Invoice Date: 2024-01-28T13:50:00
Status: SENT
Total Amount: $129.99
Invoice #2:
Invoice ID: 5
Invoice Number: INV-005
Invoice Date: 2024-01-22T11:15:00
Status: CANCELLED
Total Amount: $79.99
==================================================
Total Invoices: 2
==================================================
Assistant:
Here are the invoices for Liu Wong (The Cracker Box):
**Invoice History for THECR (The Cracker Box):**
1. **Invoice #INV-007**
- Status: SENT
- Amount: $129.99
- Invoice Date: Jan 28, 2024
- Due Date: Feb 28, 2024
- No payment date recorded
2. **Invoice #INV-005**
- Status: CANCELLED
- Amount: $79.99
- Invoice Date: Jan 22, 2024
- Due Date: Feb 22, 2024
- No payment date recorded
Would you like me to check details about the cancelled invoice or look up any other information?
The data comes from the Postgres databases behind the REST APIs behind the MCP Servers. If you would like to know which customers have orders or invoices you can go look in the following file:
ls $HOME/fantaco-redhat-one-2026/fantaco-finance-main/src/main/resources/data.sql
The LangGraph examples demonstrate agentic behavior and offers a different approach to building more complex, stateful agent systems with explicit control flow via graph-based orchestration.
Notice the key differences from direct tool invocation:
- Agent reasoning
-
The agent analyzes the user’s request, determines which tools to use, plans the response format, and synthesizes a natural language answer.
- Natural language interface
-
You provide conversational input like "Search for customer with email thomashardy@example.com" rather than specifying tool names and parameters programmatically.
- Tool selection
-
The agent autonomously decides to call
search_customerswith the appropriate email parameter extracted from the user’s message. - Response synthesis
-
After receiving tool results, the agent generates a human-friendly response, formatting the data in a readable way and offering follow-up assistance.
This is the power of agentic AI - the LLM acts as an intelligent coordinator that understands user intent, selects appropriate tools, and presents results conversationally.
Summary
In this module, you explored 2 approaches to interacting with MCP tools:
- Approach 1: Llama Stack Client (direct invocation)
-
-
Programmatic tool invocation where your code controls the workflow
-
Useful for deterministic workflows, testing, and rule-based integrations
-
Direct access to
client.tool_runtime.invoke_tool() -
No LLM reasoning - pure tool execution
-
- Approach 2: LangGraph with Llama Stack (agent-driven)
-
-
Autonomous agent that reasons about tool selection
-
Natural language interface for user input
-
Agent extracts parameters, chains tools, and synthesizes responses
-
- Key concepts demonstrated
-
-
Tool discovery: Agents can query available tools and their descriptions dynamically
-
MCP abstraction: Same tools work with both approaches - the MCP interface is consistent
-
Llama Stack flexibility: Support for native client SDK and third-party frameworks like LangGraph
-
Response API integration: Both approaches leverage Llama Stack’s Response API for streamlined inference
-
- What you built
-
-
Python scripts that discover and inspect MCP tools
-
Direct tool invocation using Llama Stack Client
-
Agents using LangGraph that reason about customer and finance queries
-
You’ve now demonstrated complete end-to-end connectivity from natural language input through agent reasoning, tool invocation, MCP servers, backend APIs, and databases.
In the next module, you will dive into Llama Stack’s native agent capabilities.