README.mdโข6.68 kB
# ๐ญ SPARQL MCP server
[](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
```