Skip to main content
Glama
hatena-blog-mcp
by sumiVer2

hatena-blog-mcp

MCP-сервер для создания и обновления записей в Hatena Blog. Тонкая обёртка над はてなブログ AtomPub API, позволяющая AI-агенту работать с черновиками, редактированием и публикацией записей.

Установка

В качестве менеджера пакетов используется pnpm (зафиксирован в поле packageManager).

pnpm install   # 依存のインストールと同時に prepare で dist がビルドされる

Получение значений настроек

В [Настройки] > [Дополнительные настройки] > [AtomPub] отображаются «Корневая конечная точка» и «API-ключ». Корневая конечная точка имеет следующий вид:

https://blog.hatena.ne.jp/{ブログ所有者のはてなID}/{ブログID}/atom

Переменная окружения

Обязательно

Значение

HATENA_ID

○

Hatena ID аккаунта, используемого для аутентификации (владелец API-ключа)

HATENA_BLOG_ID

○

Часть {ブログID} корневой конечной точки (например: tech.example.hatenablog.com)

HATENA_API_KEY

○

API-ключ

HATENA_BLOG_OWNER_ID

Часть {ブログ所有者のはてなID} корневой конечной точки. Если не указано, используется HATENA_ID

  • Если блог принадлежит вам, владелец и оператор совпадают, поэтому HATENA_BLOG_OWNER_ID не нужен.

  • В общем блоге (например, корпоративном техническом блоге) владелец и оператор различаются. В этом случае укажите ID владельца блога в HATENA_BLOG_OWNER_ID, а в HATENA_ID — свой аккаунт.

  • Даже при использовании платного тарифа с собственным доменом, в HATENA_BLOG_ID указывается домен до настройки собственного домена.

См. .env.example.

Регистрация в MCP-клиенте

Для Claude Code:

# 自分が所有するブログ
claude mcp add hatena-blog -s user \
  -e HATENA_ID=your-hatena-id \
  -e HATENA_BLOG_ID=your-blog.hatenablog.com \
  -e HATENA_API_KEY=your-api-key \
  -- node /absolute/path/to/hatena-blog-mcp/dist/index.js

# 共有ブログ(所有者と操作者が異なる場合は HATENA_BLOG_OWNER_ID を足す)
claude mcp add hatena-blog -s user \
  -e HATENA_ID=your-hatena-id \
  -e HATENA_BLOG_OWNER_ID=blog-owner-id \
  -e HATENA_BLOG_ID=blog-owner-id.hatenablog.com \
  -e HATENA_API_KEY=your-api-key \
  -- node /absolute/path/to/hatena-blog-mcp/dist/index.js

С флагом -s user доступно во всех проектах. Не используйте -s project (API-ключ будет записан в .mcp.json).

Если записывать напрямую в файл конфигурации:

{
  "mcpServers": {
    "hatena-blog": {
      "command": "node",
      "args": ["/absolute/path/to/tech-blog/dist/index.js"],
      "env": {
        "HATENA_ID": "your-hatena-id",
        "HATENA_BLOG_OWNER_ID": "blog-owner-id",
        "HATENA_BLOG_ID": "blog-owner-id.hatenablog.com",
        "HATENA_API_KEY": "your-api-key"
      }
    }
  }
}

После регистрации вызов get_blog_info подтвердит соединение.

Related MCP server: Blogger MCP Server

Инструменты

Блог в целом

Инструмент

Описание

get_blog_info

Получить заголовок блога и доступные коллекции (также для проверки соединения)

list_categories

Список категорий, используемых в блоге

Записи

Инструмент

Описание

list_entries

Список записей в порядке убывания даты (включая черновики). Продолжение через next_page

search_entries

Поиск по страницам с частичным совпадением по заголовку, тексту и категориям

get_entry

Получить одну запись (текст в исходной разметке)

create_entry

Создать новую запись (по умолчанию черновик)

update_entry

Обновить запись (дифференциальное обновление)

Статические страницы

list_pages / search_pages / get_page / create_page / update_page доступны в том же виде, что и для записей. Статические страницы доступны только на платном тарифе Hatena Blog (на бесплатном тарифе возвращается 404). Статические страницы не имеют категорий, поэтому параметр categories отсутствует.

Проектные решения

Удаление не реализовано

Удаление записей и статических страниц (DELETE) есть на стороне API, но намеренно не предоставлено как инструмент. Потому что последствия ошибочного действия велики и их нельзя отменить. Удаление выполняется через браузер.

update_entry — дифференциальное обновление

