Skip to main content
Glama
egegungordu

Kokkai Minutes MCP Agent

by egegungordu

searchSpeeches

Search Japanese Diet parliamentary speeches by keywords, speaker, date, or meeting details to retrieve specific speech content and meeting information.

Instructions

Searches for specific speeches from the Kokkai API (発言単位出力). Returns speech text and info about the meeting it belongs to. Max 100 records.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
startRecordNoStart position for retrieving search results (1-based). Default is 1.
nameOfHouseNoName of the House (e.g., '衆議院' for House of Representatives, '参議院' for House of Councillors). '両院' and '両院協議会' yield the same results.
nameOfMeetingNoName of the meeting (e.g., plenary session, committee). Partial match. Multiple terms separated by space for OR search.
anyNoKeywords to search in speech content. Partial match. Multiple terms separated by space for AND search.
speakerNoSpeaker's name. Partial match. Multiple names separated by space for OR search.
fromNoStart date for meeting search (YYYY-MM-DD). Default '0000-01-01'.
untilNoEnd date for meeting search (YYYY-MM-DD). Default '9999-12-31'.
supplementAndAppendixNoLimit search to supplements and appendices. Default false.
contentsAndIndexNoLimit search to table of contents and index. Default false.
searchRangeNoSpecifies where to search for keywords from 'any' parameter: '冒頭' (opening), '本文' (body), or '冒頭・本文' (both). Default '冒頭・本文'.
closingNoLimit search to meetings held during recess. Default false.
speechNumberNoExact match for speech number (e.g., 10).
speakerPositionNoSpeaker's position/title. Partial match.
speakerGroupNoSpeaker's affiliated political group. Partial match.
speakerRoleNoSpeaker's role: '証人' (witness), '参考人' (expert witness/referential speaker), '公述人' (public speaker).
speechIDNoUnique ID for a speech (format: issueID_paddedSpeechNumber, e.g., '100105254X00119470520_000'). Exact match.
issueIDNoUnique ID for a meeting record (21 alphanumeric characters, e.g., '100105254X00119470520'). Exact match.
sessionFromNoStarting Diet session number (up to 3 digits).
sessionToNoEnding Diet session number (up to 3 digits).
issueFromNoStarting issue number (up to 3 digits, 0 for TOC/index/appendix/supplement).
issueToNoEnding issue number (up to 3 digits, 0 for TOC/index/appendix/supplement).
maximumRecordsNoMaximum number of records to retrieve (1-100) for speeches. Default is 30.

