tools.sql 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. -- Copyright Materialize, Inc. and contributors. All rights reserved.
  2. --
  3. -- Licensed under the Apache License, Version 2.0 (the "License");
  4. -- you may not use this file except in compliance with the License.
  5. -- You may obtain a copy of the License in the LICENSE file at the
  6. -- root of this repository, or online at
  7. --
  8. -- http://www.apache.org/licenses/LICENSE-2.0
  9. --
  10. -- Unless required by applicable law or agreed to in writing, software
  11. -- distributed under the License is distributed on an "AS IS" BASIS,
  12. -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. -- See the License for the specific language governing permissions and
  14. -- limitations under the License.
  15. --
  16. -- ############################################################
  17. -- MCP Tools Definition Query
  18. -- ############################################################
  19. --
  20. -- This SQL query dynamically discovers all user-accessible indexes in your Materialize instance
  21. -- and translates each into a “tool” for the Model Context Protocol (MCP).
  22. -- For each index, it:
  23. -- 1. Builds a unique tool name based on the database, schema, and index name.
  24. -- 2. Gathers privileges to ensure only SELECT- and USAGE-permitted objects are included.
  25. -- 3. Retrieves object and column comments to annotate the tool with human-readable descriptions.
  26. -- 4. Constructs a JSON Schema for the tool’s input parameters (key columns) with
  27. -- appropriate types (number, string, boolean, date, etc.) and descriptions.
  28. -- 5. Lists the remaining indexed columns as the tool’s output values.
  29. --
  30. -- The final output is one row per index containing:
  31. -- - name: Unique MCP tool identifier
  32. -- - database: Origin database name
  33. -- - schema: Origin schema name
  34. -- - object_name: Underlying table or view name
  35. -- - cluster: Materialize cluster hosting the index
  36. -- - description: Object-level comment used as the tool description
  37. -- - input_schema: JSON Schema object defining required input fields
  38. -- - output_columns: Array of non-key columns returned by the tool
  39. --
  40. WITH tools AS (
  41. SELECT
  42. op.database || '_' || op.schema || '_' || i.name AS name,
  43. op.database,
  44. op.schema,
  45. op.name AS object_name,
  46. c.name AS cluster,
  47. cts.comment AS description,
  48. op.database || '::' || op.schema || '::' || op.name || '(' || string_agg(distinct ccol.name, ',') FILTER (WHERE ccol.position = ic.on_position) || ')' AS title,
  49. jsonb_build_object(
  50. 'type', 'object',
  51. 'required', jsonb_agg(distinct ccol.name) FILTER (WHERE ccol.position = ic.on_position),
  52. 'properties', jsonb_strip_nulls(jsonb_object_agg(
  53. ccol.name,
  54. CASE
  55. WHEN ccol.type IN (
  56. 'uint2', 'uint4','uint8', 'int', 'integer', 'smallint',
  57. 'double', 'double precision', 'bigint', 'float',
  58. 'numeric', 'real'
  59. ) THEN jsonb_build_object(
  60. 'type', 'number',
  61. 'description', cts_col.comment
  62. )
  63. WHEN ccol.type = 'boolean' THEN jsonb_build_object(
  64. 'type', 'boolean',
  65. 'description', cts_col.comment
  66. )
  67. WHEN ccol.type = 'bytea' THEN jsonb_build_object(
  68. 'type', 'string',
  69. 'description', cts_col.comment,
  70. 'contentEncoding', 'base64',
  71. 'contentMediaType', 'application/octet-stream'
  72. )
  73. WHEN ccol.type = 'date' THEN jsonb_build_object(
  74. 'type', 'string',
  75. 'format', 'date',
  76. 'description', cts_col.comment
  77. )
  78. WHEN ccol.type = 'time' THEN jsonb_build_object(
  79. 'type', 'string',
  80. 'format', 'time',
  81. 'description', cts_col.comment
  82. )
  83. WHEN ccol.type ilike 'timestamp%%' THEN jsonb_build_object(
  84. 'type', 'string',
  85. 'format', 'date-time',
  86. 'description', cts_col.comment
  87. )
  88. WHEN ccol.type = 'jsonb' THEN jsonb_build_object(
  89. 'type', 'object',
  90. 'description', cts_col.comment
  91. )
  92. WHEN ccol.type = 'uuid' THEN jsonb_build_object(
  93. 'type', 'string',
  94. 'format', 'uuid',
  95. 'description', cts_col.comment
  96. )
  97. ELSE jsonb_build_object(
  98. 'type', 'string',
  99. 'description', cts_col.comment
  100. )
  101. END
  102. ) FILTER (WHERE ccol.position = ic.on_position))
  103. ) AS input_schema,
  104. jsonb_build_object(
  105. 'type', 'object',
  106. 'required', jsonb_build_array('rows'),
  107. 'properties', jsonb_build_object(
  108. 'rows', jsonb_build_object(
  109. 'type', 'array',
  110. 'items', jsonb_build_object(
  111. 'type', 'object',
  112. 'required', jsonb_agg(distinct ccol.name) FILTER (WHERE ccol.position <> ic.on_position),
  113. 'properties', jsonb_strip_nulls(jsonb_object_agg(
  114. ccol.name,
  115. CASE
  116. WHEN ccol.type IN (
  117. 'uint2', 'uint4','uint8', 'int', 'integer', 'smallint',
  118. 'double', 'double precision', 'bigint', 'float',
  119. 'numeric', 'real'
  120. ) THEN jsonb_build_object(
  121. 'type', 'number',
  122. 'description', cts_col.comment
  123. )
  124. WHEN ccol.type = 'boolean' THEN jsonb_build_object(
  125. 'type', 'boolean',
  126. 'description', cts_col.comment
  127. )
  128. WHEN ccol.type = 'bytea' THEN jsonb_build_object(
  129. 'type', 'string',
  130. 'description', cts_col.comment,
  131. 'contentEncoding', 'base64',
  132. 'contentMediaType', 'application/octet-stream'
  133. )
  134. WHEN ccol.type = 'date' THEN jsonb_build_object(
  135. 'type', 'string',
  136. 'format', 'date',
  137. 'description', cts_col.comment
  138. )
  139. WHEN ccol.type = 'time' THEN jsonb_build_object(
  140. 'type', 'string',
  141. 'format', 'time',
  142. 'description', cts_col.comment
  143. )
  144. WHEN ccol.type ilike 'timestamp%%' THEN jsonb_build_object(
  145. 'type', 'string',
  146. 'format', 'date-time',
  147. 'description', cts_col.comment
  148. )
  149. WHEN ccol.type = 'jsonb' THEN jsonb_build_object(
  150. 'type', 'object',
  151. 'description', cts_col.comment
  152. )
  153. WHEN ccol.type = 'uuid' THEN jsonb_build_object(
  154. 'type', 'string',
  155. 'format', 'uuid',
  156. 'description', cts_col.comment
  157. )
  158. ELSE jsonb_build_object(
  159. 'type', 'string',
  160. 'description', cts_col.comment
  161. )
  162. END
  163. ) FILTER (WHERE ccol.position <> ic.on_position))
  164. )
  165. )
  166. )
  167. ) AS output_schema,
  168. array_agg(distinct ccol.name) FILTER (WHERE ccol.position <> ic.on_position) AS output_columns
  169. FROM mz_internal.mz_show_my_object_privileges op
  170. JOIN mz_objects o ON op.name = o.name AND op.object_type = o.type
  171. JOIN mz_schemas s ON s.name = op.schema AND s.id = o.schema_id
  172. JOIN mz_databases d ON d.name = op.database AND d.id = s.database_id
  173. JOIN mz_indexes i ON i.on_id = o.id
  174. JOIN mz_index_columns ic ON i.id = ic.index_id
  175. JOIN mz_columns ccol ON ccol.id = o.id
  176. JOIN mz_clusters c ON c.id = i.cluster_id
  177. JOIN mz_internal.mz_show_my_cluster_privileges cp ON cp.name = c.name
  178. JOIN mz_internal.mz_comments cts ON cts.id = o.id AND cts.object_sub_id IS NULL
  179. LEFT JOIN mz_internal.mz_comments cts_col ON cts_col.id = o.id AND cts_col.object_sub_id = ccol.position
  180. WHERE op.privilege_type = 'SELECT'
  181. AND cp.privilege_type = 'USAGE'
  182. GROUP BY 1,2,3,4,5,6
  183. )
  184. SELECT * FROM tools