UNPKG

@extenshi/mcp

Version:

Extenshi MCP server — bring the extension catalog (search, security, market research) and pre-publish scanning into your AI tools

71 lines • 3.97 kB
/** * Trust boundary for catalog data leaving the MCP server. * * Everything this server returns about an extension was written by somebody * else: the store listing and manifest by the extension's author, the review * text by arbitrary store users, and finding titles by our own scanners and by * an LLM that read the extension's code in order to describe it. All of it * lands directly in an AI client's context window, next to that client's tools. * * That is the second-order half of the injection problem. The scanning pipeline * defends its own LLM call (`llm_analysis_adapter._render_prompt`), but the * finding it produces is then read back out by a different agent — one that, * unlike the scanner, usually has a shell. A sentence planted in an extension * description that survives all the way into `get_reviews` output is the only * path in this system that runs from "text in a stranger's package" to "command * on a developer's machine". * * Two things travel with every catalog payload: * * 1. `_notice` — states, in the payload itself, that these strings are data. * An instruction is the only thing that defends against readable text * asking the reader to act on it, and it has to arrive WITH the data * rather than in documentation the agent never reads. * 2. `defangDeep` — removes what JSON encoding does not. `JSON.stringify` * escapes quotes, backslashes and control characters, so nothing here can * break out of the string it sits in; it does NOT touch zero-width or * bidi codepoints (invisible to whoever reads the transcript afterwards, * ordinary text to a tokenizer) or backtick runs (which close the markdown * fence a client renders the result in). * * Content is preserved, never deleted. An extension whose description tries to * steer an automated reader is worth seeing and reporting; a filter that * silently removed the attempt would hide exactly the thing worth knowing. * * Mirrors `_defang_untrusted_text` / `_defang_envelope` in * `dags/src/dags/scanners/llm_analysis_adapter.py`. Nothing can import across * that boundary — one side is Python in the pipeline, the other TypeScript in a * published npm package — so the two are kept in step by * `untrusted.test.ts::parity` rather than by a shared module. */ /** * C0/C1 control characters are deliberately NOT stripped here, and this differs * on purpose from `sanitizeThirdPartyLabel` in @extenshi/cli, which does strip * them (`CONTROL_RE`). * * The two paths have different sinks. Everything here is serialised by * `JSON.stringify`, which encodes control characters as escape sequences, so * they arrive as visible text rather than as terminal commands — and these * payloads are prose a reader has to read, so flattening them would cost * evidence for no gain. The CLI prints names straight to a terminal through * chalk with no encoding in between, where an ESC sequence is executed. * * So: do not "fix" the omission here, and do not copy this approach into the * CLI. The first would make descriptions unreadable; the second would reopen a * terminal-injection gap. */ export declare const UNTRUSTED_NOTICE: string; /** Neutralise what JSON encoding misses, without removing content. */ export declare function defangUntrusted(text: string, maxLength?: number): string; /** Apply `defangUntrusted` to every string in a payload. Keys are ours. */ export declare function defangDeep<T>(value: T): T; /** * Serialise a catalog payload for an MCP tool result. * * `_notice` is added as a field rather than as a prefix line so the result stays * a single parseable JSON object — `@extenshi/mcp` is published, and a consumer * doing `JSON.parse` on the tool result must keep working. The addition is * additive for anyone reading named fields. */ export declare function renderCatalogPayload(payload: unknown): string; //# sourceMappingURL=untrusted.d.ts.map