mcpField
D
dingtalk-skill-creator

dingtalk-skill-creator

github.com/breath57エージェントワークフロー10284 回インストール18 週間前に更新
リポジトリ

dingtalk-skill-creator について

DingTalk APIの領域を再利用可能なスキルにまとめる段階的な手順です。SDKとHTTPのテスト合格後に文書を作成し、新しいAPI体系を優先します。

主な機能

  1. 01SDKモジュールとインターフェース項目の調査
  2. 02SDKとHTTPリクエストの段階的な検証
  3. 03必要なアプリ権限の調査
  4. 04SKILL.mdとAPIリファレンスの作成
  5. 05プロジェクト文書と設定例の更新

活用シーン

  1. 01DingTalk API領域のスキル作成
  2. 02エンドポイント、項目、HTTP動作の検証
  3. 03必要な権限とIDの扱いの文書化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/breath57/dingtalk-skills --skill dingtalk-skill-creator

インストール後、Claude Code で/dingtalk-skill-creatorを入力して読み込まれたか確認します。

詳細

DingTalk スキル作成ツール(Dingtalk Skill Creator)

DingTalk API ドメインを再利用可能なスキルとしてまとめるための標準化された手順です。各ステップを実際に完了し、検証に合格してから次のステップに進んでください。スキップは禁止です。


フローの概要

1. [探索]  SDK 模块探索 → 整理接口清单与字段结构
2. [SDK]   Python SDK 测试 → 全部通过才能继续
3. [HTTP]  纯 requests HTTP 测试 → 全部通过才能继续
4. [创作]  编写 SKILL.md + references/api.md
5. [收尾]  更新 README.md / README_EN.md / AGENTS.md

重要な原則:テストはすべて Python を使用します(.sh スクリプトは使用しません)。
ステージ 2 とステージ 3 の uv run pytest を実際に実行し、すべて成功してからステージ 4 に進んでください。

新 API 優先 + トークン非互換の原則:DingTalk プラットフォームには新旧 2 つの API 体系があります。新しい API を優先して使用し、2 種類のトークンを混在させないでください。

  • 新 API(推奨):POST https://api.dingtalk.com/v1.0/oauth2/accessToken → accessToken + expireIn を返します。対応するのは api.dingtalk.com のインターフェースで、Header に x-acs-dingtalk-access-token を設定します。
  • 旧 API(非推奨):GET https://oapi.dingtalk.com/gettoken → access_token を返します。対応するのは oapi.dingtalk.com のインターフェースで、URL パラメーター ?access_token= を設定します。
  • 相互に非互換:新 API のトークンを旧 API のインターフェースに使用した場合、または旧 API のトークンを新 API のインターフェースに使用した場合、いずれも 401/403 が返されます。エラーメッセージからトークンの種類が誤っていることを判別できないため、原因の特定が困難です。
  • 唯一の例外:userId → unionId の変換(oapi.dingtalk.com/topapi/v2/user/get)には現時点で v1.0 の同等インターフェースがないため、旧 API のトークンが必要です。これは既知の例外です。OLD_TOKEN はこの変換ステップでのみ使用し、他の API 呼び出しに渡さないでください。 dt_helper.sh:各スキルの scripts/dt_helper.sh は、トークンの取得とキャッシュ、userId↔unionId の変換、設定の読み書きなどの基本機能をまとめています。bash スクリプト(実行スクリプトなど)から直接呼び出してください。**Python テスト(ステージ 2/3)**では引き続きインラインの requests ロジックを使用し、dt_helper.sh には依存しません。

ステージ 1:SDK の調査

1.1 SDK モジュールの検索
# 列出与目标领域相关的 SDK 模块
ls /home/breath/project/personal/dingtalk-skills/tests/.venv/lib/python3.13/site-packages/alibabacloud_dingtalk/ \
  | grep -i <关键词>
# 示例:todo / attend / approval / calendar
1.2 インターフェース一覧の作成
SDK_BASE=tests/.venv/lib/python3.13/site-packages/alibabacloud_dingtalk/<module>

# 列出所有同步方法(去掉 async)
grep -n "def " $SDK_BASE/client.py | grep -v async

# 提取 HTTP endpoint 路径 + 方法
grep -A2 "pathname=" $SDK_BASE/client.py | grep -E "pathname=|method=" | paste - -
1.3 リクエスト/レスポンスフィールドの理解
# 查看核心 Request 类
grep -n "^class " $SDK_BASE/models.py

