Zenn
📘

arXivを検索するMCPサーバを開発してみた

2025/04/06に公開
15

MCPについて、記事を読んだり、利用はしていたものの、自分で作ったことがなかったので論文検索用MCPサーバをサンプル実装してみました。

こちらの記事にインスパイアされました:
https://note.com/te_ftef/n/n0de0f4d86c04

実装したものはこちら:
https://github.com/danimal141/arxiv-search-mcp

やりたいこと

  1. arXiv.orgの論文を簡単に検索できるMCPサーバーを作成する
  2. 特定のカテゴリ(AI、機械学習など)から最新の論文を取得する
  3. 検索結果を整形して、タイトル、著者、要約、リンクなどを分かりやすく表示する
  4. Claude Desktopから利用する

技術選定

主に以下の技術を使用しました:

  • Deno: 高速で安全なTypeScriptランタイム
  • TypeScript: 型安全なコードの作成
  • FastMCP: MCPサーバーの実装をシンプルにするライブラリ (使ってみたかった)

実装の流れ

1. プロジェクト初期設定

まず基本的なディレクトリ構造を設定し、必要な依存関係を定義しました:

// deno.json
{
  "tasks": {
    "dev": "deno run --watch --allow-read --allow-env --allow-net src/main.ts",
    "test": "deno test --allow-read --allow-env --allow-net",
    "compile": "deno compile --allow-read --allow-env --allow-net --output=./bin/arxiv-search-mcp src/main.ts"
  },
  "imports": {
    "@std/assert": "jsr:@std/assert@1",
    "fastmcp": "npm:fastmcp@^1.21.0",
    "zod": "npm:zod@^3.24.2",
    "fast-xml-parser": "npm:fast-xml-parser@4.3.4"
  }
}

2. arXiv APIの統合

arXiv.orgはAPIを提供しており、このAPIを使用して論文の検索と取得を行います。実装では、以下の主要な要素を定義しました:

  • XMLレスポンスのパース用インターフェース
  • arXivエントリーのインターフェース
  • 検索パラメータのスキーマ(Zodを使用)
// 型定義
export interface XMLFeedEntry {
  title: string;
  author: { name: string }[] | { name: string };
  summary: string;
  id: string;
}

interface XMLResponse {
  feed: {
    entry: XMLFeedEntry[];
  };
}

export interface ArxivEntry {
  title: string;
  authors: string;
  summary: string;
  link: string;
}

// パラメータスキーマ
export const SearchArxivParamsZod = z.object({
  category: z.string().describe("arXiv category (e.g., cs.LG, astro-ph)"),
  max_results: z.number().min(1).max(100).default(5).describe(
    "Number of papers to fetch (1-100)",
  ),
});

3. 検索機能の実装

検索機能の中核部分は search_arxiv_execute 関数です。この関数は:

  1. 指定されたカテゴリと最大結果数に基づいてAPIリクエストを構築
  2. arXiv APIにリクエストを送信
  3. XMLレスポンスをパース
  4. 結果を整形して返す
export async function search_arxiv_execute(args: z.infer<typeof SearchArxivParamsZod>) {
  try {
    // APIリクエスト構築
    const query = new URLSearchParams({
      search_query: `cat:${args.category}`,
      sortBy: "submittedDate",
      sortOrder: "descending",
      max_results: args.max_results.toString(),
    });

    const response = await fetch(`${ARXIV_API_BASE}${query}`, {
      headers: {
        "User-Agent": USER_AGENT,
        "Accept": "application/xml",
      },
    });

    // レスポンス処理
    const xmlText = await response.text();
    const parser = new XMLParser({
      ignoreAttributes: false,
      attributeNamePrefix: "@_",
    });
    const xmlDoc = parser.parse(xmlText) as XMLResponse;

    // エントリーパース
    const entries = Array.isArray(xmlDoc.feed.entry)
      ? xmlDoc.feed.entry.map(parseArxivEntry)
      : xmlDoc.feed.entry
      ? [parseArxivEntry(xmlDoc.feed.entry)]
      : [];

    // 結果フォーマット
    const formattedPapers = entries.map((paper: ArxivEntry) =>
      `Title: ${paper.title}\nAuthors: ${paper.authors}\nSummary: ${paper.summary}\nLink: ${paper.link}`
    );

    return formattedPapers.join("\n\n---\n\n");
  } catch (error: unknown) {
    console.error("Error in search_arxiv:", error);
    const errorMessage = error instanceof Error
      ? error.message
      : "An unknown error occurred";
    return `Error during search: ${errorMessage}`;
  }
}

4. MCPサーバーの構築

FastMCPライブラリを使用して、MCPサーバーをセットアップし、検索ツールを登録しました:

const server = new FastMCP({
  name: "arXiv-Search",
  version: "1.0.0",
});

server.addTool({
  name: "search_arxiv",
  description: "Search latest papers from a specific arXiv category",
  parameters: SearchArxivParamsZod,
  execute: search_arxiv_execute,
});

server.start({
  transportType: "stdio",
});

使用方法

arXiv Search MCPサーバーは、以下のように使用できます:

  1. リポジトリをクローンして依存関係をインストール
  2. deno task compile コマンドでバイナリをビルド
  3. Claude Desktopの設定ファイルにMCPサーバーを追加
{
  "mcpServers": {
    "arxiv-search-mcp": {
      "command": "/path/to/dir/arxiv-search-mcp/bin/arxiv-search-mcp"
    }
  }
}

Claudeとの対話では、以下のようにして論文を検索できます:

cs.AIカテゴリの最新論文を5件教えてください

すると、Claudeは内部でsearch_arxivツールを呼び出し、フォーマットされた論文情報を表示します:

Title: [論文タイトル]
Authors: [著者リスト]
Summary: [論文要約]
Link: [論文へのリンク]

---

...

ひとまず使われていそうです!

まとめ

これまで利用はしていたものの、実際に手を動かしてサーバを実装してみることで改めてMCPの可能性と柔軟性、そして外部APIとの統合の重要性を実感しました。あとFastMCP良いっすね。

引き続きやっていきます。

参考資料

15

Discussion

ログインするとコメントできます