Skip to main content
Glama

board_search_precedent

Read-onlyIdempotent

Search deliberation precedent to find prior board rulings on a topic. Ground new deliberations in institutional case law with ranked cases including quality scores and citation counts.

Instructions

Search deliberation precedent (Colony Layer 1). Find prior board rulings on a topic. Returns ranked cases with quality scores, gate approval status, and citation counts. Use this to ground new deliberations in institutional case law. Cite cases by ID: "In Case board-abc123, this board ruled..."

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
topicYesThe topic or question to search precedent for. Full-text search matches against prior deliberation agendas.
charter_idNoCharter ID to scope search. When provided, searches this charter and its parent hierarchy (subcommittee sees parent board precedent).
limitNoMaximum number of cases to return (default: 5, max: 20)

Implementation Reference

  • The full handler function 'registerPrecedentTools' which registers the 'board_search_precedent' MCP tool. It defines the Zod schema for inputs (topic, charter_id, limit), implements the async handler that calls the GIA Express API /api/precedent/search endpoint, formats results with quality scores and citation counts, emits telemetry, and returns the formatted response.
    export function registerPrecedentTools(server: McpServer, engine: GovernanceEngine): void {
      server.tool(
        'board_search_precedent',
        'Search deliberation precedent (Colony Layer 1). Find prior board rulings on a topic. Returns ranked cases with quality scores, gate approval status, and citation counts. Use this to ground new deliberations in institutional case law. Cite cases by ID: "In Case board-abc123, this board ruled..."',
        {
          topic: z.string().min(3).max(500).describe(
            'The topic or question to search precedent for. Full-text search matches against prior deliberation agendas.'
          ),
          charter_id: z.string().optional().describe(
            'Charter ID to scope search. When provided, searches this charter and its parent hierarchy (subcommittee sees parent board precedent).'
          ),
          limit: z.number().min(1).max(20).optional().describe(
            'Maximum number of cases to return (default: 5, max: 20)'
          ),
        },
        {
          title: 'Search Deliberation Precedent',
          readOnlyHint: true,
          idempotentHint: true,
          destructiveHint: false,
          openWorldHint: false,
        } as Record<string, unknown>,
        async (input) => {
          const apiBase = process.env.GIA_API_URL || 'http://localhost:3001';
          // GIA_INTERNAL_API_KEY = server-side name; GIA_API_KEY = MCP container name (same value)
          const apiKey = process.env.GIA_INTERNAL_API_KEY || process.env.GIA_API_KEY || '';
          const limit = input.limit ?? 5;
    
          let result: Record<string, unknown>;
    
          try {
            const params = new URLSearchParams({
              q: input.topic,
              limit: String(limit),
            });
            if (input.charter_id) {
              params.set('charter_id', input.charter_id);
            }
    
            const resp = await fetch(`${apiBase}/api/precedent/search?${params.toString()}`, {
              headers: {
                'Authorization': `Bearer ${apiKey}`,
                'Content-Type': 'application/json',
              },
            });
    
            if (!resp.ok) {
              const body = await resp.text();
              result = {
                error: `Precedent search failed (HTTP ${resp.status})`,
                detail: body,
              };
            } else {
              const data = await resp.json() as Record<string, unknown>;
              const cases = data.cases as Array<Record<string, unknown>> | undefined;
    
              if (!cases || cases.length === 0) {
                result = {
                  query: input.topic,
                  charterId: input.charter_id ?? null,
                  cases: [],
                  count: 0,
                  message: 'No relevant precedent found. This may be a novel topic for this board.',
                  guidance: 'When no precedent exists, the board establishes new case law through this deliberation.',
                  colony: 'Layer 1 — Precedent System v2',
                };
              } else {
                // Format cases for readability
                const formattedCases = cases.map((c, i) => ({
                  rank: i + 1,
                  caseId: c.board_id,
                  shortId: typeof c.board_id === 'string' ? c.board_id.slice(0, 12) : '',
                  topic: c.question_text,
                  mode: c.mode,
                  qualityScore: c.quality_score,
                  gateApproved: c.gate_approved,
                  precedentWeight: c.precedent_weight,
                  status: c.precedent_status ?? 'active',
                  charterId: c.charter_id ?? null,
                  ruling: c.recommendation,
                  citationCount: c.citation_count ?? 0,
                  analyzedAt: c.analyzed_at,
                }));
    
                result = {
                  query: input.topic,
                  charterId: input.charter_id ?? null,
                  count: formattedCases.length,
                  cases: formattedCases,
                  citation_guidance: 'Cite cases using: "In Case [shortId], this board ruled [ruling summary]..."',
                  weight_formula: 'quality(40%) + gate_approved(20%) + genuine(15%) + mode(15%) + recency(10%)',
                  overturn_note: 'To overturn a precedent, convene a session with supermajority approval (quorum + 1).',
                  colony: 'Layer 1 — Precedent System v2 (institutional case law)',
                };
              }
            }
          } catch (err: unknown) {
            result = {
              error: 'Failed to search precedent — GIA Express API may be unreachable',
              detail: err instanceof Error ? err.message : String(err),
            };
          }
    
          // Telemetry
          engine.telemetryService.emitToolCall('board_search_precedent', `prec-${Date.now().toString(36)}`, 'INFORMATIONAL', true);
    
          return {
            content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
          };
        }
      );
    }
  • Zod input schema for board_search_precedent: topic (string, 3-500 chars), charter_id (optional string), limit (optional number, 1-20, default 5).
    {
      topic: z.string().min(3).max(500).describe(
        'The topic or question to search precedent for. Full-text search matches against prior deliberation agendas.'
      ),
      charter_id: z.string().optional().describe(
        'Charter ID to scope search. When provided, searches this charter and its parent hierarchy (subcommittee sees parent board precedent).'
      ),
      limit: z.number().min(1).max(20).optional().describe(
        'Maximum number of cases to return (default: 5, max: 20)'
      ),
    },
  • Import of registerPrecedentTools from './tools/precedent.js'.
    import { registerPrecedentTools } from './tools/precedent.js';
  • Registration of registerPrecedentTools in the TOOL_REGISTRY array at tier 'tenant' with description 'board_search_precedent (Colony Layer 1 — precedent case law)'.
    { tier: 'tenant', register: registerPrecedentTools, description: 'board_search_precedent (Colony Layer 1 — precedent case law)' },
  • References board_search_precedent in the onboarding client config under the Reasoning category.
    | Reasoning | chain_of_reasoning, board_convene_session, board_search_precedent |