Implementation Reference

  • Handler function that invokes the Kokkai API 'speech' endpoint with the provided parameters, handles errors, and returns the response as formatted JSON text content.
    async (params) => {
      const result = await this._callKokkaiApi("speech", params);
      if (result.error) {
        return {
          content: [
            {
              type: "text",
              text: `Error fetching speeches: ${result.message} ${result.details || ""}`,
            },
          ],
        };
      }
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(result, null, 2),
          },
        ],
      };
    }
  • Specific input schema for the searchSpeeches tool, extending the common Kokkai search parameters with a maximumRecords limit of 100.
    {
      ...kokkaiCommonSearchParams,
      maximumRecords: z
        .number()
        .int()
        .min(1)
        .max(100)
        .optional()
        .describe(
          "Maximum number of records to retrieve (1-100) for speeches. Default is 30."
        ),
    },
  • Shared Zod schema defining common search parameters for all Kokkai API tools, including searchSpeeches, covering fields like dates, speaker, keywords, etc.
    const kokkaiCommonSearchParams = {
      startRecord: z
        .number()
        .int()
        .min(1)
        .optional()
        .describe(
          "Start position for retrieving search results (1-based). Default is 1."
        ),
      nameOfHouse: z
        .enum(["衆議院", "参議院", "両院", "両院協議会"])
        .optional()
        .describe(
          "Name of the House (e.g., '衆議院' for House of Representatives, '参議院' for House of Councillors). '両院' and '両院協議会' yield the same results."
        ),
      nameOfMeeting: z
        .string()
        .optional()
        .describe(
          "Name of the meeting (e.g., plenary session, committee). Partial match. Multiple terms separated by space for OR search."
        ),
      any: z
        .string()
        .optional()
        .describe(
          "Keywords to search in speech content. Partial match. Multiple terms separated by space for AND search."
        ),
      speaker: z
        .string()
        .optional()
        .describe(
          "Speaker's name. Partial match. Multiple names separated by space for OR search."
        ),
      from: z
        .string()
        .regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
        .optional()
        .describe(
          "Start date for meeting search (YYYY-MM-DD). Default '0000-01-01'."
        ),
      until: z
        .string()
        .regex(/^\d{4}-\d{2}-\d{2}$/, "Date must be in YYYY-MM-DD format")
        .optional()
        .describe(
          "End date for meeting search (YYYY-MM-DD). Default '9999-12-31'."
        ),
      supplementAndAppendix: z
        .boolean()
        .optional()
        .describe(
          "Limit search to supplements and appendices. Default false."
        ),
      contentsAndIndex: z
        .boolean()
        .optional()
        .describe("Limit search to table of contents and index. Default false."),
      searchRange: z
        .enum(["冒頭", "本文", "冒頭・本文"])
        .optional()
        .describe(
          "Specifies where to search for keywords from 'any' parameter: '冒頭' (opening), '本文' (body), or '冒頭・本文' (both). Default '冒頭・本文'."
        ),
      closing: z
        .boolean()
        .optional()
        .describe("Limit search to meetings held during recess. Default false."),
      speechNumber: z
        .number()
        .int()
        .nonnegative()
        .optional()
        .describe("Exact match for speech number (e.g., 10)."),
      speakerPosition: z
        .string()
        .optional()
        .describe("Speaker's position/title. Partial match."),
      speakerGroup: z
        .string()
        .optional()
        .describe("Speaker's affiliated political group. Partial match."),
      speakerRole: z
        .enum(["証人", "参考人", "公述人"])
        .optional()
        .describe(
          "Speaker's role: '証人' (witness), '参考人' (expert witness/referential speaker), '公述人' (public speaker)."
        ),
      speechID: z
        .string()
        .optional()
        .describe(
          "Unique ID for a speech (format: issueID_paddedSpeechNumber, e.g., '100105254X00119470520_000'). Exact match."
        ),
      issueID: z
        .string()
        .optional()
        .describe(
          "Unique ID for a meeting record (21 alphanumeric characters, e.g., '100105254X00119470520'). Exact match."
        ),
      sessionFrom: z
        .number()
        .int()
        .positive()
        .optional()
        .describe("Starting Diet session number (up to 3 digits)."),
      sessionTo: z
        .number()
        .int()
        .positive()
        .optional()
        .describe("Ending Diet session number (up to 3 digits)."),
      issueFrom: z
        .number()
        .int()
        .nonnegative()
        .optional()
        .describe(
          "Starting issue number (up to 3 digits, 0 for TOC/index/appendix/supplement)."
        ),
      issueTo: z
        .number()
        .int()
        .nonnegative()
        .optional()
        .describe(
          "Ending issue number (up to 3 digits, 0 for TOC/index/appendix/supplement)."
        ),
      // recordPacking is handled internally, always 'json'
    };
  • src/index.ts:279-315 (registration)
    MCP server tool registration for 'searchSpeeches', specifying name, description, input schema, and handler function.
    this.server.tool(
      "searchSpeeches",
      "Searches for specific speeches from the Kokkai API (発言単位出力). Returns speech text and info about the meeting it belongs to. Max 100 records.",
      {
        ...kokkaiCommonSearchParams,
        maximumRecords: z
          .number()
          .int()
          .min(1)
          .max(100)
          .optional()
          .describe(
            "Maximum number of records to retrieve (1-100) for speeches. Default is 30."
          ),
      },
      async (params) => {
        const result = await this._callKokkaiApi("speech", params);
        if (result.error) {
          return {
            content: [
              {
                type: "text",
                text: `Error fetching speeches: ${result.message} ${result.details || ""}`,
              },
            ],
          };
        }
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(result, null, 2),
            },
          ],
        };
      }
    );
  • Helper method used by the searchSpeeches handler (and others) to make authenticated HTTP requests to the Kokkai API endpoints.
    private async _callKokkaiApi(
      endpoint: string,
      params: Record<string, any>
    ): Promise<any> {
      const queryParams = new URLSearchParams();
      for (const key in params) {
        if (params[key] !== undefined && params[key] !== null) {
          queryParams.append(key, String(params[key]));
        }
      }
      queryParams.append("recordPacking", "json"); // Always request JSON
    
      const url = `${KOKKAI_API_BASE_URL}/${endpoint}?${queryParams.toString()}`;
      console.log(`Calling Kokkai API: ${url}`);
    
      try {
        const response = await fetch(url, {
          headers: {
            "User-Agent": "MCP Agent Kokkai Client/1.0",
          },
        });
    
        const responseData = (await response.json()) as any;
    
        if (!response.ok) {
          const errorMessage =
            responseData.message || "Unknown API error";
          const errorDetails = responseData.details
            ? responseData.details.join("; ")
            : "";
          console.error(
            `Kokkai API Error: ${errorMessage} ${errorDetails}`,
            responseData
          );
          return {
            error: true,
            status: response.status,
            message: errorMessage,
            details: errorDetails,
            rawResponse: responseData,
          };
        }
        return responseData;
      } catch (error: any) {
        console.error("Network or parsing error calling Kokkai API:", error);
        return {
          error: true,
          message:
            error.message || "Failed to fetch or parse API response.",
        };
      }
    }
Behavior3/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. It mentions the 'Max 100 records' limit, which is valuable operational context. However, it doesn't describe authentication needs, rate limits, error conditions, pagination behavior (beyond the startRecord parameter), or what happens when no results are found. For a search tool with 22 parameters and no annotations, this leaves significant behavioral gaps.

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 perfectly concise with just two sentences that pack essential information: what it searches, what it returns, and the record limit. Every word earns its place, and it's front-loaded with the core purpose. No wasted words or redundant information.

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 tool's complexity (22 parameters, no output schema, no annotations), the description is adequate but incomplete. It covers the basic purpose and record limit but lacks information about authentication, error handling, response format, pagination strategy beyond the startRecord parameter, and explicit differentiation from sibling tools. For a search tool of this complexity, more contextual guidance would be helpful.

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%, so the schema already documents all 22 parameters thoroughly with descriptions, enums, patterns, and defaults. The description doesn't add any parameter-specific information beyond what's in the schema. According to scoring rules, when schema coverage is high (>80%), the baseline is 3 even with no param info in the description.

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 verb ('Searches'), resource ('specific speeches from the Kokkai API'), and scope ('発言単位出力'). It distinguishes from siblings by specifying it returns 'speech text and info about the meeting it belongs to' rather than just meeting lists or combined results. The mention of 'Max 100 records' further clarifies its operational limits.

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 provides clear context about what the tool returns (speech text + meeting info), which helps differentiate it from sibling tools like 'searchMeetingList' (likely returns only meeting metadata) and 'searchMeetingsWithSpeechText' (might return combined meeting-speech data). However, it doesn't explicitly state when to use this tool versus those alternatives or mention any prerequisites or exclusions.

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/egegungordu/kokkaikaigiroku-mcp'

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