narrow-chef-71655
03/27/2026, 8:42 AM{
"content": [
{
"type": "text",
"text": "Here are the results..."
}
],
"_meta": {
"nextCursor": "eyJwYWdlIjogMn0=",
"requestId": "req_abc123",
"rateLimit": {
"remaining": 42,
"resetAt": "2026-03-27T12:00:00Z"
}
}
}
here when return above response of mcp tool and then meta details will be passed to LLM or not ?tall-airline-16756
03/27/2026, 8:43 AMtall-airline-16756
03/27/2026, 8:43 AMnextCursor, requestId, rateLimit) is passed to the LLM.
Short answer: No — metadata is not passed to the LLM by default.
Details:
• The MCP integration serializes the tool’s content and that is what’s sent to the LLM by default. Meta fields such as nextCursor, requestId, and rateLimit are not automatically included.
• The MCP integration exposes a tool_result_resolver you can implement. The resolver receives the raw tool result (including metadata) and can decide which parts to include in the string sent to the LLM.
• The resolver is only invoked for successful tool calls; errors go through a ToolError path and do not hit the resolver.
If you want the LLM to receive those meta fields, I can help you with next steps. Do you want:
• an example tool_result_resolver that includes nextCursor and rateLimit in the prompt, or
• guidance on securely filtering or redacting sensitive fields before sending them to the LLM?
Tell me which option you prefer and any language/SDK you’re using (JavaScript, TypeScript, or another), and I’ll provide a concrete example.
Sources: Model Context Protocol (MCP) | LiveKit Documentation, with interactive elementsnarrow-chef-71655
03/27/2026, 8:46 AM{'type': 'function_tools_executed', 'tools': [{'call': {'id': 'item_DNx2WSqP2qJP1IEXRh2yK', 'call_id': 'call_4RdU7bAawoyKJkHv', 'name': 'FindNowServices', 'arguments': '{ \n "userQuery": "Now services" \n} \n'}, 'output': {'id': 'item_85260476ad0e', 'call_id': 'call_4RdU7bAawoyKJkHv', 'name': 'FindNowServices', 'output': '{"type":"text","text":"{\\"result\\":\\"Login to Now\\\\nOpen the Now app and sign in using UAE Pass.\\\\nSelect Residency Renewal\\\\nGo to Residency Visas → choose Renew Residence Visa (self or dependent).\\\\nUpload Documents\\\\nUpload required documents (passport, medical fitness if required, Emirates ID details).\\\\nPay & Track\\\\nPay the fees in-app and track the application status until approval.\\"}","annotations":null,"meta":{"stop_response":false}}', 'is_error': False}}], 'roomName': 'e_69c64291fd8ded37e9f6785e_-_e_699d77918d469e54465668ab_-_69c64291db3eff3d133166e0_-_40526_-_147'}
above output. meta will be passed to LLM or not ?tall-airline-16756
03/27/2026, 8:46 AMmeta field in the tool output you showed will be passed to the LLM.
Short answer: No — the meta field is not passed to the LLM by default.
Why:
• The MCP integration serializes the tool’s main `content`/`output` for the LLM. Fields like meta (for example stop_response) are not automatically included in what the LLM receives.
• The integration gives your code access to the full raw result (including meta) inside the tool_result_resolver. That resolver is where you can decide to include, redact, or transform meta fields before returning the string that will be sent to the LLM.
• The resolver runs only for successful tool calls; error paths do not call it.
If you want to include meta (or just stop_response, rateLimit, etc.) in the prompt sent to the model, I can show a concrete example of a tool_result_resolver that:
• appends selected meta fields to the tool output, and
• redacts anything sensitive.
Which SDK/language are you using (JavaScript/TypeScript, Python, or another)? Also, which meta fields would you like to include or redact?
, with interactive elementsnarrow-chef-71655
03/27/2026, 8:47 AMtall-airline-16756
03/27/2026, 8:47 AMnextCursor, requestId, rateLimit, or a tool meta.stop_response) before sending the tool result to the LLM.
Recap:
• Metadata is not passed to the LLM by default.
• The Python SDK exposes a tool_result_resolver (it receives the raw tool result) where you can inspect, include, transform, or redact metadata and return the final string that will be sent to the LLM.
Below is a focused Python example of a custom tool_result_resolver. It:
• Reads the raw tool result.
• Optionally includes selected meta fields (configured via include_meta_fields).
• Redacts values you mark as sensitive.
• Returns a clean string composed of the tool content plus included meta.
Replace placeholders with your actual SDK initialization and registration details.
# Example tool_result_resolver for Python SDK
import json
from typing import Dict, Any, List
# Configure which meta fields to include and which keys to redact
include_meta_fields: List[str] = ["nextCursor", "requestId", "rateLimit", "meta"]
redact_keys: List[str] = ["requestId"] # example: redact requestId
def redact(obj: Any, keys_to_redact: List[str]) -> Any:
if isinstance(obj, dict):
out = {}
for k, v in obj.items():
if k in keys_to_redact:
out[k] = "[REDACTED]"
else:
out[k] = redact(v, keys_to_redact)
return out
if isinstance(obj, list):
return [redact(i, keys_to_redact) for i in obj]
return obj
def tool_result_resolver(tool_name: str, arguments: Dict[str, Any], result: Dict[str, Any]) -> str:
"""
- tool_name: name of the executed tool
- arguments: arguments passed to the tool
- result: the raw result returned by the tool (includes content and any metadata)
Return: the string that the SDK will send to the LLM.
"""
parts: List[str] = []
parts.append(f"Tool: {tool_name}")
# Add tool arguments (optional)
if arguments:
try:
parts.append("Arguments:")
parts.append(json.dumps(arguments, indent=2))
except Exception:
parts.append(str(arguments))
# Prefer the main text content if present
# Common pattern: result may contain {'content': [...]} or direct 'output' string
content_text = None
if isinstance(result, dict):
# Try commonly used shapes
if "content" in result:
try:
content_text = json.dumps(result["content"], ensure_ascii=False)
except Exception:
content_text = str(result["content"])
elif "output" in result:
# `output` may itself be a JSON string; try parsing
try:
parsed = json.loads(result["output"])
# If parsed has a `text` field inside, prefer it
if isinstance(parsed, dict) and "text" in parsed:
content_text = parsed["text"]
else:
content_text = json.dumps(parsed, ensure_ascii=False)
except Exception:
content_text = str(result["output"])
elif "text" in result:
content_text = result["text"]
if content_text:
parts.append("Tool output:")
parts.append(content_text)
else:
parts.append("Tool returned a result but no main text content was found.")
parts.append(json.dumps(result, indent=2, ensure_ascii=False))
# Include selected meta fields if present
included_meta = {}
for key in include_meta_fields:
if key in result:
included_meta[key] = result[key]
# Sometimes metadata is nested under a field like 'meta' or inside parsed output
# If `result` had an 'output' string that parses to an object with 'meta', include that too
try:
if "output" in result:
parsed_output = None
try:
parsed_output = json.loads(result["output"])
except Exception:
parsed_output = None
if parsed_output and isinstance(parsed_output, dict) and "meta" in parsed_output:
included_meta.setdefault("parsed_output.meta", parsed_output["meta"])
except Exception:
pass
if included_meta:
# Redact sensitive keys
safe_meta = redact(included_meta, redact_keys)
parts.append("Included metadata:")
parts.append(json.dumps(safe_meta, indent=2, ensure_ascii=False))
# Final assembled string sent to LLM
final = "\n\n".join(parts)
return final
# --- Example usage when registering the resolver in your SDK setup ---
# sdk.register_tool_result_resolver(tool_result_resolver) # pseudo-code; use actual SDK call
Notes and suggestions:
• Keep the resolver minimal and focused: avoid sending large raw objects unless the LLM needs them.
• Redact any request identifiers or secrets before including meta. In the example, requestId is redacted.
• If you only need a single meta field (e.g., nextCursor for pagination), include only that field to keep prompts small.
• The resolver is only invoked for successful tool calls. Errors follow a different path (they raise a ToolError).
Would you like:
• a trimmed example that only appends nextCursor for pagination use cases, or
• a sample that integrates directly with the LiveKit Python SDK init/registration call you’re using?, with interactive elementsnarrow-chef-71655
03/27/2026, 8:48 AMtall-airline-16756
03/27/2026, 8:49 AMmeta fields passed to the LLM.
Short confirmation:
• Metadata (fields like nextCursor, requestId, rateLimit, or a tool meta object) is not sent to the LLM by default.
• To guarantee metadata is never sent, ensure your tool_result_resolver (or any result-handling code) explicitly omits those fields when returning the string for the LLM.
Quick actionable guidance (Python):
1) Keep the resolver minimal and only return the tool’s user-facing content — do not include any meta keys.
2) Example minimal resolver that excludes metadata entirely:
import json
from typing import Dict, Any
def tool_result_resolver(tool_name: str, arguments: Dict[str, Any], result: Dict[str, Any]) -> str:
# Prefer the human-readable text in result.content or result.output
# Do NOT include any meta fields
content_text = None
if isinstance(result, dict):
if "content" in result:
try:
# serialize only the content items (not metadata)
content_text = json.dumps(result["content"], ensure_ascii=False)
except Exception:
content_text = str(result["content"])
elif "output" in result:
try:
parsed = json.loads(result["output"])
if isinstance(parsed, dict) and "text" in parsed:
content_text = parsed["text"]
else:
# if output is structured, include only the user-facing part
content_text = json.dumps(parsed, ensure_ascii=False)
except Exception:
content_text = str(result["output"])
elif "text" in result:
content_text = result["text"]
if content_text:
return f"Tool: {tool_name}\n\nTool output:\n{content_text}"
# Fallback: return a short safe note without metadata
return f"Tool: {tool_name}\n\nTool returned a result but no user-facing content was found."
3) Additional safety suggestions:
• Don’t call json.dumps(result) or include result wholesale — that can accidentally include meta.
• If you must inspect result in your application logs, strip or redact meta before logging or storing.
• Test with a known tool response that contains meta to verify the resolver output includes no meta fields.
If you want, I can:
• Provide a slimmer resolver that extracts just a single textual field (e.g., result["content"][0]["text"]) for your exact tool shape, or
• Show how to register this resolver in your LiveKit Python SDK setup (share the SDK init snippet you’re using). Which would you prefer?, with interactive elements