OntoPortal MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@OntoPortal MCP ServerSearch for 'photosynthesis' across all ontologies"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
agroportal-mcp
An MCP server that exposes the
AgroPortal / OntoPortal API as tools for LLM
clients (Claude Desktop, Claude Code, …). It is a thin wrapper around the
ontologies_api_client Ruby gem, served with
the official mcp gem over stdio (for local
clients) or Streamable HTTP / SSE (for remote deployment).
Tools
Tool | Description |
| Full-text search over ontology classes/concepts. Returns label, URI, source ontology, and definition. Supports restricting to specific ontologies and (optionally) federated search across other OntoPortal instances. |
| List the ontologies available on the portal, optionally filtered by a case-insensitive match on acronym or name. Returns acronym, name, and URI. Supports federation. |
| Fetch a single class/concept by its URI within an ontology. Returns preferred label, definition(s), synonyms, obsolete status, and whether it has children. Accepts a |
| Get an ontology submission's metadata: version, status, format, dates, license, homepage/documentation, namespace & version IRI, natural languages, keywords, abstract, and description. Defaults to the latest submission; pass |
| List ontology submissions with their metadata. Pass an |
| Get size/structure metrics for a submission: class, individual, and property counts plus hierarchy stats (max depth, max/average child count). Defaults to the latest submission. (For SKOS vocabularies, concepts count as individuals.) |
More tools (e.g. search_ontologies, mappings, notes) can be added under
lib/agroportal_mcp/tools/ and registered in TOOLS (lib/agroportal_mcp.rb).
Related MCP server: OMOPHub MCP Server
Requirements
Ruby ≥ 2.7 (this project was set up with Homebrew Ruby at
/usr/local/opt/ruby/bin/ruby).A checkout of
ontologies_api_ruby_clientas a sibling directory (theGemfilereferences it viapath: '../ontologies_api_ruby_client').An AgroPortal API key (create one from your AgroPortal account page).
Install
export PATH="/usr/local/opt/ruby/bin:$PATH"
cd ontologies_api_mcp
bundle installConfiguration
The server reads its connection settings from the environment:
Variable | Required | Default | Notes |
| yes | — | Your API key. |
| no |
| Point at another OntoPortal API to target a different portal. |
| no | — | Enables the |
| no | — | HTTP transport only. When set, every request must send |
| no |
| HTTP transport only. |
| no |
| HTTP transport only. |
Smoke test
You can drive the stdio protocol by hand:
export AGROPORTAL_API_KEY=your_key
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_classes","arguments":{"query":"wheat","pagesize":3}}}' \
| /usr/local/opt/ruby/bin/ruby bin/agroportal_mcpRegister with an MCP client
Claude Code (CLI)
claude mcp add agroportal \
--env AGROPORTAL_API_KEY=your_key \
-- /usr/local/opt/ruby/bin/ruby \
/Users/maboukerfa/code/agroportal/ontologies_api_mcp/bin/agroportal_mcpClaude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"agroportal": {
"command": "/usr/local/opt/ruby/bin/ruby",
"args": [
"/Users/maboukerfa/code/agroportal/ontologies_api_mcp/bin/agroportal_mcp"
],
"env": {
"AGROPORTAL_API_KEY": "your_key",
"AGROPORTAL_REST_URL": "https://data.agroportal.eu"
}
}
}
}The entrypoint pins BUNDLE_GEMFILE to this project, so it can be launched from
any working directory.
Remote deployment (Streamable HTTP / SSE)
To serve the same tools to remote clients, run the MCP Streamable HTTP
transport instead of stdio. It uses SSE (text/event-stream) for streaming
server responses, and replaces the deprecated standalone HTTP+SSE transport.
config.ru mounts the server as a Rack app; install the http group
(bundle install does this by default) and run it under Puma:
export AGROPORTAL_API_KEY=your_key
export AGROPORTAL_MCP_BEARER_TOKEN=$(openssl rand -hex 32) # recommended
bundle exec puma config.ru -p 9292The endpoint serves JSON-RPC at the root path. Smoke-test the handshake (drop
the Authorization header if you left the token unset):
# 1) initialize — capture the Mcp-Session-Id from the response headers
curl -sN -i -X POST http://127.0.0.1:9292/ \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "Authorization: Bearer $AGROPORTAL_MCP_BEARER_TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}'
# 2) tools/list — reuse the session id from step 1 (response streams back as SSE)
curl -sN -X POST http://127.0.0.1:9292/ \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H "Authorization: Bearer $AGROPORTAL_MCP_BEARER_TOKEN" \
-H 'Mcp-Session-Id: <id-from-step-1>' \
-H 'MCP-Protocol-Version: 2025-11-25' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'Operational notes:
Terminate TLS in front. Run it behind a reverse proxy (nginx/Caddy) or load balancer that handles HTTPS — the bearer token is only as safe as the transport.
Don't expose it unauthenticated. With
AGROPORTAL_MCP_BEARER_TOKENunset the endpoint is open (and warns at boot). Set it, or front it with an authenticating proxy.Concurrency. In the default stateful mode each connected client holds a long-lived SSE stream open, which ties up a Puma thread; size
--threads(or setAGROPORTAL_MCP_STATELESS=true) to match expected concurrency. For many concurrent SSE streams, Falcon (fiber-based) scales better and serves the sameconfig.ru— addgem 'falcon'to the:httpgroup, thenbundle exec falcon serve -b http://0.0.0.0:9292.
Register the remote server with Claude Code:
claude mcp add --transport http agroportal https://your-host.example/ \
--header "Authorization: Bearer your_token"Multi-tenant: per-user API keys
Host one shared instance and let each user authenticate with their own AgroPortal
key. The server uses its own AGROPORTAL_API_KEY as the base credential and
forwards each caller's key as userapikey, so the API attributes requests —
permissions, rate limits, private ontologies — to that user.
export AGROPORTAL_API_KEY=server_app_key # must be allowed to use userapikey (see below)
export AGROPORTAL_MCP_REQUIRE_USER_APIKEY=true # reject requests with no user key
export AGROPORTAL_MCP_STATELESS=true # recommended for multi-tenant
bundle exec puma config.ru -p 9292Each user registers with their own key in the X-Agroportal-User-Apikey header:
claude mcp add --transport http agroportal https://mcp.agroportal.eu/ \
--header "X-Agroportal-User-Apikey: <their_personal_key>"The key is read per request and forwarded by the client's user_apikey
middleware, producing Authorization: apikey token=<server>&userapikey=<user>.
Thread#[] is fiber-local, so requests stay isolated under both Puma and Falcon.
Requirements and notes:
The server's
AGROPORTAL_API_KEYmust be permitted to useuserapikey— an admin/app account, not an ordinary user key. (You run AgroPortal, so you can mint one; confirm your API honoursuserapikeyfor it.)HTTPS is mandatory — users send their personal key on every request.
Keep the client cache off (the default). A shared cache could serve one user's results, including private ontologies, to another.
Without
AGROPORTAL_MCP_REQUIRE_USER_APIKEY, a request that omits the header falls back to the server key; set it to reject those instead.The optional
AGROPORTAL_MCP_BEARER_TOKENgate is independent and can be layered on top for a deployment-wide secret.
Layout
bin/agroportal_mcp # executable stdio entrypoint (local clients)
config.ru # Rack entrypoint: Streamable HTTP / SSE (remote)
lib/agroportal_mcp.rb # build_server + run (stdio) / http_transport (SSE)
lib/agroportal_mcp/middleware.rb # Rack middlewares: bearer gate + per-user apikey
lib/agroportal_mcp/client_setup.rb # env -> LinkedData::Client config (+ Rails.cache shim)
lib/agroportal_mcp/tools/ # one file per MCP tool
search_classes.rbThis server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/maboukerfa/ontoportal-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server