RISE & AI Sweden — Public MCP
A public MCP server that indexes AI-relevant publications from RISE and AI Sweden — Sweden's two government-funded AI organizations. Provided in good faith to support the growth of the agentic AI ecosystem.
Add it to your AI assistant
In most modern MCP-compatible tools, this URL is all you need. No login, no API key, no authentication.
Where to add it
These menus change often — if something looks different, search the app's settings for “MCP”.
mcpServers with the URL above.mcpServers config pointing at the URL.How to use it in a chat
Once added, just mention the name in your prompt. For example:
“Use rise-ai-sweden to give me the most important content related to Helsingborg.”
JSON config (for tools that need it)
{
"mcpServers": {
"rise-ai-sweden": {
"transport": { "type": "http", "url": "https://rise-ai-sweden.jardenberg.org/api/mcp" }
}
}
}Rate limit: 60 requests / 5 minutes per IP.
Tools exposed
Six tools, each returning JSON. Most accept a page_type filter (event · news · project · page). Examples below show the actual shape your assistant receives.
search_swedish_ai
Hybrid (semantic + lexical) search across all indexed RISE and AI Sweden content. Vector arm for topical queries; lexical arm (Swedish/English stemming + trigram fallback) for proper nouns and short keyword queries. Reciprocal-rank-fusion merge; lexical weighted 2x when query is ≤2 tokens.
{
query: string, // 2–500 chars
source?: "rise" | "ai_sweden",
lang?: "en" | "sv",
page_type?: "event" | "news" | "project" | "page",
limit?: number // 1–50, default 20
}{
"query": "Helsingborg",
"count": 2,
"hybrid": { "rrfK": 60, "weights": { "vector": 1, "lexical": 2 }, "tokenCount": 1 },
"results": [
{
"url": "https://www.ai.se/en/sector-initiatives-projects/.../national-city-lab",
"title": "National City Lab",
"source": "ai_sweden",
"sourceName": "AI Sweden",
"lang": "en",
"pageType": "project",
"score": 0.0312,
"arms": { "vector": 0.4912, "lexical": 0.0821 },
"snippet": "The National City Lab in Helsingborg...",
"fetchedAt": "2026-06-10T08:14:22Z"
},
{ "...": "..." }
]
}find_mentions
Lexical 'everything that mentions X' primitive. No embeddings — stemmed tsquery + exact-substring fallback. Includes a total field that mirrors a direct count(DISTINCT id) WHERE raw_markdown ILIKE '%term%' SQL query.
{
term: string, // 1–200 chars
source?: "rise" | "ai_sweden",
lang?: "en" | "sv",
page_type?: "event" | "news" | "project" | "page",
limit?: number // 1–100, default 25
}{
"term": "Helsingborg",
"total": 39,
"totalNote": "Exact-substring document count (ILIKE) matching the same filters. Reconciles with raw SQL.",
"returned": 25,
"results": [
{
"url": "https://www.ai.se/en/news/helsingborg-opens-national-city-lab",
"title": "Helsingborg opens the National City Lab",
"source": "ai_sweden",
"sourceName": "AI Sweden",
"lang": "en",
"pageType": "news",
"matchMode": "exact",
"rank": 0.0912,
"snippet": "Helsingborg opens the National City Lab...",
"fetchedAt": "2026-06-09T07:32:10Z"
},
{ "...": "..." }
]
}list_latest
Cheap 'what's new' view. Without arguments, returns the newest documents across both sources. Pass source / page_type to slice. No snippets — lightweight metadata only.
{
source?: "rise" | "ai_sweden",
lang?: "en" | "sv",
page_type?: "event" | "news" | "project" | "page",
limit?: number // 1–50, default 20
}{
"count": 2,
"results": [
{
"url": "https://www.ai.se/en/news/...",
"title": "New language model release",
"source": "ai_sweden",
"sourceName": "AI Sweden",
"lang": "en",
"pageType": "news",
"publishedAt": "2026-06-09T00:00:00Z",
"publishedAtSource": "meta",
"sitemapLastmod": "2026-06-09T00:00:00Z",
"fetchedAt": "2026-06-10T08:14:22Z"
},
{ "...": "..." }
]
}find_similar
Given a URL already in the index, return semantically nearest other documents. Uses the seed document's centroid embedding (average of all its chunks) so navigation chrome doesn't dominate matches. Great for 'more like this' after picking a hit. URL must match exactly — trailing slashes or query strings will miss.
{
url: string, // a URL from search_swedish_ai / list_latest
source?: "rise" | "ai_sweden",
lang?: "en" | "sv",
limit?: number // 1–25, default 10
}{
"seedUrl": "https://www.ri.se/en/what-we-do/projects/edge-ai-...",
"count": 2,
"results": [
{
"url": "https://www.ri.se/en/what-we-do/projects/tinyml-...",
"title": "TinyML for industrial sensors",
"source": "rise",
"sourceName": "RISE",
"lang": "en",
"score": 0.7912,
"snippet": "Running compact ML models on microcontrollers...",
"fetchedAt": "2026-06-07T11:02:08Z"
},
{ "...": "..." }
]
}get_document
Fetch full cleaned markdown for a single indexed URL. Use after search_swedish_ai to load complete context on the best hit. Body is capped at 80 000 chars — check `truncated` before assuming you have the whole document. `contentNote` / `extractionMethod` surface provenance (e.g. Firecrawl OCR for image-only PDFs, manually replaced stored copies).
{ url: string }{
"url": "https://www.ai.se/en/project/...",
"title": "Project title",
"lang": "en",
"pageType": "project",
"contentType": "html",
"source": "ai_sweden",
"sourceName": "AI Sweden",
"publishedAt": "2026-05-14T00:00:00Z",
"publishedAtSource": "meta",
"fetchedAt": "2026-06-08T09:01:44Z",
"bytesReplacedAt": null,
"extractionMethod": null,
"contentNote": null,
"content": "# Project title\n\nFull markdown body...",
"truncated": false
}list_sources
Discover scope and freshness: which sources are indexed, document counts, language breakdown, and the most recent fetch per source.
{}{
"sources": [
{
"slug": "rise",
"name": "RISE",
"rootUrl": "https://www.ri.se",
"documents": 412,
"languages": { "en": 280, "sv": 132 },
"lastUpdated": "2026-06-10T08:14:22Z"
},
{
"slug": "ai_sweden",
"name": "AI Sweden",
"rootUrl": "https://www.ai.se",
"documents": 388,
"languages": { "en": 250, "sv": 138 },
"lastUpdated": "2026-06-10T07:55:01Z"
}
]
}FAQ
- Is this open source?
- Yes — code lives at github.com/jardenberg/swedish-ai-unlocked. Issues and PRs welcome.
- Do I need an API key?
- No. Public endpoint, no auth. Rate limit: 60 requests / 5 minutes per IP.
- What's indexed?
- Public web pages and PDFs from ri.se and ai.se. No paywalled or internal content. Use
list_sourcesfor current counts and the most recent fetch per source. - How fresh is it?
- Sitemaps are re-checked daily. New documents are scraped, cleaned, chunked, and embedded in the same pass.
- Why does find_mentions return fewer rows than `total`?
totalis a reconciliation count — distinct documents whose markdown contains the exact substring, matching a direct SQLILIKEquery.returnedis what the tool hands back, capped bylimit(max 100).- Why doesn't my AI Sweden event URL show up?
- Many ai.se event pages 301-redirect to third-party sites (Invajo, Meetup, etc.). Those are deliberately skipped — the index only stores content served from ri.se and ai.se themselves.
- How short-query search works
- For queries of ≤2 tokens, the lexical arm is weighted 2× over the vector arm. Good for proper nouns and organization names; if a one-word topical query feels too literal, add a second word.
- Can I trust the dates?
publishedAtcomes from page metadata or PDF path when available, falling back to sitemap last-modified.publishedAtSourcetells you which (meta·path·sitemap).- Why does a PDF look OCR'd?
- Image-only PDFs and oversized files (~>20 MB) are routed through Firecrawl OCR.
get_documentsurfaces this viaextractionMethod: "firecrawl"and a human-readablecontentNote. - What does page_type mean?
- It's URL-derived, not editorial.
projectmeans the URL lives under a/projects/path, not that someone curated it as a project.