hatena-blog-mcp
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 аккаунта, используемого для аутентификации (владелец API-ключа) |
| ○ | Часть |
| ○ | API-ключ |
| Часть |
Если блог принадлежит вам, владелец и оператор совпадают, поэтому
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
Инструменты
Блог в целом
Инструмент | Описание |
| Получить заголовок блога и доступные коллекции (также для проверки соединения) |
| Список категорий, используемых в блоге |
Записи
Инструмент | Описание |
| Список записей в порядке убывания даты (включая черновики). Продолжение через |
| Поиск по страницам с частичным совпадением по заголовку, тексту и категориям |
| Получить одну запись (текст в исходной разметке) |
| Создать новую запись (по умолчанию черновик) |
| Обновить запись (дифференциальное обновление) |
Статические страницы
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 toolscreate_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ブログ情報取得ARead-only
接続先ブログのタイトルと、利用できるコレクション(記事・固定ページ)を取得する。設定と認証が正しいかの疎通確認にも使える。固定ページのコレクションは有料プランでのみ返る。
Inputs: no named parameters.
get_entryブログ記事取得ARead-only
ブログ記事を 1 件取得する。本文(登録記法のまま)・カテゴリ・公開状態を含む。編集前に必ずこれで現状を確認する。
Inputs: entry_id (required), include_formatted_content.
get_page固定ページ取得ARead-only
固定ページを 1 件取得する。本文(登録記法のまま)・カテゴリ・公開状態を含む。編集前に必ずこれで現状を確認する。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。
Inputs: page_id (required), include_formatted_content.
list_categoriesカテゴリ一覧ARead-only
ブログで使われているカテゴリの一覧を取得する。記事を作成・更新する前に、既存のカテゴリ名と表記を揃えるために確認する。
Inputs: no named parameters.
list_entriesブログ記事一覧ARead-only
ブログ記事を新しい順に一覧する。下書きも含まれる。1 ページあたりの件数は API 側で決まっており、続きを読むには戻り値の next_page を page に渡す。本文まで読みたい場合は get_entry を使う。
Inputs: page, include_content.
list_pages固定ページ一覧ARead-only
固定ページを新しい順に一覧する。下書きも含まれる。1 ページあたりの件数は API 側で決まっており、続きを読むには戻り値の next_page を page に渡す。本文まで読みたい場合は get_page を使う。 固定ページははてなブログの有料プランでのみ利用できる。無料プランでは 404 が返る。
Inputs: page, include_content.
search_entriesブログ記事検索ARead-only
ブログ記事をページを辿りながら検索する。タイトル・本文・カテゴリを対象に部分一致(大文字小文字は無視)。はてなブログの API は一覧の 1 ページあたり件数が少ないため、まとめて探すときはこのツールを使う。古いブログ記事まで届かない場合は max_pages を増やす。
Inputs: limit, query, status, category, +2 more.
search_pages固定ページ検索ARead-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
Scored across 13 tools
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.
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.
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.
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
Related MCP Connectors
Travel tools for AI agents: plan and edit real trips, search stays and tours, import travel videos.
Create, edit, organize, publish, and configure JustBlogged blogs from MCP clients.
SEO & marketing toolkit for AI agents: GA4, Search Console, AdSense, GTM, PageSpeed, Trends.
Manage a WordPress site from your AI assistant: read, search, propose edits, Search Console data.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables searching and retrieving articles from Hatena Blog through Claude Desktop/Web. Supports keyword search, fetching recent posts, and retrieving post details by URL.1MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to interact with the Google Blogger API v3 to manage blog posts and metadata. It supports the full post lifecycle including creating, updating, publishing, and deleting content through natural language.105 npm1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI models to interact with Google Blogger blogs, manage posts, labels, and retrieve blog information via API key or OAuth2.8 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to publish, update, and manage Hashnode blog articles, with support for tags, cover images, and publication management.-