watsonx Orchestrate

watsonx Orchestrate

Connect with experts and peers to elevate technical expertise, solve problems and share insights.

 View Only

BUILDING MULTI-TENANT SAAS APPLICATIONS AI AGENT WITH WATSONX ORCHESTRATE AND MCP

By Himanshu Gupta posted 2 days ago

  

INTRODUCTION

When building modern SaaS (Software as a Service) applications, one of the biggest challenges is managing different customers (tenants) using the same system. Each customer needs their own secure space with their own data and authentication.

This guide shows you how to build AI agents using WatsonX Orchestrate that can work with multiple customers while keeping their data separate and secure. The key is using "context variables" - think of them as labels that tell the agent which customer is making the request.

THE PROBLEM WE'RE SOLVING

Imagine you have one AI agent that needs to serve 100 different companies. When Company A asks a question, the agent needs to:

  1. Know it's Company A asking (not Company B)
  2. Use Company A's authentication credentials
  3. Access only Company A's data
  4. Keep everything separate from other companies

Without proper context management, this becomes a security nightmare. Our solution uses WatsonX Orchestrate's context variables to handle this elegantly.

STEP 1: SETTING UP YOUR WATSONX ORCHESTRATE ENVIRONMENT

Before you can create agents, you need to connect your local computer to your WatsonX Orchestrate instance.

WHAT YOU NEED:

  • WatsonX Orchestrate instance URL
  • Your API key (get this from your WatsonX dashboard)
  • Orchestrate CLI tool installed on your machine

INSTALLATION COMMAND:

Run this command in your terminal:

orchestrate env add -n nav-test-env \
  -u https://api.dl.watson-orchestrate.ibm.com/instances/YOUR-INSTANCE-ID \
  --type mcsp \
  --activate
IMPORTANT: Replace "YOUR-INSTANCE-ID" with your actual instance ID.

When prompted, paste your API key and press Enter.

WHAT THIS DOES:

  • Creates a connection named "nav-test-env" to your orchestrate instance
  • Activates it so future commands use this environment
  • Authenticates you using your API key

STEP 2: CREATING A MULTI-TENANT AGENT

Now we'll create an agent that can handle multiple tenants by accepting context variables. These variables carry information about which customer is using the agent.

AGENT CONFIGURATION FILE (save as multitenant-agent.yaml):

spec_version: v1
kind: native
name: multitenant
llm: watsonx/meta-llama/llama-3-3-70b-instruct
style: react
description: Agent for managing multi-tenant requests with context variables.

instructions: |
  You are an AI assistant that helps users with their requests. You have 
  access to the following information about the current user:
  
  - Email Address: {wxo_email_id}
  - Tenant ID: {wxo_tenant_id}
  - Billing ID: {Billing_ID}
  - Authentication Token: {Auth}
  - Custom Message: {custom_message}
  - User Name: {name}
  
  When a user asks about their information, use these variables to provide 
  accurate responses. If any variable is missing or empty, politely inform 
  the user that the information is not available.

collaborators: []
tools: []
knowledge_base: []

context_access_enabled: true

context_variables:
  - wxo_email_id
  - wxo_tenant_id
  - Billing_ID
  - custom_message
  - name
  - Auth

UNDERSTANDING THE CONFIGURATION:

1. CONTEXT_ACCESS_ENABLED: true

This is the master switch. It tells WatsonX Orchestrate that this agent needs to receive context information from API calls.

2. CONTEXT_VARIABLES SECTION:

This lists all the variables your agent can access. Think of it as declaring "these are the pieces of information I need to do my job."

Common variables:

  • wxo_email_id: The logged-in user's email
  • wxo_tenant_id: Which company/organization they belong to
  • Billing_ID: Their billing account number
  • Auth: Authentication token for making API calls on their behalf
  • name: User's display name
  • custom_message: Any custom data you want to pass

3. INSTRUCTIONS WITH VARIABLES:

