@noeva/core-mcp
v1.10.0
Published
MCP server for the Noeva core APIs (workspaces, files, folders) — protocol adapter over the noeva-server-api REST API. Ships an HTTP service (central deploy) and a stdio package (client-distributable).
Readme
@my-ginkgo/noeva-core-mcp
An MCP server for the Noeva core APIs —
workspaces, files and folders. It is a thin protocol adapter: it translates MCP
tools/call requests into HTTP calls against the existing noeva-server-api REST API.
It holds no business logic, never talks to a database, and stores no Noeva secrets.
Public install (npm)
Installazione pubblica senza credenziali GitHub:
npx -y @noeva/core-mcpConfig MCP (es. Claude Desktop):
{
"mcpServers": {
"noeva-core": {
"command": "npx",
"args": ["-y", "@noeva/core-mcp"],
"env": {
"NOEVA_API_BASE_URL": "https://api.noeva.ai",
"NOEVA_API_KEY": "noeva_sk_..."
}
}
}
}Il canale
@my-ginkgo/noeva-core-mcpsu GitHub Packages resta disponibile per uso interno (richiede un PATread:packages).
The same codebase ships two transports:
| Transport | Who runs it | Auth source | How it's distributed |
| --------- | ---------------------- | -------------------------------------------- | -------------------------- |
| HTTP | Noeva (central deploy) | per-request bearer token | Docker image |
| stdio | the customer (local) | NOEVA_API_KEY env (a noeva_sk_… API key) | npm package, run via npx |
Tools
Consolidated tools, each with an action selector:
| Tool | Actions |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| core_workspaces | list, get, members, consumption, usage_check, dashboard_stats, usage_metrics (all read-only) |
| core_files | search, get, content, versions, activities, presigned_url, file_folders (read); upload, crawl_website, make_ai_ready, upload_prepare, upload_complete (write/soft-write) |
| core_folders | tree, root, get, files (read); create, rename, move, add_file, remove_file (write) |
| core_search | semantic, keyword (read-only) |
| core_processes | list, get, aggregate (read-only) |
| core_tags | list_tags, list_categories, file_tags_categories (read); tag/category create + assign/unassign by name (write) |
| core_graph (V5) | topology, find_folder_paths, get_file_paths, find_thematic_cluster, cross_branch_files (read-only) — structural shortcuts over the knowledge-base graph, ~10× fewer tokens than equivalent semantic-search exploration |
Write actions require confirmation (elicitation or a HMAC-bound confirm_token). Every
action takes a workspace_id (UUID) except core_workspaces.list.
core_graph — knowledge-base graph (V5)
Read-only structural shortcuts over the workspace knowledge-base graph (files↔folders↔tags↔categories + folder hierarchy + Louvain thematic clusters). All actions share the same upstream call to GET /api/graph/workspace and apply a per-action slicer in the MCP dispatch layer to return compact, LLM-friendly payloads (~50-150 tokens vs MB of raw analysis on large workspaces).
| Action | Args | Use when… |
| ----------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| topology | workspace_id, optional top_k | Orientation at session start: counts + top folders/tags/categories + Louvain modularity per projection |
| find_folder_paths | workspace_id, name | Disambiguation: same-name folders under different parents (e.g. two "Contracts" folders) |
| get_file_paths | workspace_id, file_id | Provenance grounding: every path a file lives in, plus cross-branch flag |
| find_thematic_cluster | workspace_id, kind: folder \| tag \| category, id | Discovery: Louvain cluster around an entity + sibling members |
| cross_branch_files | workspace_id, optional limit | Detection of cross-cutting content (files under different top-level branches — candidates for tag-based organization) |
Authoritative description: see docs/NOEVA_GRAPH_EXPLORER_TECHNICAL_GUIDE.md § 3.6.
Install for a client (stdio)
You run the server locally; your MCP client (Claude Desktop, an IDE, …) launches it.
1. Generate a NOEVA API key
In the Noeva app, go to Profile → API Keys and create a key. It looks like
noeva_sk_…, is long-lived, personal and revocable, and acts with your own permissions;
every operation is scoped to the workspaces you belong to. (A normal session JWT expires
after ~1 hour and is rejected here — the key must start with noeva_sk_.)
2. Add the server to your MCP client config
{
"mcpServers": {
"noeva-core": {
"command": "npx",
"args": ["-y", "@my-ginkgo/noeva-core-mcp"],
"env": {
"NOEVA_API_KEY": "noeva_sk_…",
"NOEVA_API_BASE_URL": "https://api.noeva.ai",
},
},
},
}Package registry. This package is published to GitHub Packages under the private
@my-ginkgoscope, sonpxneeds read access. Add to your~/.npmrc:@my-ginkgo:registry=https://npm.pkg.github.com //npm.pkg.github.com/:_authToken=<GitHub PAT with read:packages>The PAT must belong to an account granted access to the
my-ginkgoorg.
NOEVA_API_BASE_URL must be https (plain http is allowed only for localhost).
3. Uploading a file — two paths
File bytes never travel through a tool argument (there is no inline/base64 upload). There are exactly two paths, in order of preference:
- 3-phase presigned flow (preferred). Call
core_filesaction: "upload_prepare"withfile_name/file_type/file_sizeto get afile_idand a presignedupload_url. PUT the raw file bytes to that URL yourself (setContent-Type, no auth header, do not base64-encode). Then callaction: "upload_complete"with thefile_idandsuccess: true. The bytes go straight to storage, byte-perfect, for any file up to 50 MB. Addfolder_idtoupload_completeto file it into a folder. - Drag & drop panel (fallback). When you cannot run the byte PUT yourself — you don't
have the bytes, the user dragged a file into the chat, or
upload_preparereports the file is too large — callcore_upload_uiaction: "open". The user picks the file in an interactive panel and it uploads directly to storage. On hosts without an interactive UI, the tool returns text guiding the 3-phase flow instead.
Files ≥ 50 MB are not supported in v1 (the API switches to a resumable TUS flow this server does not yet implement). Use the panel or the Noeva app for very large files.
4. Revoke access
Revoke the API key in the Noeva app (Profile → API Keys). The server has no other credentials, so revoking the key fully revokes the integration.
Confirmation for writes
Confirmed writes (e.g. rename, crawl_website, folder/tag mutations) never execute
silently. The server confirms first, via one of two channels:
- Elicitation (if your client supports it): you get a confirmation prompt.
- Dry-run + confirmation token (fallback): the first call returns a preview and a
confirm_token; call again with the identical arguments plus that token to execute. The token is bound to the exact arguments and expires.
Uploads are soft-writes: upload_prepare / upload_complete run immediately without
a confirmation gate (upload_prepare only creates a pending record; upload_complete
verifies the bytes server-side before finalizing).
Security model
noeva-server-api is the only trust boundary. This server:
- forwards your token as an opaque bearer credential and never verifies or decodes it;
- holds no Noeva secrets (no
SUPABASE_JWT_SECRET, no service key) — the stdio package is fully inspectable and contains nothing privileged; - can do nothing your token cannot already do — there is no escalation path.
The one exception to "everything goes through the REST API": during the 3-phase
upload, the file bytes are PUT directly onto a presigned storage URL that
noeva-server-api itself issued during upload_prepare. That PUT is performed by the
client (or the upload-panel iframe), never by passing bytes through this server, and only
ever targets the URL the API authorised.
Logs (always on stderr in stdio mode) never contain tokens, PII or file content.
Development
pnpm install
pnpm dev:stdio # run the stdio transport (reads .env)
pnpm dev:http # run the HTTP transport
pnpm inspect # launch the MCP Inspector against the stdio build
pnpm test # vitest
pnpm lint
pnpm buildCopy .env.example to .env for local dev (gitignored; never used in production).
HTTP deploy (central)
Built as a Docker image (Dockerfile). It is stateless and scales horizontally; set a
shared MCP_CONFIRMATION_SECRET across instances so dry-run and execute can land on
different replicas. Health check: GET /health. OAuth resource metadata is advertised at
/.well-known/oauth-protected-resource.
Status / known limitations (v1)
- API key support — done.
noeva-server-apiaccepts long-lived personal API keys (noeva_sk_…, sent asAuthorization: Bearer), so the stdio transport works with a key generated in Profile → API Keys. Same mechanism asnoeva-mcp-crm. - Large files (≥ 50 MB) are not supported (no resumable TUS client yet). Use the
drag & drop panel (
core_upload_ui) or the Noeva app. folder_idon upload links the new file to a folder; pass it tocore_files action: "upload_complete"after a successful byte PUT.- Rate limiting in-process is a courtesy guard only; authoritative per-token limiting
lives in
noeva-server-api(prerequisite P2).