Поскольку PUT в AtomPub «заменяет всё отправленным содержимым», даже если вы хотите исправить только заголовок, необходимо заново отправить текст, категории и дату публикации. Этот сервер в update_entry сначала выполняет GET, затем заменяет только указанные поля и отправляет PUT.

  • Пропущенные поля сохраняют текущие значения.

  • Если опустить updated, дата публикации записи (отображаемая дата) не изменится.

  • Если передать categories, произойдёт замена (не добавление). Чтобы сохранить существующие категории, передайте их вместе с новыми.

Новые записи по умолчанию черновик

Параметр draft в create_entry по умолчанию равен true. Чтобы запись не была опубликована внезапно из-за действий агента, публикация происходит только при явном указании draft: false.

Разметка текста

В content_type можно указать text/x-markdown / text/x-hatena-syntax / text/html / text/plain (по умолчанию text/x-markdown). Однако фактическая интерпретация зависит от настройки «Режим редактирования» на стороне блога, поэтому нужно писать в соответствии с настройками блога. При обновлении существующей записи сохраняется разметка, использованная до редактирования.

Отложенная публикация

В create_entry укажите draft: true + scheduled: true + updated с будущей датой и временем.

Постраничная навигация в списке

API Hatena Blog возвращает небольшое количество записей на страницу, и количество определяется на стороне API (в официальной документации указано 7 записей, но фактически возвращается 10). list_entries возвращает одну страницу, а передача next_page в параметр page следующего вызова позволяет получить продолжение. Для поиска по всем записям используйте search_entries, который внутри переходит по страницам. Количество просматриваемых страниц контролируется параметром max_pages.

Аутентификация и Hatena ID в URL

Используется аутентификация WSSE (заголовок X-WSSE). Для каждого запроса генерируются Nonce и Created, а Base64(SHA1(Nonce + Created + API-ключ)) отправляется как PasswordDigest.

Обратите внимание: Hatena ID в URL конечной точки (владелец блога) и аккаунт для аутентификации — это разные вещи. API-ключ выдаётся не для блога, а для аккаунта, поэтому в общем блоге

  • URL: https://blog.hatena.ne.jp/{所有者のID}/{ブログID}/atom

  • Аутентификация: Hatena ID вашего аккаунта + API-ключ

Получается такая комбинация. Если их перепутать, возникнет 401 (ключ не принадлежит владельцу) или 403 (у аккаунта нет прав на блог). Этот сервер разделяет их через HATENA_BLOG_OWNER_ID и HATENA_ID, а при отсутствии значения обрабатывает их как один и тот же ID, поэтому он работает одинаково и для собственного блога, и для общего.

Вне области действия

  • Загрузка изображений: вне области AtomPub (есть отдельный はてなフォトライフ API)

  • Изменение макета статических страниц: не поддерживается API. Настраивается через браузер

  • OAuth-аутентификация: поддерживается только WSSE-аутентификация с API-ключом

Разработка

pnpm run typecheck   # 型チェック
pnpm test            # ユニットテスト(API はモック)
pnpm run build       # dist へビルド
pnpm run dev         # ビルドせずに起動
pnpm run inspect     # MCP Inspector で手動確認

pnpm 10 по умолчанию блокирует скрипты сборки зависимостей, поэтому только esbuild, используемый tsx, разрешён в pnpm.onlyBuiltDependencies в package.json.

Структура

src/
  index.ts          エントリポイント(stdio トランスポート)
  server.ts         McpServer の組み立て
  config.ts         環境変数の読み込み
  hatena/
    client.ts       AtomPub の HTTP クライアント
    wsse.ts         WSSE 認証ヘッダの生成
    atom.ts         Atom XML のパース・生成
    types.ts        ドメイン型
  tools/
    blog.ts         ブログ全体に対するツール
    collection.ts   記事・固定ページ共通のツール定義
    shared.ts       ツールの共通ヘルパー

Записи и статические страницы имеют почти одинаковую структуру в AtomPub, поэтому registerCollectionTools из tools/collection.ts вызывается с двумя разными настройками: для записей и для статических страниц.

Лицензия

MIT License. Подробнее см. LICENSE.

Available Tools

13 tools
create_entryブログ記事作成A

ブログ記事を新規作成する。既定では下書きとして作成されるので、公開する場合は draft を false にする。予約投稿する場合は draft=true・scheduled=true と、未来日時の updated を指定する。

Inputs: title (required), content (required), draft, updated, +5 more.

create_page固定ページ作成A

固定ページを新規作成する。既定では下書きとして作成されるので、公開する場合は draft を false にする。予約投稿する場合は draft=true・scheduled=true と、未来日時の updated を指定する。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。

Inputs: title (required), content (required), draft, updated, +4 more.

get_blog_infoブログ情報取得A
Read-only

接続先ブログのタイトルと、利用できるコレクション(記事・固定ページ)を取得する。設定と認証が正しいかの疎通確認にも使える。固定ページのコレクションは有料プランでのみ返る。

Inputs: no named parameters.

get_entryブログ記事取得A
Read-only

ブログ記事を 1 件取得する。本文(登録記法のまま)・カテゴリ・公開状態を含む。編集前に必ずこれで現状を確認する。

Inputs: entry_id (required), include_formatted_content.

get_page固定ページ取得A
Read-only

固定ページを 1 件取得する。本文(登録記法のまま)・カテゴリ・公開状態を含む。編集前に必ずこれで現状を確認する。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。

Inputs: page_id (required), include_formatted_content.

list_categoriesカテゴリ一覧A
Read-only

ブログで使われているカテゴリの一覧を取得する。記事を作成・更新する前に、既存のカテゴリ名と表記を揃えるために確認する。

Inputs: no named parameters.

list_entriesブログ記事一覧A
Read-only

ブログ記事を新しい順に一覧する。下書きも含まれる。1 ページあたりの件数は API 側で決まっており、続きを読むには戻り値の next_page を page に渡す。本文まで読みたい場合は get_entry を使う。

Inputs: page, include_content.

list_pages固定ページ一覧A
Read-only

固定ページを新しい順に一覧する。下書きも含まれる。1 ページあたりの件数は API 側で決まっており、続きを読むには戻り値の next_page を page に渡す。本文まで読みたい場合は get_page を使う。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。

Inputs: page, include_content.

search_entriesブログ記事検索A
Read-only

ブログ記事をページを辿りながら検索する。タイトル・本文・カテゴリを対象に部分一致(大文字小文字は無視)。はてなブログの API は一覧の 1 ページあたり件数が少ないため、まとめて探すときはこのツールを使う。古いブログ記事まで届かない場合は max_pages を増やす。

Inputs: limit, query, status, category, +2 more.

search_pages固定ページ検索A
Read-only

固定ページをページを辿りながら検索する。タイトル・本文・カテゴリを対象に部分一致(大文字小文字は無視)。はてなブログの API は一覧の 1 ページあたり件数が少ないため、まとめて探すときはこのツールを使う。古い固定ページまで届かない場合は max_pages を増やす。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。

Inputs: limit, query, status, max_pages, +1 more.

update_entryブログ記事更新A

ブログ記事を更新する。指定した項目だけを差し替える差分更新で、省略した項目は現在の値がそのまま残る。下書きを公開するには draft=false を指定する。categories を渡すと現在のカテゴリは完全に置き換わる。

Inputs: entry_id (required), draft, title, content, +5 more.

update_page固定ページ更新A

固定ページを更新する。指定した項目だけを差し替える差分更新で、省略した項目は現在の値がそのまま残る。下書きを公開するには draft=false を指定する。categories を渡すと現在のカテゴリは完全に置き換わる。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。

Inputs: page_id (required), draft, title, content, +4 more.

upload_image画像アップロードA

ローカルの画像をはてなフォトライフにアップロードし、記事本文に貼れる記法(embed)を返す。embed は Markdown・はてな記法の編集モード向け。見たままモードのブログでは imageUrl を使う。画像は認証アカウント(HATENA_ID)のフォトライフに保存され、URL を知っていれば誰でも見られる。社外に出してよい画像だけを渡すこと。アップロードした画像の削除はブラウザから行う。

Inputs: file_path (required), title, folder.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 13 tools

    Disambiguation5/5

    Each tool maps to a distinct resource and action: entries, pages, categories, blog info, and image upload are cleanly separated. The list/search/get/create/update split is explicit, and descriptions clarify when to use list versus search.

    Naming Consistency5/5

    All tool names use consistent snake_case verb_noun patterns such as list_entries, get_entry, create_page, and update_page. Even the auxiliary tools get_blog_info, list_categories, and upload_image fit the same readable convention.

    Tool Count5/5

    With 13 tools, the set is well-scoped: entry CRUD/list/search, page CRUD/list/search, plus blog info, categories, and image upload. Each tool has a clear place, and the symmetric entries/pages coverage is reasonable rather than redundant.

    Completeness3/5

    The surface covers create, read, update, list, and search for both entries and pages, but deletion operations for entries and pages are missing. Image upload exists without an accompanying delete tool, with deletion explicitly delegated to the browser, leaving lifecycle gaps.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers