# How @ References Resolve Local Files and MCP Resources in DeepSeek-Reasonix Chat

> Discover how DeepSeek-Reasonix resolves @ references to local files and MCP resources. Learn about its three-stage pipeline for secure content injection into chat contexts.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: how-to-guide
- Published: 2026-06-22

---

**DeepSeek-Reasonix resolves @ references through a three-stage pipeline in [`internal/control/refs.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/refs.go) that extracts tokens, classifies them as MCP resources or local files, and injects sanitized content into chat context before the turn reaches the model.**

In the `esengine/DeepSeek-Reasonix` repository, any token prefixed with `@` triggers a resolution process that transforms bare filenames or server identifiers into concrete context. The implementation lives primarily in [`internal/control/refs.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/refs.go) and handles everything from **MCP resources** (`@server:uri`) to **local files**, **directories**, and **image attachments**, enforcing workspace sandboxing and size limits throughout.

## The Three-Stage Resolution Pipeline

The resolution logic follows a strict pipeline: **token extraction**, **classification**, and **content injection**. Each stage is designed to safely expand user input into model-ready markup without exposing the underlying filesystem beyond the workspace root.

### Stage 1: Token Extraction with `parseRefTokens`

The process begins with `parseRefTokens`, which scans the input line using the regular expression `@([^\s]+)`. This captures any non-whitespace string following an `@` symbol. The function returns a deduplicated list of raw tokens, automatically stripping trailing punctuation to ensure `@README.md` and `@README.md:` are treated as the same reference.

### Stage 2: Classification via `classifyRef` and `detectRefsMode`

Once extracted, each token is classified by `classifyRef` (or the inline logic of `detectRefsMode`). The classifier checks three distinct categories:

- **MCP Resource (`refResource`)**: Tokens matching the pattern `@<server>:<uri>` where `<server>` exists in `c.host.ServerNames()`. These reference external resources provided by connected Model Context Protocol servers.
- **Local File or Directory (`refFile`)**: Tokens that resolve to an existing path inside the workspace via `workspaceRefPath` and `os.Stat`. This includes directories, which receive special handling.
- **Image Attachment (`refImage`)**: Image files recognized by extension or MIME type that should be attached to the turn for vision-capable models.

Tokens that do not match these patterns (such as email addresses or @-mentions) are ignored and passed through unchanged.

### Stage 3: Content Injection with `resolveRefs`

The final stage orchestrated by `resolveRefs` (and `resolveScopedRefs`) iterates over classified references and generates XML-like tags that the model consumes:

- **MCP resources**: Calls `c.host.ReadResource(ctx, r.server, r.uri)` and wraps the result in `<resource ref="@server:uri">…</resource>` tags.
- **Files and directories**: Invokes `readFileRef(r.path, c.cpRoot)`. If the path is a directory, it produces a truncated listing (maximum 100 entries) inside `<dir>` tags. Files are wrapped in `<file>` tags.
- **Images**: Emits `<image path="…">` tags indicating an attachment available for multimodal models.

## Security and Workspace Sandboxing

Before any filesystem access occurs, `resolveAbsRef` sanitizes user-supplied paths against the controller’s workspace root (`c.cpRoot`). This prevents **directory traversal attacks** (e.g., `../../../etc/passwd`) by resolving the absolute path and ensuring it remains within the allowed workspace boundary. The `detectRefsMode` function accepts a boolean flag to toggle between scoped (workspace-only) and unscoped resolution, with the chat interface typically enforcing scoped mode for safety.

## Handling Different Resource Types

### MCP Resources

When a user references an MCP resource using the `@<server>:<uri>` syntax, the system validates the server name against active connections. The `ReadResource` call returns the content, which is injected directly into the prompt context. This allows the model to consume live data from external tools without the user manually copying content.

### Files and Directories

For local files, `readFileRef` applies several safeguards:

- **Size limits**: Text files larger than `maxFileRefBytes` (64 KB) are truncated with a clear marker indicating the omission.
- **Directory listings**: Recursive directory scans are capped at 100 entries to prevent context window overflow.
- **Binary files**: Non-text files are replaced with a placeholder indicating the file type and size rather than raw bytes.

