how can i add a _meta to a specific MCP server on ...
# ask-ai
a
how can i add a _meta to a specific MCP server on every tool call? this is following the official MCP docs (https://modelcontextprotocol.io/specification/2025-06-18/basic#_meta)
t
Thanks for reaching out, Sebastián. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding to your question about adding a
_meta
object to every tool call sent to a specific MCP server (per the MCP spec you linked). Short answer from the LiveKit docs: we do not have a documented, built-in way to automatically inject an MCP
_meta
field into every outgoing tool call. LiveKit Agents support registering MCP servers via
mcp_servers
on an
AgentSession
, and you can configure connection details (headers/auth), but there’s no explicit example or documented hook for adding
_meta
to every tool request. To help you further I need a bit more detail about your setup so I can suggest the right approach or a workaround: • Which LiveKit SDK / language are you using (Node, Python, Go, etc.)? • Are you registering the MCP server through
mcp_servers
on an
AgentSession
(yes/no)? • Do you control the MCP client code that sends tool calls (i.e., can you modify the request payload before sending)? • Is your goal to add identical
_meta
for all tools on that server, or to compute different
_meta
per-request (e.g., runtime context like job id, user id)? Possible approaches we can explore depending on your answers: • If you can modify the MCP client payload before sending, add
_meta
there programmatically so every tool call includes it. • If the SDK exposes request hooks/middleware, add a middleware that injects
_meta
for calls targeting the specific MCP server. • If neither is available, you can set server-specific headers or authentication fields (these are supported) and pass metadata via headers as an alternative, then translate them to
_meta
on the MCP server side if you control it. Tell me your SDK/language and whether you can modify the client sending tool calls, and I’ll propose concrete code snippets or steps for the best-fit approach. Sources: Tool definition and use | LiveKit Documentation | MCP Agent | LiveKit Documentation | Agent Builder | LiveKit Documentation | Job lifecycle | LiveKit Documentation | Agent session | LiveKit Documentation
a
• Which LiveKit SDK / language are you using (Node, Python, Go, etc.)? ◦ is python-agents • Are you registering the MCP server through
mcp_servers
on an
AgentSession
(yes/no)? ◦ yes • Do you control the MCP client code that sends tool calls (i.e., can you modify the request payload before sending)? ◦ no, im relying on LiveKit for this but if need to modify the LiveKit code im open to do so if you guide me • Is your goal to add identical
_meta
for all tools on that server, or to compute different
_meta
per-request (e.g., runtime context like job id, user id)? ◦ yes, would be a global conversation id from our system
t
Thanks — this helps. You're using the Python Agents SDK, you register the MCP server via
mcp_servers
, you don't control the upstream MCP client payloads, and you want a global conversation ID injected as
_meta
on every tool call. I’ll walk you through two practical options: a quick, safe monkey-patch you can run in your app, and a longer-term, more maintainable forked SDK approach. Short summary: LiveKit’s Python Agents do not provide a public hook to modify MCP tool-call JSON payloads. To add
_meta
you must either intercept the MCP client before calls are made (monkey-patch) or modify the SDK source (fork). Both approaches inject
_meta
into
tool.use
requests so your MCP server sees the global conversation id. Option A — Monkey-patch (fast, minimal changes) • When your process starts and before any MCP tool calls run, patch the internal MCP HTTP execution method to add
_meta
for
tool.use
requests. • This is low-friction and reversible (patch runs in-process), but slightly brittle across SDK upgrades. Example pattern (adapt to your codebase):
Copy code
# run this early in your app, before creating AgentSession / making MCP calls
from livekit.agents.mcp import MCPServerHTTP
_original_execute_request = MCPServerHTTP._execute_request

def make_patched_execute(conversation_id: str):
    async def _patched_execute_request(self, method: str, params=None, timeout: float = 30.0):
        # Only inject for tool invocation RPCs
        if method == "tool.use" and params is not None:
            # preserve existing params, insert or merge _meta
            params = dict(params)
            meta = params.get("_meta", {})
            meta.update({"conversation_id": conversation_id})
            params["_meta"] = meta
        return await _original_execute_request(self, method, params, timeout)
    return _patched_execute_request

# set your global conversation id or fetch from context closure
GLOBAL_CONVERSATION_ID = "conv-12345"
MCPServerHTTP._execute_request = make_patched_execute(GLOBAL_CONVERSATION_ID)
Notes for this approach: • Ensure this code runs before any MCP server discovery/tool use calls. • If you need the conversation ID to vary per AgentSession (not global process-wide), you can: ◦ store the ID on the session object when creating it and access it via
self
inside the patched function if
self
has session context, or ◦ create different patched functions per session before creating that session (less common). • Test carefully across SDK versions — method names or internals may change. Option B — Fork & modify SDK (robust, maintainable) • Clone the LiveKit Agents repo, modify the place that constructs/sends MCP RPCs (the MCP HTTP client), and add
_meta
injection there. • Advantages: cleaner, less fragile, can be covered by tests and versioned with your code. • High-level steps: a. Fork repo (or vendor the package into your repo). b. Locate the MCP HTTP client implementation file (where
_execute_request
or equivalent composes the JSON-RPC). c. Add logic to merge in
_meta
for
tool.use
(example logic shown below). d. Publish or install your modified package (e.g., pip install -e .) and use it in your app. Conceptual patch snippet for SDK:
Copy code
# pseudo-change inside the SDK's MCP request function
if method == "tool.use":
    params.setdefault("_meta", {})
    params["_meta"].update({"conversation_id": GLOBAL_CONVERSATION_ID})
# then send the request as usual
When to choose which: • Use the monkey-patch if you want to try quickly and validate behavior against your MCP server. • Use the fork if you need long-term stability, multiple environments, or want to add tests and CI coverage. Other alternatives and considerations • If you control the MCP server side, you could accept an equivalent identifier from HTTP headers (which LiveKit does support configuring) and map that into
_meta
on your server. This avoids touching client payloads but requires server-side translation. • If you need a per-session (not per-process) conversation_id, let me know how you identify sessions and I’ll tailor the patch to read the session value rather than a single global constant. • Make sure your conversation_id format and privacy requirements are acceptable for inclusion in tool call payloads. Next step • Do you want: ◦ a ready-to-run example that reads the conversation ID from an environment variable (monkey-patch version), or ◦ guidance for where exactly to change the SDK source (I can point to the file/method if you share your installed package version)? Tell me which and I’ll provide the exact code tailored to your version and whether the ID should be process-global or session-scoped. Sources: Tool definition and use | LiveKit Documentation | MCP Agent | LiveKit Documentation
a
how could i add the header?
t
Thanks — you want to add a custom HTTP header to MCP server requests from the LiveKit Python Agents SDK. There are two practical ways to do this given the SDK behavior: set headers when you configure the MCP server in
AgentSession
(static headers), or inject headers dynamically by intercepting the MCP client before requests are sent (monkey-patch). I’ll show both approaches and when to use each. What I’m responding to: adding a custom HTTP header on MCP server calls in the Python Agents SDK. Option 1 — Set headers when registering the MCP server (static headers) • When you register an MCP server via
mcp_servers
on
AgentSession
, you can provide connection/config info. The SDK supports configuring headers/auth for MCP server connections. • Use this if your header is the same for all requests and can be supplied at session creation time (e.g., a static API key or static tenant id). Example pattern (conceptual — adapt to your code):
Copy code
from livekit.agents import AgentSession
from livekit.agents import mcp

mcp_server = mcp.MCPServerHTTP(
    url="<https://your-mcp-server.com>",
    headers={
        "X-Conversation-ID": "conv-12345",
        "Authorization": "Bearer your-token"
    }
)

session = AgentSession(
    mcp_servers=[mcp_server],
    # other session params...
)
Notes: • Put this code early, before any MCP discovery/tool use. • This approach attaches the headers to the MCP server connection so all requests use them. Option 2 — Inject headers dynamically by intercepting MCP client (dynamic headers) • If you need the header to vary per request or per session (e.g., a conversation id that changes at runtime) and the SDK doesn’t expose a public hook, intercept the MCP client at the point it sends HTTP requests and add/edit headers there. • This requires a small in-process patch (monkey-patch) before any MCP calls run. Example monkey-patch pattern (run early in your app):
Copy code
from livekit.agents.mcp import MCPServerHTTP
_original_execute_request = MCPServerHTTP._execute_request

def make_patched_execute(get_headers_fn):
    async def _patched_execute_request(self, method: str, params=None, timeout: float = 30.0):
        # allow original to build request data, but inject headers via self.http_client or equivalent
        # Example: if the internal method accepts a headers kwarg or uses an httpx client:
        headers = get_headers_fn()  # function you provide to supply current headers
        # attach headers onto self or pass through to the underlying HTTP call as required
        # the exact spot to place headers depends on SDK internals; often the _execute_request
        # method calls an HTTP client where headers can be supplied.
        return await _original_execute_request(self, method, params, timeout)
    return _patched_execute_request

# Example get_headers_fn could read an env var, session state, etc.
def current_headers():
    return {"X-Conversation-ID": "conv-12345"}

MCPServerHTTP._execute_request = make_patched_execute(current_headers)
Important: • The exact mechanism to attach headers depends on the SDK internals (where the HTTP request is actually performed). The monkey-patch should run before any MCP calls. • This approach is more flexible but more brittle across SDK upgrades. If you need long-term stability, consider forking and changing the SDK source directly where the HTTP client call is performed. Alternative (server-side translation) • If you control the MCP server, another option is to accept an identifier via headers (which LiveKit supports configuring) and translate that into
_meta
server-side. This avoids altering SDK internals. Which approach fits you? • If your header is static per server/session: configure headers when creating the
MCPServerHTTP
/
AgentSession
(Option 1). • If the header must change at runtime per request or per session and the SDK doesn’t provide a hook: use the monkey-patch to inject it dynamically (Option 2) or fork the SDK to add a proper hook. If you want, tell me: • whether the header is static or must change per session/request, and • which LiveKit Agents package version you’re using …and I’ll provide a concrete code snippet tailored to that version and to whether you need process-global or session-scoped headers.
a
remember, every session will get it's own conversation id and it's not known from start, only after first start
sorry after first transcript
t
I don't have the answer you're looking for. You could also try asking your question: • in one of the other Slack channels or • to https://deepwiki.com/livekit/livekit_composite which is trained on all LiveKit source code If you find the answer, please post it here to help others!