@esaio/esa-mcp-server 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +10 -6
- package/README.md +16 -12
- package/bin/{index.js → index.mjs} +1 -1
- package/package.json +22 -3
- package/.dockerignore +0 -36
- package/.github/dependabot.yml +0 -23
- package/.github/workflows/docker-publish.yml +0 -120
- package/.github/workflows/main.yml +0 -41
- package/CLAUDE.md +0 -94
- package/Dockerfile +0 -34
- package/biome.json +0 -57
- package/src/__tests__/fixtures/mock-comment.ts +0 -90
- package/src/__tests__/fixtures/mock-post.ts +0 -79
- package/src/__tests__/index.test.ts +0 -216
- package/src/api_client/__tests__/index.test.ts +0 -149
- package/src/api_client/__tests__/middleware.test.ts +0 -120
- package/src/api_client/__tests__/with-context.test.ts +0 -98
- package/src/api_client/index.ts +0 -29
- package/src/api_client/middleware.ts +0 -21
- package/src/api_client/with-context.ts +0 -26
- package/src/config/__tests__/index.test.ts +0 -65
- package/src/config/index.ts +0 -20
- package/src/context/mcp-context.ts +0 -1
- package/src/context/stdio-context.ts +0 -6
- package/src/errors/missing-team-name-error.ts +0 -8
- package/src/formatters/__tests__/mcp-response.test.ts +0 -106
- package/src/formatters/mcp-response.ts +0 -95
- package/src/generated/api-types.ts +0 -2968
- package/src/i18n/__tests__/index.test.ts +0 -53
- package/src/i18n/index.ts +0 -39
- package/src/index.ts +0 -47
- package/src/locales/en.json +0 -13
- package/src/locales/ja.json +0 -13
- package/src/prompts/__tests__/index.test.ts +0 -48
- package/src/prompts/__tests__/summarize-post.test.ts +0 -291
- package/src/prompts/index.ts +0 -21
- package/src/prompts/summarize-post.ts +0 -94
- package/src/resources/__tests__/index.test.ts +0 -50
- package/src/resources/__tests__/recent-posts-list.test.ts +0 -92
- package/src/resources/__tests__/recent-posts.test.ts +0 -270
- package/src/resources/index.ts +0 -33
- package/src/resources/recent-posts-list.ts +0 -22
- package/src/resources/recent-posts.ts +0 -45
- package/src/schemas/team-name-schema.ts +0 -19
- package/src/tools/__tests__/attachments.test.ts +0 -460
- package/src/tools/__tests__/categories.test.ts +0 -402
- package/src/tools/__tests__/comments.test.ts +0 -970
- package/src/tools/__tests__/helps.test.ts +0 -222
- package/src/tools/__tests__/index.test.ts +0 -48
- package/src/tools/__tests__/post-actions.test.ts +0 -445
- package/src/tools/__tests__/posts.test.ts +0 -917
- package/src/tools/__tests__/search.test.ts +0 -339
- package/src/tools/__tests__/teams.test.ts +0 -615
- package/src/tools/attachments.ts +0 -167
- package/src/tools/categories.ts +0 -153
- package/src/tools/comments.ts +0 -258
- package/src/tools/helps.ts +0 -50
- package/src/tools/index.ts +0 -351
- package/src/tools/post-actions.ts +0 -132
- package/src/tools/posts.ts +0 -179
- package/src/tools/search.ts +0 -98
- package/src/tools/teams.ts +0 -157
- package/src/transformers/__tests__/category-transformer.test.ts +0 -161
- package/src/transformers/__tests__/comment-transformer.test.ts +0 -129
- package/src/transformers/__tests__/post-name-normalizer.test.ts +0 -53
- package/src/transformers/__tests__/post-transformer.test.ts +0 -70
- package/src/transformers/__tests__/query-normalizer.test.ts +0 -98
- package/src/transformers/__tests__/team-name-normalizer.test.ts +0 -21
- package/src/transformers/category-transformer.ts +0 -36
- package/src/transformers/comment-transformer.ts +0 -34
- package/src/transformers/post-name-normalizer.ts +0 -30
- package/src/transformers/post-transformer.ts +0 -38
- package/src/transformers/query-normalizer.ts +0 -36
- package/src/transformers/team-name-normalizer.ts +0 -7
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -30
- package/tsdown.config.ts +0 -13
- package/vitest.config.ts +0 -24
package/README.en.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
|
|
5
|
-
[日本語](
|
|
5
|
+
[日本語](https://github.com/esaio/esa-mcp-server#readme) | **English**
|
|
6
6
|
|
|
7
7
|
Official Model Context Protocol (MCP) server for esa.io - STDIO transport version.
|
|
8
8
|
|
|
@@ -13,6 +13,7 @@ This MCP server provides seamless integration between AI assistants and [esa.io]
|
|
|
13
13
|
## Available Tools
|
|
14
14
|
|
|
15
15
|
### Team Management
|
|
16
|
+
|
|
16
17
|
- `esa_get_teams` - Get user's accessible esa teams
|
|
17
18
|
- `esa_get_team_stats` - Get team statistics (members, posts, comments, stars, watches, active users)
|
|
18
19
|
- `esa_get_team_tags` - Get all tags used in team posts with count
|
|
@@ -26,11 +27,13 @@ This MCP server provides seamless integration between AI assistants and [esa.io]
|
|
|
26
27
|
- `esa_update_post` - Update existing post (title, content, tags, category, WIP status)
|
|
27
28
|
|
|
28
29
|
### Post Actions
|
|
30
|
+
|
|
29
31
|
- `esa_archive_post` - Archive a post by moving to Archived/ category
|
|
30
32
|
- `esa_ship_post` - Ship a post (mark as complete by setting wip to false)
|
|
31
33
|
- `esa_duplicate_post` - Prepare a post for duplication (retrieve name and body_md)
|
|
32
34
|
|
|
33
35
|
### Comment Management
|
|
36
|
+
|
|
34
37
|
- `esa_get_comment` - Get a specific comment by ID
|
|
35
38
|
- `esa_create_comment` - Create a new comment on a post
|
|
36
39
|
- `esa_update_comment` - Update an existing comment
|
|
@@ -39,6 +42,7 @@ This MCP server provides seamless integration between AI assistants and [esa.io]
|
|
|
39
42
|
- `esa_get_team_comments` - Get team comments with pagination
|
|
40
43
|
|
|
41
44
|
### Category Management
|
|
45
|
+
|
|
42
46
|
- `esa_get_categories` - Get categories and subcategories for a specific path
|
|
43
47
|
- `esa_get_top_categories` - Get all top-level categories for a team
|
|
44
48
|
- `esa_get_all_category_paths` - Get all category paths in a team (with post counts, supports filtering)
|
|
@@ -46,11 +50,13 @@ This MCP server provides seamless integration between AI assistants and [esa.io]
|
|
|
46
50
|
- Filter examples: `prefix: "dev"` for development-related, `match: "api"` for API-related categories
|
|
47
51
|
|
|
48
52
|
### Attachments
|
|
53
|
+
|
|
49
54
|
- `esa_get_attachment` - Retrieve an attachment file from esa posts and comments
|
|
50
55
|
- Returns base64-encoded data for supported images (JPEG, PNG, GIF, WebP) under 30MB
|
|
51
56
|
- Returns signed URLs (valid for 5 minutes) for other file types, larger images, or when forceSignedUrl is specified
|
|
52
57
|
|
|
53
58
|
### Help & Documentation
|
|
59
|
+
|
|
54
60
|
- `esa_get_search_options_help` - Get esa search syntax documentation
|
|
55
61
|
- `esa_get_markdown_syntax_help` - Get esa Markdown syntax documentation
|
|
56
62
|
- `esa_search_help` - Search esa documentation for features and terminology
|
|
@@ -74,8 +80,8 @@ Add to your MCP client configuration file:
|
|
|
74
80
|
### Required Environment Variables
|
|
75
81
|
|
|
76
82
|
- ESA_ACCESS_TOKEN: Access Token
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
- Required scopes: `read write` or `admin:comment read:post write:post read:category read:tag read:attachment read:team read:member`
|
|
84
|
+
- [PAT v2](https://docs.esa.io/posts/559) is recommended.
|
|
79
85
|
- LANG: Language for UI
|
|
80
86
|
|
|
81
87
|
### Claude Desktop Example
|
|
@@ -115,9 +121,7 @@ Add to `claude_desktop_config.json`:
|
|
|
115
121
|
"mcpServers": {
|
|
116
122
|
"esa": {
|
|
117
123
|
"command": "/Users/your-username/.nodenv/shims/npx",
|
|
118
|
-
"args": [
|
|
119
|
-
"@esaio/esa-mcp-server"
|
|
120
|
-
],
|
|
124
|
+
"args": ["@esaio/esa-mcp-server"],
|
|
121
125
|
"env": {
|
|
122
126
|
"ESA_ACCESS_TOKEN": "your_personal_access_token",
|
|
123
127
|
"LANG": "en"
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
4
|
|
|
5
|
-
**日本語** | [English](README.en.md)
|
|
5
|
+
**日本語** | [English](https://github.com/esaio/esa-mcp-server/blob/main/README.en.md)
|
|
6
6
|
|
|
7
|
-
esa.io の公式 MCP(Model Context Protocol)サーバー(STDIO Transport版)
|
|
7
|
+
esa.io の公式 MCP(Model Context Protocol)サーバー(STDIO Transport 版)
|
|
8
8
|
|
|
9
9
|
## 概要
|
|
10
10
|
|
|
@@ -13,6 +13,7 @@ AI アシスタントと情報共有サービス [esa](https://esa.io) をつな
|
|
|
13
13
|
## 使えるツール
|
|
14
14
|
|
|
15
15
|
### チーム管理
|
|
16
|
+
|
|
16
17
|
- `esa_get_teams` - 所属している esa チームの一覧
|
|
17
18
|
- `esa_get_team_stats` - チームの統計情報(メンバー数、記事数、コメント数など)
|
|
18
19
|
- `esa_get_team_tags` - チーム内で使われているタグと使用回数
|
|
@@ -21,16 +22,18 @@ AI アシスタントと情報共有サービス [esa](https://esa.io) をつな
|
|
|
21
22
|
### 記事管理
|
|
22
23
|
|
|
23
24
|
- `esa_search_posts` - 記事を検索
|
|
24
|
-
- `esa_get_post` - 記事IDから記事を取得
|
|
25
|
+
- `esa_get_post` - 記事 ID から記事を取得
|
|
25
26
|
- `esa_create_post` - 新しい記事を作成(タグ、カテゴリー、WIP ステータス付き)
|
|
26
27
|
- `esa_update_post` - 記事を更新(タイトル、本文、タグ、カテゴリー、WIP ステータス)
|
|
27
28
|
|
|
28
29
|
### 記事の操作
|
|
30
|
+
|
|
29
31
|
- `esa_archive_post` - 記事をアーカイブ(Archived/ カテゴリーへ移動)
|
|
30
32
|
- `esa_ship_post` - 記事を Ship It!(WIP を外して公開)
|
|
31
33
|
- `esa_duplicate_post` - 記事を複製するための準備(タイトルと本文を取得)
|
|
32
34
|
|
|
33
35
|
### コメント管理
|
|
36
|
+
|
|
34
37
|
- `esa_get_comment` - コメント ID からコメントを取得
|
|
35
38
|
- `esa_create_comment` - 記事にコメントを追加
|
|
36
39
|
- `esa_update_comment` - コメントを編集
|
|
@@ -39,18 +42,21 @@ AI アシスタントと情報共有サービス [esa](https://esa.io) をつな
|
|
|
39
42
|
- `esa_get_team_comments` - チーム全体のコメント一覧(ページング対応)
|
|
40
43
|
|
|
41
44
|
### カテゴリー管理
|
|
45
|
+
|
|
42
46
|
- `esa_get_categories` - 指定パス配下のカテゴリー一覧
|
|
43
47
|
- `esa_get_top_categories` - トップレベルのカテゴリー一覧
|
|
44
48
|
- `esa_get_all_category_paths` - チーム内の全カテゴリーパス一覧(記事数付き、フィルタリング対応)
|
|
45
49
|
- カテゴリ構造の把握、整理、統合の計画に最適
|
|
46
|
-
- フィルター例: `prefix: "dev"` で開発関連、`match: "api"` でAPI関連を検索
|
|
50
|
+
- フィルター例: `prefix: "dev"` で開発関連、`match: "api"` で API 関連を検索
|
|
47
51
|
|
|
48
52
|
### 添付ファイル
|
|
53
|
+
|
|
49
54
|
- `esa_get_attachment` - 記事やコメントの添付ファイルを取得
|
|
50
|
-
- サポート形式(JPEG, PNG, GIF, WebP)で30MB以下の画像はbase64エンコードで返却
|
|
51
|
-
- その他のファイル、大きな画像、またはforceSignedUrl指定時は署名付きURL(有効期限5分)を返却
|
|
55
|
+
- サポート形式(JPEG, PNG, GIF, WebP)で 30MB 以下の画像は base64 エンコードで返却
|
|
56
|
+
- その他のファイル、大きな画像、または forceSignedUrl 指定時は署名付き URL(有効期限 5 分)を返却
|
|
52
57
|
|
|
53
58
|
### ヘルプとドキュメント
|
|
59
|
+
|
|
54
60
|
- `esa_get_search_options_help` - esa の検索構文ヘルプ
|
|
55
61
|
- `esa_get_markdown_syntax_help` - esa の Markdown 記法ヘルプ
|
|
56
62
|
- `esa_search_help` - esa のドキュメントから機能や用語を検索
|
|
@@ -64,7 +70,7 @@ AI アシスタントと情報共有サービス [esa](https://esa.io) をつな
|
|
|
64
70
|
## プロンプト
|
|
65
71
|
|
|
66
72
|
- `esa_summarize_post` - esa の記事を要約
|
|
67
|
-
- 入力: チーム名と記事ID
|
|
73
|
+
- 入力: チーム名と記事 ID
|
|
68
74
|
- 出力: 記事の構造化された要約
|
|
69
75
|
|
|
70
76
|
## MCP クライアントの設定
|
|
@@ -74,8 +80,8 @@ MCP クライアントの設定ファイルに以下を追加します:
|
|
|
74
80
|
### 用意する環境変数
|
|
75
81
|
|
|
76
82
|
- ESA_ACCESS_TOKEN: アクセストークン
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
- 必要なスコープ: `read write` または `admin:comment read:post write:post read:category read:tag read:attachment read:team read:member`
|
|
84
|
+
- [PAT v2](https://docs.esa.io/posts/559)を推奨します。
|
|
79
85
|
- LANG: UI の言語設定
|
|
80
86
|
|
|
81
87
|
### Claude Desktop の例
|
|
@@ -115,9 +121,7 @@ MCP クライアントの設定ファイルに以下を追加します:
|
|
|
115
121
|
"mcpServers": {
|
|
116
122
|
"esa": {
|
|
117
123
|
"command": "/Users/your-username/.nodenv/shims/npx",
|
|
118
|
-
"args": [
|
|
119
|
-
"@esaio/esa-mcp-server"
|
|
120
|
-
],
|
|
124
|
+
"args": ["@esaio/esa-mcp-server"],
|
|
121
125
|
"env": {
|
|
122
126
|
"ESA_ACCESS_TOKEN": "your_personal_access_token",
|
|
123
127
|
"LANG": "ja"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{McpServer as e,ResourceTemplate as t}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as n}from"@modelcontextprotocol/sdk/server/stdio.js";import r from"i18next";import i from"openapi-fetch";import{z as a}from"zod";var o=`0.
|
|
2
|
+
import{McpServer as e,ResourceTemplate as t}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as n}from"@modelcontextprotocol/sdk/server/stdio.js";import r from"i18next";import i from"openapi-fetch";import{z as a}from"zod";var o=`0.2.2`;const s={esa:{apiAccessToken:process.env.ESA_ACCESS_TOKEN||``,apiBaseUrl:process.env.ESA_API_BASE_URL||`https://api.esa.io`},server:{name:`esa-mcp-server`,version:o,description:`Official MCP server for esa.io`}};function c(){if(!s.esa.apiAccessToken)throw Error(`ESA_ACCESS_TOKEN environment variable is required`)}var l={prompts:{summarize_post:{title:`Summarize esa post`,description:`Summarize an esa post in various formats (bullet points, paragraph, or keywords)`,args:{team_name:`The name of the esa team`,post_number:`The post number to summarize`,format:`Summary format (bullet/paragraph/keywords)`}}}},ee={prompts:{summarize_post:{title:`esaの記事の要約`,description:`esa記事を指定した形式で要約します(bullet: 箇条書き, paragraph: 文章, keywords: キーワード)`,args:{team_name:`esaチーム名`,post_number:`要約する記事番号`,format:`要約形式 (bullet/paragraph/keywords)`}}}};async function te(){let e=process.env.LC_ALL?.split(/[-_.]/)[0]||process.env.LC_MESSAGES?.split(/[-_.]/)[0]||process.env.LANG?.split(/[-_.]/)[0]||process.env.LANGUAGE?.split(/[-_.]/)[0]||`en`;return await r.init({lng:e,fallbackLng:`en`,resources:{ja:{translation:ee},en:{translation:l}},interpolation:{escapeValue:!1}}),r}function u(e,t){return r.t(e,t)}function d(e){return{async onRequest({request:t}){return t.headers.set(`Authorization`,`Bearer ${e}`),t},async onResponse({response:e}){let t=e.headers.get(`x-ratelimit-limit`),n=e.headers.get(`x-ratelimit-remaining`);return t&&n&&console.error(`Rate limit: ${n}/${t}`),e},async onError({error:e}){console.error(`Network Error:`,e)}}}const ne=o;function re(e){return{async onRequest({request:t}){return t.headers.set(`User-Agent`,`esa-mcp-server/${e} (official)`),t}}}function ie(e,t=`https://api.esa.io`){let n=i({baseUrl:t});return n.use(re(ne)),n.use(d(e)),n}async function f(e,t,...n){let r;if(`apiAccessToken`in e&&`apiBaseUrl`in e)r=ie(e.apiAccessToken,e.apiBaseUrl);else throw Error(`Unsupported context type. Only StdioContext is currently supported.`);return t(r,...n)}var p=class extends Error{constructor(){super(`Missing required parameter 'teamName'. Use esa_get_teams to list available teams, then retry with teamName specified.`),this.name=`MissingTeamNameError`}};function m(e){return e instanceof Error?`Error: ${e.message}`:typeof e==`number`&&e!==null?`Error: API Response(status: ${e})`:typeof e==`object`&&e?`Error: ${JSON.stringify(e,null,2)}`:`Error: ${String(e)}`}function h(e){return{content:[{type:`text`,text:JSON.stringify(e,null,2)}]}}function g(e,t){return{contents:[{uri:t,mimeType:`application/json`,text:JSON.stringify(e,null,2)}]}}function _(e){return{messages:[{role:`user`,content:{type:`text`,text:e}}]}}function v(e){return{content:[{type:`text`,text:m(e)}]}}function y(e,t){return{contents:[{uri:t,mimeType:`application/json`,text:m(e)}]}}function b(e){return{messages:[{role:`user`,content:{type:`text`,text:m(e)}}]}}const ae=()=>a.object({teamName:a.string().describe(u(`prompts.summarize_post.args.team_name`)),postNumber:a.string().describe(u(`prompts.summarize_post.args.post_number`)),format:a.enum([`bullet`,`paragraph`,`keywords`]).optional().describe(u(`prompts.summarize_post.args.format`))});async function oe(e,t){let{teamName:n,postNumber:r,format:i=`bullet`}=t;if(!n)throw new p;let a=Number.parseInt(r,10);if(Number.isNaN(a)||a<=0)return b(`Post number must be a positive integer`);try{let{data:t,error:r,response:o}=await e.GET(`/v1/teams/{team_name}/posts/{post_number}`,{params:{path:{team_name:n,post_number:a}}});if(r||!o.ok)return b(r||o.status);let s=t,c=`Please summarize the following post:
|
|
3
3
|
|
|
4
4
|
`;switch(c+=`Title: ${s.name}\n`,c+=`URL: ${s.url}\n`,c+=`Author: ${s.created_by.name}\n`,c+=`Created: ${s.created_at}\n`,c+=`Updated: ${s.updated_at}\n`,s.category&&(c+=`Category: ${s.category}\n`),s.tags&&s.tags.length>0&&(c+=`Tags: ${s.tags.join(`, `)}\n`),c+=`
|
|
5
5
|
---
|
package/package.json
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esaio/esa-mcp-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Official MCP server for esa.io - STDIO transport version",
|
|
5
5
|
"main": "bin/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"esa-mcp-server": "./bin/index.js"
|
|
9
9
|
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"README.md",
|
|
13
|
+
"README.en.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"registry": "https://registry.npmjs.org/",
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/esaio/esa-mcp-server.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/esaio/esa-mcp-server/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/esaio/esa-mcp-server#readme",
|
|
10
28
|
"scripts": {
|
|
11
29
|
"build": "tsdown",
|
|
12
30
|
"test": "vitest",
|
|
@@ -15,7 +33,8 @@
|
|
|
15
33
|
"lint": "biome check . --error-on-warnings",
|
|
16
34
|
"lint:fix": "biome check --write .",
|
|
17
35
|
"type-check": "tsc --noEmit",
|
|
18
|
-
"update-esa-api": "openapi-typescript ../esa/api/openapi.yaml --output src/generated/api-types.ts && npm run lint:fix"
|
|
36
|
+
"update-esa-api": "openapi-typescript ../esa/api/openapi.yaml --output src/generated/api-types.ts && npm run lint:fix",
|
|
37
|
+
"prepublishOnly": "npm run build && npm run test:run && npm run lint && npm run type-check"
|
|
19
38
|
},
|
|
20
39
|
"keywords": [
|
|
21
40
|
"mcp",
|
|
@@ -38,7 +57,7 @@
|
|
|
38
57
|
"@types/node": "^20.19.15",
|
|
39
58
|
"@vitest/coverage-v8": "^4.0.5",
|
|
40
59
|
"openapi-typescript": "^7.9.1",
|
|
41
|
-
"tsdown": "^0.
|
|
60
|
+
"tsdown": "^0.16.0",
|
|
42
61
|
"tsx": "^4.20.5",
|
|
43
62
|
"typescript": "^5.9.2",
|
|
44
63
|
"vitest": "^4.0.5"
|
package/.dockerignore
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
.git
|
|
2
|
-
.github
|
|
3
|
-
|
|
4
|
-
.env
|
|
5
|
-
.env.*
|
|
6
|
-
.envrc
|
|
7
|
-
|
|
8
|
-
.vscode
|
|
9
|
-
.idea
|
|
10
|
-
*.swp
|
|
11
|
-
*.swo
|
|
12
|
-
*~
|
|
13
|
-
.DS_Store
|
|
14
|
-
|
|
15
|
-
*.log
|
|
16
|
-
npm-debug.log*
|
|
17
|
-
|
|
18
|
-
tmp
|
|
19
|
-
temp
|
|
20
|
-
.tmp
|
|
21
|
-
|
|
22
|
-
node_modules
|
|
23
|
-
.node-version
|
|
24
|
-
|
|
25
|
-
README.md
|
|
26
|
-
LICENSE
|
|
27
|
-
|
|
28
|
-
coverage
|
|
29
|
-
|
|
30
|
-
.claude
|
|
31
|
-
CLAUDE.md
|
|
32
|
-
Dockerfile
|
|
33
|
-
|
|
34
|
-
bin
|
|
35
|
-
build
|
|
36
|
-
dist
|
package/.github/dependabot.yml
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
version: 2
|
|
2
|
-
updates:
|
|
3
|
-
- package-ecosystem: "github-actions"
|
|
4
|
-
directory: "/"
|
|
5
|
-
schedule:
|
|
6
|
-
interval: daily
|
|
7
|
-
- package-ecosystem: npm
|
|
8
|
-
directory: "/"
|
|
9
|
-
schedule:
|
|
10
|
-
interval: daily
|
|
11
|
-
time: "03:00"
|
|
12
|
-
timezone: Asia/Tokyo
|
|
13
|
-
open-pull-requests-limit: 10
|
|
14
|
-
groups:
|
|
15
|
-
vitest:
|
|
16
|
-
patterns:
|
|
17
|
-
- "vitest"
|
|
18
|
-
- "@vitest/*"
|
|
19
|
-
ignore:
|
|
20
|
-
- dependency-name: "zod"
|
|
21
|
-
update-types: ["version-update:semver-major"]
|
|
22
|
-
- dependency-name: "@types/node"
|
|
23
|
-
update-types: ["version-update:semver-major"]
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
name: Docker Build and Push
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags: [ 'v*' ]
|
|
6
|
-
|
|
7
|
-
env:
|
|
8
|
-
REGISTRY: ghcr.io
|
|
9
|
-
IMAGE_NAME: ${{ github.repository }}
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
build:
|
|
13
|
-
strategy:
|
|
14
|
-
fail-fast: true
|
|
15
|
-
matrix:
|
|
16
|
-
include:
|
|
17
|
-
- platform: linux/amd64
|
|
18
|
-
runner: ubuntu-latest
|
|
19
|
-
- platform: linux/arm64
|
|
20
|
-
runner: ubuntu-24.04-arm
|
|
21
|
-
runs-on: ${{ matrix.runner }}
|
|
22
|
-
permissions:
|
|
23
|
-
contents: read
|
|
24
|
-
packages: write
|
|
25
|
-
|
|
26
|
-
steps:
|
|
27
|
-
- name: Prepare
|
|
28
|
-
run: |
|
|
29
|
-
platform=${{ matrix.platform }}
|
|
30
|
-
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
|
31
|
-
|
|
32
|
-
- name: Checkout repository
|
|
33
|
-
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # https://github.com/actions/checkout/tree/v5
|
|
34
|
-
|
|
35
|
-
- name: Log in to Container Registry
|
|
36
|
-
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # https://github.com/docker/login-action/tree/v3
|
|
37
|
-
with:
|
|
38
|
-
registry: ${{ env.REGISTRY }}
|
|
39
|
-
username: ${{ github.actor }}
|
|
40
|
-
password: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
-
|
|
42
|
-
- name: Extract metadata
|
|
43
|
-
id: meta
|
|
44
|
-
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # https://github.com/docker/metadata-action/tree/v5
|
|
45
|
-
with:
|
|
46
|
-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
47
|
-
|
|
48
|
-
- name: Set up Docker Buildx
|
|
49
|
-
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # https://github.com/docker/setup-buildx-action/tree/v3
|
|
50
|
-
|
|
51
|
-
- name: Build and push by digest
|
|
52
|
-
id: build
|
|
53
|
-
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # https://github.com/docker/build-push-action/tree/v6
|
|
54
|
-
with:
|
|
55
|
-
context: .
|
|
56
|
-
platforms: ${{ matrix.platform }}
|
|
57
|
-
labels: ${{ steps.meta.outputs.labels }}
|
|
58
|
-
outputs: type=image,name=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
|
|
59
|
-
cache-from: type=gha
|
|
60
|
-
cache-to: type=gha,mode=max
|
|
61
|
-
|
|
62
|
-
- name: Export digest
|
|
63
|
-
run: |
|
|
64
|
-
mkdir -p /tmp/digests
|
|
65
|
-
digest="${{ steps.build.outputs.digest }}"
|
|
66
|
-
touch "/tmp/digests/${digest#sha256:}"
|
|
67
|
-
|
|
68
|
-
- name: Upload digest
|
|
69
|
-
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # https://github.com/actions/upload-artifact/tree/v4
|
|
70
|
-
with:
|
|
71
|
-
name: digests-${{ env.PLATFORM_PAIR }}
|
|
72
|
-
path: /tmp/digests/*
|
|
73
|
-
if-no-files-found: error
|
|
74
|
-
retention-days: 1
|
|
75
|
-
|
|
76
|
-
merge:
|
|
77
|
-
runs-on: ubuntu-latest
|
|
78
|
-
needs:
|
|
79
|
-
- build
|
|
80
|
-
permissions:
|
|
81
|
-
contents: read
|
|
82
|
-
packages: write
|
|
83
|
-
|
|
84
|
-
steps:
|
|
85
|
-
- name: Download digests
|
|
86
|
-
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # https://github.com/actions/download-artifact/tree/v5
|
|
87
|
-
with:
|
|
88
|
-
path: /tmp/digests
|
|
89
|
-
pattern: digests-*
|
|
90
|
-
merge-multiple: true
|
|
91
|
-
|
|
92
|
-
- name: Log in to Container Registry
|
|
93
|
-
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # https://github.com/docker/login-action/tree/v3
|
|
94
|
-
with:
|
|
95
|
-
registry: ${{ env.REGISTRY }}
|
|
96
|
-
username: ${{ github.actor }}
|
|
97
|
-
password: ${{ secrets.GITHUB_TOKEN }}
|
|
98
|
-
|
|
99
|
-
- name: Set up Docker Buildx
|
|
100
|
-
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # https://github.com/docker/setup-buildx-action/tree/v3
|
|
101
|
-
|
|
102
|
-
- name: Extract metadata
|
|
103
|
-
id: meta
|
|
104
|
-
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # https://github.com/docker/metadata-action/tree/v5
|
|
105
|
-
with:
|
|
106
|
-
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
107
|
-
tags: |
|
|
108
|
-
type=semver,pattern={{version}}
|
|
109
|
-
type=semver,pattern={{major}}.{{minor}}
|
|
110
|
-
type=semver,pattern={{major}}
|
|
111
|
-
|
|
112
|
-
- name: Create manifest list and push
|
|
113
|
-
working-directory: /tmp/digests
|
|
114
|
-
run: |
|
|
115
|
-
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
|
116
|
-
$(printf '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@sha256:%s ' *)
|
|
117
|
-
|
|
118
|
-
- name: Inspect image
|
|
119
|
-
run: |
|
|
120
|
-
docker buildx imagetools inspect ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- main
|
|
6
|
-
pull_request:
|
|
7
|
-
types: [opened, synchronize, reopened]
|
|
8
|
-
|
|
9
|
-
env:
|
|
10
|
-
NODE_VERSION: 20.19.4
|
|
11
|
-
|
|
12
|
-
jobs:
|
|
13
|
-
test:
|
|
14
|
-
runs-on: ubuntu-latest
|
|
15
|
-
steps:
|
|
16
|
-
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # https://github.com/actions/checkout/tree/v5
|
|
17
|
-
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # https://github.com/actions/setup-node/tree/v5
|
|
18
|
-
with:
|
|
19
|
-
node-version: ${{ env.NODE_VERSION }}
|
|
20
|
-
cache: "npm"
|
|
21
|
-
- name: Install dependencies
|
|
22
|
-
run: npm ci
|
|
23
|
-
- name: Run linting
|
|
24
|
-
run: |
|
|
25
|
-
output=$(npm run lint 2>&1)
|
|
26
|
-
echo "$output"
|
|
27
|
-
if echo "$output" | grep -q "schema version does not match"; then
|
|
28
|
-
echo "::error::Biome schema version mismatch detected. Please run 'npx biome migrate --write' to update biome.json"
|
|
29
|
-
exit 1
|
|
30
|
-
fi
|
|
31
|
-
- name: Run type checking
|
|
32
|
-
run: npm run type-check
|
|
33
|
-
- name: Run tests
|
|
34
|
-
run: npm run test:coverage
|
|
35
|
-
- name: Upload coverage reports
|
|
36
|
-
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # https://github.com/actions/upload-artifact/tree/v4
|
|
37
|
-
with:
|
|
38
|
-
name: coverage
|
|
39
|
-
path: coverage/
|
|
40
|
-
- name: Build
|
|
41
|
-
run: npm run build
|
package/CLAUDE.md
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
-
|
|
5
|
-
## Build and Development Commands
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
# Install dependencies
|
|
9
|
-
npm install
|
|
10
|
-
|
|
11
|
-
# Build the project
|
|
12
|
-
npm run build
|
|
13
|
-
|
|
14
|
-
# Run tests
|
|
15
|
-
npm test # Watch mode
|
|
16
|
-
npm run test:run # Single run
|
|
17
|
-
npm run test:coverage # With coverage report
|
|
18
|
-
|
|
19
|
-
# Linting
|
|
20
|
-
npm run lint # Check for linting issues
|
|
21
|
-
npm run lint:fix # Auto-fix linting and formatting issues
|
|
22
|
-
|
|
23
|
-
# Type checking
|
|
24
|
-
npm run type-check # Check TypeScript types without building
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Architecture Overview
|
|
28
|
-
|
|
29
|
-
This is an MCP (Model Context Protocol) server implementation for esa.io, using STDIO transport for communication. The architecture follows a simple structure:
|
|
30
|
-
|
|
31
|
-
### Core Components
|
|
32
|
-
|
|
33
|
-
1. **MCP Server Setup** (`src/index.ts`): Entry point that initializes the MCP server with STDIO transport. Handles transport lifecycle events and graceful error handling.
|
|
34
|
-
|
|
35
|
-
2. **Configuration** (`src/config/index.ts`): Centralized configuration management that reads from environment variables. Required env vars:
|
|
36
|
-
- `ESA_ACCESS_TOKEN`: Required for esa.io API authentication
|
|
37
|
-
- `ESA_API_BASE_URL`: Optional API base URL (defaults to https://api.esa.io)
|
|
38
|
-
|
|
39
|
-
### Key Technical Details
|
|
40
|
-
|
|
41
|
-
- **Module System**: ES modules (type: "module" in package.json)
|
|
42
|
-
- **TypeScript**: Strict mode enabled with comprehensive type checking
|
|
43
|
-
- **Code Style**: Enforced by Biome (2 spaces, double quotes, semicolons, trailing commas)
|
|
44
|
-
- **Node Version**: Requires Node.js >= 20.19.4
|
|
45
|
-
|
|
46
|
-
### MCP Server Pattern
|
|
47
|
-
|
|
48
|
-
The server follows the standard MCP pattern:
|
|
49
|
-
1. Validate configuration on startup
|
|
50
|
-
2. Create McpServer instance with name and version
|
|
51
|
-
3. Initialize StdioServerTransport for STDIO communication
|
|
52
|
-
4. Handle transport lifecycle (onclose, onerror)
|
|
53
|
-
5. Connect server to transport
|
|
54
|
-
|
|
55
|
-
When extending functionality, new tools and resources should be registered with the server instance before connecting to transport.
|
|
56
|
-
|
|
57
|
-
## Testing Guidelines
|
|
58
|
-
|
|
59
|
-
### Test Writing Principles
|
|
60
|
-
|
|
61
|
-
When writing tests, follow these principles for maintainable and readable test code:
|
|
62
|
-
|
|
63
|
-
1. **Import Order Optimization**
|
|
64
|
-
- Type imports first (`import type`)
|
|
65
|
-
- External dependencies next
|
|
66
|
-
- Internal modules last
|
|
67
|
-
- Group related imports together
|
|
68
|
-
|
|
69
|
-
2. **Mock Creation Patterns**
|
|
70
|
-
- Use `as unknown as` pattern for type casting to keep mocks minimal and focused
|
|
71
|
-
- Create helper functions for complex mock objects (e.g., `createMockConfig`, `createMockServer`)
|
|
72
|
-
- Extract repetitive mock setup into shared helper functions (e.g., `setupServerMocks`)
|
|
73
|
-
- Return mock instances from helper functions for assertion access
|
|
74
|
-
|
|
75
|
-
3. **Mock Documentation**
|
|
76
|
-
- Add concise comments explaining the purpose of each mock
|
|
77
|
-
- Focus on WHY the mock is needed, not WHAT it does
|
|
78
|
-
- Keep comments brief and directly above the mock definition
|
|
79
|
-
|
|
80
|
-
4. **Module Mocking with vi.doMock**
|
|
81
|
-
- Use `vi.doMock` for replacing entire modules during import resolution
|
|
82
|
-
- Always call `vi.doMock` before the module import
|
|
83
|
-
- Use dynamic imports (`await import()`) after setting up module mocks
|
|
84
|
-
- Remember that `vi.doMock` is fundamentally different from `vi.fn()` - it intercepts module loading
|
|
85
|
-
|
|
86
|
-
5. **Test Structure**
|
|
87
|
-
- Keep each test focused on a single behavior
|
|
88
|
-
- Use descriptive test names that explain the expected outcome
|
|
89
|
-
- Group related tests with `describe` blocks
|
|
90
|
-
- Clean up mocks in `beforeEach`/`afterEach` hooks
|
|
91
|
-
|
|
92
|
-
### Example Test Pattern
|
|
93
|
-
|
|
94
|
-
- READ src/__tests__/index.test.ts
|
package/Dockerfile
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# syntax=docker/dockerfile:1
|
|
2
|
-
|
|
3
|
-
FROM node:alpine AS base
|
|
4
|
-
|
|
5
|
-
WORKDIR /app
|
|
6
|
-
|
|
7
|
-
FROM base AS deps
|
|
8
|
-
|
|
9
|
-
RUN --mount=type=bind,source=package.json,target=package.json \
|
|
10
|
-
--mount=type=bind,source=package-lock.json,target=package-lock.json \
|
|
11
|
-
--mount=type=cache,target=/root/.npm \
|
|
12
|
-
npm ci --only=production
|
|
13
|
-
|
|
14
|
-
FROM base AS build
|
|
15
|
-
|
|
16
|
-
RUN --mount=type=bind,source=package.json,target=package.json \
|
|
17
|
-
--mount=type=bind,source=package-lock.json,target=package-lock.json \
|
|
18
|
-
--mount=type=cache,target=/root/.npm \
|
|
19
|
-
npm ci
|
|
20
|
-
|
|
21
|
-
COPY . .
|
|
22
|
-
|
|
23
|
-
RUN npm run build
|
|
24
|
-
|
|
25
|
-
FROM base AS production
|
|
26
|
-
|
|
27
|
-
ENV NODE_ENV=production
|
|
28
|
-
|
|
29
|
-
USER node
|
|
30
|
-
|
|
31
|
-
COPY --from=deps /app/node_modules ./node_modules
|
|
32
|
-
COPY --from=build /app/bin ./bin
|
|
33
|
-
|
|
34
|
-
ENTRYPOINT ["node", "bin/index.js"]
|
package/biome.json
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
3
|
-
"assist": {
|
|
4
|
-
"actions": {
|
|
5
|
-
"source": {
|
|
6
|
-
"organizeImports": "on"
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
|
-
"linter": {
|
|
11
|
-
"enabled": true,
|
|
12
|
-
"rules": {
|
|
13
|
-
"recommended": true,
|
|
14
|
-
"complexity": {
|
|
15
|
-
"noForEach": "off"
|
|
16
|
-
},
|
|
17
|
-
"suspicious": {
|
|
18
|
-
"noExplicitAny": "error",
|
|
19
|
-
"noConsole": "off"
|
|
20
|
-
},
|
|
21
|
-
"style": {
|
|
22
|
-
"useFilenamingConvention": {
|
|
23
|
-
"level": "error",
|
|
24
|
-
"options": {
|
|
25
|
-
"filenameCases": ["kebab-case"]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"formatter": {
|
|
32
|
-
"enabled": true,
|
|
33
|
-
"formatWithErrors": false,
|
|
34
|
-
"indentStyle": "space",
|
|
35
|
-
"indentWidth": 2,
|
|
36
|
-
"lineWidth": 80,
|
|
37
|
-
"lineEnding": "lf"
|
|
38
|
-
},
|
|
39
|
-
"javascript": {
|
|
40
|
-
"formatter": {
|
|
41
|
-
"quoteStyle": "double",
|
|
42
|
-
"semicolons": "always",
|
|
43
|
-
"trailingCommas": "all"
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
"files": {
|
|
47
|
-
"includes": [
|
|
48
|
-
"**",
|
|
49
|
-
"!**/node_modules",
|
|
50
|
-
"!**/bin",
|
|
51
|
-
"!**/coverage",
|
|
52
|
-
"!**/*.config.js",
|
|
53
|
-
"!**/*.config.ts",
|
|
54
|
-
"!.claude"
|
|
55
|
-
]
|
|
56
|
-
}
|
|
57
|
-
}
|