@proofofprotocol/inscribe-mcp 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 POP@AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # inscribe-mcp
2
+
3
+ > Verifiable inscription for AI agents - inscribe anything to blockchain
4
+
5
+ 「刻む」という行為を、ブロックチェーンを意識せずに。
6
+
7
+ ## What is inscribe?
8
+
9
+ **inscribe** = 残す・刻む・あとから消せない形で書く
10
+
11
+ - SNS投稿を刻む(削除される前に)
12
+ - ニュース記事をアーカイブ
13
+ - 予言・予測を証明
14
+ - AIの判断を記録
15
+ - 契約書にタイムスタンプ
16
+
17
+ すべて、**あとから検証できる**。改ざん不可能。
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. インストール
22
+
23
+ ```bash
24
+ # npx で直接実行(推奨)
25
+ npx @proofofprotocol/inscribe-mcp init
26
+
27
+ # または npm でグローバルインストール
28
+ npm install -g @proofofprotocol/inscribe-mcp
29
+ inscribe-mcp init
30
+ ```
31
+
32
+ ### 2. 初期設定
33
+
34
+ `inscribe-mcp init` を実行すると対話形式で設定できます:
35
+
36
+ ```
37
+ ? Select network: testnet
38
+ ? Enter your Hedera Account ID: 0.0.XXXXXX
39
+ ? Enter your Hedera Private Key: 302e...
40
+
41
+ Config saved to ~/.inscribe-mcp/config.json
42
+ ```
43
+
44
+ Hedera Testnet アカウントは [portal.hedera.com](https://portal.hedera.com) で無料作成。
45
+
46
+ ### 3. Claude Desktop に接続
47
+
48
+ `claude_desktop_config.json`:
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "inscribe": {
53
+ "command": "npx",
54
+ "args": ["@proofofprotocol/inscribe-mcp-server"]
55
+ }
56
+ }
57
+ }
58
+ ```
59
+
60
+ 設定は `~/.inscribe-mcp/config.json` から自動的に読み込まれます。
61
+
62
+ ### 4. 使う
63
+
64
+ ```
65
+ User: このツイートを刻んで
66
+ https://x.com/elonmusk/status/xxx
67
+
68
+ Claude: inscribe_url を使います
69
+ → 投稿内容を自動取得: "Going to Mars in 2025"
70
+ → inscription_id: "0.0.7503789-1703412000.123456789"
71
+ → この投稿が存在した証拠を刻みました!
72
+ ```
73
+
74
+ ## Layer 1 API(推奨)
75
+
76
+ | ツール | 説明 |
77
+ |--------|------|
78
+ | `inscribe_url` | **URLを刻む**(SNS、記事、動画など)|
79
+ | `inscribe` | テキストを刻む |
80
+ | `verify` | 刻んだ内容を検証 |
81
+ | `history` | 履歴を取得 |
82
+ | `identity` | 信頼IDを作成(DID) |
83
+
84
+ ### inscribe_url - キラーフィーチャー
85
+
86
+ ```javascript
87
+ // 自動取得
88
+ inscribe_url({ url: "https://x.com/user/status/xxx" })
89
+
90
+ // 目撃証言(自動取得できない場合)
91
+ inscribe_url({
92
+ url: "https://example.com/page",
93
+ content: "このページに〇〇と書いてあった",
94
+ note: "スクショも撮った"
95
+ })
96
+ ```
97
+
98
+ **対応プラットフォーム:**
99
+ - ✅ X/Twitter (oEmbed)
100
+ - ✅ YouTube (oEmbed)
101
+ - 📝 その他(手動で content 指定)
102
+
103
+ ### inscribe - テキストを刻む
104
+
105
+ ```javascript
106
+ inscribe({
107
+ content: "2025年にビットコインは10万ドルを超える",
108
+ type: "prediction",
109
+ author: "did:hedera:testnet:0.0.1234567"
110
+ })
111
+ ```
112
+
113
+ ### verify - 検証
114
+
115
+ ```javascript
116
+ verify({
117
+ inscription_id: "0.0.7503789-1703412000.123456789",
118
+ content: "検証したい元テキスト" // オプション
119
+ })
120
+ ```
121
+
122
+ ## Layer 2 API(開発者向け)
123
+
124
+ 通常は不要。デバッグや直接操作が必要な場合のみ。
125
+
126
+ | ツール | 説明 |
127
+ |--------|------|
128
+ | `hcs_create_topic` | HCS トピック作成 |
129
+ | `hcs_submit_message` | HCS メッセージ送信 |
130
+ | `hcs_get_messages` | HCS メッセージ取得 |
131
+ | `account_get_balance` | HBAR 残高確認 |
132
+ | `account_send_hbar` | HBAR 送金 |
133
+ | `account_get_info` | アカウント情報取得 |
134
+
135
+ ## Philosophy
136
+
137
+ ```
138
+ ┌─────────────────────────────────────────────┐
139
+ │ あなたが呼ぶもの │
140
+ │ inscribe / verify / history / identity │
141
+ ├─────────────────────────────────────────────┤
142
+ │ 内部で起きていること(見えない) │
143
+ │ Hedera Consensus Service │
144
+ │ Cryptographic Hashing │
145
+ │ DID / Decentralized Identity │
146
+ └─────────────────────────────────────────────┘
147
+ ```
148
+
149
+ **ブロックチェーンは手段。信頼が目的。**
150
+
151
+ ## Use Cases
152
+
153
+ ### SNS投稿の証拠保全
154
+
155
+ ```
156
+ User: イーロン・マスクのこのツイートを刻んで
157
+ https://x.com/elonmusk/status/xxx
158
+
159
+ → 後で削除されても「この時点で存在した」証明になる
160
+ ```
161
+
162
+ ### 予言・予測の証明
163
+
164
+ ```
165
+ User: 「2025年末にHBARは$1を超える」と刻んで
166
+
167
+ → 後から「俺は言ってた」と証明できる
168
+ ```
169
+
170
+ ### AI判断の記録
171
+
172
+ ```
173
+ User: この分析結果を刻んで
174
+ {"analysis": "...", "confidence": 0.95}
175
+
176
+ → AIの判断過程を検証可能な形で記録
177
+ ```
178
+
179
+ ## CLI Commands
180
+
181
+ 観測・設定用のCLIツールを提供します(Read-Only、トランザクションは送信しません)。
182
+
183
+ ```bash
184
+ # 初期設定
185
+ inscribe-mcp init
186
+
187
+ # 設定確認
188
+ inscribe-mcp config
189
+
190
+ # 残高確認
191
+ inscribe-mcp balance
192
+
193
+ # ダッシュボード表示
194
+ inscribe-mcp show
195
+
196
+ # ログ表示
197
+ inscribe-mcp log # 最新10件
198
+ inscribe-mcp log --tail 20 # 最新20件
199
+ inscribe-mcp log --since 1h # 過去1時間
200
+ inscribe-mcp log --error # エラーのみ
201
+ ```
202
+
203
+ ### ダッシュボード例
204
+
205
+ ```
206
+ inscribe-mcp status (network: testnet)
207
+ ════════════════════════════════════════════════════════════
208
+ Operator: 0.0.7455134
209
+ Balance: 985.63 HBAR
210
+ Topic: 0.0.7503789
211
+
212
+ MCP Activity (total)
213
+ ────────────────────────────────────────────────────────────
214
+ Inscribe calls: 3 (success 2 / fail 1)
215
+ Verify calls: 1 (success 1 / fail 0)
216
+ History calls: 0 (success 0 / fail 0)
217
+ Avg latency: 1460 ms
218
+
219
+ Timeline
220
+ ────────────────────────────────────────────────────────────
221
+ Last inscribe: 1m ago
222
+ Last verify: 8m ago
223
+ Last error: none
224
+
225
+ Links
226
+ ────────────────────────────────────────────────────────────
227
+ Account: https://hashscan.io/testnet/account/0.0.7455134
228
+ Topic: https://hashscan.io/testnet/topic/0.0.7503789
229
+ ```
230
+
231
+ ## Configuration
232
+
233
+ 設定は `~/.inscribe-mcp/config.json` に保存されます:
234
+
235
+ ```json
236
+ {
237
+ "network": "testnet",
238
+ "operatorAccountId": "0.0.XXXXXX",
239
+ "operatorPrivateKey": "302e...",
240
+ "defaultTopicId": "0.0.XXXXXX"
241
+ }
242
+ ```
243
+
244
+ - `defaultTopicId` は初回 inscribe 時に自動作成されます
245
+ - 環境変数(`.env`)からのフォールバックもサポート
246
+
247
+ ## Links
248
+
249
+ - [POP@AI](https://popatai.com) - Proof of Protocol for AI
250
+ - [Hedera](https://hedera.com) - The trust layer of the internet
251
+ - [HashScan](https://hashscan.io) - Hedera Explorer
252
+
253
+ ## License
254
+
255
+ MIT
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@proofofprotocol/inscribe-mcp",
3
+ "version": "0.1.0",
4
+ "description": "Verifiable inscription for AI agents - inscribe anything to blockchain with Hedera HCS",
5
+ "type": "module",
6
+ "main": "src/server.js",
7
+ "bin": {
8
+ "inscribe-mcp": "./src/cli/index.js",
9
+ "inscribe-mcp-server": "./src/server.js"
10
+ },
11
+ "scripts": {
12
+ "start": "node src/server.js",
13
+ "start:sse": "node src/server-sse.js",
14
+ "cli": "node src/cli/index.js",
15
+ "test": "node src/test.js"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "hedera",
21
+ "hcs",
22
+ "inscription",
23
+ "verifiable",
24
+ "trust",
25
+ "blockchain",
26
+ "timestamp",
27
+ "proof",
28
+ "ai-agent",
29
+ "did",
30
+ "decentralized-identity"
31
+ ],
32
+ "author": "POP@AI",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/proofofprotocol/inscribe-mcp.git"
37
+ },
38
+ "homepage": "https://github.com/proofofprotocol/inscribe-mcp#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/proofofprotocol/inscribe-mcp/issues"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ },
45
+ "files": [
46
+ "src/**/*",
47
+ "README.md",
48
+ "LICENSE"
49
+ ],
50
+ "dependencies": {
51
+ "@hashgraph/sdk": "^2.51.0",
52
+ "@modelcontextprotocol/sdk": "^1.0.0",
53
+ "commander": "^12.1.0",
54
+ "cors": "^2.8.5",
55
+ "dotenv": "^16.3.1",
56
+ "express": "^4.18.2"
57
+ }
58
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * balance command
3
+ *
4
+ * Display current account balance via Mirror Node API.
5
+ * Read-Only: No transactions sent.
6
+ */
7
+
8
+ import { Command } from 'commander';
9
+ import { configExists, readConfig, validateConfig } from '../lib/config.js';
10
+ import { EXIT_CODES } from '../lib/exit-codes.js';
11
+
12
+ // ANSI colors
13
+ const colors = {
14
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
15
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
16
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
17
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
18
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
19
+ dim: (s) => `\x1b[2m${s}\x1b[0m`
20
+ };
21
+
22
+ /**
23
+ * Get Mirror Node URL for network
24
+ */
25
+ function getMirrorUrl(network) {
26
+ return network === 'mainnet'
27
+ ? 'https://mainnet.mirrornode.hedera.com'
28
+ : 'https://testnet.mirrornode.hedera.com';
29
+ }
30
+
31
+ /**
32
+ * Format tinybars to HBAR
33
+ */
34
+ function formatHbar(tinybars) {
35
+ const hbar = tinybars / 100_000_000;
36
+ return hbar.toFixed(8) + ' HBAR';
37
+ }
38
+
39
+ /**
40
+ * Format tinybars to HBAR (short)
41
+ */
42
+ function formatHbarShort(tinybars) {
43
+ const hbar = tinybars / 100_000_000;
44
+ if (hbar >= 1) {
45
+ return hbar.toFixed(2) + ' HBAR';
46
+ }
47
+ return hbar.toFixed(6) + ' HBAR';
48
+ }
49
+
50
+ export const balanceCommand = new Command('balance')
51
+ .description('Display current account balance')
52
+ .option('--json', 'Output as JSON')
53
+ .action(async (options) => {
54
+ // Check if config exists
55
+ if (!configExists()) {
56
+ console.log('');
57
+ console.log(colors.red('Config not found.'));
58
+ console.log('');
59
+ console.log('Run ' + colors.cyan('inscribe-mcp init') + ' to create configuration.');
60
+ console.log('');
61
+ process.exit(EXIT_CODES.CONFIG_ERROR);
62
+ }
63
+
64
+ // Validate config
65
+ const config = readConfig();
66
+ const validation = validateConfig(config);
67
+
68
+ if (!validation.valid) {
69
+ console.log('');
70
+ console.log(colors.red('Invalid configuration.'));
71
+ console.log('');
72
+ process.exit(EXIT_CODES.CONFIG_ERROR);
73
+ }
74
+
75
+ const { network, operatorAccountId } = config;
76
+ const mirrorUrl = getMirrorUrl(network);
77
+
78
+ try {
79
+ // Fetch account info from Mirror Node
80
+ const response = await fetch(`${mirrorUrl}/api/v1/accounts/${operatorAccountId}`);
81
+
82
+ if (!response.ok) {
83
+ if (response.status === 404) {
84
+ console.log('');
85
+ console.log(colors.red('Account not found: ') + operatorAccountId);
86
+ console.log('');
87
+ console.log('Make sure the account exists on ' + network);
88
+ console.log('');
89
+ process.exit(EXIT_CODES.NETWORK_ERROR);
90
+ }
91
+ throw new Error(`HTTP ${response.status}`);
92
+ }
93
+
94
+ const data = await response.json();
95
+ const balance = data.balance?.balance || 0;
96
+
97
+ if (options.json) {
98
+ console.log(JSON.stringify({
99
+ network,
100
+ accountId: operatorAccountId,
101
+ balance: formatHbar(balance),
102
+ balanceTinybars: balance
103
+ }, null, 2));
104
+ process.exit(EXIT_CODES.SUCCESS);
105
+ }
106
+
107
+ // Pretty print
108
+ console.log('');
109
+ console.log(colors.bold('Account Balance'));
110
+ console.log('─'.repeat(40));
111
+ console.log('');
112
+ console.log(` ${colors.dim('Network:')} ${colors.cyan(network)}`);
113
+ console.log(` ${colors.dim('Account:')} ${operatorAccountId}`);
114
+ console.log('');
115
+ console.log(` ${colors.dim('Balance:')} ${colors.green(colors.bold(formatHbarShort(balance)))}`);
116
+ console.log(` ${colors.dim('(' + balance.toLocaleString() + ' tinybars)')}`);
117
+ console.log('');
118
+
119
+ // Estimate inscriptions
120
+ const costPerInscribe = 0.0001; // ~$0.0001 per HCS message
121
+ const hbar = balance / 100_000_000;
122
+ const estimatedInscriptions = Math.floor(hbar / costPerInscribe);
123
+
124
+ console.log(` ${colors.dim('Estimated inscriptions:')} ~${estimatedInscriptions.toLocaleString()}`);
125
+ console.log('');
126
+
127
+ // Low balance warning
128
+ if (hbar < 0.1) {
129
+ console.log(colors.yellow('⚠ Low balance warning'));
130
+ console.log(' Consider adding more HBAR to continue inscribing.');
131
+ console.log('');
132
+ }
133
+
134
+ // HashScan link
135
+ const hashscanUrl = network === 'mainnet'
136
+ ? `https://hashscan.io/mainnet/account/${operatorAccountId}`
137
+ : `https://hashscan.io/testnet/account/${operatorAccountId}`;
138
+
139
+ console.log(` ${colors.dim('HashScan:')} ${hashscanUrl}`);
140
+ console.log('');
141
+
142
+ process.exit(EXIT_CODES.SUCCESS);
143
+
144
+ } catch (error) {
145
+ console.log('');
146
+ console.log(colors.red('Failed to fetch balance:'));
147
+ console.log(' ' + error.message);
148
+ console.log('');
149
+ process.exit(EXIT_CODES.NETWORK_ERROR);
150
+ }
151
+ });
@@ -0,0 +1,87 @@
1
+ /**
2
+ * config command
3
+ *
4
+ * Display current configuration (with masked private key).
5
+ */
6
+
7
+ import { Command } from 'commander';
8
+ import { configExists, getDisplayConfig, getConfigPath, validateConfig, readConfig } from '../lib/config.js';
9
+ import { EXIT_CODES } from '../lib/exit-codes.js';
10
+
11
+ // ANSI colors
12
+ const colors = {
13
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
14
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
15
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
16
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
17
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
18
+ dim: (s) => `\x1b[2m${s}\x1b[0m`
19
+ };
20
+
21
+ export const configCommand = new Command('config')
22
+ .description('Display current configuration')
23
+ .option('--json', 'Output as JSON (private key still masked)')
24
+ .action(async (options) => {
25
+ // Check if config exists
26
+ if (!configExists()) {
27
+ console.log('');
28
+ console.log(colors.red('Config not found.'));
29
+ console.log('');
30
+ console.log('Run ' + colors.cyan('inscribe-mcp init') + ' to create configuration.');
31
+ console.log('');
32
+ process.exit(EXIT_CODES.CONFIG_ERROR);
33
+ }
34
+
35
+ // Validate config
36
+ const rawConfig = readConfig();
37
+ const validation = validateConfig(rawConfig);
38
+
39
+ if (!validation.valid) {
40
+ console.log('');
41
+ console.log(colors.red('Invalid configuration:'));
42
+ validation.errors.forEach(err => {
43
+ console.log(' • ' + err);
44
+ });
45
+ console.log('');
46
+ console.log('Run ' + colors.cyan('inscribe-mcp init --force') + ' to reconfigure.');
47
+ console.log('');
48
+ process.exit(EXIT_CODES.CONFIG_ERROR);
49
+ }
50
+
51
+ // Get display config (masked)
52
+ const config = getDisplayConfig();
53
+
54
+ if (options.json) {
55
+ console.log(JSON.stringify(config, null, 2));
56
+ process.exit(EXIT_CODES.SUCCESS);
57
+ }
58
+
59
+ // Pretty print
60
+ console.log('');
61
+ console.log(colors.bold('inscribe-mcp Configuration'));
62
+ console.log('─'.repeat(40));
63
+ console.log('');
64
+ console.log(` ${colors.dim('File:')} ${getConfigPath()}`);
65
+ console.log('');
66
+ console.log(` ${colors.dim('Network:')} ${colors.cyan(config.network)}`);
67
+ console.log(` ${colors.dim('Account:')} ${config.operatorAccountId}`);
68
+ console.log(` ${colors.dim('Key:')} ${config.operatorPrivateKey}`);
69
+
70
+ if (config.defaultTopicId) {
71
+ console.log(` ${colors.dim('Topic:')} ${config.defaultTopicId}`);
72
+ } else {
73
+ console.log(` ${colors.dim('Topic:')} ${colors.dim('(auto-create on first inscribe)')}`);
74
+ }
75
+
76
+ console.log('');
77
+
78
+ // HashScan link
79
+ const hashscanUrl = config.network === 'mainnet'
80
+ ? `https://hashscan.io/mainnet/account/${config.operatorAccountId}`
81
+ : `https://hashscan.io/testnet/account/${config.operatorAccountId}`;
82
+
83
+ console.log(` ${colors.dim('HashScan:')} ${hashscanUrl}`);
84
+ console.log('');
85
+
86
+ process.exit(EXIT_CODES.SUCCESS);
87
+ });