ClickCease

Leni developers

Leni MCP runtime reference

Connect an MCP-compatible AI host to the Leni intelligent runtime with delegated end-user OAuth, tenant-safe data access, memory context, and bounded tools.

SettingCurrent contract
Server nameleni-runtime
Remote endpointhttps://mcp.leni.co/mcp
OAuth issuerhttps://auth.leni.co
TransportStateless Streamable HTTP over HTTPS; POST requests with JSON responses
AuthenticationOAuth 2.0 authorization code with PKCE; delegated Leni user consent is always required
Client registrationApproved predefined clients or Dynamic Client Registration when advertised

OAuth discovery and lifecycle

ResourceURL or configured default
Authorization-server metadatahttps://auth.leni.co/.well-known/oauth-authorization-server
Protected-resource metadatahttps://mcp.leni.co/.well-known/oauth-protected-resource
OAuth resource / token audiencehttps://mcp.leni.co/mcp
Access tokenUp to 10 minutes; use expires_in from the token response
Refresh-token idle lifetime30 days for trusted clients; 7 days for restricted registration clients
Refresh-family absolute lifetime365 days by default; rotation cannot extend this deadline
Authorization code2 minutes
Interactive authorization transaction10 minutes

Discover endpoints from the live metadata. Standard authorization, code exchange, and refresh requests require the exact resource=https://mcp.leni.co/mcp. Use S256 PKCE and the exact registered redirect URI. Public clients use token_endpoint_auth_method: none; they do not send a client secret.

Request the permissions the integration needs. The authorization server also advertises offline_access for refresh access; this is not a tool scope. Refresh tokens are issued for clients registered for the refresh_token grant. Store each replacement refresh token atomically and serialize refreshes for a grant. Reusing an old token revokes its refresh family.

Rotation renews the idle expiry up to the family's absolute deadline. Lifetimes depend on client policy; the table gives service defaults, not a promise of a fixed connection lifetime. Reconnect after expiry, revocation, or a permission change. Revocation stops refresh access immediately; an issued access token can remain valid until its short expiry. Leni rechecks active organization membership on tool calls.

Registration must match discovery

Use registration_endpoint for Dynamic Client Registration with an approved callback host. Wildcard redirects are not supported. Published Client ID Metadata Documents are available only when discovery includes client_id_metadata_document_supported: true. Leni's public metadata did not advertise that option when checked on October 26, 2026. In Claude, choose Register automatically.

Backend and autonomous agents

MCP is the delegated end-user surface: every connected person signs in and consents with a Leni account. For a non-interactive server-to-server integration, use the HTTP API with a Leni project key. Do not automate a user password or copy a project key into an MCP client.

OAuth scopes

ScopeAllows
leni:account:readRead account, plan eligibility, and percentage usage remaining.
leni:analysis:runStart a Leni analysis that can consume account usage.
leni:analysis:readRead status and completed analysis sessions.
leni:data:readDiscover and query authorized Leni semantic-layer data.
leni:memory:readList authorized memory and folders and consult relevant context.
leni:memory:files:readCreate short-lived links for files attached to authorized memory notes.
leni:memory:writeCreate and update memory after explicit user intent.
leni:memory:deleteDelete an authorized memory note after explicit user intent.

Protocol requests and results

Use an MCP client to initialize the connection, negotiate a protocol version, send the initialized notification, and discover tools/list. Send the negotiated MCP-Protocol-Version on subsequent requests, with Authorization: Bearer <OAuth-access-token>, Content-Type: application/json, and Accept: application/json, text/event-stream. Leni does not issue an MCP session ID. Authenticated GET and DELETE requests to /mcp return 405.

A tool call after initialization has this JSON-RPC body:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": { "name": "leni_get_account", "arguments": {} }
}

Successful calls return result.structuredContent plus human-readable result.content. Use structured values for programmatic handling. The response key depends on the tool, as shown below. Check HTTP status, a JSON-RPC error, and result.isError. HTTP 200 alone does not establish tool success. Missing scopes can produce a JSON-RPC error; backend failures and tool-level limits can produce isError: true with text instead of structured output.

Tool inputs and structured results