### Images and PDFs

**Image attachments** receive special treatment: instead of injecting base64 data into the text context, the system emits `<image path="docs/arch.png">` tags that signal the frontend to attach the actual image file to the API request for vision models.

**PDF files** are handled by `readPDFRef`, which attempts to extract text via the `pdftotext` command-line tool, falling back to a Python-based extractor if necessary. This allows users to reference documentation or specifications directly without manual conversion.

## Resolution Flow Implementation

The following simplified Go code illustrates how `ResolveRefs` orchestrates the complete pipeline:

```go
func (c *Controller) ResolveRefs(ctx context.Context, line string) (block string, errs []string) {
    // 1️⃣ Detect and classify all @‑tokens.
    refs := c.detectRefsMode(line, false)      // false → allow un‑scoped refs
    // 2️⃣ Resolve bare filenames that exist somewhere under the workspace.
    refs = resolveBareNames(refs, c.cpRoot)

    var b strings.Builder
    for _, r := range refs {
        switch r.kind {
        case refResource: // MCP resource
            txt, err := c.host.ReadResource(ctx, r.server, r.uri)
            if err != nil { errs = append(errs, "@"+r.raw+" — "+err.Error()); continue }
            appendRefBlock(&b, "resource", `ref="`+r.raw+`"`, txt)

        case refFile: // local file / directory
            txt, isDir, err := readFileRef(r.path, c.cpRoot)
            if err != nil { errs = append(errs, "@"+r.raw+" — "+err.Error()); continue }
            tag := "file"
            if isDir { tag = "dir" }
            appendRefBlock(&b, tag, `path="`+r.path+`"`, txt)

        case refImage: // image attachment
            appendRefBlock(&b, "image", `path="`+r.path+`"`,
                "[image attachment available at @"+r.path+" …]")
        }
    }
    return b.String(), errs
}

```

## Summary

- **Token extraction** in [`internal/control/refs.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/control/refs.go) uses regex `@([^\s]+)` to find references, stripping trailing punctuation and deduplicating results.
- **Classification** distinguishes MCP resources (`@server:uri`) from local files and images using `classifyRef` and filesystem checks against the workspace root.
- **Security** is enforced by `resolveAbsRef`, which prevents path traversal by validating all paths against `c.cpRoot`.
- **Content injection** converts resources into XML-like tags (`<resource>`, `<file>`, `<dir>`, `<image>`) with size limits (64 KB for text, 100 entries for directories) and special handling for PDFs via `readPDFRef`.

## Frequently Asked Questions

### How does DeepSeek-Reasonix prevent path traversal attacks when resolving @ references?

The `resolveAbsRef` function sanitizes every user-supplied path by resolving it against the controller’s workspace root (`c.cpRoot`). It validates that the final absolute path remains within the workspace boundary, rejecting any attempts to use `..` sequences to escape the sandbox. This ensures that `@../../../etc/passwd` resolves safely or fails outright rather than exposing sensitive system files.

### What is the difference between @ references for files versus MCP resources?

Local file references (e.g., `@README.md`) are resolved against the workspace filesystem using `os.Stat` and `workspaceRefPath`, then injected as `<file>` or `<dir>` tags. MCP resources (e.g., `@modelcontextprotocol:specs/api.md`) use the `@<server>:<uri>` syntax, trigger a lookup against connected server names via `c.host.ServerNames()`, and call `ReadResource` to fetch content from external tools, wrapping results in `<resource>` tags.

### Are there size limits when including files via @ references?

Yes. Text files are truncated to `maxFileRefBytes` (64 KB) with a truncation marker indicating omitted content. Directories are limited to 100 entries in their recursive listing. Binary files are not inlined; instead, a placeholder description is inserted. These limits prevent individual references from consuming excessive context window space.

### How are PDF files handled differently from plain text files?

When a user references a PDF, the system invokes `readPDFRef`, which attempts text extraction via the `pdftotext` command-line utility, falling back to a Python-based extractor if necessary. The extracted text is then treated like a standard text file (subject to the 64 KB limit), whereas plain text files are read directly without conversion. This allows PDF content to be searchable and consumable by the model without requiring manual pre-processing.