Skip to main content
Glama

jp_lit_search_kaken_projects

Search KAKEN research projects by query or researcher to retrieve themes, keywords, report PDFs, and output lists, with results to be verified via CiNii/J-STAGE.

Instructions

KAKEN から研究課題を検索し、研究テーマ・キーワード・報告書 PDF・成果リストの手がかりを返す補助 tool。論文・図書の文献確定は CiNii / J-STAGE / IRDB / NDL で再確認する

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
limitNo
pageNo
detail_limitNo
researcher_nameNo
from_fiscal_yearNo
to_fiscal_yearNo
include_outputsNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
pageYes
limitYes
totalYes
itemsYes
cacheNo

Implementation Reference

  • The handler function that creates and returns the tool execution function for jp_lit_search_kaken_projects. It parses input, runs the cached tool which calls client.searchProjects, and returns structured content.
    export function createJpLitSearchKakenProjectsTool(
      client: KakenClient,
      cache: FileCache = createFileCache(),
      sessions: SessionStore = createSessionStore()
    ) {
      return async (input: unknown) => {
        const parsed = searchKakenProjectsInputSchema.parse(input);
        const { structuredContent } = await runCachedTool<SearchKakenProjectsOutput>({
          tool: "jp_lit_search_kaken_projects",
          input: parsed as Record<string, unknown>,
          cache,
          sessions,
          live: async () => searchKakenProjectsOutputSchema.parse(await client.searchProjects(parsed))
        });
    
        return {
          content: [{ type: "text" as const, text: JSON.stringify(structuredContent, null, 2) }],
          structuredContent
        };
      };
    }
  • Input schema (searchKakenProjectsInputSchema) and output schema (searchKakenProjectsOutputSchema) defining the Zod validation for the KAKEN projects search tool.
    export const searchKakenProjectsInputSchema = z.object({
      query: z.string().trim().min(1),
      limit: z.number().int().positive().max(20).default(10),
      page: z.number().int().positive().default(1),
      detail_limit: z.number().int().nonnegative().max(10).default(5),
      researcher_name: z.string().trim().min(1).optional(),
      from_fiscal_year: z.number().int().optional(),
      to_fiscal_year: z.number().int().optional(),
      include_outputs: z.boolean().default(true)
    });
    
    const kakenOutputTypeSchema = z.enum([
      "journal_article",
      "book",
      "conference_presentation",
      "report",
      "other"
    ]);
    
    const kakenProjectSchema = z.object({
      project_id: z.string(),
      title: z.string(),
      url: z.string(),
      principal_investigator: z.object({
        name: z.string(),
        affiliation: z.string().nullable(),
        researcher_number: z.string().nullable()
      }).nullable(),
      fiscal_years: z.string().nullable(),
      project_type: z.string().nullable(),
      fields: z.array(z.string()),
      keywords: z.array(z.string()),
      summary: z.string().nullable(),
      detail_fetched: z.boolean(),
      detail_omitted_reason: z.enum([
        "detail_limit_exceeded",
        "include_outputs_false",
        "fetch_failed"
      ]).nullable(),
      report_pdf_status: z.enum(["found", "none_found", "not_checked", "fetch_failed"]),
      report_pdfs: z.array(z.object({
        label: z.string(),
        fiscal_year: z.string().nullable(),
        url: z.string()
      })),
      outputs_preview: z.array(z.object({
        type: kakenOutputTypeSchema,
        raw_type: z.string().nullable(),
        title: z.string(),
        authors: z.array(z.string()),
        year: z.string().nullable(),
        doi: z.string().nullable(),
        url: z.string().nullable(),
        note: z.string().nullable()
      })),
      search_hints: z.object({
        project_terms: z.array(z.string()),
        researcher_terms: z.array(z.string()),
        keyword_terms: z.array(z.string()),
        caution: z.string()
      })
    });
    
    export const searchKakenProjectsOutputSchema = z.object({
      query: z.string(),
      page: z.number().int().positive(),
      limit: z.number().int().positive(),
      total: z.number().int().nonnegative(),
      items: z.array(kakenProjectSchema),
      cache: z.object({
        hit: z.boolean(),
        cache_key: z.string(),
        saved_at: z.string(),
        refresh_hint: z.string().nullable()
      }).optional()
    });
  • src/server.ts:397-405 (registration)
    Tool registration in the MCP server: registers 'jp_lit_search_kaken_projects' with description, input/output schemas, and the handler function.
    server.registerTool(
      "jp_lit_search_kaken_projects",
      {
        description: "KAKEN から研究課題を検索し、研究テーマ・キーワード・報告書 PDF・成果リストの手がかりを返す補助 tool。論文・図書の文献確定は CiNii / J-STAGE / IRDB / NDL で再確認する",
        inputSchema: searchKakenProjectsInputSchema,
        outputSchema: searchKakenProjectsOutputSchema
      },
      searchKakenProjectsTool
    );
  • src/server.ts:333-333 (registration)
    Tool creation: calls createJpLitSearchKakenProjectsTool with kakenClient, cache, and sessions dependencies.
    const searchKakenProjectsTool = createJpLitSearchKakenProjectsTool(kakenClient, cache, sessions);
  • The KAKEN API client (createKakenClient) that implements searchProjects(), building search URLs, parsing XML results, fetching detail pages, extracting report PDFs and outputs.
    export function createKakenClient(options: KakenClientOptions = {}) {
      const searchUrl = options.searchUrl ?? DEFAULT_SEARCH_URL;
      const detailBaseUrl = options.detailBaseUrl ?? DEFAULT_DETAIL_BASE_URL;
      const appId = options.appId ?? process.env.CINII_RESEARCH_APP_ID ?? "";
      const fetcher = options.fetcher ?? fetchText;
    
      return {
        async searchProjects(input: SearchKakenProjectsInput): Promise<SearchKakenProjectsOutput> {
          if (!appId.trim()) {
            throw new Error("KAKEN API requires CINII_RESEARCH_APP_ID.");
          }
    
          const payload = await fetcher(buildSearchUrl(searchUrl, appId, input));
          const parsed = parseSearchXml(payload.text, detailBaseUrl);
          const limited = parsed.items.slice(0, input.limit);
          const detailLimit = Math.min(input.detail_limit, limited.length);
          const items: KakenProject[] = [];
    
          for (const [index, project] of limited.entries()) {
            if (index >= detailLimit) {
              items.push({
                ...project,
                detail_omitted_reason: "detail_limit_exceeded",
                report_pdf_status: "not_checked"
              });
              continue;
            }
    
            try {
              const detail = await fetcher(new URL(project.url));
              items.push(applyDetail(project, detail.text, input.include_outputs));
            } catch {
              items.push({
                ...project,
                detail_fetched: false,
                detail_omitted_reason: "fetch_failed",
                report_pdf_status: "fetch_failed"
              });
            }
          }
    
          return {
            query: input.query,
            page: input.page,
            limit: input.limit,
            total: parsed.total,
            items
          };
        }
      };
    }
    
    export type KakenClient = ReturnType<typeof createKakenClient>;
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It notes the output as 'clues' (suggesting non-definitive results) and directs users to other databases for confirmation, but does not disclose authentication needs, rate limits, or response behavior beyond this hint.

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 extremely concise—just two sentences—with the first clearly stating the purpose and the second providing contextual guidance. Every word contributes value, no redundancy.

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

Completeness2/5

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

Despite having an output schema and 8 parameters, the description lacks details on pagination, parameter constraints, output structure, and error handling. It does not explain how 'detail_limit' or 'page' work, leaving significant gaps for correct invocation.

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

Parameters2/5

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

Schema description coverage is 0%, meaning no parameter-level descriptions exist. The tool description provides no additional explanation for the 8 parameters (query, limit, page, detail_limit, researcher_name, etc.), requiring the agent to rely on parameter names alone, which is insufficient.

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 it searches KAKEN research projects and returns clues for themes, keywords, report PDFs, and results lists. It differentiates itself from sibling tools by specifying the source (KAKEN) and the output as 'clues', and mentions alternative databases (CiNii/J-STAGE/IRDB/NDL) for confirmation.

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 implies this tool is for initial discovery ('clues') and that for definitive paper/book confirmation, other databases should be used, providing a usage hint. However, it does not explicitly state scenarios when to avoid using this tool or name specific sibling alternatives.

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/itarunnn/jp-lit-mcp'

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