{"id":6774,"date":"2025-06-13T12:59:57","date_gmt":"2025-06-13T03:59:57","guid":{"rendered":"https:\/\/blog.since2020.jp\/?p=6774"},"modified":"2025-06-13T14:04:19","modified_gmt":"2025-06-13T05:04:19","slug":"claude_mcp_databricks_2","status":"publish","type":"post","link":"https:\/\/since2020.jp\/media\/claude_mcp_databricks_2\/","title":{"rendered":"\u3010databricks\u3011Claude MCP\u3092databricks\u3067\u4f7f\u3063\u3066\u307f\u305f2: Claude\u3068databricks LLM\u306egenie\u3068\u63a5\u7d9a\u3059\u308b\u65b9\u6cd5"},"content":{"rendered":"\n<p>\u3010databricks\u3011Claude MCP\u3092databricks\u3067\u4f7f\u3063\u3066\u307f\u305f2: Claude\u3068databricks LLM\u306egenie\u3068\u63a5\u7d9a\u3059\u308b\u65b9\u6cd5<\/p>\n\n\n<h2>\u521d\u3081\u306b<\/h2>\n<p><span style=\"font-family: arial, helvetica, sans-serif\">MCP\u3068databricks\u306e\u8aac\u660e\u306b\u3064\u3044\u3066\u306f<span style=\"color: #0000ff\"><a href=\"https:\/\/blog.since2020.jp\/ai\/claude_mcp_databricks_1\" style=\"color: #0000ff\">\u524d\u56de\u306e\u30d6\u30ed\u30b0<\/a><\/span>\u3092\u3054\u53c2\u7167\u304f\u3060\u3055\u3044\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u4eca\u56de\u306fdatabricks\u306b\u5185\u8535\u3055\u308c\u3066\u3044\u308bAI\u300cGenie\u300d\u3068Claude desktop\u3092MCP\u3067\u63a5\u7d9a\u3057\u3066\u307f\u307e\u3057\u305f\u3002\u63a5\u7d9a\u306e\u30a4\u30e1\u30fc\u30b8\u306f\u4ee5\u4e0b\u306e\u901a\u308a\u3067\u3059\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\"><img decoding=\"async\" src=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/mcp_corrected_layout_diagram.webp\" alt=\"\" width=\"1224\" height=\"816\" class=\"alignnone size-full wp-image-6775\" srcset=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/mcp_corrected_layout_diagram.webp 1224w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/mcp_corrected_layout_diagram-300x200.webp 300w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/mcp_corrected_layout_diagram-1024x683.webp 1024w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/mcp_corrected_layout_diagram-768x512.webp 768w\" sizes=\"(max-width: 1224px) 100vw, 1224px\" \/><\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">Unity Catalog\u3068\u306e\u76f4\u63a5\u63a5\u7d9a\u3068\u306f\u7570\u306a\u308a\u3001Claude\u304b\u3089\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092Genie\u304c\u51e6\u7406\u3059\u308b\u4ed5\u7d44\u307f\u3068\u306a\u3063\u3066\u3044\u307e\u3059\u3002\u305d\u306e\u305f\u3081\u3001\u76f4\u63a5\u63a5\u7d9a\u307b\u3069Claude\u306e\u63a8\u8ad6\u80fd\u529b\u3092\u6d3b\u304b\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002\u4e00\u65b9\u3067\u3001Genie\u304cUnity Catalog\u304b\u3089\u306e\u30c7\u30fc\u30bf\u53d6\u5f97\u3092\u6700\u9069\u5316\u3057\u3066\u304f\u308c\u308b\u305f\u3081\u3001\u5927\u91cf\u306e\u30c7\u30fc\u30bf\u304c\u3042\u308b\u5834\u5408\u3067\u3082\u5fc5\u8981\u306a\u30c7\u30fc\u30bf\u306e\u307f\u3092\u52b9\u7387\u7684\u306b\u53d6\u5f97\u3067\u304d\u308b\u3068\u3044\u3046\u30e1\u30ea\u30c3\u30c8\u304c\u3042\u308a\u307e\u3059\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u4eca\u56de\u306f\u3053\u306e\u8a18\u4e8b\u3092\u30e1\u30a4\u30f3\u306b\u53c2\u8003\u306b\u3057\u3066\u3044\u307e\u3059\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\"><a href=\"https:\/\/qiita.com\/taka_yayoi\/items\/b29edb7daa50057d9e36\">https:\/\/qiita.com\/taka_yayoi\/items\/b29edb7daa50057d9e36<\/a><\/span><\/p>\r\n<p><!-- notionvc: 3db6606c-37a5-46d6-9b29-a079f017a91e --><\/p>\r\n<p><!-- notionvc: c97b11b1-b0ca-4c39-be69-f9cc7a7cfbfc --><\/p>\n\n<h2>\u74b0\u5883\u8a2d\u5b9a<\/h2>\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u5fc5\u8981\u306a\u3082\u306e<\/span><\/p>\r\n<ul>\r\n\t<li><span style=\"font-family: arial, helvetica, sans-serif\">Claude desktop(\u30a2\u30ab\u30a6\u30f3\u30c8)<\/span><\/li>\r\n\t<li><span style=\"font-family: arial, helvetica, sans-serif\">databricks API (\u8a2d\u5b9a\u306e\u65b9\u6cd5\u306f\u524d\u8a18\u4e8b\u53c2\u7167), genie space ID (\u4e8b\u524d\u306bgenie UI \u306b\u3044\u3063\u3066\u90e8\u5c4b\u3092\u5efa\u3066\u3066\u304f\u3060\u3055\u3044\u3002), databricks host ID<\/span><\/li>\r\n<\/ul>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">databricks host ID\u3068genie space ID\u306fURL\u306e\u4e0b\u8a18\u306e\u90e8\u5206\u306b\u8a72\u5f53\u3057\u307e\u3059\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\"><!-- notionvc: 862f9b97-0883-4755-ab55-4c930f2807ad --><\/span><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-bash\" data-lang=\"Bash\"><code>databricks host ID                            genie space ID \r\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510             \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \r\nhttps:\/\/xxxxx.cloud.databricks.com\/genie\/rooms\/xxxxxxxxxxx?o=xxxxxxxx<!-- notionvc: ebe67f66-791b-41fc-aea1-e6383899a1ed --><\/code><\/pre>\r\n<p>&nbsp;<\/p>\r\n<\/div>\n\n<h2>\u69cb\u7bc9\u624b\u9806<\/h2>\n<b><span style=\"font-family: arial, helvetica, sans-serif\">1.Local Host MCP Server\u3092\u8a2d\u5b9a\u3059\u308b<\/span><\/b>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">local \u74b0\u5883\u306b\u30d5\u30a9\u30eb\u30c0\u3092\u4f5c\u308a\u307e\u3059\u3002\u540d\u524d\u306f\u306a\u3093\u3067\u3082\u3044\u3044\u3067\u3059\u3002\u4e0b\u56f3\u306f\u30d5\u30a9\u30eb\u30c0\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30a4\u30e1\u30fc\u30b8\u3067\u3059\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\"><!-- notionvc: 6ebab7ff-a1b1-444f-9c38-eb2b20a98e1c --><\/span><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-bash\" data-lang=\"Bash\"><code>my-genie-mcp\/\r\n \u251c main.py \r\n \u251c dbapi.py\r\n \u251c databricks_formatter.py\r\n \u251c pyproject.toml<\/code><\/pre>\r\n<\/div>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">main.py<\/span><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>\"\"\"\r\nDatabricks Genie MCP Server\r\nMCP\u3092\u4f7f\u7528\u3057\u3066Genie\u3068\u306e\u5bfe\u8a71\u3092\u53ef\u80fd\u306b\u3059\u308b\u30b5\u30fc\u30d0\u30fc\r\n\"\"\"\r\nfrom mcp.server.fastmcp import FastMCP\r\nfrom dbapi import genie_conversation\r\nfrom databricks_formatter import format_query_results\r\n\r\n# MCP\u30b5\u30fc\u30d0\u30fc\u3092\u521d\u671f\u5316\r\n# \u30b5\u30fc\u30d0\u30fc\u540d\u3092\u6307\u5b9a\u3057\u3066\u65b0\u3057\u3044\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u4f5c\u6210\r\nmcp = FastMCP(\"Databricks Genie MCP Server\")\r\n\r\n@mcp.tool()\r\nasync def start_conversation(content: str) -&gt; str:\r\n  \"\"\"\r\n  Genie API\u3068\u306e\u4f1a\u8a71\u3092\u958b\u59cb\u3059\u308b\r\n\r\n  Args:\r\n    content (str): Genie\u306b\u9001\u4fe1\u3059\u308b\u30e1\u30c3\u30bb\u30fc\u30b8\u5185\u5bb9\r\n\r\n  Returns:\r\n    str: Genie\u304b\u3089\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u6574\u5f62\u3057\u305f\u7d50\u679c\r\n  \"\"\"\r\n  try:\r\n     # Genie API\u3092\u547c\u3073\u51fa\u3057\u3066\u5fdc\u7b54\u3092\u53d6\u5f97\r\n     result = await genie_conversation(content)\r\n     # \u5fdc\u7b54\u7d50\u679c\u3092\u898b\u3084\u3059\u3044\u5f62\u5f0f\u306b\u6574\u5f62\r\n     return format_query_results(result)\r\n  except Exception as e:\r\n     # \u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u305f\u5834\u5408\u306f\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u8fd4\u3059\r\n     return result\r\n\r\n# \u30e1\u30a4\u30f3\u30a8\u30f3\u30c8\u30ea\u30fc\u30dd\u30a4\u30f3\u30c8\r\nif __name__ == \"__main__\":\r\n  # \u30c7\u30d5\u30a9\u30eb\u30c8\u3067stdio\u30c8\u30e9\u30f3\u30b9\u30dd\u30fc\u30c8\u3092\u4f7f\u7528\u3057\u3066\u30b5\u30fc\u30d0\u30fc\u3092\u8d77\u52d5\r\n  # \u3053\u308c\u306b\u3088\u308a\u30b3\u30de\u30f3\u30c9\u30e9\u30a4\u30f3\u304b\u3089\u306e\u5bfe\u8a71\u304c\u53ef\u80fd\u306b\u306a\u308b\r\n  mcp.run()<\/code><\/pre>\r\n<\/div>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">dbapi.py<\/span><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>\"\"\"\r\nDatabricks API\u901a\u4fe1\u30e2\u30b8\u30e5\u30fc\u30eb\r\nGenie\u3068\u306e\u5bfe\u8a71\u306b\u5fc5\u8981\u306aAPI\u547c\u3073\u51fa\u3057\u3092\u7ba1\u7406\u3057\u307e\u3059\r\n\"\"\"\r\n\r\nfrom typing import Any, Dict, Optional\r\nimport os\r\nimport asyncio\r\nimport httpx\r\nfrom dotenv import load_dotenv\r\n\r\n# \u74b0\u5883\u5909\u6570\u3092.env\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u8aad\u307f\u8fbc\u307f\r\nload_dotenv()\r\n\r\n# Databricks\u63a5\u7d9a\u306b\u5fc5\u8981\u306a\u8a2d\u5b9a\u5024\r\nDATABRICKS_HOST = os.environ.get(\"DATABRICKS_HOST\", \"&lt;your databricks host&gt;\")\r\nDATABRICKS_TOKEN = os.environ.get(\"DATABRICKS_TOKEN\", \"&lt;your databricks token&gt;\")\r\nDATABRICKS_GENIE_SPACE_ID = os.environ.get(\"DATABRICKS_GENIE_SPACE_ID\", \"&lt;your genie space ID&gt;\")\r\n\r\n# API\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u5b9a\u7fa9\r\nGENIE_START_CONVERSATION_API = \"\/api\/2.0\/genie\/spaces\/{space_id}\/start-conversation\" # \u4f1a\u8a71\u958b\u59cb\u7528\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\r\nGENIE_GET_MESSAGE_API = \"\/api\/2.0\/genie\/spaces\/{space_id}\/conversations\/{conversation_id}\/messages\/{message_id}\" # \u30e1\u30c3\u30bb\u30fc\u30b8\u53d6\u5f97\u7528\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\r\nSTATEMENT_API = \"\/api\/2.0\/sql\/statements\/{statement_id}\" # SQL\u30b9\u30c6\u30fc\u30c8\u30e1\u30f3\u30c8\u5b9f\u884c\u7d50\u679c\u53d6\u5f97\u7528\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\r\n\r\nasync def make_databricks_request(\r\n   method: str,\r\n  endpoint: str,\r\n  json_data: Optional[Dict[str, Any]] = None,\r\n  params: Optional[Dict[str, Any]] = None\r\n  ) -&gt; Dict[str, Any]:\r\n  \"\"\"\r\n  Databricks\u306eAPI\u306b\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u3059\u308b\u6c4e\u7528\u95a2\u6570\r\n\r\n  Args:\r\n    method (str): HTTP\u30e1\u30bd\u30c3\u30c9('get'\u307e\u305f\u306f'post')\r\n    endpoint (str): API\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u30d1\u30b9\r\n    json_data (Optional[Dict[str, Any]]): POST\u30ea\u30af\u30a8\u30b9\u30c8\u7528\u306eJSON\u30c7\u30fc\u30bf\r\n    params (Optional[Dict[str, Any]]): GET\u30ea\u30af\u30a8\u30b9\u30c8\u7528\u306e\u30af\u30a8\u30ea\u30d1\u30e9\u30e1\u30fc\u30bf\r\n\r\n  Returns:\r\n    Dict[str, Any]: API\u30ec\u30b9\u30dd\u30f3\u30b9\u306eJSON\u30c7\u30fc\u30bf\r\n  \"\"\"\r\n  url = f\"{DATABRICKS_HOST}{endpoint}\"\r\n\r\n  # \u8a8d\u8a3c\u30d8\u30c3\u30c0\u30fc\u306e\u8a2d\u5b9a\r\n  headers = {\r\n    \"Authorization\": f\"Bearer {DATABRICKS_TOKEN}\",\r\n  }\r\n\r\n  async with httpx.AsyncClient() as client:\r\n    try:\r\n      # HTTP\u30e1\u30bd\u30c3\u30c9\u306b\u5fdc\u3058\u3066\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u5b9f\u884c\r\n      if method.lower() == \"get\":\r\n         response = await client.get(url, headers=headers, params=params, timeout=30.0)\r\n      elif method.lower() == \"post\":\r\n        response = await client.post(url, headers=headers, json=json_data, timeout=30.0)\r\n      else:\r\n        raise ValueError(f\"\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044HTTP\u30e1\u30bd\u30c3\u30c9: {method}\")\r\n\r\n      response.raise_for_status()\r\n      return response.json()\r\n    except httpx.HTTPStatusError as e:\r\n      # HTTP\u30a8\u30e9\u30fc\u306e\u8a73\u7d30\u60c5\u5831\u3092\u53d6\u5f97\u3057\u3066\u4f8b\u5916\u3092\u767a\u751f\r\n      error_message = f\"HTTP\u30a8\u30e9\u30fc: {e.response.status_code}\"\r\n      try:\r\n        error_detail = e.response.json()\r\n        error_message += f\" - {error_detail.get('message', '')}\"\r\n      except Exception:\r\n        pass\r\n     raise Exception(error_message)\r\n   except Exception as e:\r\n     raise Exception(f\"Databricks API\u30ea\u30af\u30a8\u30b9\u30c8\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f: {str(e)}\")\r\n\r\n\r\nasync def genie_conversation(content: str, space_id: Optional[str] = None) -&gt; Dict[str, Any]:\r\n  \"\"\"\r\n  Genie\u3068\u306e\u4f1a\u8a71\u3092\u5b9f\u884c\u3057\u3001\u7d50\u679c\u304c\u5f97\u3089\u308c\u308b\u307e\u3067\u5f85\u6a5f\u3059\u308b\r\n\r\n  Args:\r\n    content (str): Genie\u306b\u9001\u4fe1\u3059\u308b\u30e1\u30c3\u30bb\u30fc\u30b8\u5185\u5bb9\r\n    space_id (Optional[str]): Genie Space ID(\u672a\u6307\u5b9a\u6642\u306f\u74b0\u5883\u5909\u6570\u304b\u3089\u53d6\u5f97)\r\n\r\n  Returns:\r\n    Dict[str, Any]: \u4f1a\u8a71\u306e\u5b9f\u884c\u7d50\u679c\r\n    \"\"\"\r\n  if not space_id:\r\n   space_id = DATABRICKS_GENIE_SPACE_ID\r\n\r\n  if not space_id:\r\n    raise ValueError(\"Genie Space ID\u304c\u5fc5\u8981\u3067\u3059\u3002\u74b0\u5883\u5909\u6570DATABRICKS_GENIE_SPACE_ID\u3092\u8a2d\u5b9a\u3059\u308b\u304b\u3001\u30d1\u30e9\u30e1\u30fc\u30bf\u3068\u3057\u3066\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002\")\r\n\r\n  # \u4f1a\u8a71\u958b\u59cb\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u4f5c\u6210\r\n  statement_data = {\r\n    \"content\": content\r\n  }\r\n\r\n  # \u4f1a\u8a71\u3092\u958b\u59cb\u3057\u3001conversation_id\u3068message_id\u3092\u53d6\u5f97\r\n  endpoint_url = GENIE_START_CONVERSATION_API.format(space_id=space_id)\r\n  response = await make_databricks_request(\"post\", endpoint_url, json_data=statement_data)\r\n  message = response.get(\"message\")\r\n  conversation_id = message[\"conversation_id\"]\r\n  message_id = message[\"id\"]\r\n\r\n  if not conversation_id:\r\n    raise Exception(\"\u30ec\u30b9\u30dd\u30f3\u30b9\u304b\u3089conversation_ID\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\")\r\n\r\n  # \u4f1a\u8a71\u751f\u6210\u5b8c\u4e86\u3092\u30dd\u30fc\u30ea\u30f3\u30b0\r\n  max_retries = 60 # \u6700\u5927\u30ea\u30c8\u30e9\u30a4\u56de\u6570\uff0810\u79d2\u9593\u9694\u306710\u5206\uff09\r\n  retry_count = 0\r\n\r\n  while retry_count &lt; max_retries:\r\n    # \u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u78ba\u8a8d\r\n    message_status = await make_databricks_request(\r\n     \"get\",\r\n     GENIE_GET_MESSAGE_API.format(space_id=space_id, conversation_id=conversation_id, message_id=message_id)\r\n    )\r\n\r\n   status = message_status[\"status\"]\r\n\r\n   if status == \"COMPLETED\":\r\n      # \u5b8c\u4e86\u3057\u305f\u5834\u5408\u3001\u30af\u30a8\u30ea\u7d50\u679c\u3092\u53d6\u5f97\r\n      query_result_statement_id = message_status[\"attachments\"][0][\"query\"][\"statement_id\"]\r\n\r\n     statement_status = await make_databricks_request(\r\n       \"get\",\r\n       STATEMENT_API.format(statement_id=query_result_statement_id)\r\n     )\r\n\r\n     return statement_status\r\n   elif status in [\"FAILED\", \"CANCELED\"]:\r\n     error_message = message_status[\"status\"]\r\n     raise Exception(f\"\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u53d6\u5f97\u306b\u5931\u6557: {error_message}\")\r\n\r\n   # \u6b21\u306e\u30dd\u30fc\u30ea\u30f3\u30b0\u307e\u3067\u5f85\u6a5f\r\n\r\n    retry_count += 1\r\n\r\n  return message[\"content\"]<\/code><\/pre>\r\n<\/div>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">databricks_formatter.py<\/span><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>from typing import Any, Dict\r\n\r\ndef format_query_results(result: Dict[str, Any]) -&gt; str:\r\n  \"\"\"Format query results into a readable string.\"\"\"\r\n\r\n  # Check if result is empty or doesn't have the expected structure\r\n  if not result or 'manifest' not in result or 'result' not in result:\r\n    return \"No results or invalid result format.\"\r\n\r\n  # Extract column names from the manifest\r\n  column_names = []\r\n  if 'manifest' in result and 'schema' in result['manifest'] and 'columns' in result['manifest']['schema']:\r\n    columns = result['manifest']['schema']['columns']\r\n    column_names = [col['name'] for col in columns] if columns else []\r\n\r\n  # If no column names were found, return early\r\n  if not column_names:\r\n    return \"No columns found in the result.\"\r\n\r\n  # Extract rows from the result\r\n  rows = []\r\n  if 'result' in result and 'data_array' in result['result']:\r\n    rows = result['result']['data_array']\r\n\r\n    # If no rows were found, return just the column headers\r\n    if not rows:\r\n      # Format as a table\r\n      output = []\r\n      # Add header\r\n      output.append(\" | \".join(column_names))\r\n      output.append(\"-\" * (sum(len(name) + 3 for name in column_names) - 1))\r\n      output.append(\"No data rows found.\")\r\n      return \"\\n\".join(output)\r\n\r\n  # Format as a table\r\n  output = []\r\n\r\n  # Add header\r\n  output.append(\" | \".join(column_names))\r\n  output.append(\"-\" * (sum(len(name) + 3 for name in column_names) - 1))\r\n  # Add rows\r\n  for row in rows:\r\n    row_values = []\r\n    for value in row:\r\n      if value is None:\r\n        row_values.append(\"NULL\")\r\n      else:\r\n        row_values.append(str(value))\r\n    output.append(\" | \".join(row_values))\r\n\r\n  return \"\\n\".join(output)<\/code><\/pre>\r\n<\/div>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">pyproject.toml<\/span><!-- notionvc: 0431a28f-ec9f-43b4-8108-bf2b8bfbe8e5 --><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-plain\" data-lang=\"Plain Text\"><code>[project]\r\nname = \"databricks_test\"\r\nversion = \"0.1.0\"\r\ndescription = \"Databricks Genie Integration\"\r\nrequires-python = \"&gt;=3.10\"\r\ndependencies = [\r\n\"httpx&gt;=0.28.1\",\r\n\"mcp[cli]&gt;=1.3.0\",\r\n]<\/code><\/pre>\r\n<\/div>\r\n<b><span style=\"font-family: arial, helvetica, sans-serif\">2. claude_desktop_config.json\u306b\u5148\u307b\u3069\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u5165\u308c\u308b<\/span><\/b>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">claude desktop\u958b\u767a\u8005\u7528\u306e\u8a2d\u5b9a\u304b\u3089\u69cb\u6210\u3092\u7de8\u96c6\u3092\u62bc\u3059\u3068\u3001claude_desktop_config.json\u306b\u8a98\u5c0e\u3055\u308c\u307e\u3059\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\"><!-- notionvc: 34cd625a-442a-4201-a9cc-2fb739689e4c --><\/span><\/p>\r\n<p><img decoding=\"async\" src=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.29.jpg\" alt=\"\" width=\"1536\" height=\"872\" class=\"alignnone size-full wp-image-6766\" srcset=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.29.jpg 1536w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.29-300x170.jpg 300w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.29-1024x581.jpg 1024w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.29-768x436.jpg 768w\" sizes=\"(max-width: 1536px) 100vw, 1536px\" \/><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u3053\u306e\u4e2d\u306b\u6b21\u306e\u30b3\u30fc\u30c9\u3092\u5165\u308c\u3066\u304f\u3060\u3055\u3044\u3002<\/span><!-- notionvc: 8f3f440a-8752-4f80-9c8f-ee5723f5e65a --><\/p>\r\n<div class=\"hcb_wrap\">\r\n<pre class=\"prism line-numbers lang-json\" data-lang=\"JSON\"><code>{\r\n\"mcpServers\": {\r\n\"databricks_genie_test\": {\r\n\"command\": \"uv\",\r\n\"args\": [\r\n\"--directory\",\r\n\"&lt;your directory to file&gt;\/my-genie-mcp\",\r\n\"run\",\r\n\"main.py\"\r\n],\r\n\"env\": {\r\n\"DATABRICKS_HOST\": \"&lt;your databricks host&gt;\",\r\n\"DATABRICKS_TOKEN\": \"&lt;your databricks token&gt;\",\r\n\"DATABRICKS_GENIE_SPACE_ID\": \"&lt;your genie space ID&gt;\"\r\n}\r\n}\r\n}\r\n}<\/code><\/pre>\r\n<\/div>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u3053\u308c\u3067\u8a2d\u5b9a\u5b8c\u4e86\u3067\u3059\uff01claude desktop\u3092\u518d\u8d77\u52d5\u3057\u3001\u518d\u5ea6\u958b\u767a\u8005\u7528\u306e\u8a2d\u5b9a\u3092\u958b\u304f\u3068\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306adatabricks_genie\u306emcp\u304c\u898b\u308c\u308b\u306f\u305a\u3067\u3059\u3002<\/span><\/p>\r\n<p><img decoding=\"async\" src=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.16.png\" alt=\"\" width=\"1580\" height=\"1110\" class=\"alignnone size-full wp-image-6767\" srcset=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.16.png 1580w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.16-300x211.png 300w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.16-1024x719.png 1024w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.16-768x540.png 768w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-12.45.16-1536x1079.png 1536w\" sizes=\"(max-width: 1580px) 100vw, 1580px\" \/><\/p>\r\n<p><!-- notionvc: bc7e0c44-3b36-4bed-a9d8-f4206e337771 --><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\uff12\u6bb5\u76ee\u306emcp\u304c\u4eca\u56de\u8a2d\u5b9a\u3057\u305f\u3082\u306e\u3002\uff11\u6bb5\u76ee\u306e\u8a2d\u5b9a\u306b\u3064\u3044\u3066\u306f\u524d\u56de\u306e\u30d6\u30ed\u30b0\u53c2\u7167<\/span><!-- notionvc: 160dc9eb-1408-4bc1-81b8-853d6394edb0 --><\/p>\n\n<h2>\u5b9f\u969b\u306b\u4f7f\u3063\u3066\u307f\u305f<\/h2>\n<p><span style=\"font-family: arial, helvetica, sans-serif\">databricks genie\u306b\u30e6\u30fc\u30b6\u30fc\u3054\u3068\u306e\u58f2\u4e0a\u3092\u805e\u3044\u3066\u3002\u3068\u3044\u3046\u8cea\u554f\u3092\u3057\u3066\u307f\u307e\u3057\u305f\uff01<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">claude \u304cgenie\u306b\u81ea\u7136\u8a00\u8a9e\u3067\u8cea\u554f\u3057\u3066\u3044\u307e\u3059\u306d\u3002\u30ec\u30b9\u30dd\u30f3\u30b9\u306e\u30c7\u30fc\u30bf\u306f\u3057\u3063\u304b\u308a\u53d6\u5f97\u3067\u304d\u3066\u3044\u307e\u3059\u3002<\/span><\/p>\r\n<p><img decoding=\"async\" src=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.11.33.png\" alt=\"\" width=\"1482\" height=\"1118\" class=\"alignnone size-full wp-image-6782\" srcset=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.11.33.png 1482w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.11.33-300x226.png 300w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.11.33-1024x772.png 1024w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.11.33-768x579.png 768w\" sizes=\"(max-width: 1482px) 100vw, 1482px\" \/> <img decoding=\"async\" src=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44.png\" alt=\"\" width=\"1518\" height=\"708\" class=\"alignnone size-full wp-image-6783\" srcset=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44.png 1518w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44-300x140.png 300w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44-1024x478.png 1024w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44-768x358.png 768w\" sizes=\"(max-width: 1518px) 100vw, 1518px\" \/><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u3057\u304b\u3057\u3001genie\u3078\u306e\u8cea\u554f\u306b\u3088\u3063\u3066\u306f\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5931\u6557\u3057\u3066\u3057\u307e\u3063\u3066\u3044\u307e\u3059\u3002\u3053\u308c\u306f\u300c\u30c7\u30fc\u30bf\u304c\u51fa\u529b\u3055\u308c\u306a\u304b\u3063\u305f\u300d\u5834\u5408\u8fd4\u3059\u3082\u306e\u304c\u306a\u304fNull\u306b\u306a\u3063\u3066\u3057\u307e\u3046\u304b\u3089\u3067\u3059\u306d\u3002\u3053\u306e\u70b9\u306fgenie\u3092\u4f7f\u3046\u3053\u3068\u306e\u5927\u304d\u306a\u554f\u984c\u70b9\u3068\u306a\u3063\u3066\u3044\u307e\u3059\u3002<\/span><!-- notionvc: 3b2a1e80-d234-42ca-b677-976e638f57cc --><\/p>\r\n<p><img decoding=\"async\" src=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44.png\" alt=\"\" width=\"1518\" height=\"708\" class=\"alignnone size-full wp-image-6783\" srcset=\"https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44.png 1518w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44-300x140.png 300w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44-1024x478.png 1024w, https:\/\/since2020.jp\/media\/wp-content\/uploads\/2025\/06\/\u30b9\u30af\u30ea\u30fc\u30f3\u30b7\u30e7\u30c3\u30c8-2025-06-12-13.13.44-768x358.png 768w\" sizes=\"(max-width: 1518px) 100vw, 1518px\" \/><\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p>&nbsp;<\/p>\r\n<p><!-- notionvc: 591ed122-749c-475e-a7c6-83aa9b155583 --><\/p>\n\n<h2>\u307e\u3068\u3081<\/h2>\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u4eca\u56de\u306fgenie\u3092\u4f7f\u3063\u305fMCP\u3092\u5b9f\u8df5\u3057\u3066\u307f\u307e\u3057\u305f\u3002\u5206\u6790\u3057\u305f\u3044\u30c7\u30fc\u30bf\u304c\u6c7a\u307e\u3063\u3066\u3044\u308b\u5834\u5408\u306f\u3053\u3061\u3089\u3082\u512a\u79c0\u3067\u3059\u306d\u3002<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u3053\u308c\u304b\u3089\u306fdesktop\u3067\u3060\u3051\u3067\u306f\u306a\u304f\u3001web\u4e0a\u3067\u4f7f\u3048\u308b\u6280\u8853\u3082\u51fa\u3066\u304d\u307e\u3057\u305f\u306e\u3067\u3001\u3055\u3089\u306b\u624b\u8efd\u306bLLM\u3092\u751f\u304b\u3057\u305f\u30c7\u30fc\u30bf\u5206\u6790\u304c\u3067\u304d\u308b\u4e16\u754c\u306b\u306a\u308b\u304b\u3082\uff1f<\/span><\/p>\r\n<p><span style=\"font-family: arial, helvetica, sans-serif\">\u6b21\u56de\u306fdatabricks\u3068claude\u306e\u4e8c\u3064\u306e\u63a5\u7d9a\u65b9\u6cd5\u3092\u305d\u308c\u305e\u308c\u9577\u6240\u3001\u77ed\u6240\u3092\u307e\u3068\u3081\u3066\u3044\u304d\u305f\u3044\u3068\u601d\u3044\u307e\u3059\u3002<\/span><\/p>\r\n<p><!-- notionvc: 70c4309e-1b24-481d-940e-b87fab0a26b5 --><\/p>","protected":false},"excerpt":{"rendered":"<p>\u3010databricks\u3011Claude MCP\u3092databricks\u3067\u4f7f\u3063\u3066\u307f\u305f2: Claude\u3068databricks LLM\u306egenie\u3068\u63a5\u7d9a\u3059\u308b\u65b9\u6cd5 \u521d\u3081\u306b MCP\u3068databricks\u306e\u8aac\u660e\u306b\u3064\u3044\u3066\u306f\u524d\u56de\u306e\u30d6\u30ed\u30b0\u3092 [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":6170,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"content-type":"","swell_btn_cv_data":"","footnotes":"","_wp_rev_ctl_limit":""},"categories":[1249],"tags":[96,774,987,39,26],"class_list":["post-6774","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-knowledge","tag-ai","tag-databricks","tag-mcp","tag-39","tag-26"],"_links":{"self":[{"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/posts\/6774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/comments?post=6774"}],"version-history":[{"count":1,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/posts\/6774\/revisions"}],"predecessor-version":[{"id":6786,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/posts\/6774\/revisions\/6786"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/media\/6170"}],"wp:attachment":[{"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/media?parent=6774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/categories?post=6774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/since2020.jp\/media\/wp-json\/wp\/v2\/tags?post=6774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}