Behavior4/5

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

Annotations already indicate read-only, non-destructive, idempotent behavior. The description adds that it returns ranked cases with quality scores, gate approval status, and citation counts, and that it performs full-text search against prior deliberation agendas. This provides useful behavioral context beyond the annotations.

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

Conciseness5/5

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

The description is concise at 4 sentences, each adding value. It is front-loaded with the primary purpose and then provides key details. No unnecessary words or repetition.

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

Completeness5/5

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

For a search tool with 3 parameters and no output schema, the description covers purpose, usage, parameter behavior, and return format (ranked cases, quality scores, approval status, citation counts). This is fully complete for an agent to use effectively.

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

Parameters3/5

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

Schema description coverage is 100%; each parameter already has a clear description. The description adds context about full-text search for 'topic' and scope behavior for 'charter_id', but does not significantly improve upon the schema. Baseline of 3 is appropriate.

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

Purpose5/5

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

The description clearly states the tool searches deliberation precedent (Colony Layer 1) for prior board rulings, with specific details about returned data (ranked cases, quality scores, gate approval status, citation counts). It includes a usage example for citing cases, distinguishing it from sibling tools like board_approve_gate or board_convene_session.

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

Usage Guidelines4/5

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

The description explicitly frames the tool's use case: 'ground new deliberations in institutional case law.' It provides a citation format. While it does not mention when not to use it or name alternatives, the context is clear enough for an agent to decide when to invoke this tool versus others.

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/knowledgepa3/gia-mcp-server'

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