Skip to main content
Glama
ramuzes

MCP Server for Apache Jena

jena-client.ts5.25 kB
import axios from 'axios'; import dotenv from 'dotenv'; import { SparqlHelper } from './sparql-helper.js'; dotenv.config(); const FUSEKI_URL = process.env.JENA_FUSEKI_URL || 'http://localhost:3030'; const DEFAULT_DATASET = process.env.DEFAULT_DATASET || 'ds'; const JENA_USERNAME = process.env.JENA_USERNAME || ''; const JENA_PASSWORD = process.env.JENA_PASSWORD || ''; /** * Represents the result of a SPARQL query */ export interface SparqlResult { head: { vars: string[]; }; results: { bindings: Array<{ [key: string]: { type: string; value: string; datatype?: string; "xml:lang"?: string; }; }>; }; } /** * Client for interacting with Apache Jena Fuseki SPARQL endpoint */ export class JenaClient { private baseUrl: string; private dataset: string; private username: string; private password: string; /** * Creates a new Jena client * @param baseUrl - Jena Fuseki server URL. Defaults to environment variable or 'http://localhost:3030' * @param dataset - Dataset name. Defaults to environment variable or 'ds' * @param username - Username for HTTP Basic authentication. Defaults to environment variable * @param password - Password for HTTP Basic authentication. Defaults to environment variable */ constructor( baseUrl = FUSEKI_URL, dataset = DEFAULT_DATASET, username = JENA_USERNAME, password = JENA_PASSWORD ) { this.baseUrl = baseUrl; this.dataset = dataset; this.username = username; this.password = password; } /** * Executes a SPARQL query against the Jena dataset * @param sparqlQuery - The SPARQL query to execute * @returns Query results */ async executeQuery(sparqlQuery: string): Promise<SparqlResult> { try { // Validate query before execution const validation = SparqlHelper.validateQuery(sparqlQuery); if (!validation.valid) { const errorMsg = `Invalid SPARQL query:\n${validation.errors.join('\n')}`; const suggestions = validation.suggestions.length > 0 ? `\n\nSuggestions:\n${validation.suggestions.join('\n')}` : ''; throw new Error(errorMsg + suggestions); } // Add performance suggestions as warnings (but don't block execution) const improvements = SparqlHelper.suggestImprovements(sparqlQuery); if (improvements.length > 0) { console.warn('💡 Query suggestions:', improvements.join(', ')); } const config: any = { params: { query: sparqlQuery, }, headers: { Accept: 'application/sparql-results+json', }, }; // Add authentication if credentials are provided if (this.username && this.password) { config.auth = { username: this.username, password: this.password }; } const response = await axios.get(`${this.baseUrl}/${this.dataset}/query`, config); return response.data; } catch (error) { if (axios.isAxiosError(error)) { const enhancedError = SparqlHelper.enhanceErrorMessage( `SPARQL query failed: ${error.message}. ${error.response?.data?.message || ''}`, sparqlQuery ); throw new Error(enhancedError); } throw error; } } /** * Executes a SPARQL update query against the Jena dataset * @param sparqlUpdate - The SPARQL update query to execute * @returns Success message */ async executeUpdate(sparqlUpdate: string): Promise<string> { try { // Basic validation for update queries const validation = SparqlHelper.validateQuery(sparqlUpdate); if (!validation.valid) { const errorMsg = `Invalid SPARQL update:\n${validation.errors.join('\n')}`; const suggestions = validation.suggestions.length > 0 ? `\n\nSuggestions:\n${validation.suggestions.join('\n')}` : ''; throw new Error(errorMsg + suggestions); } const config: any = { headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, }; // Add authentication if credentials are provided if (this.username && this.password) { config.auth = { username: this.username, password: this.password }; } await axios.post( `${this.baseUrl}/${this.dataset}/update`, new URLSearchParams({ update: sparqlUpdate }), config ); return 'Update successful'; } catch (error) { if (axios.isAxiosError(error)) { const enhancedError = SparqlHelper.enhanceErrorMessage( `SPARQL update failed: ${error.message}. ${error.response?.data?.message || ''}`, sparqlUpdate ); throw new Error(enhancedError); } throw error; } } /** * Lists all available graphs in the dataset * @returns Array of graph URIs */ async listGraphs(): Promise<string[]> { const query = ` SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o } } `; const result = await this.executeQuery(query); return result.results.bindings.map(binding => binding.g.value); } } export default JenaClient;

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ramuzes/mcp-jena'

If you have feedback or need assistance with the MCP directory API, please join our Discord server