Inject, parse, and strip [N] citation markers in RAG output text via @mukundakatta/citecite-mcp (npx)
Three tools for managing [N]-style inline citations in LLM/RAG output: injectcitations appends or inserts markers, parsecitations finds them with positions, strip_citations removes them. Useful for RAG pipelines that need to attach source references to generated text.
@mukundakatta/citecite-mcp v0.1.1 — verified recipe
Install & run: npm install @mukundakatta/citecite-mcp → entry point src/index.js (stdio MCP)
Tools (3)
| Tool | Params | Returns | |
|---|---|---|---|
inject_citations | `{text, citations: [{idx, source_id?}], at?: "end"\ | "position", position?: int}` | {text_with_citations: string} |
parse_citations | {text} | {markers: [{pos, idx, len}]} | |
strip_citations | {text} | {stripped: string} |
Key gotchas
- Response key is `text_with_citations` NOT
text— easy to misuse and causes downstream crash instrip_citations(throws "Cannot read properties of undefined reading 'replace'" on undefined input instead of a clear error) - `position` mode inserts at raw character offset without word/sentence boundary awareness —
position: 41on "Python was created by Guido van Rossum and first released..." produces "...Rossum an[3]d first released..." (splits the word "and") - `strip_citations` leaves double spaces and trailing whitespace where markers were removed — no whitespace normalization: "The Earth [1] orbits" → "The Earth orbits"
- `position: 0` inserts without leading space: "[42]This fact needs..."
- Default `at` is "end" — omitting
atparam appends markers space-separated at the end - `parse_citations` ignores non-numeric brackets —
[abc]and[xyz]are NOT matched, only[digits] - Adjacent markers `[1][2][3]` parsed individually with correct offsets; multi-digit markers
[100]havelen: 5 - `source_id` is preserved in inject but NOT visible in parse — parse only returns
pos/idx/len
Verified trace (17 calls, 16 OK, p50=0ms)
inject_end_basic: "The capital of France is Paris..." → "...century. [1] [2]" (2ms)
inject_position_mid: position=41 → "...Rossum an[3]d first..." (0ms) ⚠️ word split
inject_end_five: 5 markers → "...at scale. [1] [2] [3] [4] [5]" (0ms)
inject_position_zero: pos=0 → "[42]This fact needs..." (1ms)
parse_basic: "[1]...[2]...[3]" → 3 markers with pos/idx/len (0ms)
parse_no_markers: "[abc] [xyz]" → empty markers array (1ms)
parse_adjacent: "[1][2][3]...[10][99]" → 5 markers, correct offsets (0ms)
strip_basic: "[1]...[2]...[3]" → text with double spaces (1ms)
strip_passthrough: no markers → unchanged (0ms)
round_trip: inject→parse→strip OK (1ms)
inject_position_sentence: pos=18 → "...star.[1] It is..." (0ms)
inject_default_mode: no at param → appends at end (1ms)
parse_triple_digit: [100][200][1] → correct len=5/5/3 (0ms)
strip_multiple: 5 markers → double spaces remain (0ms)Best practice
Use at: "end" for bulk citation appending (clean results). Avoid at: "position" unless you know exact character boundaries — it will split words. After stripping, collapse whitespace yourself: stripped.replace(/ +/g, ' ').trim().
{ "server": "@mukundakatta/citecite-mcp", "version": "0.1.1", "transport": "stdio", "entry": "src/index.js", "tools": 3, "calls": 17, "success_rate": "94%", "p50_ms": 0, "trace": [ { "tool": "inject_citations", "args": { "text": "The capital of France is Paris. It has been the capital since the 10th century.", "citations": [ { "idx": 1, "source_id": "wiki-france" }, { "idx": 2, "source_id": "hist-paris" } ], "at": "end" }, "result": { "text_with_citations": "The capital of France is Paris. It has been the capital since the 10th century. [1] [2]" }, "ms": 2 }, { "tool": "inject_citations", "args": { "text": "Python was created by Guido van Rossum and first released in 1991.", "citations": [ { "idx": 3, "source_id": "py-hist" } ], "at": "position", "position": 41 }, "result": { "text_with_citations": "Python was created by Guido van Rossum an[3]d first released in 1991." }, "ms": 0, "note": "word split at position" }, { "tool": "parse_citations", "args": { "text": "The Earth orbits the Sun [1] at approximately 107,000 km/h [2]. The Moon orbits Earth [3]." }, "result": { "markers": [ { "pos": 25, "idx": 1, "len": 3 }, { "pos": 59, "idx": 2, "len": 3 }, { "pos": 86, "idx": 3, "len": 3 } ] }, "ms": 0 }, { "tool": "strip_citations", "args": { "text": "The Earth [1] orbits the Sun [2] at 107,000 km/h [3]." }, "result": { "stripped": "The Earth orbits the Sun at 107,000 km/h ." }, "ms": 1, "note": "double spaces left behind" }, { "tool": "round_trip", "inject": "TypeScript adds static types to JavaScript. [7] [8]", "parse": { "markers": [ { "pos": 44, "idx": 7, "len": 3 }, { "pos": 48, "idx": 8, "len": 3 } ] }, "strip": "TypeScript adds static types to JavaScript. ", "ms": 1 } ] }
Verified execution trace — @mukundakatta/[email protected] (3 runs, 12/12 tool calls succeed)
Server: citecite-mcp/0.1.0 | Protocol: 2024-11-05 | Capabilities: tools p50 init: 78ms | p50 call: 0.4ms | 3 tools
All 3 tools verified with real RAG-style citation text:
inject_citations (at=end) — text: "The sky is blue. The ocean is deep.", citations: [{idx:1},{idx:2}] → {"text_with_citations":"The sky is blue. The ocean is deep. [1] [2]"} (appends markers at end)
inject_citations (at=position) — at: "position", position: 16, citations: [{idx:1,source_id:"wiki-sky"},{idx:2,source_id:"wiki-ocean"}] → {"text_with_citations":"The sky is blue.[1] [2] The ocean is deep."} (inserts at char offset 16)
parse_citations — text: "The sky is blue [1]. The ocean is deep [2]. Multiple refs [3][4]." → {"markers":[{"pos":16,"idx":1,"len":3},{"pos":39,"idx":2,"len":3},{"pos":58,"idx":3,"len":3},{"pos":61,"idx":4,"len":3}]} (finds all 4 markers with position and length)
strip_citations — same input → {"stripped":"The sky is blue . The ocean is deep . Multiple refs ."} (removes all [N] markers cleanly)
Deterministic across all 3 runs. Sub-millisecond calls. Essential for RAG pipelines that need to inject/parse/strip numbered citation markers.
{ "surface": "mcp.mukundakatta-citecite-mcp", "command": "node src/index.js", "tools": 3, "p50_init_ms": 78, "p50_call_ms": 0.4, "calls_ok": 12, "calls_total": 12, "protocol": "2024-11-05" }