Skip to main content
Glama
sib-swiss

SPARQL MCP Server

by sib-swiss
README.md
# ๐Ÿ”ญ SPARQL MCP server

[![Build](https://github.com/sib-swiss/sparql-mcp/actions/workflows/build.yml/badge.svg)](https://github.com/sib-swiss/sparql-mcp/actions/workflows/build.yml)

A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server to help users write SPARQL queries for open-access SPARQL endpoints, developed for the [SIB Expasy portal](https://expasy.org).

The server will automatically index metadata present in the list of SPARQL endpoints defined in a JSON config file, such as:

- [SPARQL query examples](https://github.com/sib-swiss/sparql-examples),
- Endpoints schema using the [Vocabulary of Interlinked Datasets (VoID)](https://www.w3.org/TR/void/), which can be automatically generated using the [void-generator](https://github.com/JervenBolleman/void-generator).

## ๐Ÿงฉ Endpoints

The HTTP API comprises 2 main endpoints:

- `/mcp`: **MCP server** that searches for relevant data to answer a user question using the EOSC Data Commons search API
  - Uses [`rmcp`](https://github.com/modelcontextprotocol/rust-sdk) with Streamable HTTP transport
  - ๐Ÿงฐ Available tools:
    - [x] `access_sparql_resources`: retrieve relevant information about the resources to help build a SPARQL query to answer the question (query examples, classes schema)
    - [x] `get_resources_info`: retrieve relevant information about the SPARQL endpoints resources themselves (e.g. description, list of available endpoints)
    - [x] `execute_sparql`: execute a SPARQL query against a given endpoint

- `/chat`: optional **HTTP POST** endpoint (JSON) to query the MCP server via an LLM provider
  - Uses [`axum`](https://github.com/tokio-rs/axum), [`utoipa`](https://github.com/juhaku/utoipa) for OpenAPI spec generation, [`llm`](https://github.com/graniet/llm) to interact with LLM providers (e.g. [Mistral](https://admin.mistral.ai/organization/api-keys), OpenAI)
  - Supports streaming response: tool call requested, then tool call results, and final search results.

## ๐Ÿš€ Use

Use it through the `sparql-mcp` package on pip:

```sh
uvx sparql-mcp ./sparql-mcp.json
```

Or download the binary corresponding to your architecture from the releases page.

## ๐Ÿ› ๏ธ Development

> [!IMPORTANT]
>
> Requirements:
>
> - [Rust](https://www.rust-lang.org/tools/install)
> - Protobuf installed (e.g. `brew install protobuf`)
> - API key for a LLM provider: [Mistral.ai](https://console.mistral.ai/api-keys) or OpenAI, you can use the free tier, you just need to login
>
> Recommend VSCode extension: [`rust-analyzer`](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)

### ๐Ÿ“ฅ Install dev dependencies

```sh
rustup update
cargo install cargo-release cargo-deny cargo-watch git-cliff
```

Create a `.cargo/config.toml` file with your [Mistral API key](https://admin.mistral.ai/organization/api-keys) or OpenAI API key:

```toml
[env]
MISTRAL_API_KEY = "YOUR_API_KEY"
OPENAI_API_KEY = "YOUR_API_KEY"
GROQ_API_KEY = "YOUR_API_KEY"
```

### โšก๏ธ Start dev server

Start the **MCP server** in dev at http://localhost:8000/mcp, with OpenAPI UI at http://localhost:8000/docs

```sh
cargo run
```

Customize server configuration through CLI arguments:

```sh
cargo run -- --force-index --mcp-only --db-path ./data/lancedb
```

Provide a custom list of servers through a `.json` file with:

```sh
cargo run -- ./sparql-mcp.json
```

Example `sparql-mcp.json`:

```json
{
  "endpoints": [
    {
      "label": "UniProt",
      "endpoint_url": "https://sparql.uniprot.org/sparql/",
      "description": "UniProt is a comprehensive resource for protein sequence and annotation data."
    },
    {
      "label": "Bgee",
      "endpoint_url": "https://www.bgee.org/sparql/",
      "description": "Bgee is a database for retrieval and comparison of gene expression patterns across multiple animal species.",
      "homepage_url": "https://www.bgee.org/"
    }
  ]
}
```

> [!TIP]
>
> Run and reload on change to the code:
>
> ```sh
> cargo watch -x run
> ```
>

> [!NOTE]
>
> Example `curl` request:
>
> ```sh
> curl -X POST http://localhost:8000/search -H "Content-Type: application/json" -H "Authorization: SECRET_KEY" -d '{"messages": [{"role": "user", "content": "What is the HGNC symbol for the P68871 protein?"}], "model": "mistral/mistral-small-latest", "stream": true}'
> ```
>
> Recommended model per supported provider:
>
> - `openai/gpt-4.1`
> - `mistralai/mistral-large-latest`
> - `groq/moonshotai/kimi-k2-instruct`

### ๐Ÿ”Œ Connect MCP client

Follow the instructions of your client, and use the `/mcp` URL of your deployed server (e.g. http://localhost:8000/mcp)

#### ๐Ÿ™ VSCode GitHub Copilot

Add a new MCP server through the VSCode UI:

- Open the Command Palette (`ctrl+shift+p` or `cmd+shift+p`)
- Search for `MCP: Add Server...`
- Choose `HTTP`, and provide the MCP server URL http://localhost:8000/mcp

Your VSCode `mcp.json` should look like:

```json
{
    "servers": {
        "sparql-mcp-server": {
            "url": "http://localhost:8000/mcp",
            "type": "http"
        }
    },
    "inputs": []
}
```

### ๐Ÿ“ฆ Build for production

Build binary in `target/release/`

```sh
cargo build --release
```

> [!NOTE]
>
> Start the server with (change flags at your convenience):
>
> ```sh
> ./target/release/sparql-mcp ./sparql-mcp.json --force-index
> ```
>
> Start using the python wheel:
>
> ```sh
> uvx --from ./target/release/sparql_mcp-0.1.0-py3-none-any.whl . sparql-mcp
> ```

## ๐Ÿ Build python package

> Require [`uv`](https://docs.astral.sh/uv/getting-started/installation/) installed

Bundle the CLI as python package in `target/wheels`:

```sh
uvx maturin build
```

### ๐Ÿณ Deploy with Docker

Create a `keys.env` file with the API keys:

```sh
MISTRAL_API_KEY=YOUR_API_KEY
SEARCH_API_KEY=SECRET_KEY_YOU_CAN_USE_IN_FRONTEND_TO_AVOID_SPAM
```

> [!TIP]
>
> `SEARCH_API_KEY` can be used to add a layer of protection against bots that might spam the LLM, if not provided no API key will be needed to query the API.

Build and deploy the service:

```sh
docker compose up
```

### ๐Ÿงผ Format & lint

Automatically format the codebase using `rustfmt`:

```sh
cargo fmt
```

Lint with `clippy`:

```sh
cargo clippy --all
```

Automatically apply possible fixes:

```sh
cargo fix
```

### โ›“๏ธ Check supply chain

Check the dependency supply chain: licenses (only accept dependencies with OSI or FSF approved licenses), and vulnerabilities (CVE advisories).

```sh
cargo deny check
```

Update dependencies in `Cargo.lock`:

```sh
cargo update
```

### ๐Ÿท๏ธ Release

Dry run:

```sh
cargo release patch
```

> Or `minor` / `major`

Create release:

```sh
cargo release patch --execute
```

Maintenance

ActivityInactive
ResponsivenessNo issues