# 读取关键请求类的 __init__ 和 to_map
sed -n '<start>,<end>p' $SDK_BASE/models.py
1.4 実際のフィールドの調査(重要!)

SDK のドキュメントが正確とは限りません。実際のリクエストを使って、実際に返されるフィールド名を調査してください。

⚠️ 調査段階では SDK を使用し、requests による直接の HTTP リクエストは禁止です。
調査の目的は SDK の実際の動作とフィールド構造を把握することです。SDK を使えば、インターフェースの呼び出し可否とフィールド名を同時に検証できます。
requests による直接リクエストはステージ 3(純粋な HTTP テスト)で使用します。調査段階で先行して導入してはいけません。

トークンと unionId の取得(dt_helper.sh を使用):

# 在 skill 根目录或 tests/ 目录下
TOKEN=$(bash scripts/dt_helper.sh --token)          # 新版 token,带缓存
UNION_ID=$(bash scripts/dt_helper.sh --to-unionid)  # 自动从 DINGTALK_MY_USER_ID 转换

調査スクリプト(SDK を使用):

# 在 tests/ 目录下运行(已有 .env 和 venv)
import os, pathlib, subprocess
from alibabacloud_dingtalk.<module>_1_0 import client as dt_client, models as dt_models
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_util import models as util_models

# 读取 .env
env = pathlib.Path(".env").read_text()
for line in env.splitlines():
    line = line.strip()
    if line and not line.startswith("#") and "=" in line:
        k, _, v = line.partition("="); os.environ.setdefault(k.strip(), v.strip())

# 获取 token(调 dt_helper.sh)
token = subprocess.check_output(
    ["bash", "../scripts/common/dt_helper.sh", "--token"], text=True).strip()
union_id = os.environ["DINGTALK_MY_OPERATOR_ID"]

# SDK 客户端
cfg = open_api_models.Config(protocol="HTTPS", endpoint="api.dingtalk.com")
client = dt_client.Client(cfg)
runtime = util_models.RuntimeOptions()

# CREATE 探测 → 打印实际响应字段
h = dt_models.CreateXxxHeaders()
h.x_acs_dingtalk_access_token = token
req = dt_models.CreateXxxRequest(subject="[probe] 探测")
resp = client.create_xxx_with_options(union_id, req, h, runtime)
print("CREATE body:", vars(resp.body))
# 根据 print 输出确定实际字段名

インターフェース一覧を表にまとめてから続行してください。

1.5 必要な権限の調査と有効化(重要!)

推奨方法(ドキュメントを調べるより迅速です):SDK で対象の各インターフェースに「ドライラン」リクエストを 1 回ずつ送信し、403 レスポンスボディの requiredScopes フィールドから必要な権限をまとめて収集します。個別にドキュメントを調べるより正確です。

# tests/probe_<skill>_perms.py(写到 tests/ 目录下,不要写到 /tmp/)
import os, pathlib, subprocess, re, time
from alibabacloud_dingtalk.<module>_1_0 import client as dt_client, models as dt_models
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_util import models as util_models

env_path = pathlib.Path(__file__).parent / ".env"
for line in env_path.read_text().splitlines():
    line = line.strip()
    if line and not line.startswith("#") and "=" in line:
        k, _, v = line.partition("="); os.environ.setdefault(k.strip(), v.strip())

token = subprocess.check_output(
    ["bash", str(pathlib.Path(__file__).parent.parent / "scripts/common/dt_helper.sh"), "--token"],
    text=True).strip()
user_id = os.environ["DINGTALK_MY_USER_ID"]

cfg = open_api_models.Config(protocol="HTTPS", endpoint="api.dingtalk.com")
client = dt_client.Client(cfg)
runtime = util_models.RuntimeOptions()

def h(cls):
    obj = cls(); obj.x_acs_dingtalk_access_token = token; return obj

cases = [
    ("接口名1", lambda: client.create_xxx_with_options(..., h(dt_models.CreateXxxHeaders), runtime)),
    ("接口名2", lambda: client.get_xxx_with_options(..., h(dt_models.GetXxxHeaders), runtime)),
]

for name, fn in cases:
    try:
        fn(); print(f"[OK]  {name}")
    except Exception as e:
        msg = str(e)
        scopes = re.findall(r"'[\w.]+(?:Read|Write)'", msg)
        if "403" in msg:
            print(f"[403] {name}  →  需要权限: {', '.join(scopes) or msg[:120]}")
        else:
            print(f"[ERR] {name}  →  {msg[:120]}")