Treat the schemas returned by tools/list as authoritative. The shared catalog contains the tools below; discovery does not mean every tool is permitted by the current grant. Each call checks its scope.

ToolInputsstructuredContent key
leni_get_accountNo arguments.account
leni_get_portfolio_occupancyOptional includeUnitCounts and includePropertyBreakdown, both default false.occupancy
leni_list_data_modelsNo arguments.dataCatalog
leni_describe_data_modelRequired modelName from model discovery.dataModel
leni_query_portfolio_dataRequired measures; optional dimensions, filters, timeDimensions, order, and limit.data
leni_consult_memory_contextRequired question; optional scope, modelType, and modelId. scope defaults to combined.context
leni_analyze_real_estate_financeRequired question; optional depth, buildingIds, memoryIds, and workbookContext.analysis
leni_get_analysis_statusRequired analysisId from a previous analysis.analysis
leni_get_analysis_sessionRequired sessionId; optional limit, default 20 and maximum 50, and cursor from nextCursor.session
leni_list_memoryRequired scope; optional modelType, modelId, search, page, and pageSize. Defaults are page 1 and pageSize 20, maximum 100.memory
leni_list_memory_foldersRequired scope; optional modelType and modelId.memoryFolders
leni_get_memory_filesRequired scope and memoryId; optional modelType, modelId, page, and pageSize. Defaults are page 1 and pageSize 20, maximum 25.memoryFiles
leni_create_memoryRequired scope, title, and content; optional modelType, modelId, folderId, and folderName.memory
leni_update_memoryRequired scope, memoryId, title, and content; optional modelType and modelId.memory
leni_delete_memoryRequired scope and memoryId; optional modelType and modelId.memory

Context tools accept scope: user or scope: organization. Only consultation accepts combined. The default model partition is leniq-pro. Preserve a returned custom analyst's modelType and modelId. Note titles accept 1–500 characters and note content accepts 1–50,000 characters. Create and update write text notes; they do not upload files.

Analysis lifecycle and saved-file analysis

Check leni_get_account before starting analysis. The analysis result contains an opaque analysisId, an optional sessionId, and a status of queued, running, completed, or failed. Wait at least pollAfterSeconds when supplied, then call leni_get_analysis_status with the same analysis ID until terminal. Completed output can contain summary or result. Never start another analysis just because the first call is still running.

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "structuredContent": {
      "analysis": {
        "analysisId": "<analysis-id>",
        "sessionId": "<session-id>",
        "status": "running",
        "pollAfterSeconds": 2
      }
    },
    "content": [{ "type": "text", "text": "Analysis is running. Poll the same analysis ID." }]
  }
}

Use leni_get_analysis_session for transcript pages, following session.nextCursor. Pass the returned session ID, not the analysis ID. The analysis-start tool does not accept a session ID to append a turn. Provide relevant prior context explicitly for a new analysis. Generated attachment metadata contains id, filename, and optional contentType; it does not expose download URLs. Context-file links are a separate operation.

To analyze a saved file, discover its note with leni_list_memory or leni_list_memory_folders, then pass the note reference to analysis. memoryIds is an array of objects, not strings. All selected notes must use the same model partition:

{
  "question": "Summarize the maturity terms in the selected loan document.",
  "depth": "quick",
  "memoryIds": [{
    "scope": "organization",
    "memoryId": "<note-id-from-discovery>",
    "modelType": "leniq-pro"
  }]
}

Include modelId when the note belongs to a custom analyst. A standard partition must use leniq-pro. Use leni_get_memory_files only when the user asks to retrieve the file or its link. Follow memoryFiles.hasMore and retry the same page with bounded backoff when partial is true. Search Personal and Organization Context separately when both are needed. A consultation result of empty means no relevant notes were found. degraded means retrieval was incomplete; explain that limitation when using the returned context.

Microsoft Copilot and Excel

Microsoft 365 Copilot uses the shared tools through an approved Leni agent package. Each user signs in with an eligible Leni subscription; active paid plans, trials, Student accounts, and eligible Enterprise seats are supported. Microsoft tenant installation policies still apply. Completing OAuth does not establish subscription eligibility. The agent does not read or edit the active Office document through the shared catalog.

Registered Copilot clients use the dedicated /oauth/microsoft-copilot/authorize and /oauth/microsoft-copilot/token endpoints on auth.leni.co. These aliases supply the MCP resource only when it is omitted and accept only the registered Copilot clients. Other integrations use the standard endpoints from discovery with an explicit resource.

The Leni Excel add-in additionally discovers leni_excel_chat, restricted to the leni-excel client with leni:analysis:run. It sends bounded workbook observations and returns proposed reads, edits, or an answer. The Office host performs edits only after the user selects Apply changes. Other MCP clients cannot request this host-specific tool. Installation and subscription eligibility remain separate from the generic MCP connection.

Optional workbookContext on the shared analysis tool is a user-selected snapshot with worksheet, address, values, and displayedValues. Both matrices must describe the same rectangular selection, at most 500 cells, 50 columns, and 6,000 serialized characters. The combined question and annotated selection must fit 8,000 characters. This snapshot grants no workbook editing capability.

Structured-data boundaries

  • Call model discovery before constructing a query; use only the returned member names.
  • Queries require 1–12 measures and allow up to 12 dimensions, 20 filters, 2 time dimensions, and 5 order fields.
  • Row limit defaults to 50 and is capped at 100.
  • A rowCount equal to limit may be incomplete. Narrow the query or query aggregate totals directly; never sum a limited breakdown into a portfolio total. Missing rows and nulls do not mean zero.
  • Clients cannot submit SQL or select a warehouse, schema, organization, or unauthorized property.
  • Server-owned organization and property filters are applied to every direct query.
MCP inputBounds
Structured-query filtersequals, notEquals, contains, notContains, startsWith, endsWith, gt, gte, lt, lte, inDateRange, notInDateRange, beforeDate, afterDate, set, and notSet
Analysis question3–8,000 characters
Analysis property selectionUp to 100 authorized building IDs
Analysis memory selectionUp to 20 scoped note references in the same model partition
Analysis depthquick or deep
Memory consultation scopecombined, user, or organization
Memory-file page sizeDefaults to 20 and is capped at 25
Shared tool data textTruncated around 100,000 characters; prefer structuredContent

MCP rate limits

LimitIdentityCurrent allowance
Runtime requestsSigned-in OAuth subject + client120 requests per 60 seconds
Structured semantic queriesSigned-in principal + client20 requests per 60 seconds
Memory context consultationLeni account across connected clients12 requests per 60 seconds

Limits overlap. Runtime HTTP 429 responses include Retry-After. Semantic-query and Context consultation failures can instead return a tool result with isError: true inside HTTP 200; do not treat that as empty data or a successful analysis. Honor a supplied retry delay and use bounded backoff for safe reads. Occupancy can issue separate aggregate and breakdown queries, each consuming query allowance. Invalid or unauthenticated traffic is separately throttled.

Read and write behavior

Portfolio and semantic-layer tools are read-only. Analysis can consume the same plan usage and funded API-credit spillover as Leni. Memory create, update, and delete are deliberate write tools protected by separate scopes and should be called only after explicit user intent. Leni never moves money or modifies property-management records through MCP.

MCP troubleshooting

SymptomAction
Connector will not registerRead live OAuth metadata. Use automatic registration for an approved callback host; use published identity only when advertised. Preserve the exact redirect URI.
OAuth expiredLet the host refresh the access token. Reconnect only when refresh fails, the grant was revoked, or scopes changed.
invalid_targetSend resource=https://mcp.leni.co/mcp on authorization, code exchange, and refresh.
invalid_grant during refreshAn expired, revoked, or replayed refresh token requires reconnecting. Serialize refreshes and save each replacement token.
HTTP 200 but no resultCheck JSON-RPC error and result.isError before reading structuredContent.
Tool is not selectedEnable Leni in the conversation and ask explicitly to use Leni for the task.
Data member is rejectedList and describe models again, then use exact current member names.
Analysis is processingKeep analysisId for status checks and sessionId for completed-session retrieval. Do not start a duplicate.
Memory file is unavailableRecheck the note scope, request a fresh link, and retry a page when partial is true.