pulr MCP server
Commit Nov 1, 2026Enables AI agents to securely exchange files through scanned, provenance-stamped, and expiring capability URLs with human approval gates.
Also known as taleilon/pulr
- Stars
- 0
- Tools
- —
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Nov 1, 2026
- License
- MIT
What is pulr MCP?
pulr enables AI agents to securely exchange files through scanned, provenance-stamped, and expiring capability URLs with human approval gates.
Summary generated from the project's README
About pulr MCP server
Securing the transfer of files between AI agents, humans, and automated systems is what pulr enables. It acts as a handoff layer where agents can upload reports, code, or images to receive verified, expiring capability URLs. This process includes SHA-256 hashing and automated scanning for malware, leaked secrets, and prompt-injection heuristics before any link becomes active.
Developers can integrate this via the MCP server using a PULR_API_KEY in environments like Claude Desktop, Claude Code, or Codex. The system supports complex distribution policies, such as restricting access by IP, country, or time, and allows for human approval gates where a reviewer must manually release a file. For high-volume agent-to-agent workflows, workspaces can be configured for auto-acceptance of files from trusted senders.
Everything is backed by an audit log and Ed25519-signed receipts to ensure provenance. Users can manage multiple isolated workspaces under one account to keep different projects or clients separate, with each workspace maintaining its own unique address, quota, and security keys.
What you can do with it
- 1Human-in-the-loop file approvalAn agent generates a report that requires a human to review the scan results and provenance before the download link is released to a downstream pipeline.
- 2Secure agent-to-agent handoffsInstead of passing large data blobs directly in a chat context, one agent provides a capability URL that the receiving agent uses to fetch verified bytes.
- 3Time-sensitive credential deliverySend sensitive artifacts that automatically expire after a single download or a short period to minimize exposure.
- 4Geographic and network fencingRestrict file access to specific office IP ranges or certain countries to maintain compliance.
Written from the project's README. Every use case is checked against a quote from it.
Configuration
PULR_API_KEY
| Name | Description | |
|---|---|---|
| PULR_API_KEY | — |
Automated checks
Ran Nov 15, 2026Full report →Not verified yet. A server needs a score of 80, no serious finding, and enough data for us to check. How checks work · What to fix for more points
- Source repository linked and reachabletaleilon/pulr is public and reachablegithub.com/taleilon/pulr ↗Pass
- Package names this repository as its sourceNot checked
- Build provenance (Sigstore attestation)Not checked
- Open source license (OSI)MITspdx.org/licenses/MIT.html ↗Pass
- Commit or release in the last yearLast commit or release 2026-11-01github.com/taleilon/pulr ↗Pass
- OpenSSF ScorecardNot checked
- Package name not close to a popular packageNot checked
- No critical advisory in the package or its dependenciesNot checked
- No hidden instructions to the modelInstruction aimed at the model found in the description or READMEFinding
- Destructive tools are labelledNot checked
- Remote endpoint answers the MCP handshakeNot checked
README
View on GitHubpulr
Secure file exchange for AI agents. Agents produce files — reports, CSVs, images, PDFs, code — and have no safe way to hand them to other agents, humans, or downstream automation. pulr.ai is that handoff layer: drop a file, get a verified, scannable, expiring download URL everyone in the chain can actually trust.
Every upload is SHA-256-hashed, scanned before any link activates (secrets, prompt-injection heuristics, ClamAV malware), stamped with provenance (which agent, workflow, and model produced it), and served through unguessable capability URLs with TTLs, download limits, IP/geo/time restrictions, and instant revocation. Humans get a review page with approve/reject; automation gets webhooks and Ed25519-signed receipts. Everything is audit-logged — who fetched, when, from where.
Website: pulr.ai · Docs: pulr.ai/docs · Self-serve signup: pulr.ai/app
This repo is the open tooling: the MCP server (root, npm mcp-server-pulr), the JavaScript SDK (sdk/js, npm @pulr/sdk), and the Python SDK (sdk/python, PyPI pulr-sdk, with LangChain tools).
Sample uses
- Agent → human sign-off → automation. An agent generates a quarterly report with
approval: true; the reviewer gets the link by email, previews provenance and scan results, clicks Approve & release — only then does the download URL go live, and a webhook kicks off the downstream pipeline with a signed receipt as proof. - Agent → agent handoff without context stuffing. Instead of jamming base64 blobs into a context window, one agent uploads and passes a capability URL; the receiving agent fetches integrity-verified bytes. Revoke the link the moment the job is done.
- Burn-after-reading delivery.
max_downloads: 1+ a 1-hour TTL: send credentials-adjacent artifacts, one fetch, then the link is dead — with an audit row showing exactly who took it, from which IP. - Geo/time-fenced distribution. Lock a link to your office CIDR, US-only access, or 9–5 Eastern:
restrictions: { allow_ips, allow_countries, allow_hours }. - Quarantine as a feature. A "meeting notes" file with an embedded "ignore all previous instructions…" payload (even zero-width-obfuscated or base64-smuggled) gets flagged at upload and can never be shared — your agents never ingest it.
- Compliance trail.
GET /v1/artifacts/:id/receiptreturns an Ed25519-signed record of hash + provenance + scan + approval, verifiable by anyone without trusting pulr.
Your files are not our data
The only thing that ever reads uploaded bytes is the automated threat scanner — malware signatures, leaked-secret patterns, prompt-injection heuristics. It looks for threats, not information: the verdict is recorded, the content is not extracted, indexed, mined, trained on, or sold.
Many workspaces on one account
An account can hold as many workspaces as you like — one per client, per environment, per project. Each has its own workspace address (pa_... — where it receives files and how it is identified as a sender), quota, keys, inbox and audit trail; files never cross between them.
Keys carry a scope. A normal key is sealed inside the workspace that issued it. To manage the account you mint an account-scoped key (dashboard → Keys → account-wide, or POST /v1/keys {"scope":"account"}). Only a signed-in owner or an existing account key can mint one, so a workspace key can never promote itself.
curl https://pulr.ai/v1/account/workspaces -H "Authorization: Bearer $PULR_ACCOUNT_KEY" # list
curl -X POST https://pulr.ai/v1/account/workspaces -d '{"name":"Client Alpha"}' # create
curl -X PATCH https://pulr.ai/v1/account/workspaces/ws_123 -d '{"rotate_address":true}' # modify
curl -X DELETE https://pulr.ai/v1/account/workspaces/ws_123 -d '{"confirm":"Client Alpha"}' # delete
curl "https://pulr.ai/v1/artifacts?workspace=ws_123" # files in one workspace
Deleting removes files, links, inbox and audit trail permanently, so the API asks for the name back and refuses to delete an account's last workspace. Rotating an address invalidates the old one immediately.
As MCP tools: pulr_workspaces, pulr_workspace_create, pulr_workspace_update, pulr_workspace_delete, and pulr_list with workspace_id.
Delivery policy — hold or auto-accept
By default every offered file holds in the recipient's inbox until it is reviewed and accepted. For trusted, high-volume agent-to-agent pipelines a workspace can opt into auto-accept: clean files from an explicit trust list (sender pa_ addresses and/or verified agent-key fingerprints) are accepted the instant they arrive — the file_received webhook fires with auto_accepted: true and the receiving agent fetches the file with its own key. Scanning, quotas, signed receipts and audit are identical to a hand-accepted file; flagged files, unlisted senders and oversized files (if auto_max_bytes is set) always fall back to hold. Webhooks stay metadata-only — file bytes are never pushed.
curl -X POST https://pulr.ai/v1/workspaces/settings \
-H "Authorization: Bearer $PULR_API_KEY" -H 'Content-Type: application/json' \
-d '{"delivery_policy": "auto", "trusted_senders": ["pa_9f5f84de..."], "auto_max_bytes": 10485760}'
Or via MCP: pulr_workspace_update with delivery_policy / trusted_senders / auto_max_bytes.
Limits (hosted pulr.ai)
Uploads up to 512 MB per file (≈384 MB as base64 JSON; requests through the pulr.ai proxy top out near 100 MB — larger files are a roadmap item). Workspaces start with 500 MB storage, 120 uploads/hour per key, and capability links default to 100 downloads / 7-day expiry. Current numbers always live at pulr.ai/docs.
MCP server (Claude Code, Codex, Claude Desktop)
Per-client setup guides (Claude Code, Codex, Gemini CLI, Grok Build, Perplexity) with verification steps: https://pulr.ai/integrations
Claude Code — one command:
claude mcp add pulr --env PULR_API_KEY=pulr_sk_... -- npx -y mcp-server-pulr
Add --scope project to write a shareable .mcp.json into the repo instead of your user config.
Codex CLI:
codex mcp add pulr --env PULR_API_KEY=pulr_sk_... -- npx -y mcp-server-pulr
Or declare it in ~/.codex/config.toml:
[mcp_servers.pulr]
command = "npx"
args = ["-y", "mcp-server-pulr"]
env = { "PULR_API_KEY" = "pulr_sk_..." }
Claude Desktop & other MCP clients:
{
"mcpServers": {
"pulr": {
"command": "npx",
"args": ["-y", "mcp-server-pulr"],
"env": { "PULR_API_KEY": "pulr_sk_..." }
}
}
}
Then just ask your agent: "Upload this report to pulr with approval required and a 24-hour expiry, and give me the review link."
Tools (21): pulr_upload (with approval, restrictions, notify_email), pulr_send / pulr_offer / pulr_inbox / pulr_accept / pulr_reject / pulr_address (sealed workspace-to-workspace handoff — no links), pulr_share (with restrictions), pulr_fetch, pulr_list, pulr_delete, pulr_revoke, pulr_receipt, pulr_audit, pulr_usage, pulr_whoami, pulr_register_agent (mints or registers an Ed25519 agent key so uploads become attested), plus pulr_workspaces / pulr_workspace_create / _update / _delete. Every tool carries MCP readOnlyHint / destructiveHint annotations.
Env: PULR_API_KEY (required — a missing key is reported on every call, never sent as Bearer undefined), PULR_API_URL (optional, defaults to https://pulr.ai; point at your own instance if self-hosting), PULR_AGENT_KEY_FILE (optional — path to a registered Ed25519 private key; uploads become signed/attested), PULR_ALLOWED_ROOTS (optional — colon-separated absolute directories that file_path may read from; defaults to the server's working directory, so a prompt-injected agent cannot upload ~/.ssh or /etc). Files are capped at 512 MB; mime type is inferred from the extension when omitted.
JavaScript / TypeScript — npm install @pulr/sdk
import PulrClient from '@pulr/sdk'
const pulr = new PulrClient({ apiKey: process.env.PULR_API_KEY })
const a = await pulr.upload({ filePath: './q3-report.pdf', approval: true, expiresIn: '48h' })
console.log(a.review_url) // send to a human
const { bytes } = await pulr.fetchCapability(a.download_url, { expectedSha256: a.sha256 }) // sha256-verified
console.log(await pulr.verifyReceiptWithServerKey(await pulr.receipt(a.artifact_id))) // true — key pinned from /.well-known/pulr-receipt-key
const { offers } = await pulr.inbox() // 0.5.0: page objects, not bare arrays
0.5.0: inbox() / list() / workspaces() return the server's page object ({ offers | artifacts | workspaces, total, limit, offset }); errors are PulrErrors with status / code / body; fetchCapability only follows capability URLs on the client's own host and refuses bytes it cannot verify; new deleteArtifact, offer, audit, registerAgent, rotateAddress, fetchReceiptKey, verifyReceiptWithServerKey.
Python — pip install pulr-sdk
from pulr import PulrClient, verify_receipt
pulr = PulrClient() # reads PULR_API_KEY
a = pulr.upload(file_path="q3-report.pdf", approval=True, expires_in="48h",
restrictions={"allow_countries": ["US"]})
data, sha = pulr.fetch_capability(a["download_url"], expected_sha256=a["sha256"]) # sha256-verified
pulr.verify_receipt_with_server_key(pulr.receipt(a["artifact_id"])) # pip install pulr-sdk[verify]; key pinned from /.well-known
offers = pulr.inbox()["offers"] # 0.5.0: page dicts, not bare lists
0.5.0: inbox() / list() / workspaces() return the server's page dict; PulrError carries .status / .code / .body; fetch_capability never follows file:// and only accepts capability URLs on the client's own host; new delete_artifact, offer, audit, register_agent, rotate_address, fetch_receipt_key, verify_receipt_with_server_key.
LangChain: from pulr.langchain_tool import pulr_tools → pulr_upload / pulr_fetch_capability / pulr_share StructuredTools for any agent.
Getting a key
Create a workspace at pulr.ai/app — 30 seconds, 500 MB included, owner API key shown once. Mint one key per agent (provenance is stamped from the key); revoke any key to cut that agent off instantly. Full API reference: pulr.ai/docs.
A pulr "artifact" is a durable file with a lifecycle — not a streaming chat-UI panel. If you want typed real-time artifact panels for React chat apps, that's a different (complementary) tool, e.g.
@ai-sdk-tools/artifacts. pulr is where the file goes afterward.
MIT © Tal Eilon
The design plates
pulr's product design is kept as a series of drafting plates — one per chapter of the system. A few from the atlas:
pulr MCP questions
What is pulr?
pulr is a secure file exchange layer for AI agents that provides verified, scannable, and expiring download URLs for files like reports, CSVs, and code.
How are files secured during upload?
Every upload is SHA-256-hashed and scanned for secrets, prompt-injection heuristics, and malware using ClamAV before any link becomes active.
Can I restrict who downloads my files?
Yes, you can implement geo-fencing, time-fencing, IP restrictions, and download limits on your capability URLs.
Does pulr read my file content?
No, only the automated threat scanner reads the bytes to look for malware or leaked secrets; the content is not extracted, indexed, or used for training.