すべての権限を収集したら、「開発者バックエンド → アプリ権限管理」で有効にし、リリース後に再実行して問題がないことを確認してからステージ 2 に進んでください。
最終的な権限一覧を references/api.md の「必要なアプリ権限」セクションに記載してください。

調査時には「明らかに無効な」パラメーター(例:process_code="PROC-000000")を渡せば十分です。目的は 403 を発生させて requiredScopes を取得することだけで、業務ロジックが正しいかどうかは問いません。


ステージ 2:Python SDK テスト(すべて成功してから続行)

2.1 ディレクトリ構成
tests/
├── .env
├── conftest.py                         # 全局 fixture(token, operator_id, api_headers)
└── dingtalk-<skill-name>/
    ├── __init__.py
    ├── conftest.py                     # 技能专属 fixture(union_id、共享测试资源)
    ├── test_<module>_sdk.py            # 阶段二:SDK 测试
    └── test_<module>.py               # 阶段三:纯 HTTP 测试
2.2 SDK クライアントの設定(すべての DingTalk v1.0 API に適用)
from alibabacloud_dingtalk.<module>_1_0 import client as dt_client, models as dt_models
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_tea_util import models as util_models

@pytest.fixture(scope="session")
def sdk_client():
    config = open_api_models.Config()
    config.protocol = "HTTPS"          # 必须是 HTTPS,HTTP 会 404
    config.endpoint = "api.dingtalk.com"
    return dt_client.Client(config)

@pytest.fixture(scope="session")
def sdk_runtime():
    return util_models.RuntimeOptions()
2.3 SDK テストのテンプレート
def test_sdk_create(sdk_client, sdk_runtime, token, union_id):
    h = dt_models.CreateXxxHeaders()
    h.x_acs_dingtalk_access_token = token
    req = dt_models.CreateXxxRequest(subject="[sdk] 测试", operator_id=union_id)
    resp = sdk_client.create_xxx_with_options(union_id, req, h, sdk_runtime)
    item = resp.body
    assert item.id, "响应无 id"           # 字段名先探测,再写断言
    # 清理
    dh = dt_models.DeleteXxxHeaders(); dh.x_acs_dingtalk_access_token = token
    dr = dt_models.DeleteXxxRequest(operator_id=union_id)
    sdk_client.delete_xxx_with_options(union_id, item.id, dr, dh, sdk_runtime)
2.4 実行してすべて成功したことを確認
cd tests
uv run pytest dingtalk-<skill-name>/test_<module>_sdk.py -v
# ✅ 全部 PASSED(允许有权限缺失导致的 SKIPPED)才能继续

ステージ 3:純粋な HTTP リクエストテスト(すべて成功してから続行)

3.1 説明

SDK は一切使用せず、requests ライブラリだけを使って REST API を直接呼び出し、インターフェースの HTTP 動作を検証します。
これは SDK とは独立した 2 段階目の検証です。endpoint パス、リクエストフィールド、HTTP メソッド、レスポンスフィールドがすべて正しいことを確認します。

3.2 テストテンプレート
"""
纯 HTTP 测试:不依赖 SDK,验证接口 HTTP 行为
响应字段(从实际探测确认):
  - 创建: id, subject, done, priority
  - 更新: result=True
  - 删除: result=True,删后 GET → 400
"""
import requests

BASE = "https://api.dingtalk.com/v1.0/xxx/users"

def _create(uid, headers, subject, **kwargs):
    r = requests.post(f"{BASE}/{uid}/items", params={"operatorId": uid},
                      headers=headers, json={"subject": subject, **kwargs}, timeout=15)
    assert r.status_code == 200, f"创建失败:{r.text}"
    d = r.json()
    assert "id" in d, f"缺少 id:{d}"   # 用探测到的实际字段名
    return d

def _delete(uid, headers, item_id):
    r = requests.delete(f"{BASE}/{uid}/items/{item_id}", params={"operatorId": uid},
                        headers=headers, timeout=15)
    assert r.status_code == 200, f"删除失败:{r.text}"
    return r.json()

def test_http_create_basic(union_id, api_headers):
    d = _create(union_id, api_headers, "[http] 基础创建")
    assert d["id"]
    _delete(union_id, api_headers, d["id"])

