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).

Ir para a instalação

Informações da origem

Repositório
databricks-solutions/vibe-coding-workshop-template
Última atividade na origem
6 de junho de 2026 às 14:09
Idioma detectado do SKILL.md
inglês
Estrelas
6
Forks
7

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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 [
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub