Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1import gleam/json
2import gleam/list
3import gleam/result
4
5/// Tool definition for MCP
6pub type Tool {
7 Tool(name: String, description: String, input_schema: json.Json)
8}
9
10/// Get all available tools
11pub fn list_tools() -> List(Tool) {
12 [
13 Tool(
14 name: "list_lexicons",
15 description: "List all registered lexicons with their NSIDs and types",
16 input_schema: json.object([
17 #("type", json.string("object")),
18 #("properties", json.object([])),
19 ]),
20 ),
21 Tool(
22 name: "get_lexicon",
23 description: "Get full lexicon definition by NSID",
24 input_schema: json.object([
25 #("type", json.string("object")),
26 #(
27 "properties",
28 json.object([
29 #(
30 "nsid",
31 json.object([
32 #("type", json.string("string")),
33 #(
34 "description",
35 json.string("Lexicon NSID (e.g., app.bsky.feed.post)"),
36 ),
37 ]),
38 ),
39 ]),
40 ),
41 #("required", json.array(["nsid"], json.string)),
42 ]),
43 ),
44 Tool(
45 name: "list_queries",
46 description: "List available GraphQL queries and their arguments",
47 input_schema: json.object([
48 #("type", json.string("object")),
49 #("properties", json.object([])),
50 ]),
51 ),
52 Tool(
53 name: "get_oauth_info",
54 description: "Get supported OAuth flows, scopes, and endpoints",
55 input_schema: json.object([
56 #("type", json.string("object")),
57 #("properties", json.object([])),
58 ]),
59 ),
60 Tool(
61 name: "get_server_capabilities",
62 description: "Get server capabilities, version, and features",
63 input_schema: json.object([
64 #("type", json.string("object")),
65 #("properties", json.object([])),
66 ]),
67 ),
68 Tool(
69 name: "execute_query",
70 description: "Execute a GraphQL query. IMPORTANT: Use introspect_schema first to discover exact field names and enum values. Sort fields use camelCase (e.g., createdAt, not CREATED_AT). Example: sortBy: [{ field: createdAt, direction: DESC }]",
71 input_schema: json.object([
72 #("type", json.string("object")),
73 #(
74 "properties",
75 json.object([
76 #(
77 "query",
78 json.object([
79 #("type", json.string("string")),
80 #(
81 "description",
82 json.string(
83 "GraphQL query string. Use introspect_schema to discover available types, fields, and enum values before querying.",
84 ),
85 ),
86 ]),
87 ),
88 #(
89 "variables",
90 json.object([
91 #("type", json.string("object")),
92 #(
93 "description",
94 json.string("Query variables as JSON (optional)"),
95 ),
96 ]),
97 ),
98 ]),
99 ),
100 #("required", json.array(["query"], json.string)),
101 ]),
102 ),
103 Tool(
104 name: "introspect_schema",
105 description: "Get full GraphQL schema introspection. ALWAYS call this before execute_query to discover: available types, field names (camelCase), sort field values (camelCase like createdAt), and query arguments.",
106 input_schema: json.object([
107 #("type", json.string("object")),
108 #("properties", json.object([])),
109 ]),
110 ),
111 ]
112}
113
114/// Get a tool by name
115pub fn get_tool(name: String) -> Result(Tool, String) {
116 list_tools()
117 |> list.find(fn(t) { t.name == name })
118 |> result.replace_error("Tool not found: " <> name)
119}
120
121/// Encode tools list as MCP format
122pub fn encode_tools_list() -> json.Json {
123 json.object([
124 #(
125 "tools",
126 json.array(list_tools(), fn(tool) {
127 json.object([
128 #("name", json.string(tool.name)),
129 #("description", json.string(tool.description)),
130 #("inputSchema", tool.input_schema),
131 ])
132 }),
133 ),
134 ])
135}