Atlas / MCP servers / fabriziosalmi / noted

notedBLOCK

mcp/fabriziosalmi/noted

Desktop app for taking notes in Markdown/HTML, with built-in AI, note links (wikilinks), global search, local history, and Git integration

Verdict
BLOCK
Grade
D
Trust score
63 /100
Exposed tools
3 3r · 0w · 0d
Transport
sse · stdio · streamable-http
License
MIT
Stars
1
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://github.com/fabriziosalmi/noted/actions/workflows/ci.yml) [](https://github.com/fabriziosalmi/noted/releases/latest) [](https://fabriziosalmi.github.io/noted/) [](./LICENSE)

Noted is an open-source desktop app for taking notes in Markdown/HTML, with built-in AI, note links (wikilinks), global search, local history, and Git integration. Local-first: your notes stay on your machine, there is no account and no telemetry.

▶ Watch the 15-second demo · Documentation

Full-text search — every note, title and body Quick open — jump anywhere by name (⌘K)

Documentation: [fabriziosalmi.github.io/noted](https://fabriziosalmi.github.io/noted/) — installation, features, settings, keyboard shortcuts, th

Read from source at commit c07fe1325305OBSERVED · 2026-10-11
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add noted-markdown-spike --env GIT_AUTHOR_EMAIL=${GIT_AUTHOR_EMAIL} --env GIT_AUTHOR_NAME=${GIT_AUTHOR_NAME} --env NOTED_MCP_AUTH_TOKEN=${NOTED_MCP_AUTH_TOKEN} -- npx -y noted-markdown-spike
claude-desktop
{
  "mcpServers": {
    "noted-markdown-spike": {
      "command": "npx",
      "args": [
        "-y",
        "noted-markdown-spike"
      ],
      "env": {
        "GIT_AUTHOR_EMAIL": "${GIT_AUTHOR_EMAIL}",
        "GIT_AUTHOR_NAME": "${GIT_AUTHOR_NAME}",
        "NOTED_MCP_AUTH_TOKEN": "${NOTED_MCP_AUTH_TOKEN}"
      }
    }
  }
}
03

Exposed tools (3)

3 read · 0 write · 0 destructive.

ToolRiskDescription
make-formalreadRewrite formally
notereadThe whole note, if the prompt is about one
selectionreadThe text to work on
04

Trust audit

BLOCKgrade D · trust 63/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryWARN
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (3 observation(s))
Network
none-observed
Shell
declared (5 observation(s))
Dependencies
not all pinned
Secrets in source
none-found

Findings (25)

HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
electron/ipc/app.ts:51
exec(`osascript "${scriptFile}"`, (err) => {
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
MEDIUMInventory / provenance · inv.binary · CWE-1104
public/icon.icns
icon.icns
Why it matters. a compiled or binary member cannot be reviewed from source
Fix. ship source, or explain the binary in the README
MEDIUMObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
shared/markdown/golden.ts:113
['inline', 'emoji-zwj', 'Family 👨👩👧 and flag 🇮🇹.'],
MEDIUMObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
shared/markdown/golden.ts:258
['doc', 'bom', '# Title', '# Title'],
MEDIUMObfuscation / stealth · obf.zero_width · CWE-506, CWE-94
shared/markdown/sections.ts:34
const bom = markdown.startsWith('') ? 1 : 0;
LOWInventory / provenance · inv.hidden_file · CWE-1104
.env.local.example
.env.local.example
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInventory / provenance · inv.hidden_file · CWE-1104
.fleet.toml
.fleet.toml
Why it matters. hidden member outside the usual dotfiles
Fix. review its purpose
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
e2e/evernote-import.e2e.ts:9
const md5 = (b: Buffer) => crypto.createHash('md5').update(b).digest('hex');
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
e2e/obsidian-vault.e2e.ts:34
else out[r] = `${crypto.createHash('sha1').update(fs.readFileSync(path.join(root, r))).digest('hex')}@${fs.statSync(path.join(root, r)).mtimeMs}`;
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
electron/embedding-store.ts:32
const id = crypto.createHash('sha1').update(`${provider}\0${model}`).digest('hex').slice(0, 8);
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
electron/enex-stream.ts:60
note.resources.push({ data, mime: resource.mime, fileName: resource.fileName, hash: crypto.createHash('md5').update(data).digest('hex') });
LOWInsecure crypto · crypto.weak_hash · CWE-327, CWE-338
electron/import-enex.test.ts:15
const md5 = (b: Buffer) => crypto.createHash('md5').update(b).digest('hex');
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
e2e/capture.e2e.ts:36
expect(await capture('odd', '../../etc')).toMatchObject({ success: true });
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
electron/app-protocol.test.ts:19
'/a/../../outside',
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
electron/attachments.test.ts:81
for (const bad of ['../outside.png', 'attachments/../../x.png', '/etc/hosts.png', '.noted_history/secret.png', 'notes.md', 'attachments/nope.png', 'attachments/ok.svg', '%2e%2e/x.png']) {
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
electron/core/dom.ts:1
import type { DomEnv } from '../../shared/markdown/html';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
electron/core/language.ts:7
import { LANGS, dictionaryFor, ensureLocale, type Dictionary, type Lang } from '../../shared/i18n/locales';
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
electron/ingest-fetch.test.ts:10
for (const ip of ['127.0.0.1', '127.9.9.9', '0.0.0.0', '10.0.0.5', '172.16.0.1', '172.31.255.255', '192.168.1.1', '169.254.169.254', '100.64.0.1', '224.0.0.1', '255.255.255.255', '198.18.0.1',
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
electron/ingest-fetch.test.ts:71
const err = await fails(fetchPage(url(), { isPublic: a => a === '127.0.0.1', resolve: async h => (h === 'metadata.test' ? ['169.254.169.254'] : ['127.0.0.1']) }));
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
electron/ingest-fetch.test.ts:84
for (const bad of ['http://127.0.0.1/', 'http://2130706433/', 'http://0x7f.0.0.1/', 'http://[::1]/', 'http://[::ffff:127.0.0.1]/', 'http://169.254.169.254/latest/', 'http://10.1.2.3:8080/', 'http://lo
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
electron/llm-guard.test.ts:20
'http://169.254.169.254/latest/meta-data/',
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
electron/llm-guard.test.ts:21
'http://metadata.google.internal/computeMetadata/v1/',
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
e2e/citations.e2e.ts:43
j.state.settings = { ...(j.state.settings || {}), language: 'en', llmProvider: 'lmstudio', lmStudioUrl: `http://127.0.0.1:${p}/v1`, llmModel: 'fake', piiMasking: false, embeddingsEnabled: false };
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
e2e/ingest.e2e.ts:41
j.state.settings = { ...(j.state.settings || {}), language: 'en', llmProvider: 'lmstudio', lmStudioUrl: `http://127.0.0.1:${p}/v1`, llmModel: 'fake', piiMasking: false, embeddingsEnabled: false };
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
e2e/ingest.e2e.ts:50
await dialog.getByLabel('Web address').fill(`http://127.0.0.1:${targetPort}/secret`);

Gates applied: no_behavioural_pass.

Audited 2026-10-11 · audit v0.4.1 · source sha c07fe1325305full audit observations/trust-audit/mcp-server/fabriziosalmi__noted.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-11c07fe1325305BLOCKD63first audit
06

Questions

What is the noted MCP server?

Desktop app for taking notes in Markdown/HTML, with built-in AI, note links (wikilinks), global search, local history, and Git integration

What tools does noted expose?

3 in total: 3 read-only, 0 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is noted safe to connect to an agent?

No — not without reading the findings first. The audit graded it D (63/100) and found 1 critical or high issue in the source. Each one is listed on this page with the file and line it is on.

What credentials does noted need?

It reads GIT_AUTHOR_EMAIL, GIT_AUTHOR_NAME and NOTED_MCP_AUTH_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does noted run?

It speaks sse, stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as noted-markdown-spike.

How current is this page?

The grade is for one exact copy of the source (c07fe1325305), read on 2026-10-11. The repository is watched and re-audited when it changes.

Advertisement