lendlord-mcp
Summary: An MCP server that lets an AI agent read and write a Lendlord landlord account — properties, documents, tenants, maintenance, tasks, money and email filing — with a once-per-session write confirmation and read-only/auto-confirm modes.
Account: view user, team role, currency/country, owners and plan limits.
Properties: list/search, view all fields plus tenants and linked documents, create, partially update (auto-converting dates, money, area, percentages), replace/remove gallery photos, delete, and see available field names and document slots.
Compliance: portfolio-wide overview of upcoming/overdue expiries (EPC, gas, EICR, insurance, mortgage rate…).
Documents: list and filter, upload (file path / URL / base64 into a named slot or custom key), rename, link to another property or tenant, email to recipients, delete.
Tenants: list, view with their documents, add, update (including moving to another property), delete.
Maintenance & communications: list up to 1000 entries, view one with its messages, create maintenance reports (typed, optionally shared with tenants), log past email/call/letter history, update status/type/sharing/archive, add internal notes or tenant-visible replies, delete.
Email filing: rank properties against an email's text, then store the email (and attachments) as dated
.eml/file documents on a property or tenant.Tasks & alerts: list tasks and alerts by status/category, create dated tasks (optionally per property), edit or complete/reopen/delete them.
Money: expected rent collection per tenant between dates, search transactions by date/amount/type/property/receipt, view a transaction with its receipt link, re-categorise or re-link a transaction, attach or remove a receipt, and get per-property P&L by month.
Raw API access: call any Lendlord
/apiendpoint directly (GET reads; writes need confirmation) for anything without a dedicated tool.Safety: first write is refused until the user approves (
confirm: true), then writes pass for the session;LENDLORD_READ_ONLYdisables writes,LENDLORD_AUTO_CONFIRMskips prompts, admin endpoints are blocked, and credentials stay in your environment.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lendlord-mcp show compliance status for all my properties"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
lendlord-mcp
An MCP server that lets AI agents (Claude Code, Claude Desktop, Claude.ai connectors, or any MCP client) manage a Lendlord landlord account: properties, documents, tenants, maintenance, tasks, rent, transactions, compliance, and filing emails against properties.
Lendlord has no public API. This server wraps the private JSON API used by the Lendlord web app, reverse-engineered from browser traffic and the public JS bundle (docs/api.md). Every write tool has passed a live round-trip test against a real account (test/live-write.test.ts): it creates a throwaway property, exercises the tool, reads the result back, and cleans up.
Disclaimer: Unofficial and not affiliated with Lendlord. It uses undocumented endpoints that may change without notice. Use it only with your own account, at your own risk, and check Lendlord's terms of service.
Quick start
Local (Claude Code / Claude Desktop / any stdio client)
{
"mcpServers": {
"lendlord": {
"command": "npx",
"args": ["-y", "lendlord-mcp"],
"env": {
"LENDLORD_EMAIL": "you@example.com",
"LENDLORD_PASSWORD": "your-password"
}
}
}
}Claude Code CLI:
claude mcp add lendlord -e LENDLORD_EMAIL=you@example.com -e LENDLORD_PASSWORD=... -- npx -y lendlord-mcpCursor
Add the server to ~/.cursor/mcp.json (or the project's .cursor/mcp.json):
{
"mcpServers": {
"lendlord": {
"command": "npx",
"args": ["-y", "lendlord-mcp@latest"],
"env": {
"LENDLORD_EMAIL": "you@example.com",
"LENDLORD_PASSWORD": "your-password"
}
}
}
}Cursor starts the configured command as its MCP server. To pick up a newly published tool or version, use lendlord-mcp@latest as above, then restart the server from Cursor's MCP settings (or restart Cursor). If the tool list is still stale, remove and re-add the server so Cursor starts a fresh npx process.
If several MCP clients start at once, install the package once (npm install --global lendlord-mcp) and configure each client to run lendlord-mcp directly. This avoids having every client invoke npx to resolve or install the package at startup. You can confirm the installed version with lendlord-mcp --version.
Remote (online / hosted agents)
Run it as a Streamable HTTP server behind HTTPS, then point the agent at https://<host>/mcp with the bearer token.
docker build -t lendlord-mcp .
docker run -p 8080:8080 \
-e MCP_AUTH_TOKEN=$(openssl rand -hex 32) \
-e LENDLORD_EMAIL=you@example.com -e LENDLORD_PASSWORD=... \
lendlord-mcpWithout Docker: MCP_TRANSPORT=http MCP_AUTH_TOKEN=... npx -y lendlord-mcp. GET /health is the health check, and every /mcp request must send Authorization: Bearer <MCP_AUTH_TOKEN>.
Related MCP server: TenantCloud MCP Server
Safety model
Write confirmation once per session. The first tool call that would change data is refused, with a message telling the agent to ask you. After you approve, the agent repeats the call with
confirm: true, and later writes in the same session go through without asking again. A new session (a new stdio process, or a newMcp-Session-Idover HTTP) starts locked again.LENDLORD_READ_ONLY=truedisables every write.LENDLORD_AUTO_CONFIRM=trueskips the confirmation for unattended automation.Lendlord admin endpoints are blocked, including through the raw
lendlord_requesttool.Credentials stay in your environment. Nothing is sent anywhere except
app.lendlord.io.
Tools
Area | Read | Write |
Account |
| |
Properties |
|
|
Documents |
|
|
Email filing |
|
|
Tenants |
|
|
Maintenance & history |
|
|
Tasks & alerts |
|
|
Money |
|
|
Anything else |
|
|
Property fields use Lendlord's own names, for example "Property Value", "EPC Due Date" and "Gas Certificate Due Date". Call list_property_fields for the full list. Updates are partial: only the fields you pass change, and null clears a field.
Values are checked and converted before anything is sent, and the response lists any conversions:
Kind | Accepts | Stored as |
Dates |
| ISO timestamp |
Money / counts |
| number |
|
| square metres |
Rates, agent fee, ownership |
| fraction ( |
Anything ambiguous, such as "73 m" or "about 150k", is rejected with a field-specific error before the confirmation prompt, so no write is attempted.
Tenants belong to exactly one property (propertyDetailsId). list_tenants, get_tenant and get_property show the linked property's address, and propertyMissing: true flags a link to a deleted property. To move a tenant, use update_tenant { fields: { propertyDetailsId } }.
Reliability: network drops and Lendlord's transient 500 socket hang up / 502–504 errors are retried automatically for reads and updates. Document uploads are retried only after checking that the file didn't actually land, so a retry never creates a duplicate document.
Property Photos: update_property_images uploads image files into the property's Photos gallery using Lendlord's legacy images collection. Pass files to add images, removeImageKeys to remove them, or both to replace old images after the new uploads succeed. The image keys are available under get_property → fields.images. upload_document remains for Documents such as deeds and EPCs.
Filing emails against properties
The server doesn't read any mailbox. Your agent reads mail with its own email tools (Gmail, Outlook, IMAP and so on) and uses two helpers:
find_property { text }ranks properties against the email's subject and body. It scores postcode matches (spacing-insensitive), house number plus street, tenant email or name, and policy, certificate and account numbers.file_email { entityId, emlBase64 | subject/from/to/date/text/html, attachments[] }stores the email as an.emldocument namedYYYY-MM-DD - Subject.emlon the property (or tenant). Each attachment becomes its own document namedYYYY-MM-DD - Subject - file.pdf.log_communication { propertyId, date, subject, summary, counterparties[] }adds a dated entry to the property's communication history, so threads appear inlist_communications. Lendlord has no generic communication log, and landlords can't start a tenant "conversation" without a tenant. So the entry is stored as a back-dated, closed maintenance report of type "Other" that isn't shared with tenants.
A typical agent instruction: "For each new email about a rental property, call find_property with the subject and body. If the top score is clearly ahead, file_email it to that property and log_communication a one-line summary. Otherwise ask me."
Attaching invoices to payments
Bank and manual transactions (payments) keep their attachment as a receipt on the transaction, not as a normal document, so upload_document can't reach them. Use:
list_transactions { startDate, endDate, search?, amount?, hasReceipt? }to find the payment, for example the £27.74 Octopus payment with no receipt yet.attach_transaction_receipt { transactionId, filePath | url | base64+fileName }to attach the invoice. A transaction holds one attachment, and attaching again replaces it.get_transactionreturns the receipt name and a temporary download link, andremove_transaction_receiptremoves it.update_transactioncan change a transaction's property and/or category while keeping its receipt attached.
Only the receipt changes: the rest of the transaction is re-saved exactly as it was.
Configuration
Env var | Purpose |
| Login. |
| Alternative to email/password: a |
| Base32 TOTP secret, if 2FA is enabled. |
|
|
|
|
|
|
| HTTP port (default 8080). |
| Required bearer token in HTTP mode. |
| Override the auto-discovered payload key (normally not needed). |
How it works
Auth:
POST /api/loginUsersets a session cookie, and the client logs in again automatically when the session expires. TOTP 2FA is supported.Payload encryption: the web app wraps JSON bodies as
ivHex:cipherHexusing AES-256-CTR with a static key that ships in its public JavaScript. The client finds that key in the live bundle at startup and caches it in~/.cache/lendlord-mcp. The key is never stored in this repo, and the client picks up a new one if Lendlord rotates it.Data model:
GET /api/getUserByIdreturns most of the account in one payload: properties, tenants, tasks and alerts ("opportunities"), owners and companies. Documents link to properties and tenants throughentities.
The full protocol notes, including request formats captured from the web app, are in docs/api.md.
Development
npm install
npm run build
npm test # offline: unit tests + in-memory MCP tests against a fake LendlordLive tests run against your own account. Put LENDLORD_EMAIL and LENDLORD_PASSWORD in .env, which is git-ignored.
LENDLORD_LIVE_TESTS=1 node --env-file=.env node_modules/vitest/vitest.mjs run test/live.test.ts
LENDLORD_LIVE_WRITE_TESTS=1 LENDLORD_LIVE_UPLOAD_TESTS=1 node --env-file=.env node_modules/vitest/vitest.mjs run test/live-write.test.tsThe write test creates and deletes its own ZZ TEST lendlord-mcp … property, tenant, report, task and documents.
Adding a tool: capture the real request in the web app first, implement it, then add a step to test/live-write.test.ts that reads the result back. Never commit captures: .playwright-mcp/, captures/ and .env are git-ignored.
Before pushing, run npm run check (Biome lint and format check, typecheck, tests). npm run format fixes formatting. CI runs the same checks plus tests on Node 20, 22 and 24, a build and package-contents check, a dependency audit and a Docker smoke test.
Issues and the roadmap are tracked with Beads (bd ready).
Versioning and releases
The project uses Semantic Versioning, driven by Conventional Commits:
Commit / PR title | Release |
| patch (0.1.0 → 0.1.1) |
| minor (0.1.0 → 0.2.0) |
| major after 1.0. Before 1.0 it bumps minor |
| no release on their own |
release-please keeps a release PR open with the next version and CHANGELOG entries. Merging it:
bumps
package.json,server.jsonandCHANGELOG.md, and tagsvX.Y.Z;creates the GitHub release;
publishes
ghcr.io/dniasoff/lendlord-mcp:X.Y.Z(and:latest);publishes to npm via trusted publishing (OIDC, no token) with a signed provenance statement.
To pin a version, use npx -y lendlord-mcp@0.1.0 (or github:dniasoff/lendlord-mcp#v0.1.0) or the matching Docker tag. lendlord-mcp --version and GET /health report the running version.
License
Available Tools
40 toolsadd_communication_messageAdd communication messageA
Add a message to a maintenance report/conversation. kind "note" = internal note (landlord only); kind "message" = reply visible to the tenant.
Inputs: message (required), communicationId (required), kind, confirm.
add_propertyAdd propertyA
Create a property. fields uses Lendlord field names (see list_property_fields), e.g. {"Property Value": 150000, "Date of Purchase": "2024-05-01"}. Owned by the first applicant unless ownerApplicantId is given.
Inputs: address (required), city, fields, status, +3 more.
add_tenantAdd tenantB
Add a tenant to a property. Optional fields may include: phone, mobile, dob, notes, unitName, tenancyStartDate, tenancyEndDate, firstPaymentDate, rentReviewDate (dates YYYY-MM-DD), rentReviewFrequency (Quarterly|Semi-Annually|Annually|Every 2 Years|Every 3 Years|Every 5 Years), generatePaymentScheduleFor (3 months|6 months|12 months|24 months), depositScheme (TDS|DPS|Mydeposits|Zerodeposits|FlatFair|SafeDeposits|Other), depositAmount, guarantor/rollingTenancy/inventoryUndertaken/legionellaInspectionRequired (Yes|No).
Inputs: name (required), propertyId (required), email, fields, +4 more.
attach_transaction_receiptAttach receipt to a bank transactionA
Attach an invoice, receipt or other file to a bank/manual transaction (payment). A transaction holds ONE attachment: attaching again replaces it. Use this instead of upload_document, which only links files to properties and tenants. Provide exactly one of filePath (on the server's machine), url, or base64 + fileName. Accepts PDF, images, Word/Excel/PowerPoint, CSV and text. Use list_transactions (search / amount / hasReceipt) to find the transaction.
Inputs: transactionId (required), url, base64, confirm, +3 more.
compliance_overviewCompliance overviewARead-only
Upcoming and overdue expiry dates across the portfolio (EPC, insurance, gas safety, EICR, mortgage rate expiry, …), sorted soonest first.
Inputs: withinDays.
create_maintenance_reportCreate maintenance reportB
Log a maintenance issue on a property. maintenanceType is one of: Air-conditioning, Heating and boiler, Electricity, Internet, Lighting, Plumbing, Water or leaks, Basin, Bathroom and Toilet, Laundry, Alarms and smoke detectors, Security camera system maintenance, Intercom, Doors and locks, Pests/Vermin, Floors walls and ceilings, Structural Issues, Windows, Furniture, Kitchen, Appliances, Mold, Cleaning, Carpentry, Exterior Maintenance, Roof, Garden, Garage, Shared facilities, Bike storage, Bin storage, Chimney, Stairs, Other. Not shared with tenants unless shareWithTenants is true.
Inputs: summary (required), propertyId (required), maintenanceType (required), confirm, +3 more.
create_taskCreate taskC
Add a custom task with a due date, optionally tied to a property.
Inputs: dueDate (required), subject (required), confirm, propertyId, +1 more.
delete_communicationDelete communicationADestructive
Permanently delete a maintenance report/conversation (use update_communication archived:true to keep history).
Inputs: communicationId (required), confirm.
delete_documentDelete documentADestructive
Remove a document from the property/tenant it is linked to (deletes it if that was its only link).
Inputs: entityId (required), documentId (required), confirm, entityType.
delete_propertyDelete propertyCDestructive
Permanently delete a property from the portfolio.
Inputs: propertyId (required), confirm.
delete_tenantDelete tenantCDestructive
Permanently delete a tenant.
Inputs: tenantId (required), confirm.
file_emailFile email to propertyA
Store an email (and its attachments) as documents on a property or tenant. Pass either emlBase64 (raw RFC 822 message) or subject/from/to/date/text/html. Attachments are uploaded as separate documents named " - - ".
Inputs: entityId (required), to, date, from, +7 more.
find_propertyFind propertyARead-only
Rank properties against free text such as an email's subject/body, an address, postcode, tenant name/email, or a policy/certificate number. Use before file_email to pick the property.
Inputs: text (required), limit.
get_accountGet accountARead-only
The Lendlord account: user, team role, currency/country settings, applicants (property owners), and plan usage limits. Excludes property data (use list_properties).
Inputs: no named parameters.
get_communicationGet communicationCRead-only
One maintenance report or conversation, including its messages.
Inputs: communicationId (required), type.
get_profit_and_lossGet profit and lossBRead-only
P&L per property by month, with the category list used for transactions.
Inputs: no named parameters.
get_propertyGet propertyBRead-only
Every stored field for one property, plus its tenants and the documents linked to it.
Inputs: propertyId (required).
get_rent_collectionGet rent collectionBRead-only
Expected rent payments (per tenant, with due dates and matched transactions) between two dates.
Inputs: to (required), from (required).
get_tenantGet tenantBRead-only
Every stored field for one tenant, plus documents linked to them.
Inputs: tenantId (required).
get_transactionGet transactionARead-only
One bank/manual transaction with all its fields. If it has a receipt, receipt holds its name and a temporary download link.
Inputs: transactionId (required).
lendlord_requestRaw Lendlord API requestADestructive
Call any Lendlord /api endpoint directly (encryption handled). Use for features without a dedicated tool; see docs/api.md for endpoints. GET is read-only; other methods change data and need write confirmation.
Inputs: path (required), method (required), body, query, +1 more.
link_documentLink documentA
Attach an existing document to another property or tenant. Lendlord stores this as a separate copy (same file, own id) under the original name.
Inputs: entityId (required), documentId (required), confirm, entityType.
list_communicationsList communicationsARead-only
Maintenance reports and other tenant/landlord communications, newest first. Fetches Lendlord's 100-item pages as needed up to limit (max 1000); continue with skip = nextSkip while hasMore is true.
Inputs: skip, type, limit, propertyId.
list_documentsList documentsBRead-only
Documents stored in Lendlord, with the entities (property, tenant, …) each is linked to. Optionally filter by linked entity id or name text.
Inputs: search, entityId.
list_propertiesList propertiesBRead-only
All properties in the portfolio with key figures (address, postcode, value, rent, mortgage). Optionally filter by free text matched against address/postcode.
Inputs: search, status.
list_property_fieldsList property fieldsARead-only
Field names accepted by add_property / update_property, and the document slot keys for upload_document.
Inputs: no named parameters.
list_tasksList tasks and alertsBRead-only
Tasks (custom and Lendlord-generated, e.g. MISSING_DUE_DATES) and alerts (e.g. Payment Overdue). Defaults to active ones.
Inputs: status, category.
list_tenantsList tenantsARead-only
Tenants (actual and prospect), optionally for one property. Each tenant is linked to exactly one property (propertyId + propertyAddress); propertyMissing means it points at a property that no longer exists. Fix a wrong link with update_tenant { propertyDetailsId }.
Inputs: propertyId.
list_transactionsList transactionsARead-only
Bank/manual transactions between two dates, with optional filters to find the one you want (e.g. the payment an invoice belongs to). A transaction's file is its attached receipt (see attach_transaction_receipt).
Inputs: endDate (required), startDate (required), type, amount, +4 more.
log_communicationLog communication historyA
Record a past email thread, call or letter against a property (issue #3). Lendlord has no generic communication log and landlords cannot start a "conversation" without a tenant, so this is stored as a back-dated maintenance report (default type "Other", status closed, not shared with tenants) whose description lists the date, counterparties and summary. It then appears in list_communications/get_communication with the original date. Use file_email as well to keep the full message and attachments as documents.
Inputs: date (required), subject (required), summary (required), propertyId (required), +6 more.
remove_transaction_receiptRemove a transaction's receiptA
Remove the file attached to a bank/manual transaction. The transaction itself is not changed.
Inputs: transactionId (required), confirm.
rename_documentRename documentC
Change a document's display name.
Inputs: name (required), documentId (required), confirm.
send_documentSend document by emailA
Email a stored document to someone (Lendlord sends it with the file attached). Replies go to the account's email unless replyTo is given. This sends a real email.
Inputs: to (required), subject (required), documentId (required), cc, +3 more.
update_communicationUpdate communicationC
Change a maintenance report/conversation: status (open|closed), archived, summary, description, maintenanceType, shared.
Inputs: communicationId (required), shared, status, confirm, +4 more.
update_propertyUpdate propertyA
Change fields on a property. Only the fields you pass change; set a field to null to clear it. Field names from list_property_fields. Dates as YYYY-MM-DD (DD/MM/YYYY also accepted). Money accepts 150000, "£150,000" or "150k". "Internal Area" is square metres ("73", "73 sq m"; "790 sq ft" is converted). Percentages (rates, agent fee, ownership) are stored as fractions: send "4.5%" or 4.5 (stored as 0.045); values of 1 or less are taken as fractions already. Invalid values are rejected with a field-specific error.
Inputs: fields (required), propertyId (required), confirm.
update_property_imagesUpdate property PhotosA
Add photos to a property's Photos gallery, remove selected gallery images by key, or replace images by adding new files and removing old keys together. This is separate from upload_document, which stores files under Documents. Provide one or more image files and/or removeImageKeys. Image keys are the keys shown by get_property under fields.images.
Inputs: propertyId (required), files, confirm, removeImageKeys.
update_taskUpdate taskB
Edit a task, or change its status: completed, active (reopen) or deleted.
Inputs: taskId (required), status, confirm, dueDate, +2 more.
update_tenantUpdate tenantA
Change fields on a tenant (same field names as add_tenant). Only the fields you pass change; null clears. Move a tenant to another property with { propertyDetailsId: }.
Inputs: fields (required), tenantId (required), confirm.
update_transactionUpdate transactionA
Change the property or category linked to a bank/manual transaction. Only the fields you pass change. The existing receipt is kept; this does not upload or remove a receipt.
Inputs: transactionId (required), confirm, categoryId, propertyDetailsId.
upload_documentUpload documentA
Upload a file to Lendlord and link it to a property (or tenant). To attach a file to a bank transaction (payment) use attach_transaction_receipt instead. Provide exactly one of filePath (on the server's machine), url, or base64 + fileName. key is a document slot from list_property_fields (e.g. gasCertificate, epc, eicr, insurancePolicy); any other key creates a custom document. Uses the account's upload quota.
Inputs: key (required), entityId (required), url, name, +6 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 40 tools
Most tools target distinct resource+action pairs, and descriptions explicitly distinguish overlapping areas such as upload_document vs. attach_transaction_receipt vs. link_document vs. file_email. However, the generic lendlord_request and the maintenance-report workaround used by log_communication still require careful reading and could invite occasional misselection.
Nearly all tool names use snake_case with a clear verb_noun pattern, such as list_tenants, add_property, update_tenant, and delete_document. A few names break the pattern slightly (compliance_overview, lendlord_request, get_profit_and_loss), but the set remains readable and predictable.
With 40 tools, the server is far beyond the typical 3–15 well-scoped range and exceeds the 25+ threshold for being too heavy. While the property-management domain is broad, this many tools increases selection burden and suggests consolidation is needed.
Coverage is broad: CRUD for properties, tenants, communications, tasks, and documents, plus financials, compliance, rent collection, account details, and a raw API fallback. Minor gaps remain, such as no direct create/delete transaction tool and no get-single-task tool, but lendlord_request can work around less common operations.
Maintenance
Related MCP Connectors
AgentiSend is a transactional email API: send through verified domains with a message log, budgets, a preflight and refusals that name the fix; built so AI agents can send on your behalf. The hosted MCP server at https://api.agentisend.com/mcp exposes 82 tools (44 on tools/list; the rest via list_more_tools). A send is one message or a batch of up to 500 items with per-item results. preflight_email runs every gate a real send runs, sends nothing, and costs nothing. Every 4xx returns code, message, and fix. There is no tool for unsolicited mail. Auth is a bearer API key or OAuth 2.1 with dynamic client registration. Starter prompts: "Send this receipt to the customer." "Preflight this send and tell me what would stop it." "What can I spend today?"
Email, calendar and contacts for AI agents: Gmail, Microsoft 365 and IMAP accounts behind one API.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
Related MCP Servers
- FlicenseAqualityDmaintenanceConnects AI assistants to the Lanten property management API, allowing them to manage tenants, units, and work orders using natural language.157 npm-
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to manage rental properties on TenantCloud via natural language, including contacts, messaging, maintenance, and financials.-
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to operate property management systems via natural language, covering repair orders, owner info, payments, notices, and inspections. Features a full agentic workflow with human-in-the-loop and observability.1MIT
- AlicenseAqualityBmaintenanceEnables an AI agent to control one or more remote GPIO agents through a conversation by proxying tool calls to their REST APIs. It supports API-key authentication, LAN discovery, and both stdio and Streamable HTTP transports.1849 npm1MIT