Configuring Tools for Catalog Registration
Add tool to catalog registration
After discovering available tools, add them to your agent-catalog-registration.json:
Run Discovery
python scripts/list_mcp_tools.py --format catalogSelect required tools
Choose only the tools your agent needs:
{
"tools": [
{
"name": "servicenow_mcp",
"operations": [
"servicenow_get_all_incidents",
"servicenow_search_incidents"
]
},
{
"name": "bridge_mcp",
"operations": [
"bridge_execute_query",
"bridge_list_domains",
"bridge_list_tables",
"bridge_get_table_details"
]
}
]
}Update Registration JSON
Copy the tools configuration to your agent-catalog-registration.json file.
Using MCP tools in your agent
Calling tools with MCPClient
import os
from bridge_agent_sdk import MCPClient
# Initialize client — base_url is optional (SDK resolves from KAIF_HOST)
mcp = MCPClient(
agent_payload=state.get("platform_context", {}),
)
# Call a tool
result = await mcp.call_tool(
tool_name="servicenow_get_all_incidents",
arguments={"limit": 10}
)
# Process result
incidents = result.get("data", [])Tool naming convention
MCP tool names follow the pattern: _
Pattern | Example |
|---|---|
servicenow_* | servicenow_get_all_incidents |
bridge_* | bridge_execute_query |
azure_* | azure_keyvault |
aiops_* | aiops_ask_me_anything |
Error handling
Try the following:
result = await mcp.call_tool(tool_name="servicenow_search_incidents", arguments={"limit": 10})
if "error" in result:
logger.error(f"MCP tool error: {result['error']}")
return {"error": result["error"]}
return result.get("data", [])
except Exception as e:
logger.exception(f"MCP call failed: {{e}}")
raiseMCP Wire Protocol (JSON-RPC 2.0)
The Bridge MCP server uses the JSON-RPC 2.0 protocol. While the SDK's MCPClient handles this for you, understanding the wire format is essential for debugging and writing test scripts.
Listing Tools - tools/list
curl -s -X POST "$BRIDGE_MCP_SERVER_URL" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}' | jq '.result.tools | length'
Response structure:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "servicenow_search_incidents",
"description": "Search for incidents...",
"inputSchema": { "type": "object", "properties": {{...}}, "required": [...] }
}
]
}
}
Calling a Tool - tools/call
curl -s -X POST "${{BRIDGE_MCP_SERVER_URL}}?tenant_id=${{ACCOUNT_ID}}&account_id=${{ACCOUNT_ID}}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "accept: application/json" \
-H "x-instance-id: $DEPLOYMENT_NAME" \
-H "X-Route-Version: v3" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "servicenow_search_incidents",
"arguments": {
"search_term": "INC0010001",
"search_fields": ["number"]
}
}
}'Common mistake: Sending a flat payload like {"tool_name": "...", "arguments": } will return 422 Unprocessable Entity. You must use the JSON-RPC envelope with jsonrpc, method, and params fields.
Required headers for MCP calls
When calling MCP tools (either directly or via the SDK), the following HTTP headers are required:
Header | Required | Value | Purpose |
|---|---|---|---|
Authorization | Yes | Bearer <IAM_TOKEN> | Authentication — obtained from /api/iam/v4/identity/token |
Content-Type | Yes | application/json | Request body format |
x-instance-id | Yes | Your deployment name (e.g., inc-enrichment-deploy-v1) | Routes the call to the correct agent deployment |
X-Route-Version | Yes | v3 | Critical — Tells the MCP gateway to use v3 routing. Without this header you will get 403 — Agent instance not found in default collection |
accept | Recommended | application/json | Response format |
The X-Route-Version: v3 Header
This is the most commonly missed header. The SDK sets it automatically, but when writing test scripts or curl commands you must include it:
headers = {
"Authorization": f"Bearer {{token}}",
"Content-Type": "application/json",
"accept": "application/json",
"x-instance-id": deployment_name, # your deployment name
"X-Route-Version": "v3", # ← CRITICAL — do not omit
}Without this header, the MCP gateway falls back to the default routing collection and returns:
{
"detail": "Agent instance not found in default collection",
"status_code": 403
}Query parameters
When making direct HTTP calls, append tenant and account IDs as query parameters:
POST ?tenant_id=&account_id=
The SDK's MCPClient appends these automatically (you can see it in the logs: Internal route - adding query params: ['tenant_id', 'account_id']).
Testing MCP tools
Method 1: Discovery script
Always start by discovering what tools are actually available:
# List all tools grouped by MCP server
python scripts/list_mcp_tools.py
# Filter to a specific server
python scripts/list_mcp_tools.py --filter servicenow
# Export full schemas to JSON
python scripts/list_mcp_tools.py --output available-tools.json --format rawMethod 2: Get full tool schemas
Create scripts/get_tool_schema.py to inspect exact inputSchema of tools:
#!/usr/bin/env python3
"""Get the full input schema for specific MCP tools."""
import os, json, requests
from dotenv import load_dotenv
load_dotenv()
kaif_host = os.getenv("KAIF_HOST")
service_api_key = os.getenv("SERVICE_API_KEY")
mcp_url = os.getenv("BRIDGE_MCP_SERVER_URL")Get Bridge Access Management token
token = requests.post(
f"{{kaif_host}}/api/iam/v4/identity/token",
json={"apikey": service_api_key},
headers={"Content-Type": "application/json"},
timeout=30,
).json().get("token")List tools (JSON-RPC 2.0)
resp = requests.post(
mcp_url,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {{token}}",
},
json={"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}},
timeout=60,
)
tools = resp.json().get("result", {}).get("tools", [])Filter and print (change the prefix to inspect other servers)
for t in tools:
if "servicenow" in t.get("name", ""):
print(json.dumps(t, indent=2))
print("---")Method 3: Direct tool call (test script)
Test a specific tool call with all required headers
#!/usr/bin/env python3
"""Test a single MCP tool call with full headers."""
import os, json, requests
from dotenv import load_dotenv
load_dotenv()
kaif_host = os.getenv("KAIF_HOST")
service_api_key = os.getenv("SERVICE_API_KEY")
account_id = os.getenv("BRIDGE_ACCOUNT_ID")
mcp_url = os.getenv("BRIDGE_MCP_SERVER_URL")
deployment_name = "inc-enrichment-deploy-v1" # ← your deployment nameAuthenticate
token = requests.post(
f"{{kaif_host}}/api/iam/v4/identity/token",
json={"apikey": service_api_key},
headers={"Content-Type": "application/json"},
timeout=30,
).json()["token"]Build request
headers = {
"Authorization": f"Bearer {{token}}",
"Content-Type": "application/json",
"accept": "application/json",
"x-instance-id": deployment_name, # routes to your deployment
"X-Route-Version": "v3", # ← CRITICAL
}
payload = {
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "servicenow_search_incidents",
"arguments": {
"search_term": "INC0010001",
"search_fields": ["number"],
},
},
}
full_url = f"{{mcp_url}}?tenant_id={{account_id}}&account_id={{account_id}}"Call
resp = requests.post(full_url, headers=headers, json=payload, timeout=30)
print(f"Status : {{resp.status_code}}")
print(f"Body : {json.dumps(resp.json(), indent=2)}")Method 4: Curl one-liner
Get Bridge Access Management token
TOKEN=$(curl -s -X POST "$KAIF_HOST/api/iam/v4/identity/token" \
-H "Content-Type: application/json" \
-d "{\"apikey\": \"$SERVICE_API_KEY\"}" | jq -r '.token')Call tool
curl -s -X POST "${{BRIDGE_MCP_SERVER_URL}}?tenant_id=${{BRIDGE_ACCOUNT_ID}}&account_id=${{BRIDGE_ACCOUNT_ID}}" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "accept: application/json" \
-H "x-instance-id: inc-enrichment-deploy-v1" \
-H "X-Route-Version: v3" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "bridge_execute_query",
"arguments": {
"query": "SELECT number, short_description FROM \"ITSM\".incident LIMIT 5"
}
}
}' | jq .