skosmos-mcp
Wraps the Skosmos REST API to enable AI assistants to browse, search, and traverse SKOS vocabularies via MCP tools and resources.
README
skosmos-mcp
A production-quality Model Context Protocol (MCP) server that wraps the Skosmos REST API, enabling AI assistants to navigate and query SKOS vocabularies. Also includes SPARQL query capabilities for direct RDF data access.
Features
- 13 MCP tools covering vocabulary browsing, concept lookup, full-text search, label resolution, and BFS traversal
- 4 SPARQL tools for direct SPARQL query execution, updates, graph discovery, and query templates
- 3 MCP resources for direct URI-based access to vocabularies and concepts
- BFS traversal engine with configurable depth cap, cycle detection, and duplicate elimination
- TTL-based in-memory cache to avoid redundant API calls
- Retry logic with exponential backoff for 5xx and network errors
- AbortController timeout on every HTTP request
- Strict TypeScript (strict mode,
noUncheckedIndexedAccess,exactOptionalPropertyTypes) - Zod-validated inputs on all tools
- stdio transport — reads from stdin, writes to stdout; all logging goes to stderr
- StreamableHTTP transport — HTTP server at
/mcpfor remote or web-based MCP clients
Installation
npm install
npm run build
Or run directly with tsx:
npm run dev
Docker / Docker Compose
Build and run the Streamable HTTP MCP server in a container:
docker compose up --build -d
This starts the Streamable HTTP MCP server on port 3000 and uses Docker Compose's restart: unless-stopped policy so it will come back up automatically after crashes. The image defaults to the Finto endpoints, runs the HTTP MCP server on 0.0.0.0:3000, and enables alternate Skosmos/SPARQL connections by default. The container logs a warning at startup when those options are enabled because allowing other endpoints can be a security risk. The container reads the same environment variables as the local app, so copy .env.example to .env if you want to override those defaults.
Container Images from GitHub Container Registry
Releases publish two container image variants to GitHub Container Registry (GHCR):
HTTP variant (for remote access via HTTP):
docker pull ghcr.io/jsilvanus/skosmos-mcp:http
docker pull ghcr.io/jsilvanus/skosmos-mcp:http-latest
# Or use a specific release version:
docker pull ghcr.io/jsilvanus/skosmos-mcp:v0.2.1-http
Stdio variant (for local stdio MCP protocol):
docker pull ghcr.io/jsilvanus/skosmos-mcp:stdio
docker pull ghcr.io/jsilvanus/skosmos-mcp:stdio-latest
# Or use a specific release version:
docker pull ghcr.io/jsilvanus/skosmos-mcp:v0.2.1-stdio
Each release publishes both variants automatically. Choose the one that matches your use case:
- HTTP variant: Runs an HTTP server on port 3000, suitable for remote access or web-based MCP clients
- Stdio variant: Uses stdin/stdout for the MCP protocol, suitable for local integration with AI assistants or other MCP clients
Configuration
Copy .env.example to .env and fill in values:
SKOSMOS_BASE_URL=https://api.finto.fi # required
SKOSMOS_DEFAULT_VOCABULARY= # optional
SKOSMOS_DEFAULT_LANGUAGE=en
SKOSMOS_TIMEOUT=30000
SKOSMOS_USER_AGENT=skosmos-mcp/0.2.0
SKOSMOS_CACHE_TTL=300
SKOSMOS_MAX_TRAVERSAL_DEPTH=5
SKOSMOS_TOOL_SERVER_URL_ALLOWED=true
# SPARQL Configuration (optional)
SPARQL_ENDPOINT_URL=https://api.finto.fi/sparql
SPARQL_USERNAME=
SPARQL_PASSWORD=
SPARQL_ALLOW_OTHER_ENDPOINTS=true
| Variable | Default | Description |
|---|---|---|
SKOSMOS_BASE_URL |
(required) | Base URL of the Skosmos instance |
SKOSMOS_DEFAULT_VOCABULARY |
— | Default vocabulary id when not specified in a tool call |
SKOSMOS_DEFAULT_LANGUAGE |
en |
Default language code for labels |
SKOSMOS_TIMEOUT |
30000 |
HTTP request timeout in milliseconds |
SKOSMOS_USER_AGENT |
skosmos-mcp/0.1.0 |
User-Agent header sent with API requests |
SKOSMOS_CACHE_TTL |
300 |
Cache entry TTL in seconds |
SKOSMOS_MAX_TRAVERSAL_DEPTH |
3 |
Hard cap on BFS traversal depth |
SKOSMOS_TOOL_SERVER_URL_ALLOWED |
false |
When true, allows tools to accept optional server_url parameter to call a different Skosmos instance |
LOG_LEVEL |
info |
Log level: debug, info, warn, error (written to stderr) |
MCP_HTTP_PORT |
3000 |
TCP port for the StreamableHTTP server |
MCP_HTTP_HOST |
127.0.0.1 |
Bind address for the StreamableHTTP server |
SPARQL_ENDPOINT_URL |
— | SPARQL endpoint URL (optional; enables SPARQL tools) |
SPARQL_USERNAME |
— | Username for SPARQL endpoint HTTP Basic auth (optional) |
SPARQL_PASSWORD |
— | Password for SPARQL endpoint HTTP Basic auth (optional) |
SPARQL_ALLOW_OTHER_ENDPOINTS |
false |
When true, allows SPARQL tools to accept optional endpoint parameter to query a different SPARQL endpoint |
MCP Tools Reference
Vocabulary Tools
list_vocabularies
List all available vocabularies.
| Parameter | Type | Required | Description |
|---|---|---|---|
lang |
string | no | Language code for labels |
get_vocabulary
Get vocabulary metadata and top concepts.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Vocabulary identifier (e.g. "yso") |
lang |
string | no | Language code |
Concept Tools
get_concept
Fetch full concept details: labels, broader, narrower, related.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Concept URI |
vocabulary |
string | no | Vocabulary identifier (required if no default set) |
lang |
string | no | Language code |
get_concept_label
Get all labels for a concept URI.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Concept URI |
vocabulary |
string | yes | Vocabulary identifier |
lang |
string | no | Language code |
concept_path
Get the hierarchy path from a concept to its root.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Concept URI |
vocabulary |
string | yes | Vocabulary identifier |
lang |
string | no | Language code |
Search Tools
search_concepts
Full-text search across one or all vocabularies.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | yes | Search string (supports trailing * wildcard) |
vocabulary |
string | no | Limit to this vocabulary |
lang |
string | no | Language code |
maxhits |
integer | no | Max results |
offset |
integer | no | Pagination offset |
autocomplete
Autocomplete concept labels by prefix.
| Parameter | Type | Required | Description |
|---|---|---|---|
prefix |
string | yes | Label prefix |
vocabulary |
string | no | Limit to this vocabulary |
lang |
string | no | Language code |
maxhits |
integer | no | Max suggestions |
resolve_label
Resolve a label text to concept URIs.
| Parameter | Type | Required | Description |
|---|---|---|---|
text |
string | yes | Label text to resolve |
vocabulary |
string | yes | Vocabulary identifier |
lang |
string | no | Language code |
Labels Tool
labels
Get all labels (prefLabel, altLabel, hiddenLabel) for a concept URI.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Concept URI |
vocabulary |
string | yes | Vocabulary identifier |
lang |
string | no | Language code |
Traversal Tools
All traversal tools use BFS with cycle detection. Depth is capped at Math.min(depth, SKOSMOS_MAX_TRAVERSAL_DEPTH).
broader_concepts
Traverse broader (parent) concepts.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Starting concept URI |
vocabulary |
string | yes | Vocabulary identifier |
depth |
integer | no | Max traversal depth |
lang |
string | no | Language code |
narrower_concepts
Traverse narrower (child) concepts.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Starting concept URI |
vocabulary |
string | yes | Vocabulary identifier |
depth |
integer | no | Max traversal depth |
lang |
string | no | Language code |
related_concepts
Traverse related concepts.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Starting concept URI |
vocabulary |
string | yes | Vocabulary identifier |
depth |
integer | no | Max traversal depth |
lang |
string | no | Language code |
traverse_concepts
BFS using a mix of relationship types.
| Parameter | Type | Required | Description |
|---|---|---|---|
uri |
URL | yes | Starting concept URI |
vocabulary |
string | yes | Vocabulary identifier |
relationships |
array | yes | One or more of: "broader", "narrower", "related" |
depth |
integer | no | Max traversal depth |
lang |
string | no | Language code |
SPARQL Tools
SPARQL tools enable direct querying of RDF data. Set SPARQL_ENDPOINT_URL environment variable to enable these tools. Supports both SPARQL 1.1 Query and Update protocols, with optional HTTP Basic authentication.
See the Attribution section for licensing details about the SPARQL implementation.
execute_sparql_query
Execute a SPARQL query (SELECT, CONSTRUCT, ASK, DESCRIBE) against the configured endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | yes | The SPARQL query to execute |
endpoint |
URL | no | Optional custom SPARQL endpoint (overrides default) |
Example Query:
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT ?concept ?label
WHERE {
?concept a skos:Concept ;
skos:prefLabel ?label .
}
LIMIT 10
execute_sparql_update
Execute a SPARQL update query (INSERT, DELETE, etc.) against the configured endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
update |
string | yes | The SPARQL update query to execute |
endpoint |
URL | no | Optional custom SPARQL endpoint (overrides default) |
Example Update:
PREFIX ex: <http://example.org/>
INSERT DATA {
ex:subject1 ex:predicate1 "object1" .
}
list_sparql_graphs
List all available named graphs in the SPARQL endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
endpoint |
URL | no | Optional custom SPARQL endpoint (overrides default) |
Returns: JSON array of graph URIs.
sparql_query_templates
Get pre-built SPARQL query templates for common data exploration patterns.
| Parameter | Type | Required | Description |
|---|---|---|---|
category |
string | yes | Template category: exploration, property-paths, statistics, validation, schema, or all |
Categories:
exploration— Basic data discovery and statisticsproperty-paths— Complex graph navigation using SPARQL property pathsstatistics— Knowledge graph metrics and analysisvalidation— Data quality and consistency checksschema— Structure discovery and ontology exploration
MCP Resources
| URI Pattern | Description |
|---|---|
skosmos://vocabularies |
JSON list of all vocabularies |
skosmos://{vocid} |
Vocabulary metadata for {vocid} |
skosmos://{vocid}/{encodedUri} |
Concept data (labels, broader, narrower, related) |
Traversal Examples
Get all ancestors of a concept (depth 3)
{
"tool": "broader_concepts",
"args": {
"uri": "http://www.yso.fi/onto/yso/p8966",
"vocabulary": "yso",
"depth": 3,
"lang": "en"
}
}
Response includes nodes (with depth), edges (directed relationships), rootUri, and maxDepth.
Mixed traversal (broader + related)
{
"tool": "traverse_concepts",
"args": {
"uri": "http://www.yso.fi/onto/yso/p8966",
"vocabulary": "yso",
"relationships": ["broader", "related"],
"depth": 2
}
}
Using Optional Server URL Parameter
All 13 MCP tools support an optional server_url parameter. When SKOSMOS_TOOL_SERVER_URL_ALLOWED=true is set in the environment, you can pass a server_url parameter to any tool to make it query a different Skosmos instance instead of the configured SKOSMOS_BASE_URL.
Example: Query a different Skosmos instance
{
"tool": "get_concept",
"args": {
"uri": "http://www.yso.fi/onto/yso/p8966",
"vocabulary": "yso",
"lang": "en",
"server_url": "https://alternative-skosmos.example.org"
}
}
This allows a single MCP session to interact with multiple Skosmos instances. The server_url parameter is:
- Optional on all tools
- Ignored unless
SKOSMOS_TOOL_SERVER_URL_ALLOWED=true(default:false) - Can be any valid URL pointing to a Skosmos instance with a compatible REST API
Why use this feature?
- Query multiple Skosmos instances in parallel within a single session
- Test against different Skosmos servers without restarting the MCP
- Support scenarios where vocabularies are distributed across multiple instances
stdio (standard MCP deployment)
SKOSMOS_BASE_URL=https://skosmos.example.org node dist/index.js
StreamableHTTP
SKOSMOS_BASE_URL=https://skosmos.example.org MCP_HTTP_PORT=3000 node dist/http.js
The server listens on http://<MCP_HTTP_HOST>:<MCP_HTTP_PORT>/mcp (default: http://127.0.0.1:3000/mcp).
Each POST request is handled as a stateless MCP session (no session ID). The SkosmosClient and CacheManager instances are shared across requests for the lifetime of the process.
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"skosmos": {
"command": "node",
"args": ["/path/to/skosmos-mcp/dist/index.js"],
"env": {
"SKOSMOS_BASE_URL": "https://skosmos.example.org",
"SKOSMOS_DEFAULT_LANGUAGE": "en"
}
}
}
}
Development
npm run dev # run with tsx (no build)
npm run typecheck # check types without emitting
npm run test # run tests
npm run test:watch # watch mode
npm run build # compile to dist/
npm run lint # lint src/ and tests/
Architecture
MCP Client (AI Assistant)
│ stdio (JSON-RPC)
▼
McpServer (SDK)
├── 13 Tools (Zod-validated)
└── 3 Resources
│
┌────┴────┐
│ │
TraversalEngine CacheManager
(BFS + cycle (TTL, per-type)
detection)
│
SkosmosClient
(fetch + retry
+ timeout)
│
Skosmos REST API
Key Design Decisions
- No global mutable state: config, client, cache, and traversal engine are created once in
src/index.tsand passed via dependency injection. - BFS traversal: uses a queue (not recursion) to ensure breadth-first ordering and avoid stack overflows.
- Depth capping:
Math.min(requestedDepth, config.maxTraversalDepth)is applied in both the traversal engine and tool handlers. - Cache keys include all relevant parameters:
vocabulary:${vocid}:${lang},label:${vocab}:${uri}:${lang}, etc. - All logging to stderr — stdout is reserved exclusively for MCP JSON-RPC.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Attribution
SPARQL functionality in this project is derived from ramuzes/mcp-jena and is used under the MIT License.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。