|
10 | 10 | "This example aspires to verify the points listed in [POC - AI with Splunk Apps](https://cisco-my.sharepoint.com/:w:/r/personal/hbalacha_cisco_com/Documents/POC%20-%20AI%20with%20Splunk%20Apps.docx?d=w2776e089011943abbd84c0fa30a53f34&csf=1&web=1&e=RxvShR)\n",
|
11 | 11 | "\n",
|
12 | 12 | "- Develop @tool Decorator\n",
|
13 |
| - " - [ ] Capture e.g. tool_name, description, inputs, outputs\n", |
14 |
| - "- MCP JSONSchema can (and most probably should) be used for tool registration in Splunk\n" |
| 13 | + " - [ ] Capture e.g. tool_name, description, inputs, outputs\n" |
| 14 | + ] |
| 15 | + }, |
| 16 | + { |
| 17 | + "cell_type": "code", |
| 18 | + "execution_count": null, |
| 19 | + "id": "18ab5550", |
| 20 | + "metadata": {}, |
| 21 | + "outputs": [], |
| 22 | + "source": [] |
| 23 | + }, |
| 24 | + { |
| 25 | + "cell_type": "markdown", |
| 26 | + "id": "363201e8", |
| 27 | + "metadata": {}, |
| 28 | + "source": [ |
| 29 | + "- MCP JSONSchema can (and most probably should) be used for tool registration in Splunk" |
15 | 30 | ]
|
16 | 31 | },
|
17 | 32 | {
|
|
98 | 113 | " - [ ] Call MCP registry with credentials (from App Manager)\n",
|
99 | 114 | " - [ ] Log success/fail to MCP audit\n"
|
100 | 115 | ]
|
101 |
| - }, |
102 |
| - { |
103 |
| - "cell_type": "code", |
104 |
| - "execution_count": null, |
105 |
| - "id": "2e594272", |
106 |
| - "metadata": {}, |
107 |
| - "outputs": [ |
108 |
| - { |
109 |
| - "name": "stdout", |
110 |
| - "output_type": "stream", |
111 |
| - "text": [ |
112 |
| - "/Users/bjedreck/Projects/spl-mcp-tool/bin/../default/app.conf\n", |
113 |
| - "name='aws_logs_search' title=None description='Execute SPL queries against AWS logs' inputSchema={'type': 'object', 'properties': {}, 'required': []} outputSchema={'type': 'object', 'properties': {}, 'required': []} icons=None annotations=None meta={'permissions': ['role:search_admin', 'role:aws_analyst'], 'tool_type': 'search', 'schema_version': '1.0'}\n" |
114 |
| - ] |
115 |
| - } |
116 |
| - ], |
117 |
| - "source": [ |
118 |
| - "import configparser\n", |
119 |
| - "import os\n", |
120 |
| - "from dataclasses import asdict, dataclass, field\n", |
121 |
| - "from typing import Any, Literal\n", |
122 |
| - "\n", |
123 |
| - "from mcp.types import Tool\n", |
124 |
| - "\n", |
125 |
| - "\n", |
126 |
| - "@dataclass\n", |
127 |
| - "class SplunkMeta:\n", |
128 |
| - " permissions: list[str]\n", |
129 |
| - " tool_type: str\n", |
130 |
| - " schema_version: str\n", |
131 |
| - "\n", |
132 |
| - "\n", |
133 |
| - "@dataclass\n", |
134 |
| - "class McpInputOutputSchema:\n", |
135 |
| - " type: Literal[\"object\"] = \"object\"\n", |
136 |
| - " properties: dict[str, Any] = field(default_factory=lambda: {}) # pyright: ignore[reportExplicitAny]\n", |
137 |
| - " required: list[str] = field(default_factory=lambda: [])\n", |
138 |
| - "\n", |
139 |
| - "\n", |
140 |
| - "tool_reg_prefix = \"app:mcp_tool\"\n", |
141 |
| - "\n", |
142 |
| - "\n", |
143 |
| - "def filter_sections(section_name: str):\n", |
144 |
| - " return section_name.startswith(tool_reg_prefix)\n", |
145 |
| - "\n", |
146 |
| - "\n", |
147 |
| - "def match_input_schema(input: Literal[\"query_string\"] | Literal[\"other\"]):\n", |
148 |
| - " match input:\n", |
149 |
| - " case \"query_string\":\n", |
150 |
| - " return {\n", |
151 |
| - " \"type\": \"object\",\n", |
152 |
| - " \"properties\": {\n", |
153 |
| - " \"query_string\": {\n", |
154 |
| - " \"type\": \"string\",\n", |
155 |
| - " \"description\": \"SPL2 query string\",\n", |
156 |
| - " }\n", |
157 |
| - " },\n", |
158 |
| - " }\n", |
159 |
| - " case _:\n", |
160 |
| - " raise NotImplementedError(\"We don't know what to put here lol\")\n", |
161 |
| - "\n", |
162 |
| - "\n", |
163 |
| - "def parse_app_conf_tool_registrations(file_path: str) -> list[Tool]:\n", |
164 |
| - " config = configparser.ConfigParser()\n", |
165 |
| - " all_sections_len = config.read(file_path)\n", |
166 |
| - " if len(all_sections_len) == 0:\n", |
167 |
| - " return []\n", |
168 |
| - "\n", |
169 |
| - " tool_reg_sections: list[str] = list(filter(filter_sections, config.sections()))\n", |
170 |
| - " if len(tool_reg_sections) == 0:\n", |
171 |
| - " return []\n", |
172 |
| - "\n", |
173 |
| - " ini_tools: list[Tool] = []\n", |
174 |
| - " for reg_section in tool_reg_sections:\n", |
175 |
| - " reg_section_data = config[reg_section]\n", |
176 |
| - "\n", |
177 |
| - " name: str = reg_section.split(\":\")[2]\n", |
178 |
| - " description = reg_section_data[\"description\"]\n", |
179 |
| - " # https://modelcontextprotocol.io/specification/2025-06-18/schema#tool\n", |
180 |
| - " inputSchema = McpInputOutputSchema(properties={}, required=[])\n", |
181 |
| - " outputSchema = McpInputOutputSchema(properties={}, required=[])\n", |
182 |
| - " meta = SplunkMeta(\n", |
183 |
| - " permissions=[\n", |
184 |
| - " perm.strip()\n", |
185 |
| - " for perm in reg_section_data[\"permissions\"].strip().split(\",\")\n", |
186 |
| - " ],\n", |
187 |
| - " tool_type=\"search\",\n", |
188 |
| - " schema_version=reg_section_data[\"schema_version\"].strip(),\n", |
189 |
| - " )\n", |
190 |
| - "\n", |
191 |
| - " ini_tool = Tool(\n", |
192 |
| - " name=name,\n", |
193 |
| - " description=description,\n", |
194 |
| - " inputSchema=asdict(inputSchema),\n", |
195 |
| - " outputSchema=asdict(outputSchema),\n", |
196 |
| - " _meta=asdict(meta),\n", |
197 |
| - " )\n", |
198 |
| - " ini_tools.append(ini_tool)\n", |
199 |
| - "\n", |
200 |
| - " return ini_tools\n", |
201 |
| - "\n", |
202 |
| - "\n", |
203 |
| - "async def post_install():\n", |
204 |
| - " curr_path = os.path.join(os.getcwd(), \"..\", \"default\", \"app.conf\")\n", |
205 |
| - " print(curr_path)\n", |
206 |
| - " yaml_tool_registrations: list[Tool] = parse_app_conf_tool_registrations(curr_path)\n", |
207 |
| - " [print(toolReg) for toolReg in yaml_tool_registrations]\n", |
208 |
| - "\n", |
209 |
| - "\n", |
210 |
| - "await post_install()\n" |
211 |
| - ] |
212 | 116 | }
|
213 | 117 | ],
|
214 | 118 | "metadata": {
|
|
0 commit comments