{
  "schema_version": 2,
  "id": "develop/ai/context-engine/context-gateway/quickstart",
  "title": "Redis Context Gateway quickstart",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/quickstart/",
  "summary": "Discover and call Context Gateway tools with Python, TypeScript, or the Iris CLI in search or full mode.",
  "aliases": [
    "/develop/ai/context-engine/context-retriever/quickstart/"
  ],
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-11-03T06:42:48-08:00",
  "page_type": "content",
  "content_hash": "51a7d086bdf031b9869c153533384739b23764b83c953541feee501c153f10a3",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Discover tools and query a sample clinic directory through Redis Context Gateway using Python, TypeScript, or the Iris command-line interface (CLI).\n\nYou’ll find a tool for filtering healthcare providers, inspect its inputs, and use it to find cardiologists. Choose **Search mode** to discover relevant tools on demand, or **Full mode** to list available tools.\n\nPython and CLI examples use the unified `redis-iris` package. TypeScript examples use the separate `@redis-iris/context-gateway` package. You don’t need an agent framework or a model-provider API key."
    },
    {
      "id": "before-you-begin",
      "title": "Before you begin",
      "role": "content",
      "text": "You need a Gateway with the sample clinic directory registered as a Context Surface, its Model Context Protocol (MCP) endpoint, and an agent key with permission to use it. Follow the [sample setup guide](https://redis.io/docs/latest/operate/iris/context-gateway/self-managed/api-examples), or ask your administrator for a prepared sample.\n\nThe setup guide creates two Gateways. Choose **Operations** for search mode or **Front desk** for full mode. You only need one endpoint for this walkthrough. Selecting a documentation option does not change the Gateway’s configuration.\n\nThe directory contains three cardiologists: two at `clinic-a` and one at `clinic-b`. Compression is not required for this query."
    },
    {
      "id": "install-the-client",
      "title": "1. Install the client",
      "role": "content",
      "text": "Choose a client and use it throughout the walkthrough. Changing a client dropdown updates the other client dropdowns on this page. The Search/Full mode choice is independent.\n\n**Python:**\n\nUse Python 3.11 or later.\n\n[code example]\n\n**TypeScript:**\n\nUse Node.js 22 or later. Create a project and install the TypeScript SDK and runner:\n\n[code example]\n\nUse the `beta` release channel for these examples. The default `latest` tag currently selects an older alpha release.\n\n**CLI:**\n\nUse Python 3.11 or later. The same package installs the `iris` command:\n\n[code example]"
    },
    {
      "id": "save-connection-values",
      "title": "2. Configure the connection",
      "role": "content",
      "text": "Set the endpoint and key for the Gateway you chose:\n\n[code example]\n\nUse the returned `mcpEndpoint`, not the administration URL. The Redis SDKs require HTTPS except for local development on a loopback address such as `localhost`. Keep your key out of source control and model prompts.\n\nThe snippets explain each step of the [complete examples](#complete-examples). Use those programs to run the walkthrough without assembling fragments.\n\n**Python:**\n\n[code example]\n\n`from_env()` reads the connection values. The SDK manages MCP sessions for discovery and calls.\n\n**TypeScript:**\n\n[code example]\n\nThe TypeScript SDK opens an MCP session. The complete program closes it in a `finally` block.\n\n**CLI:**\n\nThe CLI reads the same environment variables. Run commands in the shell where you set them."
    },
    {
      "id": "discover-a-tool",
      "title": "3. Discover a tool",
      "role": "content",
      "text": "![In full mode, the agent lists all tool definitions and calls a tool by name. In search mode, the agent searches for matching definitions and calls the selected tool through run_tool.](https://redis.io/docs/latest/images/ai/context-engine/context-gateway-exposure-modes.svg)\n\nChoose the mode configured on your Gateway. In the results, look for `scheduling__filter_provider`.\n\n**Search mode:**\n\nSearch matches words in tool names, titles, and descriptions. This example searches for the sample filter.\n\n**Python**\n\n[code example]\n\n**TypeScript**\n\n[code example]\n\n`ToolDefinition` is a local type declared in the complete example.\n\n**CLI**\n\n[code example]\n\n**Full mode:**\n\nList the available tool definitions.\n\n**Python**\n\n[code example]\n\n**TypeScript**\n\n[code example]\n\nThe loop follows the catalog’s pages. `ToolDefinition` is declared in the complete example.\n\n**CLI**\n\n[code example]"
    },
    {
      "id": "4-inspect-the-tool",
      "title": "4. Inspect the tool",
      "role": "content",
      "text": "The input schema describes the arguments the tool accepts. You’ll use `tag_conditions` to match the `specialty` field and `limit` to bound the number of returned records.\n\n**Python:**\n\n[code example]\n\n**TypeScript:**\n\n[code example]\n\n**CLI:**\n\nFind the tool’s `inputSchema` in the discovery output. Save these arguments in `provider-filter.json`:\n\n[code example]"
    },
    {
      "id": "5-find-cardiologists",
      "title": "5. Find cardiologists",
      "role": "content",
      "text": "Python and CLI use the same call in either mode. TypeScript uses the MCP session directly: call `run_tool` with the discovered identity in search mode, or call the tool’s name in full mode.\n\n**Python:**\n\n[code example]\n\n**TypeScript:**\n\n[code example]\n\n**Search mode**\n\n[code example]\n\n**Full mode**\n\n[code example]\n\nCheck the result in either mode:\n\n[code example]\n\n**CLI:**\n\n[code example]\n\n\n\nCheck the tool’s error flag before using its result. Connection and protocol failures can also raise exceptions. See [Limits and errors](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/limits#python-client-errors)."
    },
    {
      "id": "6-check-the-result",
      "title": "6. Check the result",
      "role": "content",
      "text": "With the sample data, the result contains three providers whose specialty is cardiology:\n\n| Clinic | Matching providers |\n| --- | ---: |\n| `clinic-a` | 2 |\n| `clinic-b` | 1 |\n\nPython exposes the returned data through `result.data`. TypeScript and CLI return MCP responses containing structured content and text content.\n\nYou’ve discovered and called a tool through Context Gateway. An agent can use the same tool definitions and results to answer questions about the directory."
    },
    {
      "id": "complete-examples",
      "title": "Complete examples",
      "role": "content",
      "text": "Run one program using the connection values you set. Each defaults to search mode. Selecting a mode in the program does not reconfigure the Gateway.\n\n**Python:**\n\nSave as `quickstart.py`. Change `mode` to `\"full\"` for a full-mode Gateway. Run `python quickstart.py`.\n\n[code example]\n\n**TypeScript:**\n\nSave as `quickstart.mts`. Run `npx tsx quickstart.mts`, or `GATEWAY_MODE=full npx tsx quickstart.mts` for full mode.\n\n[code example]\n\n**CLI:**\n\nSave as `quickstart.cli.sh`. Run `bash quickstart.cli.sh`, or `GATEWAY_MODE=full bash quickstart.cli.sh` for full mode. The script writes `provider-filter.json` in the current directory.\n\n[code example]"
    },
    {
      "id": "troubleshooting",
      "title": "Troubleshooting",
      "role": "errors",
      "text": "| Problem | What to check |\n| --- | --- |\n| Connection or authentication fails | Check the MCP endpoint, key, and the key’s access to this Gateway. |\n| Search reports that the Gateway is in full mode | Use the Full mode example or the search-mode endpoint. |\n| The sample tool is missing | Confirm that the `scheduling` Context Surface is enabled and its catalog contains `filter_provider`. |\n| No records match | Confirm that the sample data is loaded and indexing has completed. |\n\nSee [Limits and errors](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/limits) for further troubleshooting."
    },
    {
      "id": "next-steps",
      "title": "Next steps",
      "role": "content",
      "text": "- [Integrate with an agent](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/agent-integration): Connect the Gateway to an agent framework.\n- [Manage Gateways and Upstreams](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/manage-gateways): Add tool sources and configure caching and compression.\n- [Connect with MCP](https://redis.io/docs/latest/develop/ai/context-engine/context-gateway/mcp): Work directly with sessions and stored results."
    }
  ],
  "examples": [
    {
      "id": "install-the-client-ex0",
      "language": "bash",
      "code": "python -m venv .venv\nsource .venv/bin/activate\npip install redis-iris",
      "section_id": "install-the-client"
    },
    {
      "id": "install-the-client-ex1",
      "language": "bash",
      "code": "mkdir gateway-quickstart\ncd gateway-quickstart\nnpm init -y\nnpm install @redis-iris/context-gateway@beta\nnpm install --save-dev tsx",
      "section_id": "install-the-client"
    },
    {
      "id": "install-the-client-ex2",
      "language": "bash",
      "code": "python -m venv .venv\nsource .venv/bin/activate\npip install redis-iris",
      "section_id": "install-the-client"
    },
    {
      "id": "save-connection-values-ex0",
      "language": "bash",
      "code": "export IRIS_CONTEXT_GATEWAY_URL='<gateway-mcp-endpoint>'\nexport IRIS_CONTEXT_GATEWAY_API_KEY='<agent-key>'",
      "section_id": "save-connection-values"
    },
    {
      "id": "save-connection-values-ex1",
      "language": "python",
      "code": "import json\n\nfrom redis_iris import ContextGateway\n\ngateway = ContextGateway.from_env()",
      "section_id": "save-connection-values"
    },
    {
      "id": "save-connection-values-ex2",
      "language": "typescript",
      "code": "import { ContextGateway } from \"@redis-iris/context-gateway\";\n\nconst gateway = new ContextGateway({\n  url: process.env.IRIS_CONTEXT_GATEWAY_URL!,\n  agentKey: process.env.IRIS_CONTEXT_GATEWAY_API_KEY!,\n});\nconst client = await gateway.connect();",
      "section_id": "save-connection-values"
    },
    {
      "id": "discover-a-tool-ex0",
      "language": "python",
      "code": "tools = gateway.search(\"filter_provider\")\nfor tool in tools:\n    print(tool.name, tool.description)",
      "section_id": "discover-a-tool"
    },
    {
      "id": "discover-a-tool-ex1",
      "language": "typescript",
      "code": "const found = await client.callTool({\n  name: \"search_tools\",\n  arguments: { query: \"filter_provider\", limit: 5 },\n});\nif (found.isError) throw new Error(JSON.stringify(found.content));\nconst data = found.structuredContent as { tools?: ToolDefinition[] } | undefined;\nif (!Array.isArray(data?.tools)) throw new Error(\"Search returned no tool definitions.\");\nconst tools = data.tools;",
      "section_id": "discover-a-tool"
    },
    {
      "id": "discover-a-tool-ex2",
      "language": "bash",
      "code": "iris --json context-gateway tools search filter_provider",
      "section_id": "discover-a-tool"
    },
    {
      "id": "discover-a-tool-ex3",
      "language": "python",
      "code": "tools = gateway.tools()\nfor tool in tools:\n    print(tool.name, tool.description)",
      "section_id": "discover-a-tool"
    },
    {
      "id": "discover-a-tool-ex4",
      "language": "typescript",
      "code": "const tools: ToolDefinition[] = [];\nlet cursor: string | undefined;\ndo {\n  const page = await client.listTools(cursor ? { cursor } : {});\n  tools.push(...page.tools);\n  cursor = page.nextCursor;\n} while (cursor);",
      "section_id": "discover-a-tool"
    },
    {
      "id": "discover-a-tool-ex5",
      "language": "bash",
      "code": "iris --json context-gateway tools list",
      "section_id": "discover-a-tool"
    },
    {
      "id": "4-inspect-the-tool-ex0",
      "language": "python",
      "code": "provider_filter = next(\n    (tool for tool in tools if tool.name == \"scheduling__filter_provider\"),\n    None,\n)\nif provider_filter is None:\n    raise RuntimeError(\"The sample tool was not found. Check the scheduling Upstream.\")\n\nprint(json.dumps(provider_filter.input_schema, indent=2))",
      "section_id": "4-inspect-the-tool"
    },
    {
      "id": "4-inspect-the-tool-ex1",
      "language": "typescript",
      "code": "const providerFilter = tools.find(\n  (tool) => tool.name === \"scheduling__filter_provider\",\n);\nif (!providerFilter) throw new Error(\"The sample tool was not found.\");\nconsole.log(JSON.stringify(providerFilter.inputSchema, null, 2));",
      "section_id": "4-inspect-the-tool"
    },
    {
      "id": "4-inspect-the-tool-ex2",
      "language": "json",
      "code": "{\n  \"tag_conditions\": [{\"field\": \"specialty\", \"value\": \"cardiology\"}],\n  \"limit\": 100\n}",
      "section_id": "4-inspect-the-tool"
    },
    {
      "id": "5-find-cardiologists-ex0",
      "language": "python",
      "code": "result = gateway.call(\n    provider_filter.name,\n    tag_conditions=[{\"field\": \"specialty\", \"value\": \"cardiology\"}],\n    limit=100,\n)\nif result.is_error:\n    raise RuntimeError(result.as_text())\n\nprint(json.dumps(result.data, indent=2))",
      "section_id": "5-find-cardiologists"
    },
    {
      "id": "5-find-cardiologists-ex1",
      "language": "typescript",
      "code": "const toolArgs = {\n  tag_conditions: [{ field: \"specialty\", value: \"cardiology\" }],\n  limit: 100,\n};",
      "section_id": "5-find-cardiologists"
    },
    {
      "id": "5-find-cardiologists-ex2",
      "language": "typescript",
      "code": "const identity = providerFilter._meta?.[\"com.redis.context-gateway/tool\"] as\n  | { upstreamId?: string; originalName?: string }\n  | undefined;\nif (!identity?.upstreamId || !identity.originalName) {\n  throw new Error(\"The discovered tool has no identity.\");\n}\nconst result = await client.callTool({\n  name: \"run_tool\",\n  arguments: {\n    tool: { upstreamId: identity.upstreamId, originalName: identity.originalName },\n    toolArgs,\n  },\n});",
      "section_id": "5-find-cardiologists"
    },
    {
      "id": "5-find-cardiologists-ex3",
      "language": "typescript",
      "code": "const result = await client.callTool({\n  name: providerFilter.name,\n  arguments: toolArgs,\n});",
      "section_id": "5-find-cardiologists"
    },
    {
      "id": "5-find-cardiologists-ex4",
      "language": "typescript",
      "code": "if (result.isError) throw new Error(JSON.stringify(result.content));\nconsole.log(JSON.stringify(result.structuredContent ?? result.content, null, 2));",
      "section_id": "5-find-cardiologists"
    },
    {
      "id": "5-find-cardiologists-ex5",
      "language": "bash",
      "code": "iris --json context-gateway tools call scheduling__filter_provider \\\n  --input provider-filter.json",
      "section_id": "5-find-cardiologists"
    },
    {
      "id": "complete-examples-ex0",
      "language": "python",
      "code": "import json\n\nfrom redis_iris import ContextGateway\n\ngateway = ContextGateway.from_env()\n\nmode = \"search\"  # Use \"full\" for a full-mode Gateway.\nif mode == \"search\":\n    tools = gateway.search(\"filter_provider\")\nelif mode == \"full\":\n    tools = gateway.tools()\nelse:\n    raise ValueError(\"Choose search or full mode.\")\n\nfor tool in tools:\n    print(tool.name, tool.description)\n\nprovider_filter = next(\n    (tool for tool in tools if tool.name == \"scheduling__filter_provider\"),\n    None,\n)\nif provider_filter is None:\n    raise RuntimeError(\"The sample tool was not found. Check the scheduling Upstream.\")\n\nprint(json.dumps(provider_filter.input_schema, indent=2))\n\nresult = gateway.call(\n    provider_filter.name,\n    tag_conditions=[{\"field\": \"specialty\", \"value\": \"cardiology\"}],\n    limit=100,\n)\nif result.is_error:\n    raise RuntimeError(result.as_text())\n\nprint(json.dumps(result.data, indent=2))",
      "section_id": "complete-examples"
    },
    {
      "id": "complete-examples-ex1",
      "language": "typescript",
      "code": "import { ContextGateway } from \"@redis-iris/context-gateway\";\n\nconst gateway = new ContextGateway({\n  url: process.env.IRIS_CONTEXT_GATEWAY_URL!,\n  agentKey: process.env.IRIS_CONTEXT_GATEWAY_API_KEY!,\n});\nconst client = await gateway.connect();\n\ntype ToolDefinition = {\n  name: string;\n  description?: string;\n  inputSchema: Record<string, unknown>;\n  _meta?: Record<string, unknown>;\n};\n\n// Set GATEWAY_MODE=full to use a full-mode Gateway.\nconst mode = process.env.GATEWAY_MODE ?? \"search\";\n\ntry {\n  let tools: ToolDefinition[];\n  if (mode === \"search\") {\n    const found = await client.callTool({\n      name: \"search_tools\",\n      arguments: { query: \"filter_provider\", limit: 5 },\n    });\n    if (found.isError) throw new Error(JSON.stringify(found.content));\n    const data = found.structuredContent as { tools?: ToolDefinition[] } | undefined;\n    if (!Array.isArray(data?.tools)) throw new Error(\"Search returned no tool definitions.\");\n    tools = data.tools;\n  } else if (mode === \"full\") {\n    tools = [];\n    let cursor: string | undefined;\n    do {\n      const page = await client.listTools(cursor ? { cursor } : {});\n      tools.push(...page.tools);\n      cursor = page.nextCursor;\n    } while (cursor);\n  } else {\n    throw new Error(\"Choose search or full mode.\");\n  }\n  for (const tool of tools) console.log(tool.name, tool.description);\n\n  const providerFilter = tools.find(\n    (tool) => tool.name === \"scheduling__filter_provider\",\n  );\n  if (!providerFilter) throw new Error(\"The sample tool was not found.\");\n  console.log(JSON.stringify(providerFilter.inputSchema, null, 2));\n\n  const toolArgs = {\n    tag_conditions: [{ field: \"specialty\", value: \"cardiology\" }],\n    limit: 100,\n  };\n\n  if (mode === \"search\") {\n    const identity = providerFilter._meta?.[\"com.redis.context-gateway/tool\"] as\n      | { upstreamId?: string; originalName?: string }\n      | undefined;\n    if (!identity?.upstreamId || !identity.originalName) {\n      throw new Error(\"The discovered tool has no identity.\");\n    }\n    const result = await client.callTool({\n      name: \"run_tool\",\n      arguments: {\n        tool: { upstreamId: identity.upstreamId, originalName: identity.originalName },\n        toolArgs,\n      },\n    });\n    if (result.isError) throw new Error(JSON.stringify(result.content));\n    console.log(JSON.stringify(result.structuredContent ?? result.content, null, 2));\n  } else {\n    const result = await client.callTool({\n      name: providerFilter.name,\n      arguments: toolArgs,\n    });\n    if (result.isError) throw new Error(JSON.stringify(result.content));\n    console.log(JSON.stringify(result.structuredContent ?? result.content, null, 2));\n  }\n} finally {\n  await client.close();\n}",
      "section_id": "complete-examples"
    },
    {
      "id": "complete-examples-ex2",
      "language": "bash",
      "code": "set -euo pipefail\n\n# Use GATEWAY_MODE=full for a full-mode Gateway.\ncase \"${GATEWAY_MODE:-search}\" in\n  search) iris --json context-gateway tools search filter_provider ;;\n  full) iris --json context-gateway tools list ;;\n  *) echo 'Choose search or full mode.' >&2; exit 2 ;;\nesac\n\ncat > provider-filter.json <<'JSON'\n{\"tag_conditions\":[{\"field\":\"specialty\",\"value\":\"cardiology\"}],\"limit\":100}\nJSON\niris --json context-gateway tools call scheduling__filter_provider --input provider-filter.json",
      "section_id": "complete-examples"
    }
  ]
}