Notice the {variable_name} syntax in the instructions. This is how the agent accesses the context variables. When the agent runs, these placeholders get replaced with actual values.

4. LLM SELECTION:

We're using "llama-3-3-70b-instruct" - a powerful language model. You can change this to other supported models based on your needs.

WHY THIS MATTERS:
Without declaring context_variables, the agent won't receive tenant information. It's like trying to deliver a package without knowing the address.

STEP 3: CALLING YOUR AGENT WITH TENANT CONTEXT

Once your agent is deployed, you call it through the WatsonX Orchestrate Chat API. This is where you pass the tenant-specific information.

API REQUEST EXAMPLE:

curl --location 'https://api.dl.watson-orchestrate.ibm.com/instances/YOUR-INSTANCE-ID/v1/orchestrate/YOUR-AGENT-ID/chat/completions' \
--header 'Authorization: Bearer YOUR-API-TOKEN' \
--header 'Content-Type: application/json' \
--data '{
  "stream": false,
  "context": {
    "Billing_ID": 23424,
    "Auth": "4c8c0398-811e-4014-a4cc-6b6c7953faa3-GunPJwW",
    "wxo_tenant_id": "company-abc-123",
    "wxo_email_id": "user@company.com",
    "name": "John Doe"
  },
  "messages": [
    {
      "content": "What is my authentication token?",
      "role": "user"
    }
  ]
}'

BREAKING DOWN THE API CALL:

1. URL STRUCTURE:

  • YOUR-INSTANCE-ID: Your WatsonX Orchestrate instance identifier
  • YOUR-AGENT-ID: The ID of the agent you created (you get this after deploying the agent)

2. AUTHORIZATION HEADER:

  • Replace YOUR-API-TOKEN with your actual bearer token
  • This authenticates your application to WatsonX Orchestrate

3. THE "CONTEXT" OBJECT:

This is the magic! Everything inside "context" becomes available to your agent as context variables.

Example: If you put "Billing_ID": 23424 in context, the agent can access it using {Billing_ID} in its instructions.

4. THE "MESSAGES" ARRAY:

This is the actual conversation. Each message has:

  • content: What the user is asking
  • role: Either "user" (the person asking) or "assistant" (the AI)

5. STREAM: false

This means you want the complete response at once, not streamed word by word. Set to true if you want real-time streaming responses.

HOW THE FLOW WORKS:

Step 1: User logs into your portal (e.g., company-abc.yourapp.com)

Step 2: Your portal identifies the user and their tenant

Step 3: Portal makes API call to WatsonX with context variables

Step 4: WatsonX Orchestrate injects these variables into the agent

Step 5: Agent processes the request with tenant-specific context

Step 6: Agent returns response (can include tenant-specific data)

Step 7: Portal displays response to user

REAL-WORLD EXAMPLE:

Imagine you're building a customer support chatbot for a SaaS platform:

User: "What's my current subscription plan?"

Your portal sends:

context: {
  "tenant_id": "acme-corp",
  "user_email": "john@acme.com",
  "auth_token": "xyz123"
}

Agent receives these variables and can:

  • Query the subscription database using tenant_id
  • Verify the user using user_email
  • Authenticate API calls using auth_token
  • Return: "Your current plan is Enterprise, renews on Jan 15, 2026"

STEP 4: INTEGRATING WITH MCP SERVERS

MCP (Model Context Protocol) servers are tools that your agent can call to perform actions or fetch data. The key is passing tenant context to these tools so they know which customer's data to access.

WHAT IS AN MCP SERVER?

Think of an MCP server as a specialized worker that does specific tasks:

  • Fetch customer data from a database
  • Call external APIs (like payment processors)
  • Perform calculations or data transformations
  • Access file systems or cloud storage

Your WatsonX agent acts as the "brain" that decides when to call these workers.

SETTING UP MCP WITH TENANT CONTEXT:

When you create an MCP server, it needs to:

1. ACCEPT CONTEXT VARIABLES:

Your MCP server should have parameters that match your context variables.