# 权限不足的接口 → 遇到 403 时 pytest.skip
def test_http_list(union_id, api_headers):
    r = requests.post(f"{BASE}/{union_id}/items/list", params={"operatorId": union_id},
                      headers=api_headers, json={"isDone": False}, timeout=15)
    if r.status_code == 403:
        pytest.skip(f"缺少权限 → {r.json().get('message','')[:100]}")
    assert r.status_code == 200
    assert "items" in r.json()  # 使用实际响应字段名
3.3 実行してすべて成功したことを確認
uv run pytest dingtalk-<skill-name>/test_<module>.py -v
# ✅ 全部 PASSED/SKIPPED 才能继续(FAILED = 禁止进入阶段四)

ステージ 4:SKILL.md + references/api.md の作成

ステージ 2 とステージ 3 がすべて成功した後にのみ、このステージを実行してください。

4.1 ディレクトリ構成
.agents/skills/dingtalk-<skill-name>/
├── SKILL.md
└── references/
    └── api.md
4.2 SKILL.md テンプレート

dingtalk-message または dingtalk-todo の SKILL.md を参考にし、以下を必ず含めてください。

  • frontmatter:name + description(トリガーとなるキーワードを漏れなく記載)
  • ワークフロー:設定の読み込み → 不足情報の収集 → 永続化 → Token の取得 → 操作の実行
  • 設定項目の表:各 CONFIG キーの取得元の説明。優先して DINGTALK_MY_USER_ID(企業従業員 ID。管理バックエンドの連絡先から確認できます。電話番号でも unionId でもありません)を収集してください。API が unionId を必要とする場合は、スクリプトで自動変換します。
  • ID の説明:userId と unionId の違い、このスキルの API がどちらの ID を使用するか、自動変換のロジックを説明します。
  • 実行スクリプトのテンプレート:完全な bash スクリプト(create_file /tmp/<task>.sh の後に bash で実行し、heredoc は禁止)。scripts/dt_helper.sh を呼び出してトークンと unionId を取得し、トークンキャッシュや ID 変換のロジックをインラインで記述する必要はありません。
      HELPER="<THE_SKILLMD_FILE_PATH>/scripts/dt_helper.sh"
    TOKEN=$(bash "$HELPER" --token)                    # 新版 token(带缓存)
    UNION_ID=$(bash "$HELPER" --to-unionid)            # 自动转换,如 API 需要 userId 则用 --get DINGTALK_MY_USER_ID
    USER_ID=$(bash "$HELPER" --get DINGTALK_MY_USER_ID)
    
  • 詳細なリファレンス:references/api.md を参照し、grep を使った索引検索の方法を記載します。

注意:API によって使用するユーザー ID の種類は異なります。たとえば、メッセージ API は userId のみを受け付け、ToDo API は unionId のみを受け付けます。SKILL.md には、その違いを明記してください。

スキル独立性の原則:各スキルは完全に独立しています。エージェントが特定のスキルを読み込むとき、そのスキルの SKILL.md だけを参照でき、他のスキルの存在や内容をまったく認識しません。そのため:

  • ID 変換ロジック(userId → unionId)は、それが必要な各スキル自身の SKILL.md に完全に記載し、他のスキルを参照してはいけません。
  • 複数のスキル間で共有できる仕組みは 2 つだけです:~/.dingtalk-skills/config(設定ファイル)と scripts/dt_helper.sh(common_scripts_load.sh によって各スキルの scripts/ ディレクトリに配布されるツールスクリプト)。
  • bash 実行スクリプトから scripts/dt_helper.sh を直接呼び出してください。トークンキャッシュや userId→unionId 変換のロジックをインラインで記述する必要はありません。
  • SKILL.md 内の説明(ワークフロー、設定項目の表、ID の説明など)は引き続き完全かつ自己完結した内容にしてください。エージェントが読むのは、現在のスキルの SKILL.md だけです。
4.3 references/api.md の仕様
# 钉钉 <功能> API 参考

每个接口包含:
- 完整请求体 JSON 示例(含必填标注)
- 实际响应 JSON 示例(从测试中截取)
- 错误响应示例(含状态码)
- curl 示例

## 错误码表

| HTTP 状态 | 错误码 | 说明 | 处理建议 |

ステージ 5:仕上げと更新

# 1. AGENTS.md 技能目录新增一行
# 2. README.md 技能列表新增一行(含安装命令和能力表)
# 3. README_EN.md 技能列表新增对应英文条目
# 4. tests/.env.example 补充新技能所需配置项(如有)

コメント