Auto-indexing service and GraphQL API for AT Protocol Records quickslice.slices.network/
atproto gleam graphql
at main 135 lines 4.1 kB view raw
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}