How MCP Plugin Resources Are Referenced in Chat: DeepSeek-Reasonix Implementation
MCP plugin resources are referenced in chat using the @<server>:<uri> syntax, which the controller detects, validates against connected servers, and injects into the conversation context after fetching the content via RPC calls.
DeepSeek-Reasonix treats MCP (Multi-Channel Plugin) resources as first-class references that can be injected directly into any chat turn. When a user types a token matching the @server:uri pattern, the system automatically resolves the reference by communicating with the connected MCP server and inserting the retrieved content into the model's prompt.
The Reference Syntax Pattern
Reasonix uses a concise, mention-style syntax for resource references that mirrors familiar social media patterns. A valid reference follows the format @<server>:<uri>, where the server name identifies the connected MCP plugin and the URI specifies the resource path.
For example, when a user writes:
Please summarise the API spec: @docs:file://README.md
The controller identifies @docs:file://README.md as a potential MCP resource reference. The prefix before the colon (docs) must match a connected MCP server name stored in the controller's known map, while the suffix (file://README.md) represents the resource URI that the server understands.
Detection and Classification Pipeline
The reference detection logic resides in internal/control/refs.go and operates in two distinct phases to ensure only valid MCP resources are processed.
Token Detection
The detectRefs routine scans each line of chat input for tokens beginning with @. When it finds a candidate, it extracts the server name and URI by splitting on the first colon:
// inside detectRefs (internal/control/refs.go)
if i := strings.Index(tok, ":"); i > 0 && i+1 < len(tok) && known[tok[:i]] {
// → token matches a connected server name
refs = append(refs, ref{
kind: refResource,
server: tok[:i],
uri: tok[i+1:],
raw: tok,
})
}
This creates a ref struct with kind set to refResource (defined at line 39 of internal/control/refs.go), capturing both the server identifier and the specific resource URI.
Server Validation
The classifyRef function validates references against the known map of currently connected MCP servers (see line 74 of internal/control/refs.go). If the server prefix does not match an active connection, the token is ignored or treated as plain text, preventing invalid RPC calls to disconnected plugins.
MCP Resource Lifecycle
Once a reference is validated, Reasonix coordinates with the MCP plugin through a three-stage lifecycle: enumeration, retrieval, and injection.
Listing Available Resources
When an MCP server connects, the Host queries the plugin to discover available resources via the listResources method in internal/plugin/resources.go. This method invokes the RPC method resources/list and unmarshals the response into a slice of plugin.Resource objects:
// internal/plugin/resources.go
func (c *Client) listResources(ctx context.Context) ([]Resource, error) {
res, err := c.call(ctx, "resources/list", map[string]any{})
// … unmarshal JSON into []Resource …
}
The resource list is aggregated at the host level through internal/plugin/plugin.go (specifically the Resources() and fetchResources methods), making discovered resources available to the UI for auto-completion and status displays.
Reading Resource Content
When the controller needs to resolve a specific reference, it calls readResource (line 50 of internal/plugin/resources.go) to fetch the actual content:
// internal/plugin/resources.go
func (c *Client) readResource(ctx context.Context, uri string) (string, error) {
res, err := c.call(ctx, "resources/read", map[string]any{"uri": uri})
// … concatenate text portions, omit binary blobs …
return sb.String(), nil
}
This method invokes the resources/read RPC method. The response may contain text or binary blobs. Text content is concatenated and preserved for injection, while binary data is summarized (e.g., "[binary resource …]") to prevent token bloat in the model's context window.
Content Injection into Chat Context
The ResolveRefs method in internal/control/controller.go orchestrates the final injection. It replaces the original @server:uri token with the fetched content, prepending the resource text to the user's prompt:
func (c *Controller) ResolveRefs(line string) string {
for _, r := range c.detectRefs(line) {
if r.kind == refResource {
txt, _ := c.mcp.client(r.server).readResource(context.Background(), r.uri)
line = strings.Replace(line, "@"+r.raw, txt, 1)
}
}
return line
}
The resolved content is sent to the LLM as part of the conversation history, allowing the model to reason about external documents, code files, or web-accessible resources without manual copy-pasting.
Key Implementation Files
The end-to-end flow spans several components within the Reasonix codebase:
internal/control/refs.go– ContainsdetectRefsandclassifyReffor parsing@tokens and distinguishing MCP resources (refResource).internal/plugin/resources.go– Defines theResourcestruct and implementslistResourcesandreadResourcefor RPC communication.internal/plugin/plugin.go– Host-level aggregation viaResources()andfetchResourcesmethods that collect resources from all connected servers.internal/control/controller.go– Session driver that callsdetectRefsand injects resource content into chat turns.internal/cli/mcp_manager_view.go– CLI helper that renders MCP status, including the number of discovered resources for each connection.
Summary
- Reference syntax follows the pattern
@<server>:<uri>, where the server prefix must match a connected MCP plugin. - Detection occurs in
internal/control/refs.goviadetectRefs, which createsrefResourcestructs for valid tokens. - Validation checks the server name against the
knownmap inclassifyRefbefore attempting RPC calls. - Resource enumeration uses
listResources(RPCresources/list) to discover available items when servers connect. - Content retrieval happens through
readResource(RPCresources/read), which handles both text and binary data. - Injection replaces the original token with fetched content via
ResolveRefsin the controller, prepending resource data to the model prompt.
Frequently Asked Questions
What happens if I reference an MCP server that isn't connected?
If the server prefix in your @server:uri token does not match an entry in the controller's known map, the classifyRef function treats the token as plain text. The system does not attempt to resolve the reference via RPC, and the literal text remains in your chat message without triggering a resource fetch.
Can MCP resources contain binary data like images or PDFs?
Yes, but with limitations. The readResource implementation in internal/plugin/resources.go detects binary responses and summarizes them (e.g., "[binary resource …]") rather than injecting raw bytes into the chat context. This prevents token overflow while still informing the model that a binary resource exists at the referenced location.
How does Reasonix handle multiple resource references in a single message?
The ResolveRefs method iterates over all detected references in the input line, fetching content for each valid @server:uri token sequentially. Each reference is replaced with its corresponding content, and the fully resolved string is then sent to the LLM. The order of resolution follows the left-to-right appearance of tokens in the original message.
Where can I see which MCP resources are available before referencing them?
The internal/cli/mcp_manager_view.go file renders the MCP status interface, which displays the number of discovered resources for each connected server. Additionally, the Resources() method in internal/plugin/plugin.go aggregates available resources from all connections, making them accessible to the UI for browse-and-select functionality or auto-completion hints.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →