MCP + Lekha: Financial Document Tools for Any AI Agent
Expose Lekha's Indian financial document extraction as MCP tools so Claude, GPT-4o, or any agent can parse bank statements and more.
The Model Context Protocol (MCP) has become the standard way to give AI agents new capabilities. Instead of baking document-parsing logic into every agent prompt, you expose it once as an MCP tool and any MCP-compatible agent — Claude Desktop, Cursor, your own CrewAI workflow — can call it on demand.
This guide shows you how to wrap Lekha's financial document extraction API as a set of MCP tools, then call those tools from a Claude agent to answer questions like _"What was my total EMI outgo last month?"_ or _"Is this applicant's salary sufficient for a ₹25L loan?"_.
Why MCP for Financial Documents?
Traditional approaches hardcode document-parsing prompts inside agent instructions. That works for a single use case but breaks down when you need to:
MCP solves all of this. Your Lekha MCP server becomes a shared capability layer — declare it once, use it everywhere.
Prerequisites
Step 1: Scaffold the MCP Server
Install the official MCP TypeScript SDK:
bun add @modelcontextprotocol/sdk zod
bun add -d @types/node typescript
Create lekha-mcp/index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const LEKHA_API_KEY = process.env.LEKHA_API_KEY!;
const LEKHA_BASE_URL = "https://api.lekhadev.com";
const server = new McpServer({
name: "lekha-financial-docs",
version: "1.0.0",
});
Step 2: Add the Bank Statement Tool
Each Lekha endpoint maps naturally to one MCP tool. Here's the bank statement extractor:
server.tool(
"extract_bank_statement",
"Extract structured transactions, balance, and summary from an Indian bank statement PDF.",
{
file_url: z
.string()
.url()
.describe("Publicly accessible URL of the bank statement PDF"),
bank: z
.string()
.optional()
.describe(
"Bank name hint (e.g. 'HDFC', 'SBI'). Auto-detected if omitted.",
),
},
async ({ file_url, bank }) => {
const response = await fetch(
${LEKHA_BASE_URL}/v1/extract/bank-statement,
{
method: "POST",
headers: {
Authorization: Bearer ${LEKHA_API_KEY},
"Content-Type": "application/json",
},
body: JSON.stringify({ file_url, bank }),
},
);
if (!response.ok) {
const err = await response.json();
throw new Error(
Lekha API error: ${err.error?.message ?? response.statusText},
);
}
const { data } = await response.json();
return {
content: [
{
type: "text",
text: JSON.stringify(data, null, 2),
},
],
};
},
);
Step 3: Add Salary Slip and CIBIL Tools
Extend the server with additional document types your agents will need:
server.tool(
"extract_salary_slip",
"Extract gross pay, net pay, deductions, and employer details from an Indian salary slip.",
{
file_url: z.string().url().describe("URL of the salary slip PDF or image"),
},
async ({ file_url }) => {
const response = await fetch(${LEKHA_BASE_URL}/v1/extract/salary-slip, {
method: "POST",
headers: {
Authorization: Bearer ${LEKHA_API_KEY},
"Content-Type": "application/json",
},
body: JSON.stringify({ file_url }),
});
const { data } = await response.json();
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
},
);
server.tool(
"extract_cibil_report",
"Extract credit score, active loans, payment history, and risk flags from a CIBIL credit report PDF.",
{
file_url: z.string().url().describe("URL of the CIBIL report PDF"),
},
async ({ file_url }) => {
const response = await fetch(${LEKHA_BASE_URL}/v1/extract/cibil, {
method: "POST",
headers: {
Authorization: Bearer ${LEKHA_API_KEY},
"Content-Type": "application/json",
},
body: JSON.stringify({ file_url }),
});
const { data } = await response.json();
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
},
);
Step 4: Start the Server
Wire up the stdio transport and launch:
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Lekha MCP server running on stdio");
}
main().catch(console.error);
Add a build script to package.json:
{
"scripts": {
"start": "bun run index.ts"
}
}
Step 5: Connect to Claude Desktop
Open ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on Windows, and add your server:
{
"mcpServers": {
"lekha": {
"command": "bun",
"args": ["/absolute/path/to/lekha-mcp/index.ts"],
"env": {
"LEKHA_API_KEY": "lk_live_your_key_here"
}
}
}
}
Restart Claude Desktop. You'll see a hammer icon — click it to confirm your three tools (extract_bank_statement, extract_salary_slip, extract_cibil_report) are listed.
Step 6: Use it in an Agent Conversation
With the server connected, you can now ask Claude natural questions backed by real document data:
> You: Here's a bank statement from my HDFC account: [paste URL]. What was my average monthly spend on EMIs last quarter?
Claude will automatically call extract_bank_statement, receive the structured JSON from Lekha, and compute the answer — no prompt engineering for document parsing required.
For a loan underwriting workflow:
> You: The applicant submitted their salary slip [URL] and CIBIL report [URL]. Can they afford a ₹30L home loan at 9% over 20 years?
Claude calls both tools, gets structured data back, runs the eligibility math, and gives you a reasoned answer with the supporting numbers.
Using Lekha MCP in a Programmatic Agent
If you're building a custom agent with the Claude API rather than Claude Desktop, wire it up with the MCP client:
import Anthropic from "@anthropic-ai/sdk";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "bun",
args: ["./lekha-mcp/index.ts"],
env: { LEKHA_API_KEY: process.env.LEKHA_API_KEY! },
});
const mcpClient = new Client({ name: "loan-agent", version: "1.0.0" });
await mcpClient.connect(transport);
// List available tools
const { tools } = await mcpClient.listTools();
// Convert to Anthropic tool format
const anthropicTools = tools.map((tool) => ({
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema,
}));
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
tools: anthropicTools,
messages: [
{
role: "user",
content:
"Extract and summarize the bank statement at https://example.com/statement.pdf",
},
],
});
// Handle tool calls
for (const block of response.content) {
if (block.type === "tool_use") {
const result = await mcpClient.callTool({
name: block.name,
arguments: block.input as Record,
});
console.log("Extraction result:", result.content);
}
}
This pattern lets you run Lekha extraction inside any agent loop — add financial document intelligence to a lending bot, expense tracker, or compliance checker with a dozen lines of code.
Supported Document Types
The full list of Lekha endpoints you can expose as MCP tools:
| Tool name | Document type | Key fields extracted |
| ------------------------ | --------------------------------------- | --------------------------------------------- |
| extract_bank_statement | Bank statement (all major Indian banks) | Transactions, balances, EMIs, salary credits |
| extract_salary_slip | Salary slip | Gross pay, net pay, PF, TDS, employer |
| extract_cibil_report | CIBIL credit report | Score, DPD history, active loans, utilisation |
| extract_cas | Mutual fund CAS | Holdings, NAV, XIRR, folios |
| extract_form16 | Form 16 / ITR | Tax computation, TDS, employer details |
| extract_gst_invoice | GST invoice | Line items, GSTIN, tax breakdown |
See the full schema reference at lekhadev.com/docs.
Tips for Production
Cache aggressively. Bank statements don't change — cache extraction results by document hash. Lekha returns anextraction_id you can use as the cache key.
Set a timeout. Multi-page PDFs can take 8-12 seconds. Set AbortController timeouts in your MCP tool handlers so a slow extraction doesn't hang the whole agent.
Return only what the agent needs. If your agent only cares about salary credits, filter the transaction list before returning it as tool output. Smaller tool results mean less token usage and faster reasoning.
Validate before passing to Claude. Use Zod to validate the Lekha response shape inside the tool handler. An unexpected null from a malformed PDF is better surfaced as a tool error than silently broken data in the agent's context.
FAQ
Can I use this MCP server with tools other than Claude Desktop?Yes. Any MCP-compatible client works — Cursor, Cline, Continue, or a custom agent built with the MCP TypeScript SDK. The stdio transport is universal; swap it for SSE if you need a hosted server.
Does Lekha store the documents I send?No. Lekha processes documents in memory and never writes them to disk, in compliance with India's DPDP Act. Extracted JSON is returned in the API response and not retained unless you explicitly store it in your own system.
What Indian banks are supported?All major Indian banks: HDFC, SBI, ICICI, Axis, Kotak, Yes Bank, IndusInd, IDFC First, Bank of Baroda, PNB, Canara Bank, and 30+ others. The classifier auto-detects the format — you don't need to specify the bank unless you want to override detection.
Can I add custom document types?Today you can expose any Lekha-supported document type as an MCP tool. If you need a document type not yet supported, reach out — new formats are added regularly based on developer requests.
MCP turns Lekha from a REST API call into a first-class capability that any AI agent can discover and invoke on demand. Once your server is running, adding financial intelligence to a new agent is a config change, not a development sprint.
Try it out at lekhadev.com/playground or grab a free API key at lekhadev.com to start building.