# File downloads (MCP resources)

Wire containers expose every uploaded file as an MCP **resource**. Connected agents can fetch the original bytes of a file, not just the chunks or canonical entries that come out of analysis. This is how your agent pulls a raw PDF, reads a CSV start to finish, or grabs an image that lives alongside your structured context.

## The URI scheme

Every file in a container is addressable under:

```
wire://container/{containerId}/file/{fileId}
```

This is not a fetchable URL on its own. It's an opaque identifier that only has meaning inside an authenticated MCP session with your container. Clients resolve it by calling the MCP `resources/read` method — Wire mints a short-lived signed download URL and returns it.

## How resolution works

```text
┌──────────┐    resources/read         ┌──────────────────┐
│   Agent  │────────────────────────→  │  Wire MCP server │
│  client  │   { uri: "wire://..." }   │                  │
└──────────┘                           └─────────┬────────┘
     ▲                                           │
     │                                           │ validate session,
     │                                           │ mint signed URL,
     │      { contents: [{                       │ record activity event
     │        uri, mimeType:                     │
     │        "text/uri-list",                   │
     │        text: "https://…?token=…" }] }     │
     └───────────────────────────────────────────┘
                 │
                 │  HTTPS GET (out of band)
                 ▼
     ┌─────────────────────────────┐
     │  Wire download route        │
     │  • verifies the token       │
     │  • streams the file bytes   │
     │  • returns with correct     │
     │    Content-Type / Filename  │
     └─────────────────────────────┘
```

1. The agent's MCP client calls `resources/read` on a `wire://` URI.
2. Wire validates the session, checks that the URI's container matches the session's container (blocks swap attacks), mints a JWT (HS256, 5 minute TTL), and returns a `text/uri-list` resource with a single entry — the signed HTTPS download URL.
3. The client follows the URL over ordinary HTTPS. Wire validates the token, streams the file bytes, charges 2 credits, records an activity event, and returns the response with the correct `Content-Type` and `Content-Disposition`.

The signed URL is never placed into your model's context — only the opaque `wire://` URI is.

## How agents discover resources

Two tool surfaces embed `resource_link` content entries in their responses so agents find downloadable files in the normal flow of retrieval, not through a separate catalog.

### `wire_navigate` (`mode: source`)

When an agent lands on a chunk via `wire_search` and calls `wire_navigate` in source mode, the response includes the chunks from that file plus a `resource_link` pointing at the underlying file's `wire://` URI.

```json
{
  "content": [
    { "type": "text", "text": "{ \"mode\": \"source\", \"results\": [...] }" },
    {
      "type": "resource_link",
      "uri": "wire://container/abc/file/xyz",
      "name": "customers.csv",
      "mimeType": "text/csv",
      "description": "Source file (12.4 KB). Call resources/read on this URI for a short-lived signed download URL."
    }
  ]
}
```

### `wire_explore` (`mode: get` on `_document`)

Every uploaded file has a `_document` canonical entry. When an agent calls `wire_explore` with `mode: "get"` on a `_document`, the response includes a `resource_link` for the file the entry represents.

## `resources/list`

`resources/list` is implemented but returns an empty list. The `wire://` URI scheme is resolvable on demand — any valid URI the agent encounters (via `resource_link` in a tool response) can be passed to `resources/read` without pre-enumeration. We intentionally avoid emitting a flat catalog of every file on every connection, which would bloat context with entries the session isn't actually working with.

## Credits and audit

- **2 credits** per successful download.
- Charge happens at the download step, not when the `wire://` reference is emitted or listed. If an agent surfaces 50 files and downloads 3, you pay for 3.
- Every successful download writes a `file_downloaded` container event (visible in the activity feed) and a `usage_event` row (visible in the credits ledger). Both carry user / API key attribution.

## URL lifetime

- **5 minutes.** After that the JWT is rejected and a new `resources/read` call is required.
- The token is bound to a specific `(containerId, fileId)` pair. A leaked URL cannot be reused against a different file even during its valid window.

## Client support

- **Claude Desktop, Claude web, MCP Inspector, Continue, Zed** — surface `resource_link` as a first-class attachment; follow `text/uri-list` responses natively.
- **Claude Code (today)** — reads the tool responses as text, so agents see the `wire://` URI and can call `resources/read` explicitly, but resource_link content entries are not yet rendered as attachments.

Behavior upstream of Wire will catch up. Wire itself stays spec-compliant — agents on any conforming client will be able to resolve resources as soon as the client supports it.