AppFolio MCP Server
Click on "Install 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., "@AppFolio MCP Servershow me the financial reports"
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.
AppFolio MCP Server
An MCP (Model Context Protocol) server for AppFolio Property Manager, connecting your property management data to AI tools.
Quick start
Claude
bash (macOS/Linux):
APPFOLIO_VHOST="yourcompany"
APPFOLIO_CLIENT_ID="your-reports-client-id"
APPFOLIO_CLIENT_SECRET="your-reports-client-secret"
APPFOLIO_DB_DEVELOPER_ID="your-developer-id"
APPFOLIO_DB_CLIENT_ID="your-db-client-id"
APPFOLIO_DB_CLIENT_SECRET="your-db-client-secret"
claude mcp add appfolio \
--env APPFOLIO_VHOST="$APPFOLIO_VHOST" \
--env APPFOLIO_CLIENT_ID="$APPFOLIO_CLIENT_ID" \
--env APPFOLIO_CLIENT_SECRET="$APPFOLIO_CLIENT_SECRET" \
--env APPFOLIO_DB_DEVELOPER_ID="$APPFOLIO_DB_DEVELOPER_ID" \
--env APPFOLIO_DB_CLIENT_ID="$APPFOLIO_DB_CLIENT_ID" \
--env APPFOLIO_DB_CLIENT_SECRET="$APPFOLIO_DB_CLIENT_SECRET" \
-- npx -y @nightsquawktech/appfolio-mcp-serverPowerShell (Windows):
$APPFOLIO_VHOST = "yourcompany"
$APPFOLIO_CLIENT_ID = "your-reports-client-id"
$APPFOLIO_CLIENT_SECRET = "your-reports-client-secret"
$APPFOLIO_DB_DEVELOPER_ID = "your-developer-id"
$APPFOLIO_DB_CLIENT_ID = "your-db-client-id"
$APPFOLIO_DB_CLIENT_SECRET = "your-db-client-secret"
claude mcp add appfolio `
--env "APPFOLIO_VHOST=$APPFOLIO_VHOST" `
--env "APPFOLIO_CLIENT_ID=$APPFOLIO_CLIENT_ID" `
--env "APPFOLIO_CLIENT_SECRET=$APPFOLIO_CLIENT_SECRET" `
--env "APPFOLIO_DB_DEVELOPER_ID=$APPFOLIO_DB_DEVELOPER_ID" `
--env "APPFOLIO_DB_CLIENT_ID=$APPFOLIO_DB_CLIENT_ID" `
--env "APPFOLIO_DB_CLIENT_SECRET=$APPFOLIO_DB_CLIENT_SECRET" `
-- npx -y @nightsquawktech/appfolio-mcp-serverCursor
Or put the mcp.json block in .cursor/mcp.json, then verify with:
agent mcp list(The Cursor CLI manages configured servers but has no mcp add; install is via the button or mcp.json.)
VS Code
bash (macOS/Linux):
APPFOLIO_VHOST="yourcompany"
APPFOLIO_CLIENT_ID="your-reports-client-id"
APPFOLIO_CLIENT_SECRET="your-reports-client-secret"
APPFOLIO_DB_DEVELOPER_ID="your-developer-id"
APPFOLIO_DB_CLIENT_ID="your-db-client-id"
APPFOLIO_DB_CLIENT_SECRET="your-db-client-secret"
code --add-mcp '{"name":"appfolio","command":"npx","args":["-y","@nightsquawktech/appfolio-mcp-server"],"env":{"APPFOLIO_VHOST":"'"$APPFOLIO_VHOST"'","APPFOLIO_CLIENT_ID":"'"$APPFOLIO_CLIENT_ID"'","APPFOLIO_CLIENT_SECRET":"'"$APPFOLIO_CLIENT_SECRET"'","APPFOLIO_DB_DEVELOPER_ID":"'"$APPFOLIO_DB_DEVELOPER_ID"'","APPFOLIO_DB_CLIENT_ID":"'"$APPFOLIO_DB_CLIENT_ID"'","APPFOLIO_DB_CLIENT_SECRET":"'"$APPFOLIO_DB_CLIENT_SECRET"'"}}'PowerShell (Windows):
$APPFOLIO_VHOST = "yourcompany"
$APPFOLIO_CLIENT_ID = "your-reports-client-id"
$APPFOLIO_CLIENT_SECRET = "your-reports-client-secret"
$APPFOLIO_DB_DEVELOPER_ID = "your-developer-id"
$APPFOLIO_DB_CLIENT_ID = "your-db-client-id"
$APPFOLIO_DB_CLIENT_SECRET = "your-db-client-secret"
$config = @{
name = "appfolio"
command = "npx"
args = @("-y", "@nightsquawktech/appfolio-mcp-server")
env = @{
APPFOLIO_VHOST = $APPFOLIO_VHOST
APPFOLIO_CLIENT_ID = $APPFOLIO_CLIENT_ID
APPFOLIO_CLIENT_SECRET = $APPFOLIO_CLIENT_SECRET
APPFOLIO_DB_DEVELOPER_ID = $APPFOLIO_DB_DEVELOPER_ID
APPFOLIO_DB_CLIENT_ID = $APPFOLIO_DB_CLIENT_ID
APPFOLIO_DB_CLIENT_SECRET = $APPFOLIO_DB_CLIENT_SECRET
}
} | ConvertTo-Json -Compress
code --add-mcp $configCodex
bash (macOS/Linux):
APPFOLIO_VHOST="yourcompany"
APPFOLIO_CLIENT_ID="your-reports-client-id"
APPFOLIO_CLIENT_SECRET="your-reports-client-secret"
APPFOLIO_DB_DEVELOPER_ID="your-developer-id"
APPFOLIO_DB_CLIENT_ID="your-db-client-id"
APPFOLIO_DB_CLIENT_SECRET="your-db-client-secret"
codex mcp add appfolio \
--env APPFOLIO_VHOST="$APPFOLIO_VHOST" \
--env APPFOLIO_CLIENT_ID="$APPFOLIO_CLIENT_ID" \
--env APPFOLIO_CLIENT_SECRET="$APPFOLIO_CLIENT_SECRET" \
--env APPFOLIO_DB_DEVELOPER_ID="$APPFOLIO_DB_DEVELOPER_ID" \
--env APPFOLIO_DB_CLIENT_ID="$APPFOLIO_DB_CLIENT_ID" \
--env APPFOLIO_DB_CLIENT_SECRET="$APPFOLIO_DB_CLIENT_SECRET" \
-- npx -y @nightsquawktech/appfolio-mcp-serverPowerShell (Windows):
$APPFOLIO_VHOST = "yourcompany"
$APPFOLIO_CLIENT_ID = "your-reports-client-id"
$APPFOLIO_CLIENT_SECRET = "your-reports-client-secret"
$APPFOLIO_DB_DEVELOPER_ID = "your-developer-id"
$APPFOLIO_DB_CLIENT_ID = "your-db-client-id"
$APPFOLIO_DB_CLIENT_SECRET = "your-db-client-secret"
codex mcp add appfolio `
--env "APPFOLIO_VHOST=$APPFOLIO_VHOST" `
--env "APPFOLIO_CLIENT_ID=$APPFOLIO_CLIENT_ID" `
--env "APPFOLIO_CLIENT_SECRET=$APPFOLIO_CLIENT_SECRET" `
--env "APPFOLIO_DB_DEVELOPER_ID=$APPFOLIO_DB_DEVELOPER_ID" `
--env "APPFOLIO_DB_CLIENT_ID=$APPFOLIO_DB_CLIENT_ID" `
--env "APPFOLIO_DB_CLIENT_SECRET=$APPFOLIO_DB_CLIENT_SECRET" `
-- npx -y @nightsquawktech/appfolio-mcp-serverOr add it to ~/.codex/config.toml under [mcp_servers.appfolio].
mcp.json
Every environment variable the server reads, with recommended values:
{
"mcpServers": {
"appfolio": {
"command": "npx",
"args": ["-y", "@nightsquawktech/appfolio-mcp-server"],
"env": {
"APPFOLIO_VHOST": "yourcompany",
"APPFOLIO_CLIENT_ID": "your-reports-client-id",
"APPFOLIO_CLIENT_SECRET": "your-reports-client-secret",
"APPFOLIO_DB_DEVELOPER_ID": "your-developer-id",
"APPFOLIO_DB_CLIENT_ID": "your-db-client-id",
"APPFOLIO_DB_CLIENT_SECRET": "your-db-client-secret"
}
}
}
}File locations: .mcp.json in your project root (Claude Code), claude_desktop_config.json (Claude Desktop), .cursor/mcp.json (Cursor).
Related MCP server: Qobrix CRM MCP Server
Configuration
The server talks to two AppFolio APIs, each with its own credentials. Configure one set or both: each API's tools only need their own variables, and the other API's tools return an error at call time if their variables are unset.
Variable | Required | Default | Purpose |
| for Reports API tools | Your AppFolio database name, the subdomain in | |
| for Reports API tools | Reports API Client ID (Account Settings > Manage API Settings > Reports API Credentials) | |
| for Reports API tools | Reports API Client Secret | |
| for Database API tools | Your AppFolio Developer ID (Admin > Developer ID) | |
| for Database API tools | Database API Basic Auth Client ID (API Credentials > Basic Auth) | |
| for Database API tools | Database API Basic Auth Client Secret |
Security & write safety
AppFolio credentials: create dedicated API credentials for this server. Reports API credentials come from Account Settings > Manage API Settings > Reports API Credentials; Database API credentials are a Developer ID plus Basic Auth Client ID and Secret from API Credentials > Basic Auth.
The Reports API tools (
list_reports,describe_report,run_report) are read-only: reports return data and never modify anything.The Database API tool
call_endpointexecutes reads and writes. Of the 156 endpoints, 58 are GET reads and 98 are write operations (55 POST, 33 PATCH, 4 PUT, 6 DELETE) that execute live against your AppFolio database. There is no environment write gate in this version.For a read-only posture, configure only the Reports API variables: without
APPFOLIO_DB_*credentials, everycall_endpointrequest fails before reaching AppFolio.Every request is validated against the local catalog first (known operation, required path params, required report filters), and the client enforces AppFolio's documented rate limits (7 requests per 15 seconds on the Reports API, all three Database API windows).
All requests go directly from your machine to
{vhost}.appfolio.comandapi.appfolio.com; nothing passes through third parties.
The tool surface is a guardrail, not a security boundary. The env vars in your MCP config are real AppFolio credentials, and an AI agent with shell access can bypass the MCP tools and call the AppFolio API directly with them. If you need hard read-only, enforce it at the source: scope the API credentials themselves, or only issue the read-oriented Reports API credentials and leave the Database API credentials out of the config.
Tools
Both APIs are catalog-backed: instead of one MCP tool per report or endpoint, each API exposes a list/describe/call triple built on mcp-core. list_* discovers what exists (137 reports, 156 endpoints), describe_* returns the full parameter spec for one entry from a local catalog, and the execute tool (run_report / call_endpoint) validates the request against that spec before calling AppFolio. Six tools cover 293 operations without flooding your client's tool list.
list_reports List the 137 AppFolio reports (slug, name, category, required filters)
describe_report Full parameter spec for one report: filters, types, enums, response columns
run_report Run a report and return its rows, auto-paginated
list_endpoints List the 156 Database API endpoints (operationId, method, path, category)
describe_endpoint Full spec for one endpoint: path params, filters, body schema, response fields
call_endpoint Call a Database API endpoint after validating it against the catalogAPI coverage
293 operations covered: 137 reports (Reports API v2) and 156 endpoints (Database API v0).
Category | Operations |
Reports: Association / HOA | 16 |
Reports: Financial | 34 |
Reports: Leasing | 16 |
Reports: Maintenance & Workflow | 12 |
Reports: Other | 2 |
Reports: Owner | 6 |
Reports: Property & Unit | 19 |
Reports: Registers & Transactions | 9 |
Reports: Rent Roll | 5 |
Reports: Tenant | 13 |
Reports: Vendor | 5 |
Database API: Accounting | 30 |
Database API: Community Associations | 12 |
Database API: Corporate Accounting | 2 |
Database API: Custom Fields | 1 |
Database API: Leasing | 20 |
Database API: Maintenance | 29 |
Database API: People | 21 |
Database API: Properties | 40 |
Database API: System | 1 |
Report | ID |
Board of Directors |
|
Dues Roll |
|
Dues Roll (Itemized) |
|
Eligible Debt Summary |
|
Fund Balance Sheet |
|
Fund Balance Sheet - Active Funds |
|
Fund Income Statement |
|
Homeowner Delinquency |
|
Homeowner Delinquency (As Of) |
|
Homeowner Directory |
|
Homeowner Ledger |
|
Homeowner Prepayment Balance |
|
Homeowner Resale |
|
Homeowner Vehicle Info |
|
Insurance Enforcement |
|
Violation Detail |
|
Report | ID |
Account Totals |
|
Additional Fees |
|
Aged Payables Summary |
|
Aged Receivable Detail |
|
Annual Budget - Comparative |
|
Annual Budget - Forecast |
|
Balance Sheet |
|
Balance Sheet - Comparative |
|
Balance Sheet - Property Comparison |
|
Bank Account Association |
|
Budget - Comparative |
|
Budget - Property Comparison |
|
Cash Flow |
|
Cash Flow - Property Comparison |
|
Cash Flow Detail |
|
Chart of Accounts |
|
Email Delivery Errors |
|
Expense Distribution |
|
Fixed Assets |
|
General Ledger |
|
Import Variances |
|
Income Statement |
|
Income Statement - Comparative |
|
Income Statement - Property Comparison |
|
Income Statement (Date Range) |
|
Insurance Usage |
|
Late Fee Policy Comparison |
|
Loans |
|
Trial Balance |
|
Trial Balance by Property |
|
Trust Account Balance |
|
Trust Account Detail |
|
Cash Flow - 12 Month |
|
Income Statement - 12 Month |
|
Report | ID |
Guest Card Inquiries |
|
Guest Card Interests |
|
Historical Advertised Rent |
|
Inactive Guest Card Interests |
|
Lease Expiration Detail By Month |
|
Lease Expiration Summary By Month |
|
Lease History |
|
Leasing Agent Performance |
|
Leasing Funnel Performance |
|
Leasing Summary |
|
Prospect Source Tracking |
|
Renewal Summary |
|
Rental Applications |
|
Screening Assessments |
|
Screening Usage |
|
Showings |
|
Report | ID |
Association Work Order |
|
Cancelled Workflows |
|
Completed Workflows |
|
Realm-X Flows Assigned Tasks |
|
In-Progress Workflows |
|
Inspection Detail |
|
Project Budget Detail |
|
Project Directory |
|
Unit Inspection |
|
Activities Summary |
|
Work Order |
|
Work Order Labor Summary |
|
Report | ID |
Receivables Activity |
|
Survey Responses |
|
Report | ID |
Owner Custom Fields |
|
Owner Directory |
|
Owner Leasing |
|
Owner Withholdings |
|
Owner 1099 Summary |
|
Owner 1099 Detail |
|
Report | ID |
Amenities By Property |
|
AppFolio Stackâ„¢ Usage |
|
Inventory Status |
|
Inventory Usage |
|
Keys Detail |
|
Occupancy Custom Fields |
|
Occupancy Summary |
|
Premium Listing Billing Detail |
|
Property Budget |
|
Property Custom Fields |
|
Property Directory |
|
Property Group Directory |
|
Property Performance |
|
Property Staff Assignments |
|
Rentable Items |
|
Unit Custom Fields |
|
Unit Directory |
|
Unit Turn Detail |
|
Unit Vacancy Detail |
|
Report | ID |
Bill Detail |
|
Charge Detail |
|
Check Register |
|
Check Register Detail (Enhanced) |
|
Deposit Register |
|
Expense Register |
|
Income Register |
|
Payment Plans |
|
Purchase Order |
|
Report | ID |
Gross Potential Rent |
|
Rent Roll |
|
Rent Roll (Commercial) |
|
Rent Roll (Itemized) |
|
Rent Roll (By Bed) |
|
Report | ID |
Delinquency |
|
Delinquency (As Of) |
|
Renter Directory |
|
Resident Financial Activity |
|
Security Deposit Funds Detail |
|
Debt Collections Status |
|
Tenant Directory |
|
Tenant Ledger |
|
Tenant Tickler |
|
Tenant Transactions Summary |
|
Tenant Unpaid Charges Summary |
|
Tenant Vehicle Info |
|
Unpaid Balances by Month |
|
Report | ID |
Vendor Custom Fields |
|
Vendor Directory |
|
Vendor Ledger |
|
Vendor Ledger (Enhanced) |
|
Vendor 1099 Summary |
|
Method | Path | Operation ID |
GET |
|
|
POST |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
POST |
|
|
GET |
|
|
POST |
|
|
POST |
|
|
POST |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
GET |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
GET |
|
|
Method | Path | Operation ID |
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
Method | Path | Operation ID |
GET |
|
|
POST |
|
|
Method | Path | Operation ID |
GET |
|
|
Method | Path | Operation ID |
GET |
|
|
POST |
|
|
POST |
|
|
PATCH |
|
|
PATCH |
|
|
GET |
|
|
GET |
|
|
PATCH |
|
|
GET |
|
|
PUT |
|
|
GET |
|
|
GET |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
PATCH |
|
|
GET |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
Method | Path | Operation ID |
POST |
|
|
DELETE |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
GET |
|
|
POST |
|
|
DELETE |
|
|
PATCH |
|
|
POST |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
DELETE |
|
|
POST |
|
|
PATCH |
|
|
GET |
|
|
Method | Path | Operation ID |
GET |
|
|
POST |
|
|
PATCH |
|
|
GET |
|
|
POST |
|
|
GET |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
PATCH |
|
|
GET |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
PATCH |
|
|
POST |
|
|
PATCH |
|
|
PATCH |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
Method | Path | Operation ID |
POST |
|
|
GET |
|
|
GET |
|
|
PATCH |
|
|
GET |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
DELETE |
|
|
PATCH |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
DELETE |
|
|
PATCH |
|
|
GET |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
GET |
|
|
PATCH |
|
|
GET |
|
|
PATCH |
|
|
POST |
|
|
GET |
|
|
PATCH |
|
|
POST |
|
|
POST |
|
|
PATCH |
|
|
POST |
|
|
DELETE |
|
|
PATCH |
|
|
PUT |
|
|
GET |
|
|
POST |
|
|
GET |
|
|
GET |
|
|
PUT |
|
|
PUT |
|
|
Method | Path | Operation ID |
GET |
|
|
Contributing
Contributions and issues are welcome. Please open an issue first before submitting a PR.
License
AGPL-3.0: free for personal and open-source use. Organizations that cannot comply with the AGPL can purchase a commercial license, and hosted/managed versions are available. See COMMERCIAL.md or contact hello@nightsquawk.tech.
Copyright
For copyright concerns or takedown requests, contact hello@nightsquawk.tech.
Available Tools
6 toolscall_endpointA
Call an AppFolio Database API endpoint and return its JSON response. Validates the operationId and required path params against the catalog before calling AppFolio, then executes (GET reads are auto-paginated; POST/PATCH/PUT/DELETE writes execute live against your AppFolio database). Use describe_endpoint first to learn the exact params and body.
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden - and it does well: it discloses that GET reads are auto-paginated, that write operations execute live against the database (a significant side-effect disclosure), and that it validates against a catalog before calling. It falls just short of 5 because it doesn't explicitly note result size limits, rate limits, or what happens on validation failure, though the schema's pagination default of 1000 partially fills this gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, zero filler. Front-loaded with the primary purpose, then the payload structure. Every clause earns its place, covering validation, execution mode, pagination, and the prerequisite workflow without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex, generic dispatch tool (no output schema, nested objects, many free-form params), the description explains the overall execution model, safety difference between reads and writes, and the prerequisite (describe_endpoint). It's fairly complete given the inherent genericness of the tool. Slight gap: it doesn't describe error/response format or note limits, but given the tool is inherently generic across many endpoints, the description realistically cannot enumerate every behavior, so 4 is appropriate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate - and it partially does by explaining the flow of validation and pagination. However, the parameter-level semantics are mostly carried by the schema's own per-field descriptions (filters, paginate_results, body, etc.) which are detailed. The description adds value by explaining the GET-write behavioral distinction and the describe_endpoint prerequisite, but doesn't explain the filters wrapper or pagination fields - those are already in the schema, which does the heavy lifting for parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb+resource ('Call an AppFolio Database API endpoint and return its JSON response') and clearly outlines the execution flow (validates operationId, auto-paginates GET reads, executes live writes). It distinguishes from siblings by explicitly referencing describe_endpoint and list_endpoints as the setup tools, establishing a clear division of labor within the tool family.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance on when to use this tool: 'Use describe_endpoint first to learn the exact params and body.' It also clarifies behavioral differences between GET (auto-paginated) and POST/PATCH/PUT/DELETE (live writes), helping the agent understand when live writes occur versus safe reads. This functional distinction is effectively an implied when-to-use/alternatives guideline given sibling tools are list/describe functions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_endpointA
Get the full specification for a single AppFolio Database API endpoint: HTTP method, path and path params, query filters (GET), request body schema with nested attributes (writes), response fields, and a request sample. Call this before call_endpoint to know exactly which parameters to pass.
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. While it accurately describes the tool's behavior (retrieving endpoint specs, not executing them), it doesn't disclose what happens on invalid operation_id, whether the full response fields might be extensive, or potential size/rate implications. However, since this is a fundamentally read-only, low-risk metadata tool, the description is adequate but could note error behavior for invalid operationIds.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense sentence plus one directive sentence. It front-loads the purpose and packs a substantial amount of concrete detail (method, path, params, filters, request body, response fields, sample). The only minor inefficiency is the length of the enumeration, but every element is informative. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a metadata/read tool with just one parameter and no output schema, the description covers the essentials: what it returns (full spec contents), when to use it (before call_endpoint), and how to identify the target (operation_id examples). It could improve by noting the handle for invalid/unknown operation_ids, but overall it's quite complete for a tool of this simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, meaning the schema provides no description for the operation_id parameter. However, the description compensates by explaining operation_id is an 'endpoint operationId' with examples ('get_tenants', 'post_bills') and references list_endpoints as the source. While it doesn't fully explain what an operationId is or its format constraints, the examples plus context are reasonable. The 0% coverage means the description must compensate, and it does partially.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb 'Get' with a clear resource: 'the full specification for a single AppFolio Database API endpoint'. It enumerates exactly what the specification contains (method, path, query filters, request body, response fields, request sample). This clearly distinguishes it from siblings like list_endpoints (which lists endpoints) and call_endpoint (which executes them).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is provided: 'Call this before call_endpoint to know exactly which parameters to pass.' This gives a clear when-to-use directive and names the specific alternative it pairs with, establishing a workflow. The contrast with call_endpoint makes the usage context unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_reportA
Get the full parameter specification for a single AppFolio report: required and optional filters, types, enums, defaults, nested attributes, and response columns. Call this before run_report to know exactly which parameters to pass.
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must convey behavioral traits. It states the tool returns a specification, implying a read-only operation, and details the contents (filters, types, enums, defaults, etc.). However, it does not discuss permissions, error behavior, or side effects, which is a moderate gap given the lack of annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose, and includes a helpful usage tip. Every word adds value—no fluff, no redundancy—making it highly concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple with one parameter and no output schema. The description adequately explains the purpose and usage but fails to explicitly identify the input parameter or discuss potential errors/auth. Given the simplicity, it is minimally sufficient but not comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description does not mention the actual parameter 'report_name' or its type/format, leaving the agent to infer it from the schema. The schema does provide a description and example, but the tool description fails to compensate for the 0% schema description coverage in the text, making the semantics unclear without relying on structured data.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Get the full parameter specification for a single AppFolio report.' The verb 'Get' plus the resource 'parameter specification' make it evident, and it distinguishes itself from siblings like list_reports (which lists reports) and run_report (which executes reports).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Call this before run_report to know exactly which parameters to pass,' which provides a clear usage context. It does not explicitly mention alternatives or exclusions, but the guidance to call before run_report is actionable and sufficient for choosing this tool over siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_endpointsA
List the available AppFolio Database API endpoints (operationId, method, path, category, description). Optionally filter by category, resource, method, or reads-only. Use this to discover which endpoint to use, then call describe_endpoint for its parameters and call_endpoint to execute it. This is the AppFolio v0 Database API (records/CRUD), distinct from the Reporting API (list_reports/run_report).
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. The description discloses the filter capabilities (category, resource, method, reads-only) and the API version (v0), which is useful, but does not describe pagination behavior, output volume, or whether results are ordered. It does convey listing/discovery semantics effectively, though the scale of results is not addressed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact (three sentences) and front-loaded with the core purpose, followed by the optional filter capabilities, then workflow guidance. Every sentence adds value with zero waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a discovery/listing tool with no output schema, the description covers purpose, filters, workflow linkage to sibling tools, and API/version differentiation. It lacks explicit note on return volume/pagination, which is a minor gap for a listing tool that could return many endpoints. Overall it is well-rounded and sufficient for an agent to select and invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the parameters are wrapped in a 'params' object with individual property descriptions in the schema that are reasonably self-explanatory (method, category, resource, reads_only each have filtering descriptions with examples). The description adds workflow context but the parameter meanings are largely conveyed through the schema's property-level descriptions rather than the tool description itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'List the available AppFolio Database API endpoints' with specific output fields (operationId, method, path, category, description). It distinguishes this discovery tool from siblings by naming describe_endpoint (for params) and call_endpoint (for execution), and explicitly contrasts the Database API with the Reporting API (list_reports/run_report).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit workflow guidance: 'Use this to discover which endpoint to use, then call describe_endpoint for its parameters and call_endpoint to execute it.' It also names the alternative toolset for Reporting API, giving clear when-to-use vs when-not-to-use context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_reportsA
List the available AppFolio reports (slug, name, category, required filters). Optionally filter by category. Use this to discover which report to run, then call describe_report for its parameters and run_report to execute it.
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses that filtering is optional and that it returns a listing rather than data. However, it doesn't disclose pagination, response volume, or whether 'required filters' are full or abbreviated. For a read-only listing tool, the disclosure is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences that are dense with information - return fields, filtering behavior, workflow guidance, and sibling-tool routing. No filler. Slightly longer than strictly minimal, but each clause earns its place by aiding agent selection and next steps.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a discovery/list tool with one optional parameter and no output schema, the description is quite complete. It covers purpose, output contents, filtering, and next-step routing. The main omission is lacking detail on the structure of the returned list (e.g., whether required filters come as a list or string), but this is modest for a discovery tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for the single category parameter, but the description compensates well by explaining what category does, providing examples ('Financial', 'Leasing', 'Tenant'), noting it's optional, and advising to omit it initially to see all categories. This adds meaningful usage insight beyond the raw schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource ('List the available AppFolio reports') and enumerates the return fields (slug, name, category, required filters), which clearly distinguishes it from siblings like run_report, describe_report, and call_endpoint. It also explains the tool's role in the discovery workflow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use ('to discover which report to run') and how it fits with alternatives ('then call describe_report for its parameters and run_report to execute it'), naming sibling tools directly. It also explains the category filtering use case and suggests 'call without args first to see all categories'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_reportA
Run an AppFolio report and return its rows. Validates the report name, required filters, and parameter names against the report catalog before calling AppFolio. Use describe_report first to learn the exact filter keys for the report.
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that the tool validates against a report catalog before calling AppFolio, implying pre-flight checks. It mentions required filters must be included or the request is rejected, which is a useful behavioral constraint. However, it doesn't disclose potential rate limits, error behaviors beyond validation, or what happens on partial failures; still, the validation disclosure is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences that each earn their place: the first states the primary action and validates, the second gives critical usage guidance (use describe_report first). No filler, no redundancy with the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has nested objects (params > report_name required, filters as arbitrary JSON object), no output schema, and no annotations. The description handles this well by pointing to describe_report for filter keys and stating the validation behavior, which collectively inform the agent how to construct a valid call. It covers the critical unknowns (required filters, parameter naming), though paginate_results behavior is left to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It references describe_report for filter keys, which directs the agent to the authoritative source for parameter semantics. It explains that filters must match parameter names from describe_report. However, the description itself doesn't detail individual parameter formats beyond pointing to describe_report, so the agent must do a follow-up lookup; still, this is a reasonable delegation given the report-specific nature of filters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the tool's function: 'Run an AppFolio report and return its rows.' It names the specific verb (run), resource (AppFolio report), and outcome (return rows). It distinguishes from siblings: list_reports lists available reports while this executes them, and call_endpoint/describe_endpoint target endpoints rather than reports.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance provided: 'Use describe_report first to learn the exact filter keys for the report.' This clearly instructs the agent on the prerequisite step before invocation. The description also clarifies validation behavior (validates report name, required filters, parameter names against the catalog), setting expectations that malformed calls will be rejected.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v0.1.0- First observed
call_endpoint - First observed
describe_endpoint - First observed
describe_report - First observed
list_endpoints - First observed
list_reports - First observed
run_report
TDQS
The tools clearly separate into two distinct domains: reporting (list_reports, describe_report, run_report) and database API (list_endpoints, describe_endpoint, call_endpoint). Within each domain, the list/describe/execute functions have unambiguous roles, making misselection highly unlikely.
All tool names follow a consistent lowercase verb_noun pattern (list_, describe_, run_, call_). The naming clearly indicates both the action and the target resource, with no mixing of conventions or vague verbs.
With exactly 6 tools, the server is well-scoped. It covers two complementary API surfaces (reports and database endpoints) with a discover-describe-execute pattern for each, and every tool serves a distinct and necessary role.
The toolset fully covers the intended workflow for both reports and database endpoints: discover available options, inspect detailed parameters, and execute the operation. There are no obvious missing operations or dead ends, as call_endpoint handles all HTTP methods and reports are predefined resources.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Provide seamless access to Appfolio Property Manager Reporting API through a standardized MCP serv…
Read-only MCP server over the APIs.io catalog — discover APIs, providers, tags & artifacts.
Governed data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
MCP server for Codat — companies, connections, invoices, bills and financial statements.
Related MCP Servers
- AlicenseAqualityCmaintenanceA read-only MCP server for AppDynamics that exposes 12 task-oriented tools to query applications, topology, metrics, snapshots, health rules, anomalies, events, alerting config, analytics events, and dependency maps via OAuth API-client credentials.121MIT
- AlicenseAqualityAmaintenanceA read-only MCP server providing 56 tools to query Qobrix real-estate CRM data, covering listings, leads, viewings, offers, contracts, analytics, and more, with RESO Data Dictionary alignment and caching support.643Apache 2.0
- AlicenseNot gradedqualityBmaintenanceUnified MCP server for ArcGIS Online and Enterprise providing tools for user/group management, item management, geoprocessing, feature layer queries/editing, and server administration.2MIT
- FlicenseNot gradedqualityCmaintenanceA Model Context Protocol (MCP) server that wraps AppFolio's REST API so Claude can call it natively in any conversation. 38 tools covering portfolio structure, leasing, financials, maintenance, and admin.1-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/NightSquawk/appfolio-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server