Server data from the Official MCP Registry
Read-only access to AMIRA, the Africa Multiple research-data platform on Omeka S.
About
Read-only access to AMIRA, the Africa Multiple research-data platform on Omeka S.
Remote endpoints: streamable-http: https://data.africamultiple.uni-bayreuth.de/mcp
Security Report
Valid MCP server (4 strong, 2 medium validity signals). No known CVEs in dependencies. Imported from the Official MCP Registry. Trust signals: 4 highly-trusted packages.
37 tools verified · Open access · No issues found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Permissions Found in Source Code
Found by scanning the linked source code. This listing connects to a hosted endpoint, so none of this runs on your machine: it describes what the server software does where it is hosted.
How to Connect
Remote Plugin
No local installation needed. Your AI client connects to the remote endpoint directly.
Add this to your MCP configuration to connect:
{
"mcpServers": {
"io-github-am-digital-research-environment-amira-mcp-server": {
"url": "https://data.africamultiple.uni-bayreuth.de/mcp"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
AMIRA MCP Server
Read-only Model Context Protocol server for the Africa Multiple Interactive Research Atlas (AMIRA), the research-data platform of the Africa Multiple Cluster of Excellence at the University of Bayreuth. AMIRA is published on the cluster's public Omeka S site at data.africamultiple.uni-bayreuth.de.
AMIRA is built and maintained by the Cluster's Digital Research Environment (DRE), its digital infrastructure unit. The DRE designs, builds, and maintains the data systems that connect researchers across the Africa Multiple Research Centres (AMRCs) and partner institutions worldwide. Curation and description are joint efforts with partners at the AMRCs in Université Joseph Ki-Zerbo, Rhodes University, the University of Lagos, and Moi University. Bayreuth hosts the coordinating DRE infrastructure and metadata layer. Federal University of Bahia is a privileged partner, not an AMRC.
Storage stays distributed by default: data remains in its local repository, while Bayreuth holds the metadata layer that points to it. Research data becomes findable without being relocated. High-quality metadata makes researchers' data more discoverable and their work more visible to a wider community of peers.
This server exposes AMIRA's projects, thematic research sections, ~4,000 digitised research items, people, institutions, groups, collections, the cluster bibliography with searchable full text (extracted from the open-access PDFs) and its journals, podcast episodes with transcripts, and the cluster's YouTube videos with searchable transcripts — as 36 core tools an LLM can query, five research-workflow prompts, and resources for citable records and bulk exports. From one MCP interface, clients can move across records and the places, languages, and subjects that connect them.
Every record carries an amira_url — its public page on the Omeka S site
(…/s/amira/item/<id>) — so findings can be cited as links back to the source.
AMIRA focuses on the Cluster's research data. For news, events, and general
information about the Africa Multiple Cluster of Excellence, visit
africamultiple.uni-bayreuth.de.
Coverage checked 6 October 2026: 3,975 research items (1,419 with digitised
media), 93 projects, 555 publications (60 with extracted full text), 87 journals,
43 podcast episodes, 140 videos and 3,085 subject authorities (646 Library of
Congress headings). Counts are a dated snapshot; use get_collection_overview for
what your running server actually holds. See the publication guide,
the changelog for what each release changed, and the
roadmap for further improvements.
How it gets its data — and why nothing else is needed
The server is self-contained and offline-first. It reads from two sources:
- A complete data snapshot bundled inside the
.mcpb— crawled from the public Omeka S REST API at build time and transformed into compact typed records, so the server works fully offline with zero setup. - (optional, on by default) the Omeka S API over HTTPS. At startup and daily, probes compare item and item-set modification signatures and totals. A changed signal triggers a complete crawl; a weekly forced crawl also catches vocabulary-only edits. A writer lock, immutable generations and an atomic pointer preserve the previous usable snapshot if refresh fails. The API origin and installation path partition the cache and must match the manifest before its records can be served under that site's citation URLs.
End users need no API key, no credentials, and no VPN — it's the same openly published data that powers the public site.
Tools
Call get_collection_overview first to scope the data, then drill in.
| Tool | Purpose |
|---|---|
get_collection_overview | Counts and breakdowns across the whole collection + snapshot freshness |
search_research_items | Find items by keyword (every word must match; quote a phrase), subject, location (hierarchy-aware), country (exact, with aliases such as Côte d'Ivoire = Ivory Coast), contributor, project, section, university, resource type, format/genre, language, year, has_media, added_since / modified_since, mentions_country (ILAM articles whose full text names a country; see below); `export=csv |
get_research_item | Full metadata for one item (by Omeka id or typed id): typed dates, roles with the affiliation at the time, places with their region/country chain, provenance as linked institutions, typed identifiers, collections, related items, media files and the IIIF manifest — plus a generated citation and a BibTeX/RIS/CSL-JSON export (citation_format). ILAM African Music articles add closest_in_content and full_text_map (see below) |
search_projects / get_project | Projects by keyword or acronym, university, section, PI, member, funder — detail with item breakdown, top subjects and sample items |
list_research_sections / get_research_section | Thematic sections with funding phases (AM 1.0 / AM 2.0), PIs, counts, projects; detail by name or id |
search_persons / get_person | People (either name order works) — profile with GND and other authority identifiers, project and research-section roles, items, publications, podcasts, videos and top collaborators, with a coverage_note on how to read the counts. A name that matches nobody returns near-miss suggestions ("Rudigr Seeman" → Seesemann, Rüdiger); get_person lists them in its not_found error |
list_institutions / get_institution / list_cluster_partners / list_groups | Organisations (institutions, Africa Multiple partner categories, and research groups) by name, acronym or id, their projects, people and items |
list_subjects | Subject headings ranked by item frequency, each marked as a Library of Congress heading (with its id.loc.gov URI) or a free tag (`vocabulary=lcsh |
list_locations | Every place — countries and the places under them in one flat list (hierarchy rolled up) — ranked by item count, with coordinates and Wikidata ids. Each row's level is country or place (a city, region or site, with its country); filter by country, name, near (radius) or bbox |
list_collections | Collections ranked by research-item count. A collection is a research project: cited by the project page, with the item set(s) filing it (item_sets, collection code) and IIIF collection links — pair with the collection filter, which takes a project id, item-set id or code |
list_categories | Facet values: formats/genres, languages, resource types |
list_years | Date histogram of research items by year or decade — coverage over time, most-covered year/decade |
search_publications / get_publication | Filter the bibliography by author, subject, language, type, venue, year, date added and full-text availability; search abstracts in every language and extracted PDF text. Detail adds every abstract with its language, linked authorities, conference/extent/access/thesis metadata. citation_format selects BibTeX/RIS/CSL-JSON per page; export links the whole result as one file |
list_publication_facets | Counts by type, year, language, subject, author/editor or venue across the complete filtered bibliography; ranked and paginated |
list_journals | The journals the cluster publishes in, ranked by publication count, with ISSN and country — pair with the venue filter |
find_related | Cross-entity discovery: pivot from a subject/place/person/project to co-occurring entities (incl. publications), from an ILAM African Music article (entity_type=research_item) to its closest articles by full text, or from any embedded record (entity_type=record) to its closest records by meaning and what they share |
search_podcasts / get_podcast | Cluster podcast episodes with searchable transcripts, filterable by language; detail gives the duration, audio file and the model that generated the transcript; transcript text is opt-in |
search_videos / get_video | The cluster's YouTube videos — full-text search over transcripts (match snippets; thumbnail; transcript opt-in on detail) |
resolve_entity | Resolve names or typed IDs (either vocabulary: item:9902 = research_item:9902); return separate candidates for homonyms and unreconciled literals. A query that resolves to nothing, untyped or with type=person, returns near-miss person suggestions |
get_entity_graph | Bounded one-hop graph with distinct explicit links/co-occurrences and paginated cited evidence |
get_text_passages | Find passages in selected publication/video/podcast records, with exact original-text offsets |
compare_collections | Compare 2–4 projects or collections using common filters, denominators and missingness |
get_data_quality | Snapshot coverage, missing metadata and unresolved-reference counts |
get_snapshot_changes | Page added, updated or deleted records across retained snapshots from the same instance |
get_fulltext_map | The ILAM journal African Music read through its private full text, from public derived counts: content groups (AI-labelled) with their articles, the countries articles name, and word rates per year for up to six words |
get_similar_items | Records whose catalogue descriptions read most alike, across research items, publications, videos, podcasts, projects and sections, with cosine scores and amira_urls, each saying what the pair also shares (shared subjects, places, people, project) or basis: "wording_only"; types narrows the result, and a record without neighbours says why (low_signal, not_in_release). The detail tools take include_similar for the same, five at a time. See Semantic neighbours |
get_semantic_map | The collection as unnamed groups of records close in meaning: each group's size, type mix, top subjects, countries and projects, and the records nearest its centre; group lists one group's records, id finds the group a record falls in |
Prompts and resources
Five prompts package multi-step research workflows. Hosts show them as slash
commands; their arguments autocomplete from the snapshot's own authority names, and
each restates the citation rules. They are listed through prompts/list, so they
add nothing to the per-turn tool payload.
| Prompt | Arguments | Workflow |
|---|---|---|
literature_review | topic, year_from?, year_to? | Facets, publications, full-text passages and related research data on a topic |
project_dossier | project | Team, holdings, periods, places and connections of one project |
person_profile | name | Disambiguation, profile, graph and publication list of one person, presented as AMIRA's records rather than an assessment of the person |
place_report | place | Items, projects, subjects and periods for a country, city or region |
transcript_evidence | query | Quoted passages from transcripts and open-access full texts |
Resources expose data outside the tool calls:
| URI | Content |
|---|---|
amira://record/{kind}/{id} | Any record as citable JSON — the same projection as its get_* tool; kinds follow resolve_entity ids (research_item, publication, person, location, subject, …) |
amira://export/{corpus}/{format}/{query} | A filtered export (CSV/JSONL for research items; CSV/JSONL/BibTeX/RIS/CSL-JSON for publications). The search tools return these links as resource_links when called with export |
amira://dataset | A schema.org Dataset description of the served snapshot: counts, coverage, licence mix, funder, how to cite it and the vector space behind get_similar_items (amira:semantic_space) |
Profiles and research workflows
AMIRA_TOOL_PROFILE=full is the default: 36 core tools, or 38 over HTTP.
research, discovery and visualization expose smaller documented subsets
(23/12/14 core tools respectively; HTTP adds search and fetch). Profiles are
fixed at startup; they reduce discovery cost, not access permissions. Tools
outside a profile are removed, and so are the apps that render them. See
src/toolProfiles.ts for the exact lists.
Typed ids work everywhere in either vocabulary (item: / research_item:,
pub: / publication:, section:, person:, organisation:, project:,
video:, podcast:), including the id of every get_* tool. Paged results
stop early, with response_limited: true and a correct next_offset, when a page
would exceed 40,000 characters — Claude Code moves larger tool results out of
the conversation. Error results carry the error as JSON text only. Structured
content travels only where a client reads it: on the tools with an output schema
and on those that render an app; elsewhere the result is its compact JSON text
alone, instead of the same bytes twice. Control and private-use characters are
scrubbed from every result, and a call that has not answered within 60 seconds
returns a deadline_exceeded error.
Use resolve_entity before graph traversal; pass its typed id unchanged to
get_entity_graph. Graph edges count distinct source records, separate each
corpus, and distinguish catalogue links from co-occurrence. types (for example
["person"]) keeps only neighbours of those types and applies before the bounds;
neighbour_types counts every neighbour by type either way. Neither co-occurrence
nor a shared subject establishes collaboration. Follow an edge with edge_id
and the returned snapshot_id for stable evidence paging. Graphs cap at 100 nodes,
200 edges and 42,000 JSON bytes, so check truncated.
get_text_passages takes 1–10 publication:ID (or pub:ID), video:ID or
podcast:ID identifiers. It returns at most 20 passages per page, original UTF-16
offsets and source citations; every match is reachable through next_offset
(scanned_matches_capped reports a document with more than 10,000 matches). These are extracted-text offsets, not
PDF page numbers or audio timestamps. get_snapshot_changes requires two local
same-source generations; it reports available history instead of inventing a diff.
The ILAM full-text map
The full text of ILAM's journal African Music (item set 27724, about 1,000
articles from 1954 on) is private in Omeka, so the public API this server
crawls never carries it, and nothing here reads or quotes it.
DRE Visualizations
computed a map from it offline and committed only derived, public files: ids,
map coordinates, content groups, nearest-neighbour scores, per-article country
counts and aggregate word counts per year. The crawl fetches two of them at a
pinned release tag (v2.48.0, FULLTEXT_SOURCE in
src/fulltextMaps.ts), validates their shape, keeps only
the declared fields, and stores them beside the snapshot as
fulltext_maps.json. If GitHub is unreachable, the snapshot ships without the
map and its surfaces answer fulltext_map_unavailable. Every result is filtered
to research items present in the snapshot and filed in the item set, and cites
them by amira_url.
| Surface | What it adds |
|---|---|
get_research_item | For an article on the map: closest_in_content (its 8 closest articles by full-text embedding, google/embeddinggemma-2, with cosine scores) and full_text_map (its content group, the countries its text names). An ILAM article off the map says so |
find_related entity_type=research_item | The same neighbours, with the subjects, people, countries and formats they share |
mentions_country filter | Articles whose full text names a country at least three times; each row carries country_mentions. Shared by search_research_items, list_years, list_locations, compare_collections and exports |
get_fulltext_map | The groups with sample articles, the countries named across the journal, a group's articles (group), or word rates per 10,000 words per year (words, up to six) |
Limits, stated in every response: group names are AI-generated (Claude Opus
5.5, from the titles of each group's articles) and experimental; judge a group
by its articles. Neighbour scores sit in a narrow band (about 0.90 to 0.97), so
ranks say more than raw values. Countries come from a gazetteer, with three
mentions minimum and journal addresses excluded; a mention is not a subject.
Word counts cover words found in at least ten articles, single word forms
without stemming; years with few words are marked sparse. 657 articles are on
the map: articles without full text, and those excluded as shared section text,
journal furniture or under 300 words, are not. These surfaces need the
descriptive exposure level. Searching passages of the text itself is a
separate decision, with ILAM and Rhodes University, and is not offered.
Example questions it can answer
| You ask… | The model uses… |
|---|---|
| "What does the collection hold on Islam?" | list_subjects keyword=Islam → search_research_items subject=Islam |
| "Show me all the French-language items" | search_research_items language=French (codes fr/fra/legacy fre work too) |
| "What has Ulli Beier contributed?" | get_person name="Ulli Beier" (resolves to 'Beier, Ulli') |
| "Which items come from Nigeria?" | search_research_items location=Nigeria (Lagos items count too — location walks the place hierarchy) or country=Nigeria (exact: Niger stays out) |
| "What does AMIRA hold from Côte d'Ivoire?" | search_research_items country="Côte d'Ivoire" (the authority stores "Ivory Coast"; common aliases resolve) |
| "What has been added since September?" | search_research_items added_since=2026-09-01 (or search_publications added_since=…) |
| "Which African Music articles write about Ghana, and when?" | search_research_items mentions_country=Ghana → list_years filters={mentions_country: "Ghana"} |
| "How did African Music use the word kwaito over time?" | get_fulltext_map words=["kwaito"] (rates per 10,000 words; sparse years flagged) |
| "Which articles are closest in content to this ILAM article?" | get_research_item (closest_in_content) or find_related entity_type=research_item |
| "Which Lagos items have digitised images?" | search_research_items location=Lagos has_media=true → get_research_item for the files and IIIF manifest |
| "Give me all Islam-related items as a spreadsheet" | search_research_items subject=Islam export=csv → read the returned amira://export/… link |
| "What audio recordings are in the ILAM collection?" | search_research_items project_id=37700 resource_type=Audio |
| "In which talks does anyone discuss decoloniality?" | search_videos keyword=decolonial (matches inside transcripts, flagged matched_in) |
| "Which cluster publications discuss migration control — and what do they actually say?" | search_publications keyword="migration control" (matches inside the extracted full text, flagged matched_in) → get_publication include_fulltext=true |
| "How many French-language publications are there, and of which types?" | list_publication_facets facet=type language=fr → search_publications language=fr |
| "Export the French-language bibliography for my reference manager" | search_publications language=fr citation_format=ris → follow next_offset; combine the complete ris records |
| "Which journals does the cluster publish in?" | list_journals (ranked by publication count) |
| "What themes travel with Architecture across projects?" | find_related entity_type=subject value=Architecture |
| "When was this photograph taken?" | get_research_item → typed dates (created/collected/issued/…) |
| "Give me a citation for this item — and the BibTeX" | get_research_item → generated_citation + bibtex (citation_format=ris/csl-json for a reference manager) |
| "Which decade does the collection cover most?" | list_years bucket=decade sort=count |
Companion skill
A research-workflow skill ships in .claude/skills/amira-mcp/:
cluster context, a query workflow, a tool-by-task map, the citation discipline, and coverage caveats.
Install it either way:
- Download
amira-mcp-skill.zipfrom the releases page and unzip it into your Claude skills directory (e.g.~/.claude/skills/) — it expands to~/.claude/skills/amira-mcp/. - Or copy the
.claude/skills/amira-mcp/folder from this repo there.
…or let the server hand it over (Skills over MCP)
Official extension; host support varies. SEP-2640 is now Final. The server follows the published Skills extension, including SHA-256 digests and byte sizes for every file. The zip above remains available for clients without extension support. The research tools and citation contract work either way.
The server also serves that same skill over the connection, following the
SEP-2640 extension
(io.modelcontextprotocol/skills). Nothing to download and nothing to keep in sync: a host that
implements the extension discovers the skill on connect, and the copy it gets is the one built into
the running server rather than a zip that may predate the tool surface it describes. It is the only
route that reaches the remote HTTP surface — ChatGPT, Claude.ai connectors and the APIs have no
local skills directory.
| Method | What it returns |
|---|---|
skills/list | The catalog: skill://amira-mcp/SKILL.md, its frontmatter, and a SHA-256 digest and byte size for every file |
skills/get | One skill by URI, to refresh digests without re-listing |
resources/read | Any single file — SKILL.md or a reference — read on demand |
resources/directory/read | One directory level at a time (skill://amira-mcp, skill://amira-mcp/references) |
Cost when unused: near zero. Skill text is never injected into any tool description, so the
tools/list payload — the part re-sent every turn — is byte-identical whether or not a host
supports the extension. The instructions add one sentence naming skill://amira-mcp/SKILL.md, and
resources/list names every skill file with a title and a one-line summary, so a host without the
extension (Claude Desktop, Claude Code) can still find the workflow and its three references and
read them with resources/read. Disclosure timing stays a host decision; the reference files load
only when something actually reads them.
Set AMIRA_SKILLS=0 to drop the capability and the three methods entirely.
Install (end users)
Download amira-mcp-server.mcpb from the
releases page
and double-click it. Claude Desktop shows an install dialog; click Install.
No further configuration is required. The latest tagged release carries the
current data; the rolling data-latest pre-release always tracks the freshest
site snapshot.
Use it from ChatGPT, the API, or any remote client
The .mcpb is the local, offline option for Claude Desktop. The same server can
also run as a remote Streamable HTTP endpoint — one HTTPS URL that ChatGPT,
Claude (web + desktop remote connectors), the OpenAI and Anthropic APIs, Cursor,
VS Code and other clients connect to by pasting a URL (no download, always-fresh
data). The remote surface serves the same 36 tools plus the
OpenAI-compatible search / fetch tools for ChatGPT research integrations (36
total). Access is unauthenticated — the data is public and read-only.
search takes plain keywords (matched term-by-term, not as an exact phrase),
with optional limit and types to keep the result set tight, and returns
ranked hits across research items, the bibliography (reaching into publication
full text), podcasts, videos, projects and research sections. The url on
search results and fetch documents is
always the AMIRA/Omeka public record page; DOI, YouTube/watch, and podcast/listen
URLs are kept as secondary metadata/text links. fetch returns one record's full
text by the id search hands back — for videos and podcasts the transcript is omitted by default
(metadata + description only, since a full one can run to tens of thousands of
characters), and include_transcript=true pulls it in — paged with
transcript_offset / transcript_max_chars (the same names get_video /
get_podcast use). Publication full text works the same way
(include_fulltext=true, paged with fulltext_offset / fulltext_max_chars,
matching get_publication), and max_chars caps the whole text body. The
appended window is sized against what max_chars leaves after the metadata
header, so *_returned_chars is exactly what landed in text and the next page
starts at offset + returned_chars with no gap.
npm run build && npm run start:http # → http://localhost:8787/mcp
# or, self-contained, via Docker:
docker build -t amira-mcp . && docker run -p 8787:8787 amira-mcp
Endpoints: POST /mcp (the MCP endpoint), GET /healthz and GET /metrics
(request count and p50/p95 latency of the last 256 /mcp requests, rate-limit
buckets, refresh state). Bind with PORT / HOST. Every release also publishes
the tested image, with build provenance, as
ghcr.io/am-digital-research-environment/amira-mcp-server:<version> (and
:latest), so a deployment updates by pulling a tag.
-
ChatGPT → enable Developer mode under Settings → Security and login, then add your server URL from ChatGPT Plugins. Research integrations use
search+fetch; see the current OpenAI setup guide. -
Claude (web or desktop) → Settings → Connectors → Add custom connector →
https://<your-host>/mcp. -
OpenAI API (Responses) — point the
mcptool at the endpoint:{ "type": "mcp", "server_label": "amira", "server_url": "https://<your-host>/mcp", "allowed_tools": ["search", "fetch"], "require_approval": "never" }
Deploy (self-hosted, e.g. alongside the amira site)
The multi-stage Dockerfile crawls a fresh snapshot at build time
and runs the self-contained bundle (no node_modules at runtime). On a Linux
host you can equally run it under systemd behind a reverse proxy:
# /etc/systemd/system/amira-mcp.service
[Service]
ExecStart=/usr/bin/node /opt/amira-mcp/server/http.js
Environment=PORT=8787 HOST=127.0.0.1 AMIRA_LIVE_REFRESH=true
Restart=always
User=www-data
location /mcp { proxy_pass http://127.0.0.1:8787/mcp; proxy_buffering off; client_max_body_size 64k; }
proxy_buffering off keeps the Streamable-HTTP/SSE responses flowing. The refresh uses AMIRA_SITE_BASE (the public HTTPS API by default), even when
co-located with Omeka. It performs a full crawl when changes are detected;
co-location does not eliminate API load. The server caps request bodies at 64 KiB
and rate-limit state at 10,000 clients. Configure connection, request-rate and
concurrency limits at the reverse proxy for public deployments; the in-process
limiter is a courtesy control. Shutdown cancels refresh work and gives HTTP
connections a ten-second drain window.
For a build that consumes a previously reviewed data/ snapshot without calling
Omeka during the build:
docker build --build-arg SNAPSHOT_STAGE=bundled -t amira-mcp .
The default SNAPSHOT_STAGE=fetch still crawls fresh data. Both stages validate the
snapshot. The image pins its base digest; npm ci uses the committed lockfile.
Develop / rebuild
npm ci
npm run fetch-data # crawl the public Omeka API -> ./data snapshot (~1 min)
npm run typecheck # tsc --noEmit
npm run build # esbuild -> server/{index,http,fetchCli,lib}.js
npm test # unit tests: transform fixtures, folding, snapshot + store lifecycle,
# and the full tool layer against a fixture snapshot via
# InMemoryTransport (offline)
npm run test:live # integration tests against the live API (network)
npm run smoke # test/smoke/stdio.mjs: spawn the stdio server, exercise every tool offline
npm run smoke:http # test/smoke/http.mjs: spawn the HTTP server on a free port: search/fetch +
# parity, CORS preflight for both protocol revisions, the rate limiter
npm run weigh # token budget report (needs ./data — run fetch-data first)
npm run benchmark # offline latency baseline against ./data (30 warm samples per query)
npm run lint # Biome, lint rules only (biome.json)
npm run evaluate-retrieval -- --judgments judgments.json --output report.json
# precision, recall, nDCG and MRR at k against researcher-authored judgments
Token budgets
Context is the scarcest resource a client has, so both halves of what this server
spends are measured and gated (scripts/weigh.mjs, estimating tokens as
bytes/4 — comparable to itself, not to a billing statement):
| what | budget | drift | |
|---|---|---|---|
| Surface | the tools/list payload, re-sent every turn | 14,000 tok per full-profile transport | fails over 3 % |
| Responses | each tool called at its maximum limit | 20,000 tok and < 45,000 characters per call | warns over 10 % |
No tool description is derived from the snapshot, so the surface is a pure
function of the code: test/unit/budget.test.mjs gates it offline against no
data at all, and asserts that the empty-store measurement still matches the
baseline recorded against the full snapshot. Response weight needs real data, so
npm run weigh -- --check runs in the smoke job instead. Drift there is only a
warning — a routine npm run fetch-data must not red the build — while the
absolute cap (Claude Code truncates tool results at 25,000 tokens) is fatal, as
is any probe whose call failed, since a structured refusal is ~60 tokens and
would otherwise sail under every ceiling.
Version 1.18 deliberately raises the full-profile ceiling to 14,000 estimated
tokens to accommodate six tools and useful output schemas. Smaller profile gates
are 10,100 (research, raised from 10,000 for resolve_entity's near-miss
fields), 6,500 (discovery) and 9,500 (visualization). The guidance-off
surfaces of the evaluation ablation are measured and gated like the shipped ones.
The committed baseline records the exact surface size,
text bytes, serialized wire bytes (text and structured content both count) and the
snapshot it was measured on. Every response must also stay under 45,000 characters:
Claude Code stores any tool result over 50,000 characters in a file instead of the
conversation. Paged results and the graph are byte-bounded to fit.
When a change legitimately grows either number:
npm run weigh -- --update # rewrites test/token-baseline.json
Commit the diff. That is the point of the file: the cost of a new tool or a richer result summary lands in code review as a number instead of arriving unnoticed.
Pack the extension:
npm run prepack-mcpb # clean + typecheck + build + test + smoke
npm run validate:manifest
npm run pack-mcpb # -> amira-mcp-server.mcpb
scripts/census.mjs re-runs the property census behind the field mapping
(scripts/census-report.json) — rerun and diff it if the instance's templates
change. The design decisions behind it are in ROADMAP.md; CHANGELOG.md
records each release.
Continuous delivery
Three GitHub Actions cover pull requests and distribution (the two distribution workflows crawl the public API — no credentials):
-
CI (
.github/workflows/ci.yml) — on pull requests and pushes tomain: type-checks and lints once, then runs the offline unit suite (including the tool-surface token budget) on Node.js 22.0.0, 22, 24 and 26 on Linux and Node.js 24 on Windows, then exercises both MCP transports, weighs every tool's response at its maximum limit, and validates the MCPB manifest. The complete dependency audit fails on high or critical advisories. The packed.mcpbis then unpacked on Windows and macOS and smoke-tested there, so CI runs the bytes users install. A separate container job builds an offline fixture image and checks health. Windows CI also packs a fixture extension and checks its file list. A non-blocking job runs the official MCP conformance suite against the HTTP server. Actions are pinned to commit SHAs; every job has a timeout. -
Release (
.github/workflows/release.yml) — on a pushedv*tag: refuses a version already published on GitHub or the MCP Registry (released bytes are never replaced; fix a release with a new version), checks the tag againstpackage.json, crawls a fresh snapshot, runs unit, live and smoke tests, packs the.mcpb, zips the companion skill (amira-mcp-skill.zip) and builds the image in a read-only job that records the SHA-256 of each. The publish job verifies those bytes, repeats the guard, attests their build provenance, and creates the release as a draft with the version'sCHANGELOG.mdsection as its notes before making it public. Non-blocking jobs push the tested image to GHCR with an attestation and publishserver.jsonto the MCP Registry with a pinned, checksum-verified publisher. -
Refresh data snapshot (
.github/workflows/refresh-data.yml) — weekly and on demand; rebuilds only when the transformed snapshot content hash changes, including item-set and vocabulary changes, updating the rollingdata-latestpre-release.
Publishing from Actions requires a writable token. If the organization disables write permissions for the default workflow token, either (a) enable Read and write permissions under Organization → Settings → Actions → General → Workflow permissions, or (b) add a repo/org secret
RELEASE_TOKEN(a PAT or GitHub App token withcontents: write). The workflows usesecrets.RELEASE_TOKENwhen present and fall back to the default token.
Semantic neighbours
get_similar_items finds records whose catalogue descriptions read most alike,
across research items, publications, videos, podcasts, projects and research
sections. The vectors come from the versioned
DRE Visualizations
releases semantic-embeddings-v1-<build>: google/embeddinggemma-2, 768
dimensions, L2-normalised, built offline from the public API only (title,
abstract or description, subjects and places; never full text).
The crawl downloads the newest release (or the one AMIRA_SEMANTIC_RELEASE
pins), verifies the model, dimensions, normalisation, row count, byte length,
SHA-256 and row norms against its manifest, and refuses any mismatch, so two
vector spaces never mix. It then computes, for every record present in the
snapshot, its ten closest records of each type, and stores those
(semantic_neighbours.json), never the ~15 MB of vectors: no model and no
vector runs at request time. Records absent from the snapshot are dropped
before ranking, and lists are filtered again at load, so a neighbour is always a
record the snapshot can cite. When no release verifies, the crawl keeps the
neighbours already served. A new release is picked up by the next crawl, which
a change on the Omeka site or the weekly forced crawl
(AMIRA_FULL_REFRESH_HOURS) triggers: a release alone does not start one. get_data_quality reports the release and its
coverage per type: records with neighbours, low-signal records (too little
own text, excluded by design) and records the build predates.
Scores are cosine similarities of descriptions: similar wording is not
evidence of a documented relation. So every neighbour is explained from the
catalogue links: shared names up to three subjects, places (a place shares
its country), people or the project the pair also shares (research sections
are too broad to count), with shared_counts when there are more, and basis: "wording_only"
marks a pair that shares none of them. get_research_item, get_publication,
get_podcast, get_video and get_project add the same five neighbours as a
similar block with include_similar: true; a record without neighbours
carries the reason there instead of an error. find_related entity_type=record
pivots on the same neighbours: the projects, sections, subjects, people,
countries and formats that the seed's 20 closest records share, counted per
corpus.
The same vectors give get_semantic_map: the crawl groups the records by
seeded spherical k-means (about a hundred per group, at most 30 groups, low-
signal records left out) and stores each group's member ids, nearest the
centre first. The groups are unnamed on purpose. The tool describes each one
by its type mix and its most frequent subjects, countries and projects, with
the records nearest its centre, so a group is characterised from its contents
rather than given an invented label. Group ids are renumbered per build
(1 = the largest).
Configuration (environment / extension settings)
Documentation truncated — see the full README on GitHub.
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Rea
Freeby Morluto · Developer Tools
Reverse engineer anything from your terminal or agent with one CLI and MCP server.
Paperclip
Freeby Paperclipai · Developer Tools
Trending hip-hop artist momentum scores across four cultural dimensions.
Fetch
Freeby Modelcontextprotocol · Developer Tools
Web content fetching and conversion for efficient LLM usage
Git
Freeby Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
