Skip to main content
Glama

Contract Clause Extractor

extract_contract_clauses

Extract key clauses from contracts including parties, payment terms, and liability, while optionally identifying risky provisions with severity ratings for legal review.

Instructions

Extract key clauses from a contract — parties, payment terms, termination, liability, IP ownership, confidentiality, and more. Optionally flags risky or one-sided clauses with severity ratings. Powered by Claude.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contractYesThe contract or legal document text
clausesNoWhich clause types to extract
flagRisksNoFlag risky or unfavorable clauses

Implementation Reference

  • The handler function that executes the LLM call and processes the contract analysis.
    async function handler(input: Input) {
      const { contract, clauses, flagRisks } = input;
    
      if (!config.anthropicApiKey) {
        throw new Error("ANTHROPIC_API_KEY is not configured");
      }
    
      const client = new Anthropic({ apiKey: config.anthropicApiKey });
    
      const systemPrompt =
        "You are an expert contract analyst and legal document reviewer. " +
        "You extract and summarize key clauses from contracts and legal agreements with precision. " +
        "Always respond with valid JSON exactly matching the requested schema. " +
        "When quoting contract text, use the exact wording from the document. " +
        "Risk flags should be specific and actionable — explain exactly why a clause is concerning.";
    
      const clauseDescriptions: Record<string, string> = {
        parties: "names, roles, and contact details of all parties involved",
        dates: "effective date, expiration date, key milestones, and deadlines",
        payment_terms: "amounts, payment schedules, currencies, and billing conditions",
        termination: "conditions and notice requirements for ending the agreement",
        liability: "liability caps, indemnification obligations, and damage limitations",
        ip_ownership: "who owns intellectual property created under the agreement",
        confidentiality: "NDA terms, what information is protected, and for how long",
        governing_law: "which jurisdiction's laws apply and where disputes are handled",
        penalties: "late fees, breach penalties, and liquidated damages",
        renewal: "auto-renewal conditions, notice periods, and renewal terms",
        warranties: "representations, guarantees, and disclaimers",
        dispute_resolution: "arbitration, mediation, or litigation procedures",
      };
    
      const requestedClauses = clauses.map((c) => `- ${c}: ${clauseDescriptions[c]}`).join("\n");
    
      const riskInstructions = flagRisks
        ? `
    For each extracted clause, also evaluate whether it poses a risk to the party receiving this analysis.
    Include a "riskFlags" array in your response listing any concerning clauses with:
    - clause: which clause type
    - issue: specific concern in plain language
    - severity: "high" | "medium" | "low"
    - excerpt: the exact contract text that is concerning`
        : "";
    
      const userPrompt = `Extract the following clause types from this contract:
    ${requestedClauses}
    ${riskInstructions}
    
    Return a JSON object with this structure:
    {
      "contractType": "inferred type of contract (e.g. 'Software License Agreement', 'Employment Contract')",
      "clauses": {
        "<clause_type>": {
          "found": true | false,
          "summary": "plain-English summary of the clause",
          "excerpt": "direct quote of the most relevant text (or null if not found)",
          "details": { <structured key-value pairs relevant to this clause type, e.g. amount, date, jurisdiction> }
        }
        // ... one entry per requested clause type
      }${flagRisks ? `,
      "riskFlags": [
        {
          "clause": "<clause_type>",
          "issue": "plain-language description of the risk",
          "severity": "high | medium | low",
          "excerpt": "the specific text that is concerning"
        }
      ],
      "riskSummary": "overall risk assessment in 1-2 sentences"` : ""}
    }
    
    Only include clause types that were requested. If a clause is not found in the document, set found: false and omit excerpt/details.
    
    Contract text:
    ${contract}`;
    
      const message = await client.messages.create({
        model: "claude-haiku-4-5-20251001",
        max_tokens: 4096,
        messages: [{ role: "user", content: userPrompt }],
        system: systemPrompt,
      });
    
      const rawText = message.content[0].type === "text" ? message.content[0].text : "";
      const jsonText = rawText.replace(/^```(?:json)?\n?/m, "").replace(/\n?```$/m, "").trim();
    
      let parsed: Record<string, unknown>;
      try {
        parsed = JSON.parse(jsonText);
      } catch {
        throw new Error("Failed to parse structured response from LLM");
      }
    
      const clauseResults = parsed.clauses as Record<string, unknown>;
      const foundCount = clauseResults
        ? Object.values(clauseResults).filter((c: any) => c?.found).length
        : 0;
    
      return {
        contractType: parsed.contractType ?? "Unknown",
        clausesRequested: clauses.length,
        clausesFound: foundCount,
        clauses: clauseResults,
        ...(flagRisks && {
          riskFlags: parsed.riskFlags ?? [],
          riskSummary: parsed.riskSummary ?? "",
        }),
      };
    }
  • Input validation schema for the contract clause extractor tool using Zod.
    const inputSchema = z.object({
      contract: z
        .string()
        .min(10)
        .max(100_000)
        .describe("The contract or legal document text to analyze"),
      clauses: z
        .array(z.enum(CLAUSE_TYPES))
        .default([...CLAUSE_TYPES])
        .describe(
          "Which clause types to extract. Defaults to all. " +
          "Options: parties, dates, payment_terms, termination, liability, ip_ownership, " +
          "confidentiality, governing_law, penalties, renewal, warranties, dispute_resolution"
        ),
      flagRisks: z
        .boolean()
        .default(true)
        .describe("If true, flag clauses that may be unfavorable or risky (one-sided terms, missing protections, unusual penalties)"),
    });
  • Registration of the tool in the registry. Note: the MCP server alias 'extract_contract_clauses' maps to this 'contract-clause-extractor' internal name.
    const contractClauseExtractorTool: ToolDefinition<Input> = {
      name: "contract-clause-extractor",
      description:
        "Extract and summarize key clauses from contracts and legal documents. " +
        "Identifies parties, payment terms, termination conditions, liability caps, IP ownership, confidentiality, and more. " +
        "Optionally flags risky or one-sided clauses with severity ratings. Powered by Claude.",
      version: "1.0.0",
      inputSchema,
      handler,
      metadata: {
        tags: ["contract", "legal", "extraction", "risk", "llm", "enterprise"],
        pricing: "$0.10 per call",
        exampleInput: {
          contract: "This Software License Agreement is entered into between Acme Corp ('Licensor') and Client Inc ('Licensee')...",
          clauses: ["parties", "payment_terms", "termination", "liability", "ip_ownership"],
          flagRisks: true,
        },
      },
    };
    
    registerTool(contractClauseExtractorTool);
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description must carry the full burden of behavioral disclosure. It successfully adds context about the severity ratings system for risk flagging, which is not evident in the schema. However, it fails to disclose whether the tool is read-only (safe to call), what output format to expect (structured vs. text), or any rate limiting concerns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is efficiently structured with the primary action front-loaded, followed by enumerated examples and optional functionality. It avoids excessive verbosity. Minor deduction for 'Powered by Claude' which provides implementation trivia rather than selection-relevant information, and for 'and more' which is slightly vague (though mitigated by the schema enum).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of an output schema and annotations, the description adequately covers input parameters but leaves a significant gap regarding the return value structure—critical for an extraction tool. It does not indicate whether results are returned as JSON, markdown, or plain text, nor does it describe the structure of the severity ratings mentioned.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 100% schema coverage (baseline 3), the description adds meaningful semantic value by listing representative clause types that map to the enum values in the 'clauses' parameter, and crucially elaborates that 'flagRisks' produces 'severity ratings'—a behavioral detail absent from the schema's generic 'Flag risky or unfavorable clauses' description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action (extract) and resource (contract clauses), enumerating concrete examples like parties, payment terms, and liability. However, it lacks explicit differentiation from the sibling tool 'extract_from_text', leaving implicit the distinction that this tool is specialized for legal contracts versus general text extraction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

While the domain (contracts) is specific enough to imply usage, the description provides no explicit guidance on when to use this tool versus alternatives like 'extract_from_text' or 'compare_documents'. There are no stated prerequisites, exclusions, or conditions that would help an agent decide between this and similar extraction capabilities.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/marras0914/agent-toolbelt'

If you have feedback or need assistance with the MCP directory API, please join our Discord server