languages
Query and filter language data using GraphQL to integrate and manage multilingual content in applications via the MCP server.
Instructions
GraphQL languages query
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No | filter - Input type: LanguageFilterInput |
Implementation Reference
- src/graphql-mcp-server.ts:1057-1076 (registration)The 'tools/list' RPC handler fetches the GraphQL schema and generates the list of available tools using getToolsFromSchema(), which dynamically includes the 'languages' tool corresponding to the 'languages' query field.const schema = await fetchSchema(); const queryTools = getToolsFromSchema(schema); // Only include mutations if they are enabled const mutationTools = ENABLE_MUTATIONS ? getToolsFromMutationType(schema) : []; const allTools = [...queryTools, ...mutationTools]; log( "info", `Returning ${allTools.length} tools (${queryTools.length} queries, ${mutationTools.length} mutations${!ENABLE_MUTATIONS ? ' - mutations disabled' : ''})` ); const response: JSONRPCResponse = { jsonrpc: "2.0", id, result: { tools: allTools, }, }; console.log(JSON.stringify(response));
- src/graphql-mcp-server.ts:389-407 (schema)Within getToolsFromSchema(), this code block creates the MCPTool definition for each query field (including 'languages'), setting its name, description, and inputSchema derived from the field's GraphQL arguments.// Create a tool for this field - Truncate name to 64 characters if needed const truncatedName = fieldName.length > 64 ? fieldName.substring(0, 64) : fieldName; // Store mapping from truncated to original name if truncation occurred if (truncatedName !== fieldName) { toolNameMappings[truncatedName] = fieldName; } const tool: MCPTool = { name: truncatedName, description: field.description || `GraphQL ${fieldName} query`, inputSchema: { type: "object", properties: properties, required: required, }, };
- src/graphql-mcp-server.ts:1086-1100 (handler)In the 'tools/call' RPC handler, tool calls are dispatched based on name; for 'languages' (not a mutation), it calls executeGraphQLTool(name, args).const isMutation = name.startsWith("mutation_"); // Check if mutations are enabled if (isMutation && !ENABLE_MUTATIONS) { log("error", `Mutation ${name} called but mutations are disabled`); const response: JSONRPCResponse = { jsonrpc: "2.0", id, error: { code: -32000, message: "Mutations are disabled. Set ENABLE_MUTATIONS=true to enable them.", }, }; console.log(JSON.stringify(response)); return;
- src/graphql-mcp-server.ts:729-845 (handler)The core handler function for query tools like 'languages'. It fetches the schema, looks up the GraphQL field by name, processes arguments, dynamically generates a GraphQL query (including selection set via analyzeFields), and executes it.async function executeGraphQLTool( name: string, args: Record<string, any> | undefined ): Promise<any> { try { // If this name is in our mapping, use the original field name const actualFieldName = toolNameMappings[name] || name; // Check if the tool is in the whitelist (if whitelist is enabled) if (WHITELISTED_QUERIES && !WHITELISTED_QUERIES.includes(actualFieldName)) { throw new Error(`Tool '${actualFieldName}' is not in the whitelist`); } // Get the schema const schema = await fetchSchema(); if (!schema) { throw new Error("Schema not available"); } // Get the query type const queryType = schema.getQueryType(); if (!queryType) { throw new Error("Schema has no query type"); } // Get the field for this tool using the resolved field name const fields = queryType.getFields(); const field = fields[actualFieldName]; if (!field) { throw new Error(`Unknown field: ${actualFieldName}`); } try { // Process input arguments const processedArgs = processArguments(args, field.args, schema); // Get return type and analyze it const returnType = getNamedType(field.type); // First determine which arguments are actually being used const usedArgNames: string[] = []; field.args.forEach((arg) => { if (processedArgs && processedArgs[arg.name] !== undefined) { usedArgNames.push(arg.name); } }); // Build variables definition - only for arguments that are actually used const varDefs = field.args .filter((arg) => usedArgNames.includes(arg.name)) .map((arg) => { // Need to preserve non-null and list wrappers in variable definitions const typeStr = arg.type.toString(); return `$${arg.name}: ${typeStr}`; }) .filter(Boolean) .join(", "); // Build field arguments - only for arguments that are actually used const fieldArgs = usedArgNames .map((argName) => { return `${argName}: $${argName}`; }) .join(", "); // Build selection set based on return type let selectionSet = ""; if (isObjectType(returnType)) { // For objects or lists of objects, analyze fields const fields = analyzeFields(returnType, schema); selectionSet = buildSelectionSet(fields); } else if (isListType(returnType)) { // For lists, unwrap and analyze the inner type const innerType = getNamedType(returnType.ofType); if (isObjectType(innerType)) { const fields = analyzeFields(innerType as GraphQLObjectType, schema); selectionSet = buildSelectionSet(fields); } } // Build the final query // Only include variable definitions if fieldArgs is used const shouldIncludeVarDefs = fieldArgs && fieldArgs.length > 0; const query = ` query ${name}Query${shouldIncludeVarDefs ? `(${varDefs})` : ""} { ${name}${fieldArgs && fieldArgs.length > 0 ? `(${fieldArgs})` : ""} ${ selectionSet ? `{\n${selectionSet} }` : "" } } `; log("debug", `Generated query for ${name}:`, { query, variables: processedArgs, }); // Execute the query return await executeQuery({ query, variables: processedArgs }); } catch (error) { throw new Error( `Error executing query for ${name}: ${ error instanceof Error ? error.message : String(error) }` ); } } catch (error) { log( "error", `Error executing tool ${name}: ${ error instanceof Error ? error.message : String(error) }` ); throw error; } }