Skip to main content
Glama

jp_lit_export_session

Export a current or past research session to a structured file (Markdown, JSON, or CSL-JSON) for documentation and sharing.

Instructions

現在の調査セッション、または session_id で指定した過去セッションを repo 内の exports/ に書き出す。既定は Markdown で、人間が読み返しやすい形に整形する

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idNo
formatNomarkdown
profileNofull_log
output_pathNo
include_unselectedNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes
formatYes
profileYes
pathYes
exported_atYes
item_countYes

Implementation Reference

  • The main handler function for the jp_lit_export_session tool. It parses input via exportSessionInputSchema, reads a session (current or by session_id), delegates to the SessionExporter to write the export file, and returns structured output with session metadata and item count.
    export function createJpLitExportSessionTool(
      sessionStore: SessionStore,
      exporter: SessionExporter
    ) {
      return async (input: unknown) => {
        const parsed = exportSessionInputSchema.parse(input);
        const session = parsed.session_id
          ? await sessionStore.readById(parsed.session_id)
          : await sessionStore.readCurrent();
        const exported = await exporter.exportSession({
          session,
          format: parsed.format,
          profile: parsed.profile,
          outputPath: parsed.output_path,
          includeUnselected: parsed.include_unselected
        });
    
        const structuredContent: ExportSessionOutput = exportSessionOutputSchema.parse({
          session_id: session.session_id,
          format: parsed.format,
          profile: parsed.profile,
          path: exported.path,
          exported_at: new Date().toISOString(),
          item_count: exported.itemCount
        });
    
        return {
          content: [
            {
              type: "text" as const,
              text: JSON.stringify(structuredContent, null, 2)
            }
          ],
          structuredContent
        };
      };
    }
  • Input schema (Zod) for the export tool: session_id (optional regex), format (markdown/json/csl-json, default markdown), profile (full_log/selected/unselected, default full_log), output_path (optional), include_unselected (boolean, default true).
    export const exportSessionInputSchema = z.object({
      session_id: z.string().trim().regex(/^\d{4}-\d{2}-\d{2}-\d{6}$/).optional(),
      format: z.enum(["markdown", "json", "csl-json"]).default("markdown"),
      profile: z
        .enum(["full_log", "selected", "unselected"])
        .default("full_log"),
      output_path: z.string().trim().min(1).optional(),
      include_unselected: z.boolean().default(true)
    });
  • Output schema (Zod) for the export tool: session_id, format, profile, path (the written file path), exported_at (ISO timestamp), item_count (non-negative integer).
    export const exportSessionOutputSchema = z.object({
      session_id: z.string(),
      format: z.enum(["markdown", "json", "csl-json"]),
      profile: z.enum(["full_log", "selected", "unselected"]),
      path: z.string(),
      exported_at: z.string(),
      item_count: z.number().int().nonnegative()
    });
  • src/server.ts:437-445 (registration)
    Registers the tool with the MCP server under name 'jp_lit_export_session', providing description, inputSchema, and outputSchema, with the handler created by createJpLitExportSessionTool(sessions, sessionExporter).
    server.registerTool(
      "jp_lit_export_session",
      {
        description: "現在の調査セッション、または session_id で指定した過去セッションを repo 内の exports/ に書き出す。既定は Markdown で、人間が読み返しやすい形に整形する",
        inputSchema: exportSessionInputSchema,
        outputSchema: exportSessionOutputSchema
      },
      exportSessionTool
    );
  • The SessionExporter implementation (createSessionExporter). Handles the actual file writing in three formats: markdown (renderMarkdown), JSON (session data with filtered items), and csl-json (CSL-JSON array). Resolves cached items via FileCache for unselected item inclusion.
    export function createSessionExporter(
      cache: FileCache,
      baseDir = process.cwd()
    ): SessionExporter {
      return {
        async exportSession({ session, format, profile, outputPath, includeUnselected }) {
          const target =
            outputPath ??
            defaultExportPath(baseDir, session.session_id, profile, format);
          const unresolvedItems = new Map<string, Array<Record<string, unknown>>>();
    
          await mkdir(path.dirname(target), { recursive: true });
    
          if ((profile === "full_log" && includeUnselected) || profile === "unselected") {
            for (const entry of session.entries) {
              const envelope = await cache.read<unknown>(entry.result_ref.tool, entry.result_ref.cache_key);
              unresolvedItems.set(entry.cache_key, extractUnselectedItems(envelope));
            }
          }
    
          let itemCount = session.entries.reduce((sum, entry) => {
            const selectedCount = filterSelectedItems(entry, profile).length;
            const shouldCountUnselected =
              format !== "csl-json" && profile === "full_log" && includeUnselected;
            const unselectedCount = shouldCountUnselected || profile === "unselected"
              ? filterUnselectedItems(
                  unresolvedItems.get(entry.cache_key) ?? [],
                  entry.selected_items
                ).length
              : 0;
    
            return sum + selectedCount + unselectedCount;
          }, 0);
    
          if (format === "csl-json") {
            const cslItems = [];
    
            for (const entry of session.entries) {
              const cachedItems = await readEntryItems(cache, entry);
    
              for (const selectedItem of filterSelectedItems(entry, profile)) {
                cslItems.push(toCslItem(selectedItem, findCslSourceItem(cachedItems, selectedItem)));
              }
    
              if (profile === "unselected") {
                for (const unselectedItem of filterUnselectedItems(cachedItems, entry.selected_items)) {
                  cslItems.push(toCslItem(toFallbackSelectedItem(unselectedItem), unselectedItem));
                }
              }
            }
    
            itemCount = cslItems.length;
            await writeFile(target, JSON.stringify(cslItems, null, 2), "utf8");
          } else if (format === "json") {
            const payload = {
              ...session,
              entries: session.entries.map((entry) => {
                const baseEntry = {
                  ...entry,
                  selected_items: filterSelectedItems(entry, profile)
                };
    
                if ((profile === "full_log" && includeUnselected) || profile === "unselected") {
                  return {
                    ...baseEntry,
                    unselected_items: filterUnselectedItems(
                      unresolvedItems.get(entry.cache_key) ?? [],
                      entry.selected_items
                    )
                  };
                }
    
                return baseEntry;
              })
            };
    
            await writeFile(target, JSON.stringify(payload, null, 2), "utf8");
          } else {
            await writeFile(
              target,
              renderMarkdown(session, profile, includeUnselected, unresolvedItems),
              "utf8"
            );
          }
    
          return {
            path: target,
            itemCount
          };
        }
      };
    }
Behavior2/5

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

The description mentions writing to a specific directory and default formatting, but fails to disclose critical behavioral traits such as overwrite behavior, error handling for missing session IDs, required permissions, or the effect of parameters like 'include_unselected'. With no annotations, the description should provide more detail.

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 concise, consisting of two clear sentences. It front-loads the main action and output location. However, it is too brief to cover essential parameter information, sacrificing completeness for brevity.

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?

Given the tool has 5 parameters (all optional), no annotations, and an output schema not explained, the description is insufficient. It does not describe the output format or content, lacks parameter explanations, and fails to provide context relative to sibling tools.

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

Parameters1/5

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

Schema description coverage is 0%, yet the description only hints at session_id and default format. It does not explain the meaning or effect of the other three parameters (format enum, profile enum, output_path, include_unselected). The description adds negligible value beyond the schema itself.

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 exports a research session (current or by session_id) to a specific directory (exports/), with default Markdown formatting for human readability. It distinguishes itself from sibling tools like jp_lit_export_view, which likely exports a different resource.

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?

No guidance is provided on when to use this tool versus alternatives. The description does not mention any prerequisites, exclusions, or comparison with sibling tools. The agent is left to infer usage context from the tool name and description alone.

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