{
  "schema_version": 2,
  "id": "develop/ai/context-engine/context-gateway/mcp",
  "title": "Connect with MCP",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/mcp/",
  "summary": "Connect a Streamable HTTP MCP client to a Gateway with an agent key or your identity provider, use full or search mode, and read handles.",
  "aliases": [
    "/develop/ai/context-engine/context-gateway/connect-agents/",
    "/develop/ai/context-engine/context-gateway/developer-guide/"
  ],
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-02T17:32:57-08:00",
  "page_type": "content",
  "content_hash": "8353ab20b178144ab4c72753b60ff73992405666b39198c339535040493140ee",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Connect a Model Context Protocol (MCP) client to Redis Context Gateway to discover tools, call them, and retrieve results through one endpoint.\n\nThis guide covers connection settings, authentication, tool discovery, and result handling. For a first working program, follow the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart). For framework-specific examples, see [Integrate with an agent](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/agent-integration)."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "You need:\n\n- The Gateway's MCP endpoint.\n- An agent key with a `use` grant on the Gateway, or identity-provider sign-in enabled for your deployment.\n- An MCP client that supports Streamable HTTP and the authentication method you use.\n\nFor agent-key authentication, save your connection values:\n\n[code example]\n\nThe endpoint must be reachable from the environment where your client runs. Keep credentials in connection settings and out of agent instructions."
    },
    {
      "id": "choose-a-client",
      "title": "Choose a client",
      "role": "content",
      "text": "Use `redis-iris` for the Python SDK and Iris command-line interface (CLI). For JavaScript and TypeScript, install the separate `@redis-iris/context-gateway` package.\n\n| Client | Use it for | Installation |\n| --- | --- | --- |\n| Python 3.11 or later | Discovering and calling tools through `redis_iris.ContextGateway`, or opening a direct MCP session through `gateway.client.connect()`. | `pip install redis-iris` |\n| CLI, with Python 3.11 or later | Discovering, inspecting, and calling tools from a shell. | Included in `redis-iris`. |\n| TypeScript, with Node.js 22 or later | Opening MCP sessions through `ContextGateway` from `@redis-iris/context-gateway`. | `npm install @redis-iris/context-gateway@beta` |\n| An existing MCP client or agent framework | Connecting with the Gateway endpoint and credentials. | Use the client's dependencies. A Redis SDK is not required. |\n\nThe npm `beta` tag selects the release used by these examples. The default `latest` tag currently selects an older alpha release.\n\nThere is no unified TypeScript package corresponding to `redis-iris`. See the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart#install-the-client) for Python, TypeScript, and CLI examples.\n\nAdministration uses separate credentials. Python exposes the administration client through `gateway.service`. The TypeScript package exports `ContextGatewayService`. See [Manage Gateways and Upstreams](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/manage-gateways)."
    },
    {
      "id": "configure-the-connection",
      "title": "Configure the connection",
      "role": "configuration",
      "text": "Use the following settings in your MCP client:\n\n| Setting | Value |\n| --- | --- |\n| Transport | Streamable HTTP |\n| Endpoint | `<data-plane-base-url>/iris/data/v1/context-gateway/gateways/<gateway-id>/mcp` |\n| Agent-key authentication | `Authorization: Bearer <agent-key>` or `X-Api-Key: <agent-key>` |\n| Identity-provider authentication | `Authorization: Bearer <access-token>` |\n| Supported protocol versions | `2026-07-28`, `2025-11-25`, `2025-06-18`, and `2025-03-26` |\n\nThe Redis SDKs require HTTPS, except for loopback addresses such as `localhost` during local development."
    },
    {
      "id": "authenticate-with-an-agent-key",
      "title": "Authenticate with an agent key",
      "role": "security",
      "text": "Give the client an agent key with a `use` grant on the Gateway. The key authenticates the caller. Its grants determine which Gateways the caller can use.\n\nIn Python, `gateway.client.connect()` sends the key in the `Authorization: Bearer` header."
    },
    {
      "id": "sign-in-with-your-identity-provider",
      "title": "Sign in with your identity provider",
      "role": "content",
      "text": "If your deployment enables identity-provider sign-in, a compatible MCP client can authenticate a user instead of using an agent key.\n\nAn unauthenticated request receives `401` with a `WWW-Authenticate` header pointing to the Gateway's protected resource metadata. Clients that support MCP authorization use this metadata to find the identity provider (IdP) and start sign-in.\n\nThe client sends the resulting access token as:\n\n[code example]\n\nThe Gateway does not accept IdP tokens in `X-Api-Key`.\n\nThe token must be issued for the Gateway's own API. A token issued only for the shared Iris audience used by the Iris console does not grant Gateway access. The signed-in user also needs a grant on the Gateway.\n\nThe IdP token is not forwarded to an Upstream. See [Identity provider sign-in](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/authentication#identity-provider-sign-in) for deployment configuration."
    },
    {
      "id": "connect-a-coding-assistant",
      "title": "Connect a coding assistant",
      "role": "content",
      "text": "Use an existing coding assistant to discover and call Gateway tools without writing an agent application. These examples use agent-key authentication and the search-mode clinic Gateway from the [sample setup](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/api-examples). Compression is not required for this first request.\n\nKeep the connection values from [Before you begin](#before-you-begin) in the environment that starts the client. The configuration files reference the key's environment variable rather than storing the key. Merge new server entries into existing configuration files.\n\n**Claude Code:**\n\n#### Register the Gateway\n\nSet the endpoint and agent key before starting Claude Code:\n\n[code example]\n\nAdd this server entry to `.mcp.json` in your project root:\n\n[code example]\n\nStart Claude Code from that directory and environment:\n\n[code example]\n\nApprove the project MCP configuration when prompted. Run `/mcp`, open `context-gateway`, and inspect its connection status and tools. For search mode, expect `search_tools` and `run_tool`. See [Claude Code MCP configuration](https://code.claude.com/docs/en/mcp#environment-variable-expansion-in-mcpjson).\n\n#### Make a first request\n\n[code example]\n\nInspect the tool calls in the conversation to confirm that Claude discovered and invoked the filter.\n\n**Cursor:**\n\n#### Register the Gateway\n\nSet these variables in the environment that starts Cursor, then restart Cursor from that environment:\n\n[code example]\n\nAdd this server entry to `.cursor/mcp.json` in your project:\n\n[code example]\n\nCursor uses `${env:NAME}` for environment variables. Remote server entries do not load an `envFile`. See [Cursor MCP configuration](https://cursor.com/docs/mcp#config-interpolation).\n\nOpen **Customize**, enable `context-gateway`, and inspect **Available Tools**. For search mode, expect `search_tools` and `run_tool`.\n\n#### Make a first request\n\nIn an Agent chat, enter:\n\n[code example]\n\nExpand the tool calls to inspect their arguments and results.\n\n**Codex:**\n\n#### Register the Gateway\n\nSet the connection values in the terminal where you run Codex:\n\n[code example]\n\nThe native Codex command saves the endpoint and the key's environment-variable name in `~/.codex/config.toml`. The Iris CLI does not have a `--client codex` option. See [Codex MCP configuration](https://learn.chatgpt.com/docs/extend/mcp#streamable-http-servers).\n\nCheck the saved registration, then start Codex from the same environment:\n\n[code example]\n\nRun `/mcp` to inspect the active server and its tools. For search mode, expect `search_tools` and `run_tool`. Registration alone does not verify that the Gateway is reachable.\n\n#### Make a first request\n\n[code example]\n\nInspect the tool calls to confirm that Codex used the Gateway's returned tool identity.\n\n\n\nIn full mode, expect qualified tool names instead of `search_tools` and `run_tool`. Ask the assistant to inspect and call the discovered provider filter directly. See [Discover and call tools](#use-the-tools)."
    },
    {
      "id": "generate-client-configuration-with-the-cli",
      "title": "Generate client configuration with the CLI",
      "role": "content",
      "text": "If you have administration access, the Iris CLI can look up a Gateway's endpoint and generate configuration for Claude Code, Cursor, Google Agent Development Kit (ADK), or a generic JSON client. For self-managed deployments, configure the administration connection described in [Manage Gateways and Upstreams](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/manage-gateways#before-you-begin), then set the Gateway ID:\n\n[code example]\n\nUse `--client cursor`, `adk`, or `json` for another format. By default, the command prints configuration or a registration command. For Claude Code or Cursor, add `--write <path>` to merge the entry into a file, such as `--write .mcp.json` or `--write .cursor/mcp.json`. The parent directory must exist.\n\nGenerated client templates reference the agent-key environment variable. The generic JSON format describes the header value your client must supply rather than assuming it supports environment-variable expansion."
    },
    {
      "id": "connect-a-client",
      "title": "Open a Python MCP session",
      "role": "content",
      "text": "The unified Python package provides access to an initialized MCP session:\n\n[code example]\n\nSave this as `list_tools.py` and run:\n\n[code example]\n\nThe tools returned depend on the Gateway's exposure mode. In search mode, this lists the discovery tools rather than the complete Upstream tool catalog."
    },
    {
      "id": "use-the-tools",
      "title": "Discover and call tools",
      "role": "content",
      "text": "The Gateway's [tool exposure mode](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/concepts#tool-exposure-modes) determines how clients discover and invoke Upstream tools."
    },
    {
      "id": "search-mode",
      "title": "Search mode",
      "role": "content",
      "text": "In search mode, the client first finds relevant tool definitions, then calls a selected tool. This lets an agent discover the tools it needs without loading the entire catalog.\n\n`tools/list` returns the discovery tools below, along with stored-result tools when compression is enabled.\n\n| Tool | Arguments | Result |\n| --- | --- | --- |\n| `search_tools` | Required `query`: 1 to 200 characters, or `*` to search across all tools. Optional `limit`: 1 to 100, default 5. | Matching tool definitions in ranked order, plus `matched`, `returned`, and `truncated`. |\n| `run_tool` | Required `tool`: an object containing `upstreamId` and `originalName`. Required `toolArgs`: the selected tool's arguments, or `{}` if it takes none. | The selected tool's result. |\n\nFollow this sequence:\n\n1. **Find relevant tools.** Search for words that appear in a tool's name, title, or description. Search matches words, not semantic meaning.\n2. **Inspect a definition.** Read its input schema before preparing arguments.\n3. **Copy the tool identity.** Read `upstreamId` and `originalName` from the definition's `_meta[\"com.redis.context-gateway/tool\"]`.\n4. **Call `run_tool`.** Pass those two identity fields in `tool` and the arguments in `toolArgs`.\n\nDo not construct the identity yourself or copy the entire metadata object. `run_tool` rejects additional identity fields, including the catalog revision.\n\n#### Handle truncated discovery results\n\nA wildcard query is still subject to result limits. When `truncated` is `true`, narrow the query or adjust the limit:\n\n| Response | What to do |\n| --- | --- |\n| `returned` equals `limit`. | Narrow the query, or increase `limit` up to 100. |\n| `returned` is below `limit`. | The response-size cap stopped the results. Narrow the query. Increasing `limit` will not help. |"
    },
    {
      "id": "full-mode",
      "title": "Full mode",
      "role": "content",
      "text": "In full mode, `tools/list` returns every exposed tool under its qualified name. Inspect the tool's input schema, then call that name with `tools/call`.\n\nFor example, a Context Surface in the `scheduling` namespace can expose a tool named `scheduling__filter_provider`. Use the name returned by discovery."
    },
    {
      "id": "choose-the-invocation-interface",
      "title": "Choose the invocation interface",
      "role": "content",
      "text": "The unified Python wrapper and direct MCP sessions provide different levels of abstraction:\n\n| Interface | Calling behavior |\n| --- | --- |\n| `redis_iris.ContextGateway.call()` | Resolves a discovered tool name in either exposure mode. |\n| Python MCP session's `call_tool()` | Sends the tool name and arguments you provide. In search mode, use `run_tool` to invoke an Upstream tool. |\n| TypeScript MCP client's `callTool()` | Uses the direct MCP interface. In search mode, use `run_tool` to invoke an Upstream tool. |\n\nSee the [quickstart](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart#complete-examples) for complete examples."
    },
    {
      "id": "read-client-results",
      "title": "Read tool results",
      "role": "content",
      "text": "Check whether a tool returned an error before reading its result data. Field names differ between the unified Python wrapper and direct MCP clients:\n\n| Information | Unified Python result | Python MCP result | TypeScript MCP result / JSON |\n| --- | --- | --- | --- |\n| Tool error flag | `is_error` | `is_error` | `isError` |\n| Result data | `data` | `structured_content` | `structuredContent` |\n| Metadata | `meta` | `meta` | `_meta` |\n\nThe unified wrapper's `data` contains structured content, or JSON parsed from text when structured content is absent. It is not an alias for the direct MCP result's `structured_content` field. Use `as_text()` for a text representation.\n\nA tool error is different from a connection or protocol failure, which can raise an exception. See [Python client errors](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/limits#python-client-errors) for how the interfaces report these failures.\n\nWhen compression is enabled, a successful call may return a handle to a stored result instead of the entire result."
    },
    {
      "id": "read-handles",
      "title": "Work with stored results",
      "role": "content",
      "text": "<a id=\"work-with-stored-results\"></a>\n\nStored results let an agent inspect a large tool response without bringing all of it into its context. The Gateway stores the result and returns a small response containing a handle, a preview, and a suggested next call.\n\n![A large tool result is stored in the Gateway database, automatically or through run_tool_as_handle, and the agent receives a small stub. The agent reads a page or a query from the stored result, then releases the handle.](https://redis.io/docs/latest/images/ai/context-engine/context-gateway-handles.svg)\n\nWhen compression is enabled on the Gateway, the following tools are available in both exposure modes:\n\n| Tool | Purpose |\n| --- | --- |\n| `run_tool_as_handle` | Call a tool and explicitly request a stored result, even below the automatic capture threshold. |\n| `describe_result` | Inspect a stored result's shape, size, fields, and expiry. |\n| `page_results` | Read a stored result in order. |\n| `query_results` | Select nodes from a stored JSON result with a JSONPath expression. |\n| `count_results` | Count items, selected nodes, or items grouped by a field's value. |\n| `aggregate_results` | Calculate the count, sum, minimum, maximum, or average of selected numbers. |\n| `release_results` | Delete a stored result before it expires. |\n\nSee the [MCP API Reference](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/api-reference) for argument schemas."
    },
    {
      "id": "detect-a-stored-result",
      "title": "Detect a stored result",
      "role": "content",
      "text": "An ordinary tool call can return a handle when its result exceeds the configured threshold, unless the tool's policy opts out of capture.\n\nLook for the handle metadata at:\n\n[code example]\n\nIn Python MCP results, read this from `result.meta`.\n\nAutomatic capture can fall back to returning the complete result inline, for example, when the Gateway database is low on memory. Always check whether handle metadata is present before attempting to read a stored result."
    },
    {
      "id": "request-a-stored-result-explicitly",
      "title": "Request a stored result explicitly",
      "role": "content",
      "text": "Use `run_tool_as_handle` when you want to work with a handle even for a small result.\n\nThe tool identity depends on the exposure mode:\n\n| Mode | Tool identity |\n| --- | --- |\n| Search | Pass a `tool` object with `upstreamId` and `originalName`, as you would for `run_tool`. |\n| Full | Pass the discovered tool's qualified name in `name`. |\n\nUnlike automatic capture, an explicit capture request returns a tool error if capture is refused. It does not fall back to an inline result."
    },
    {
      "id": "inspect-retrieve-and-release",
      "title": "Inspect, retrieve, and release",
      "role": "content",
      "text": "Start with `describe_result` to understand the stored result. Then retrieve the information your agent needs:\n\n- Use `page_results` to read items in order.\n- Use `query_results` with a `jsonpath` expression to select nodes.\n- Use `count_results` or `aggregate_results` to compute a summary.\n\nInspect `completeness` and `warning` before treating any result as complete. A handle can contain only part of the source data. Paging through it does not fetch records that were never captured.\n\nRelease the result when you finish, or let it expire. Handles are bound to the caller: another caller's handle, an expired handle, or a released handle returns a tool error with reason `unknown_handle`."
    },
    {
      "id": "stored-result-example",
      "title": "Example: inspect providers by clinic",
      "role": "example",
      "text": "This example uses the search-mode Gateway and clinic records from the [sample setup](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/api-examples).\n\nThe Gateway must have compression enabled, a compatible Gateway database, and compression support enabled in the deployment. Use an agent key with access to this Gateway:\n\n[code example]\n\nThe example:\n\n1. Finds the provider filter and reads its input schema.\n2. Calls the filter through `run_tool`.\n3. Calls it again with explicit capture to obtain a handle.\n4. Describes the result, reads a page, and counts providers by clinic.\n5. Releases the handle in `finally`.\n\nThe sample data is small, so the example requests capture explicitly. With the unchanged sample records, the count should report two cardiologists for `clinic-a` and one for `clinic-b`. Check completeness and warnings before treating those counts as totals.\n\nSave the following program as `gateway_mcp.py`:\n\n[code example]\n\nRun it with:\n\n[code example]"
    },
    {
      "id": "troubleshoot-the-connection",
      "title": "Troubleshoot the connection",
      "role": "errors",
      "text": "Start with the response type to distinguish connection failures from tool failures.\n\n| Response | Meaning | Action |\n| --- | --- | --- |\n| `401` | The credential is missing or was not accepted. | Check the authentication header and whether the key or token has expired. For IdP tokens, also check the audience. |\n| `403` | The caller lacks a grant, or the Gateway or its tenant is suspended. | Ask your administrator to check the caller's `use` grant and the suspension state. |\n| `404` | No Gateway is available at this URL for your tenant. | Check the complete MCP endpoint. |\n| `503` | The Gateway's records could not be read. | Retry with backoff. |\n| JSON-RPC error with reason `unknown_tool` | A direct call names a tool the Gateway does not expose. | List the tools again and use a returned name. In search mode, invoke Upstream tools through `run_tool`. |\n| Tool error with reason `unknown_tool` and completion `not_dispatched` | The target passed through `run_tool` or `run_tool_as_handle` is unknown or inaccessible. | Discover tools again and copy the returned identity. |\n| Tool result with its error flag set | The tool or its Upstream failed. | Read `reason` and `completion` in the failure metadata. See [Limits and errors](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/limits). |"
    },
    {
      "id": "find-the-trace-for-a-failed-request",
      "title": "Find the trace for a failed request",
      "role": "content",
      "text": "Give your platform team the `traceId` from either:\n\n- A JSON-RPC error's `data`.\n- A tool result's `_meta[\"com.redis.context-gateway/invocation\"]`.\n\nThey can use it to find the request in their logs.\n\nWith the Control Plane token and Identity Service settings (`--identity` and `--identity-token`), an administrator can run:\n\n[code example]\n\nThis checks the token, Gateway, Identity Service, agent key, and one `tools/list` request, in that order. It stops at the first failure.\n\nTo inspect the Gateway's configuration, run:\n\n[code example]\n\nKeep the diagnostic information needed to investigate the failure without logging credentials or tool results containing private data."
    }
  ],
  "examples": [
    {
      "id": "before-you-begin-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL='<gateway-mcp-endpoint>'\nexport IRIS_CONTEXT_GATEWAY_API_KEY='<agent-key>'",
      "section_id": "before-you-begin"
    },
    {
      "id": "sign-in-with-your-identity-provider-ex0",
      "language": "http",
      "code": "Authorization: Bearer <access-token>",
      "section_id": "sign-in-with-your-identity-provider"
    },
    {
      "id": "connect-a-coding-assistant-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL='<search-mode-gateway-mcp-endpoint>'\nexport IRIS_CONTEXT_GATEWAY_API_KEY='<agent-key>'",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex1",
      "language": "json",
      "code": "{\n  \"mcpServers\": {\n    \"context-gateway\": {\n      \"type\": \"http\",\n      \"url\": \"${IRIS_CONTEXT_GATEWAY_URL}\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${IRIS_CONTEXT_GATEWAY_API_KEY}\"\n      }\n    }\n  }\n}",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex2",
      "language": "bash",
      "code": "claude",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex3",
      "language": "text",
      "code": "Use context-gateway to find the provider filter in the sample clinic\ndirectory. Inspect its input schema and filter for cardiologists.\nCopy the discovered upstreamId and originalName into run_tool's tool\nreference. Report the returned provider IDs and any completeness\nlimitations. If the intended tool is ambiguous, ask me to choose it.",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex4",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL='<search-mode-gateway-mcp-endpoint>'\nexport IRIS_CONTEXT_GATEWAY_API_KEY='<agent-key>'",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex5",
      "language": "json",
      "code": "{\n  \"mcpServers\": {\n    \"context-gateway\": {\n      \"url\": \"${env:IRIS_CONTEXT_GATEWAY_URL}\",\n      \"headers\": {\n        \"Authorization\": \"Bearer ${env:IRIS_CONTEXT_GATEWAY_API_KEY}\"\n      }\n    }\n  }\n}",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex6",
      "language": "text",
      "code": "Use context-gateway to find the provider filter in the sample clinic\ndirectory. Inspect its input schema and filter for cardiologists.\nCopy the discovered upstreamId and originalName into run_tool's tool\nreference. Report the returned provider IDs and any completeness\nlimitations. If the intended tool is ambiguous, ask me to choose it.",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex7",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL='<search-mode-gateway-mcp-endpoint>'\nexport IRIS_CONTEXT_GATEWAY_API_KEY='<agent-key>'\n\ncodex mcp add context-gateway \\\n  --url \"$IRIS_CONTEXT_GATEWAY_URL\" \\\n  --bearer-token-env-var IRIS_CONTEXT_GATEWAY_API_KEY",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex8",
      "language": "bash",
      "code": "codex mcp get context-gateway\ncodex",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "connect-a-coding-assistant-ex9",
      "language": "text",
      "code": "Use context-gateway to find the provider filter in the sample clinic\ndirectory. Inspect its input schema and filter for cardiologists.\nCopy the discovered upstreamId and originalName into run_tool's tool\nreference. Report the returned provider IDs and any completeness\nlimitations. If the intended tool is ambiguous, ask me to choose it.",
      "section_id": "connect-a-coding-assistant"
    },
    {
      "id": "generate-client-configuration-with-the-cli-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_ID='<gateway-id>'\n\niris context-gateway connect --client claude-code",
      "section_id": "generate-client-configuration-with-the-cli"
    },
    {
      "id": "connect-a-client-ex0",
      "language": "python",
      "code": "import asyncio\n\nfrom redis_iris import ContextGateway\n\n\nasync def main():\n    gateway = ContextGateway.from_env()\n\n    async with gateway.client.connect() as session:\n        listed = await session.list_tools()\n        print([tool.name for tool in listed.tools])\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
      "section_id": "connect-a-client"
    },
    {
      "id": "connect-a-client-ex1",
      "language": "bash",
      "code": "python list_tools.py",
      "section_id": "connect-a-client"
    },
    {
      "id": "detect-a-stored-result-ex0",
      "language": "text",
      "code": "_meta[\"com.redis.context-gateway/handle\"]",
      "section_id": "detect-a-stored-result"
    },
    {
      "id": "stored-result-example-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL='<search-mode-gateway-mcp-endpoint>'\nexport IRIS_CONTEXT_GATEWAY_API_KEY='<agent-key>'",
      "section_id": "stored-result-example"
    },
    {
      "id": "stored-result-example-ex1",
      "language": "python",
      "code": "import asyncio\n\nfrom redis_iris import ContextGateway\n\nTOOL_META_KEY = \"com.redis.context-gateway/tool\"\nHANDLE_META_KEY = \"com.redis.context-gateway/handle\"\n\nFILTER = {\n    \"tag_conditions\": [\n        {\"field\": \"specialty\", \"value\": \"cardiology\"}\n    ],\n    \"limit\": 100,\n}\n\n\ndef checked(result):\n    if result.is_error:\n        raise RuntimeError(result.model_dump_json(by_alias=True))\n    return result\n\n\nasync def main():\n    gateway = ContextGateway.from_env()\n\n    async with gateway.client.connect() as session:\n        # Find the filter and inspect its schema.\n        found = checked(\n            await session.call_tool(\n                \"search_tools\",\n                {\"query\": \"filter_provider\", \"limit\": 100},\n            )\n        )\n        matches = [\n            tool\n            for tool in found.structured_content[\"tools\"]\n            if tool.get(\"_meta\", {})\n            .get(TOOL_META_KEY, {})\n            .get(\"originalName\") == \"filter_provider\"\n        ]\n        if len(matches) != 1:\n            raise RuntimeError(\n                \"Expected one provider filter from the sample setup. \"\n                \"Inspect the discovered tools and select the intended Upstream.\"\n            )\n\n        provider_filter = matches[0]\n        print(\"Filter schema:\", provider_filter[\"inputSchema\"])\n\n        identity = provider_filter[\"_meta\"][TOOL_META_KEY]\n        reference = {\n            \"upstreamId\": identity[\"upstreamId\"],\n            \"originalName\": identity[\"originalName\"],\n        }\n\n        # Call the tool normally.\n        result = checked(\n            await session.call_tool(\n                \"run_tool\",\n                {\"tool\": reference, \"toolArgs\": FILTER},\n            )\n        )\n        print(\"Cardiologists:\", result.model_dump_json(by_alias=True))\n\n        # Call it again and explicitly request a stored result.\n        captured = checked(\n            await session.call_tool(\n                \"run_tool_as_handle\",\n                {\"tool\": reference, \"toolArgs\": FILTER},\n            )\n        )\n        handle_metadata = (captured.meta or {}).get(HANDLE_META_KEY)\n        if handle_metadata is None:\n            raise RuntimeError(\"Explicit capture returned no handle\")\n\n        handle = handle_metadata[\"handle\"]\n        try:\n            operations = [\n                (\"describe_result\", {\"handle\": handle}),\n                (\n                    \"page_results\",\n                    {\"handle\": handle, \"offset\": 0, \"limit\": 2},\n                ),\n                (\n                    \"count_results\",\n                    {\"handle\": handle, \"groupBy\": \"location_id\"},\n                ),\n            ]\n\n            for name, arguments in operations:\n                answer = checked(\n                    await session.call_tool(name, arguments)\n                )\n                # Inspect completeness and warning in the responses\n                # before interpreting pages or counts as complete.\n                print(name, answer.model_dump_json(by_alias=True))\n        finally:\n            checked(\n                await session.call_tool(\n                    \"release_results\",\n                    {\"handle\": handle},\n                )\n            )\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())",
      "section_id": "stored-result-example"
    },
    {
      "id": "stored-result-example-ex2",
      "language": "bash",
      "code": "python gateway_mcp.py",
      "section_id": "stored-result-example"
    },
    {
      "id": "find-the-trace-for-a-failed-request-ex0",
      "language": "bash",
      "code": "iris context-gateway service check <gateway-id>",
      "section_id": "find-the-trace-for-a-failed-request"
    },
    {
      "id": "find-the-trace-for-a-failed-request-ex1",
      "language": "bash",
      "code": "iris context-gateway service diagnose <gateway-id>",
      "section_id": "find-the-trace-for-a-failed-request"
    }
  ]
}