Example MCP tool definition:

{
  "name": "get_billing_info",
  "parameters": {
    "tenant_id": "{wxo_tenant_id}",
    "auth_token": "{Auth}",
    "billing_id": "{Billing_ID}"
  }
}

2. USE CONTEXT FOR AUTHENTICATION:

When the MCP tool makes API calls, it uses the auth_token from context:

headers = {
  "Authorization": f"Bearer {auth_token}",
  "X-Tenant-ID": tenant_id
}

3. MAINTAIN DATA ISOLATION:

The MCP server must validate that the tenant_id matches the requested data. Never allow cross-tenant data access!

COMPLETE FLOW DIAGRAM:

[User Portal]

(Sets tenant context: tenant_id, auth_token, etc.)

[WatsonX Orchestrate Chat API]

(Injects context into agent)

[Your Multi-Tenant Agent]

(Decides to call MCP tool with context)

[MCP Server/Tool]

(Uses auth_token and tenant_id)

[External API / Database]

(Returns tenant-specific data)

[Response flows back to user]

EXAMPLE MCP TOOL USAGE:

Let's say your agent needs to fetch billing information:

Agent thinks: "User asked about billing. I need to call the billing tool."

Agent calls MCP tool:

Tool: get_billing_info
Parameters:
  - tenant_id: "company-abc-123" (from context)
  - auth_token: "xyz789" (from context)
  - billing_id: 23424 (from context)

MCP server:

  1. Validates auth_token
  2. Queries billing database WHERE tenant_id = "company-abc-123"
  3. Returns billing data
  4. Agent formats response for user

BEST PRACTICES AND SECURITY

SECURITY CONSIDERATIONS:

1. NEVER HARDCODE CREDENTIALS:

Bad: auth_token = "hardcoded-token-123"

Good: auth_token = context.get("Auth")

2. VALIDATE TENANT CONTEXT:

Always verify that the tenant_id in the request matches the authenticated user's tenant. Don't trust client-side data blindly.

3. USE SHORT-LIVED TOKENS:

Authentication tokens should expire after a reasonable time (e.g., 1 hour). Implement token refresh mechanisms.

4. ENCRYPT SENSITIVE CONTEXT:

If passing sensitive data like API keys, consider encrypting them before putting them in context variables.

5. LOG CONTEXT ACCESS:

Keep audit logs of which tenants accessed what data and when. This helps with compliance and debugging.

PERFORMANCE OPTIMIZATION:

1. CACHE CONTEXT WHEN APPROPRIATE:

If a user has multiple interactions in a session, cache their context instead of fetching it every time.

2. MINIMIZE CONTEXT SIZE:

Only pass variables you actually need. Large context objects slow down API calls.

3. USE EFFICIENT DATA STRUCTURES:

Instead of passing entire objects, pass IDs and fetch details when needed.

ERROR HANDLING:

1. HANDLE MISSING CONTEXT GRACEFULLY:

if not context.get("tenant_id"):
    return "I'm sorry, I couldn't identify your account. Please log in again."

2. PROVIDE CLEAR ERROR MESSAGES:

Instead of: "Error 500"
Use: "I couldn't access your billing information. Please contact support."

3. IMPLEMENT FALLBACKS:

If a context variable is missing, try alternative methods or ask the user for the information.

TESTING YOUR SETUP:

1. TEST WITH MULTIPLE TENANTS:

Create test accounts for different tenants and verify data isolation.

2. TEST MISSING CONTEXT:

Try calling the API without context variables to ensure proper error handling.

3. TEST INVALID TOKENS:

Use expired or invalid auth tokens to verify security measures work.

4. LOAD TESTING:

Simulate multiple tenants making concurrent requests to check performance.

CONCLUSION

By leveraging WatsonX Orchestrate's context variable system, you can build sophisticated AI agents that serve multiple customers while maintaining security and data isolation.

ADDITIONAL RESOURCES

0 comments
26 views

Permalink