Skip to main content

03-tools-and-mcp

Use when wiring tools into an OpenAI Agents SDK agent: local Python function tools, DatabricksMCPClient connections, and MCPServerSse for MCP servers. Track A Step 3. Builds on shared concepts from F3 (Tools and Data Access).

Quellinformationen

Repository
databricks-solutions/vibe-coding-workshop-template
Letzte Quellaktivität
6. Juni 2026 um 14:09
Erkannte Sprache von SKILL.md
Englisch
Sterne
6
Forks
8

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
03-tools-and-mcp
description
Use when wiring tools into an OpenAI Agents SDK agent: local Python function tools, DatabricksMCPClient connections, and MCPServerSse for MCP servers. Track A Step 3. Builds on shared concepts from F3 (Tools and Data Access).
license
Apache-2.0
clients
["ide_cli","genie_code"]
bundle_resource
none
deploy_verb
none
deploy_note
Tool + MCP wiring (local function tools, DatabricksMCPClient, MCPServerSse) — code, no bundle resource. Resolves identically on both clients; on Genie Code use its built-in tool surface for ad-hoc calls and runDatabricksCli for grants. See `skills/genie-code-environment`.
coverage
full
metadata
{"last_verified":"2026-06-05","volatility":"high","upstream_sources":[],"author":"prashanth-subrahmanyam","version":"3.1.0","domain":"genai-agents","pipeline_position":"A3","consumes":"customized_agent, agent_class, mcp_server_knowledge","produces":"agent_with_tools, mcp_connections, resource_grants","grounded_in":"docs.databricks.com/aws/en/generative-ai/agent-framework/author-agent, docs.databricks.com/aws/en/generative-ai/agent-framework/build-agent-tool, openai.github.io/openai-agents-python/tools/"}
fields_read
["agent.tools","agent.mcp_servers","agent.knowledge_base_backend","docs.agent_tool_plan.selected_tools","docs.agent_tool_plan.selected_mcp_servers"]
# Track A Step 3: Agent SDK Tool Wiring Wire tools into your OpenAI Agents SDK agent so it can query data, search documents, call functions, and connect to external services. This step focuses on **how to wire tools into the Agent class**. For background on which MCP servers exist, how external MCP works, resource grants, and retriever schemas, see [F3: Tools and Data Access](../../../foundation/03-tools-and-data-access/SKILL.md). ## Tool Plan Input Contract For the Agents Accelerator, prefer `docs/agent_tool_plan.yaml` over inferred defaults. Wire only the tools listed in `selected_tools[]`. Tool families not selected are skipped and recorded in verification as skipped, not failed. For SQL MCP, enforce the read-only guardrails from the plan before any smoke test. Reject generated SQL containing `INSERT`, `UPDATE`, `DELETE`, `DROP`, `ALTER`, `CREATE`, `MERGE`, or `TRUNCATE` when `readonly: true`. Use `docs/agent_tool_plan.yaml.verification.tool_smoke_tests[]` as the source of smoke prompts. Every selected tool must produce at least one MLflow TOOL span. OpenAI Agents SDK SQL MCP wiring example: ```python from agents.mcp import MCPServerSse sql_mcp = MCPServerSse( url=f"{host}/api/2.0/mcp/sql", headers={"Authorization": f"Bearer {workspace_client.config.token}"}, ) ``` ## When to Use - Your agent is running (Steps 1-2) but only generates text — it needs to **do things**: query data, search documents, call APIs. - You want to connect to **Databricks managed MCP servers** or **external MCP servers** from an OpenAI Agents SDK agent. - You need to add **local function tools** for custom business logic. ## Foundation Prerequisite Check Foundation Step 3 (Tools and Data Access) should be understood before this step. Verify: ```bash python3 -c "from databricks_mcp import DatabricksMCPClient; print('F3: OK')" 2>/dev/null || echo "F3: FAIL — pip install databricks-mcp" ``` If F3 fails, install `databricks-mcp` and review [F3: Tools and Data Access](../../../foundation/03-tools-and-data-access/SKILL.md). --- ## Canonical Tool Catalog (pick what your agent needs) Track A custom agents typically combine **three classes** of tools. Pick from this catalog based on the data your agent must reach: | Class | What it answers | Backing skill | Wire-in pattern | |---|---|---|---| | **Knowledge Assistant** (managed doc Q&A with citations) | "What does our policy say about X?" | [F5: Knowledge Assistant Lifecycle](../../../foundation/05-knowledge-assistant/SKILL.md) — produces `ka_endpoint_name` | Call the KA Model Serving endpoint from a `@function_tool` (see _Wiring KA as a function tool_ below) | | **Genie Space** (NL → SQL on UC tables, conversational analytics) | "How many active customers signed up last week?" | [`data_product_accelerator/skills/semantic-layer/03-genie-space-patterns`](../../../../data_product_accelerator/skills/semantic-layer/03-genie-space-patterns/SKILL.md) and [`04-genie-space-export-import-api`](../../../../data_product_accelerator/skills/semantic-layer/04-genie-space-export-import-api/SKILL.md) — produces `genie_space_id` | Call Genie via the Databricks SDK from a `@function_tool`, **or** wire as Genie MCP server (see F3) | | **Unity Catalog functions** (deterministic Python or SQL functions, registered in UC) | "Compute next-tier-distance for this customer" | [F3: Tools and Data Access](../../../foundation/03-tools-and-data-access/SKILL.md) (UC Functions MCP section) | Wire as UC Functions MCP server, or call directly via the SDK | | **Vector Search MCP** (custom retrieval pipeline) | "Custom hybrid search with re-ranker" | F3 (Vector Search MCP) | `MCPServerSse` direct wiring (see below) | | **Local Python tools** (business logic, math, formatting) | "Compute margin", "format response" | This skill — `@function_tool` (see below) | Decorator | > **Canonical default for the SkyLoyalty walkthrough:** Knowledge Assistant > + Genie Space + a small set of `@function_tool` helpers. This pairing > covers structured analytics (Genie), unstructured Q&A (KA), and bespoke > business logic (functions) without a custom RAG stack. ### Serving-endpoint API shape per endpoint kind Different endpoint kinds use different request shapes. The most common bug in this skill's history is reaching for Chat Completions on every endpoint; **KA uses Responses API and Genie uses a two-call SDK sequence**. Use this table as the canonical wiring reference: | Endpoint kind | Wire via | Request shape | Notes | |---|---|---|---| | **Knowledge Assistant** | Raw `requests.post` to `{host}/serving-endpoints/{name}/invocations` | Responses API: `{"input": [{"role": "user", "content": "..."}]}` | Parse `output[].content[].text`. Do NOT use `serving_endpoints.query(messages=...)` — KA rejects `messages` and the SDK's typing surfaces it as `'dict' object has no attribute 'as_dict'`. | | **Foundation Model API** (Sonnet, llama-3.3, gpt-5-2) | `databricks_openai.AsyncDatabricksOpenAI` or `OpenAI(base_url=...)` | OpenAI Chat Completions: `messages=[...]` | Standard OpenAI-compatible client patterns apply. | | **Genie Space** | SDK two-call sequence | (1) `w.genie.start_conversation_and_wait(space_id=..., content=...)` returns description + attachments[] (2) `w.genie.get_message_query_result_by_attachment(space_id, conversation_id, message_id, attachment_id)` returns rows | First call alone surfaces the SQL plan as prose, not the rows — always make both calls. See **Wiring Genie as a function tool** below. | | **AI Gateway endpoint** | REST `POST /api/2.0/serving-endpoints` | `external_model.databricks-model-serving` shape | See [F4: AI Gateway](../../../foundation/04-ai-gateway/SKILL.md) for the create-endpoint payload. | ### Wiring KA as a function tool (Track A pattern) KA exposes a Model Serving endpoint, but **KA serves the Responses API, not Chat Completions.** A `serving_endpoints.query(name=..., messages=[...])` call against a KA endpoint fails with `Invalid request: 'messages' field is not supported` (and may surface earlier as a Python `'dict' object has no attribute 'as_dict'` typing trap inside the SDK shim). Call the invocations URL directly with the Responses-API request body: ```json {"input": [{"role": "user", "content": "question"}]} ``` and parse the response as `output[].content[].text`: ```python import os import requests from agents import function_tool from databricks.sdk import WorkspaceClient KA_ENDPOINT = os.environ["KA_ENDPOINT_NAME"] # captured in F5 @function_tool def search_policy_docs(query: str) -> str: """Search policy documents and return cited answers. Args: query: Natural-language question about loyalty program policy. """ w = WorkspaceClient() host = w.config.host.rstrip("/") url = f"{host}/serving-endpoints/{KA_ENDPOINT}/invocations" # KA uses the Responses API: `input`, NOT Chat Completions `messages`. body = {"input": [{"role": "user", "content": query}]} resp = requests.post( url, headers={"Authorization": f"Bearer {w.config.token}", "Content-Type": "application/json"}, json=body, timeout=60, ) resp.raise_for_status() payload = resp.json() # Responses API: payload["output"][i]["content"][j]["text"] parts = [] for item in payload.get("output", []): for chunk in item.get("content", []): text = chunk.get("text") if text: parts.append(text) return "\n".join(parts) or "(no answer)" ``` > **DON'T** use `w.serving_endpoints.query(name=..., messages=[...])` against > a KA endpoint. KA does not accept Chat Completions `messages`. Use raw > `requests.post` with `{"input": [...]}` against the invocations URL as > shown above. (Foundation Model API endpoints — Sonnet, llama-3.3, gpt-5-2 — > do accept Chat Completions and can use the OpenAI-compatible client.) Declare the KA endpoint as a `serving_endpoint` resource (`CAN_QUERY`) in `databricks.yml` so the deployed agent has access — see the resource-kind reference below. ### Wiring Genie as a function tool Genie spaces require a **two-call sequence** via the SDK. The first call returns the planner description and message metadata; the rows live on the attachment and must be fetched in a second call. Tools that return only the first call's output deliver SQL-as-prose to the LLM, not data. 1. `w.genie.start_conversation_and_wait(space_id=..., content=...)` — starts the conversation, runs the planner, and returns a `GenieMessage` whose `attachments[]` carry the query metadata (each attachment has an `attachment_id`). The message's `content`/text is the **description**, not the rows. 2. `w.genie.get_message_query_result_by_attachment(space_id=..., conversation_id=..., message_id=..., attachment_id=...)` — pulls the actual SQL execution result (rows + columns) for the chosen attachment. Combine both into a single tool so the Agents SDK gets both the description and the rows in one return value: ```python import os from agents import function_tool from databricks.sdk import WorkspaceClient GENIE_SPACE_ID = os.environ["GENIE_SPACE_ID"] # captured during semantic-layer setup @function_tool def query_loyalty_analytics(question: str) -> str: """Answer analytics questions over loyalty data using Genie. Args: question: Natural-language analytics question (e.g. "active members by tier"). """ w = WorkspaceClient() # CALL 1: start_conversation_and_wait — planner runs, returns description. msg = w.genie.start_conversation_and_wait( space_id=GENIE_SPACE_ID, content=question, ) description = (msg.content or "").strip() if not msg.attachments: return description or "(no answer)" # CALL 2: get_message_query_result_by_attachment — fetches the rows. attachment_id = msg.attachments[0].attachment_id result = w.genie.get_message_query_result_by_attachment( space_id=GENIE_SPACE_ID, conversation_id=msg.conversation_id, message_id=msg.message_id, attachment_id=attachment_id, ) # Render rows as a small markdown-ish table for the LLM. rows_text = "(no rows)" sm = getattr(result, "statement_response", None) if sm and getattr(sm, "result", None) and getattr(sm.result, "data_array", None): rows = sm.result.data_array cols = [c.name for c in (sm.manifest.schema.columns or [])] if sm.manifest else [] header = " | ".join(cols) body = "\n".join(" | ".join(str(c) for c in row) for row in rows) rows_text = f"{header}\n{body}" if header else body return f"{description}\n\n{rows_text}" ``` > **DON'T** stop after `start_conversation_and_wait`. The first call may > return only a description (and zero attachments for refusals); always > fetch `get_message_query_result_by_attachment` for each attachment whose > rows you want to surface to the LLM. Declare a `genie_space` resource in `databricks.yml`. **Bundle bindings use `name` + `space_id`** (not a bare `id`): ```yaml - name: genie-space genie_space: space_id: ${var.genie_space_id} permission: CAN_RUN ``` The outer `name:` is the resource binding (referenced by `valueFrom:` in `app.yaml`); the inner `space_id:` is the Genie Space identifier the platform looks up. Plus declare the underlying `sql_warehouse` the space uses. --- ## Local Function Tools ### OpenAI Agents SDK: `@function_tool` The simplest way to give your agent capabilities — define Python functions and decorate them: ```python from agents import Agent, function_tool from datetime import datetime @function_tool def get_current_time() -> str: """Get the current date and time in ISO format.""" return datetime.now().isoformat() @function_tool def calculate_metrics(revenue: float, cost: float) -> dict: """Calculate profit margin and ROI from revenue and cost. Args: revenue: Total revenue in dollars. cost: Total cost in dollars. """ profit = revenue - cost margin = (profit / revenue * 100) if revenue > 0 else 0 return {"profit": profit, "margin_pct": round(margin, 2)} @function_tool def search_knowledge_base(query: str, max_results: int = 5) -> list[dict]: """Search the internal knowledge base for relevant documents. Args: query: Natural language search query. max_results: Maximum number of results to return (default 5). """ from databricks.sdk import WorkspaceClient w = WorkspaceClient() results = w.vector_search_indexes.query_index( index_name="prod.docs.knowledge_index", columns=["content", "source", "score"], query_text=query, num_results=max_results, ) return [
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen