note-connector 0.2.5 → 0.2.6
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/dist/paths.js +4 -0
- package/dist/setup-dependencies.js +56 -13
- package/package.json +3 -2
- package/py/pyproject.toml +86 -0
- package/py/src/note_mcp/__init__.py +7 -0
- package/py/src/note_mcp/__main__.py +65 -0
- package/py/src/note_mcp/api/__init__.py +31 -0
- package/py/src/note_mcp/api/articles.py +1395 -0
- package/py/src/note_mcp/api/client.py +318 -0
- package/py/src/note_mcp/api/embeds.py +482 -0
- package/py/src/note_mcp/api/images.py +456 -0
- package/py/src/note_mcp/api/preview.py +142 -0
- package/py/src/note_mcp/api/public_notes.py +150 -0
- package/py/src/note_mcp/auth/__init__.py +9 -0
- package/py/src/note_mcp/auth/browser.py +574 -0
- package/py/src/note_mcp/auth/file_session.py +145 -0
- package/py/src/note_mcp/auth/session.py +240 -0
- package/py/src/note_mcp/browser/__init__.py +10 -0
- package/py/src/note_mcp/browser/config.py +21 -0
- package/py/src/note_mcp/browser/manager.py +182 -0
- package/py/src/note_mcp/browser/preview.py +68 -0
- package/py/src/note_mcp/browser/url_helpers.py +18 -0
- package/py/src/note_mcp/chatgpt/__init__.py +1 -0
- package/py/src/note_mcp/chatgpt/__main__.py +63 -0
- package/py/src/note_mcp/chatgpt/access_log.py +25 -0
- package/py/src/note_mcp/chatgpt/auth.py +52 -0
- package/py/src/note_mcp/chatgpt/images.py +92 -0
- package/py/src/note_mcp/chatgpt/login_once.py +26 -0
- package/py/src/note_mcp/chatgpt/middleware.py +31 -0
- package/py/src/note_mcp/chatgpt/tools.py +255 -0
- package/py/src/note_mcp/chatgpt/widgets.py +121 -0
- package/py/src/note_mcp/decorators.py +113 -0
- package/py/src/note_mcp/investigator/__init__.py +33 -0
- package/py/src/note_mcp/investigator/__main__.py +11 -0
- package/py/src/note_mcp/investigator/cli.py +313 -0
- package/py/src/note_mcp/investigator/core.py +653 -0
- package/py/src/note_mcp/investigator/mcp_tools.py +225 -0
- package/py/src/note_mcp/models.py +557 -0
- package/py/src/note_mcp/py.typed +0 -0
- package/py/src/note_mcp/server.py +905 -0
- package/py/src/note_mcp/utils/__init__.py +7 -0
- package/py/src/note_mcp/utils/file_parser.py +314 -0
- package/py/src/note_mcp/utils/html_to_markdown.py +477 -0
- package/py/src/note_mcp/utils/logging.py +119 -0
- package/py/src/note_mcp/utils/markdown.py +12 -0
- package/py/src/note_mcp/utils/markdown_to_html.py +826 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Investigator MCP tools for AI-driven API investigation.
|
|
2
|
+
|
|
3
|
+
Provides MCP tools for browser automation and HTTP traffic analysis.
|
|
4
|
+
These tools enable AI agents to investigate note.com's API behavior
|
|
5
|
+
through direct browser interaction and traffic capture.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from typing import TYPE_CHECKING, Annotated
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from fastmcp import FastMCP
|
|
16
|
+
|
|
17
|
+
from note_mcp.investigator.core import CaptureSessionManager
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def register_investigator_tools(mcp: FastMCP) -> None:
|
|
23
|
+
"""Register investigator MCP tools with the server.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
mcp: FastMCP server instance to register tools with
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
@mcp.tool()
|
|
30
|
+
async def investigator_start_capture(
|
|
31
|
+
domain: Annotated[str, "キャプチャ対象ドメイン(例: api.note.com)"],
|
|
32
|
+
port: Annotated[int, "プロキシポート"] = 8080,
|
|
33
|
+
) -> str:
|
|
34
|
+
"""キャプチャセッションを開始します。
|
|
35
|
+
|
|
36
|
+
ブラウザとプロキシを起動し、指定ドメインのHTTPトラフィックを
|
|
37
|
+
キャプチャ可能な状態にします。
|
|
38
|
+
"""
|
|
39
|
+
try:
|
|
40
|
+
await CaptureSessionManager.get_or_create(domain, port)
|
|
41
|
+
return f"Capture session started for domain: {domain}, port: {port}"
|
|
42
|
+
except RuntimeError as e:
|
|
43
|
+
return f"Error: Failed to start capture session: {e}"
|
|
44
|
+
except Exception as e:
|
|
45
|
+
logger.error(f"Unexpected error starting capture: {e}")
|
|
46
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
47
|
+
|
|
48
|
+
@mcp.tool()
|
|
49
|
+
async def investigator_stop_capture() -> str:
|
|
50
|
+
"""キャプチャセッションを停止します。
|
|
51
|
+
|
|
52
|
+
ブラウザとプロキシを終了し、キャプチャデータを保存します。
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
await CaptureSessionManager.close()
|
|
56
|
+
return "Capture session stopped"
|
|
57
|
+
except Exception as e:
|
|
58
|
+
logger.error(f"Error stopping capture: {e}")
|
|
59
|
+
return f"Error: Failed to stop capture session: {e}"
|
|
60
|
+
|
|
61
|
+
@mcp.tool()
|
|
62
|
+
async def investigator_get_status() -> str:
|
|
63
|
+
"""現在のキャプチャセッション状態を取得します。
|
|
64
|
+
|
|
65
|
+
セッションがアクティブか、キャプチャ中のドメイン等の情報を返します。
|
|
66
|
+
"""
|
|
67
|
+
status = CaptureSessionManager.get_status()
|
|
68
|
+
return json.dumps(status, ensure_ascii=False, indent=2)
|
|
69
|
+
|
|
70
|
+
@mcp.tool()
|
|
71
|
+
async def investigator_navigate(
|
|
72
|
+
url: Annotated[str, "移動先URL"],
|
|
73
|
+
) -> str:
|
|
74
|
+
"""指定URLに移動します。
|
|
75
|
+
|
|
76
|
+
ブラウザを指定URLに移動させ、ページタイトルを返します。
|
|
77
|
+
トラフィックは自動的にキャプチャされます。
|
|
78
|
+
"""
|
|
79
|
+
session = await CaptureSessionManager.get_active_session()
|
|
80
|
+
if not session:
|
|
81
|
+
return "Error: No active capture session. Start one first."
|
|
82
|
+
try:
|
|
83
|
+
return await session.navigate(url)
|
|
84
|
+
except TimeoutError:
|
|
85
|
+
return f"Error: Navigation to {url} timed out."
|
|
86
|
+
except RuntimeError as e:
|
|
87
|
+
return f"Error: {e}"
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error(f"Navigation failed: {e}")
|
|
90
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
91
|
+
|
|
92
|
+
@mcp.tool()
|
|
93
|
+
async def investigator_click(
|
|
94
|
+
selector: Annotated[str, "CSSセレクタ"],
|
|
95
|
+
) -> str:
|
|
96
|
+
"""セレクタで指定した要素をクリックします。
|
|
97
|
+
|
|
98
|
+
CSSセレクタを使用してページ上の要素を特定し、クリックします。
|
|
99
|
+
クリックにより発生するHTTPリクエストはキャプチャされます。
|
|
100
|
+
"""
|
|
101
|
+
session = await CaptureSessionManager.get_active_session()
|
|
102
|
+
if not session:
|
|
103
|
+
return "Error: No active capture session. Start one first."
|
|
104
|
+
try:
|
|
105
|
+
return await session.click(selector)
|
|
106
|
+
except TimeoutError:
|
|
107
|
+
return f"Error: Click on '{selector}' timed out."
|
|
108
|
+
except RuntimeError as e:
|
|
109
|
+
return f"Error: {e}"
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.error(f"Click failed: {e}")
|
|
112
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
113
|
+
|
|
114
|
+
@mcp.tool()
|
|
115
|
+
async def investigator_type(
|
|
116
|
+
selector: Annotated[str, "CSSセレクタ"],
|
|
117
|
+
text: Annotated[str, "入力テキスト"],
|
|
118
|
+
) -> str:
|
|
119
|
+
"""指定要素にテキストを入力します。
|
|
120
|
+
|
|
121
|
+
CSSセレクタで特定した入力要素にテキストを入力します。
|
|
122
|
+
"""
|
|
123
|
+
session = await CaptureSessionManager.get_active_session()
|
|
124
|
+
if not session:
|
|
125
|
+
return "Error: No active capture session. Start one first."
|
|
126
|
+
try:
|
|
127
|
+
return await session.type_text(selector, text)
|
|
128
|
+
except TimeoutError:
|
|
129
|
+
return f"Error: Typing into '{selector}' timed out."
|
|
130
|
+
except RuntimeError as e:
|
|
131
|
+
return f"Error: {e}"
|
|
132
|
+
except Exception as e:
|
|
133
|
+
logger.error(f"Type failed: {e}")
|
|
134
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
135
|
+
|
|
136
|
+
@mcp.tool()
|
|
137
|
+
async def investigator_screenshot() -> str:
|
|
138
|
+
"""現在のページのスクリーンショットを取得します。
|
|
139
|
+
|
|
140
|
+
ページ全体のスクリーンショットをbase64エンコードされたPNG形式で返します。
|
|
141
|
+
"""
|
|
142
|
+
session = await CaptureSessionManager.get_active_session()
|
|
143
|
+
if not session:
|
|
144
|
+
return "Error: No active capture session. Start one first."
|
|
145
|
+
try:
|
|
146
|
+
return await session.screenshot()
|
|
147
|
+
except RuntimeError as e:
|
|
148
|
+
return f"Error: {e}"
|
|
149
|
+
except Exception as e:
|
|
150
|
+
logger.error(f"Screenshot failed: {e}")
|
|
151
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
152
|
+
|
|
153
|
+
@mcp.tool()
|
|
154
|
+
async def investigator_get_page_content() -> str:
|
|
155
|
+
"""現在のページのHTMLを取得します。
|
|
156
|
+
|
|
157
|
+
ページの完全なHTMLソースを返します。
|
|
158
|
+
"""
|
|
159
|
+
session = await CaptureSessionManager.get_active_session()
|
|
160
|
+
if not session:
|
|
161
|
+
return "Error: No active capture session. Start one first."
|
|
162
|
+
try:
|
|
163
|
+
return await session.get_page_content()
|
|
164
|
+
except RuntimeError as e:
|
|
165
|
+
return f"Error: {e}"
|
|
166
|
+
except Exception as e:
|
|
167
|
+
logger.error(f"Get page content failed: {e}")
|
|
168
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
169
|
+
|
|
170
|
+
@mcp.tool()
|
|
171
|
+
async def investigator_get_traffic(
|
|
172
|
+
pattern: Annotated[str | None, "URLパターンでフィルタ(正規表現)"] = None,
|
|
173
|
+
) -> str:
|
|
174
|
+
"""キャプチャしたトラフィック一覧を取得します。
|
|
175
|
+
|
|
176
|
+
これまでにキャプチャしたHTTPリクエストの一覧をJSON形式で返します。
|
|
177
|
+
パターンを指定すると、URLが一致するリクエストのみ返します。
|
|
178
|
+
"""
|
|
179
|
+
session = await CaptureSessionManager.get_active_session()
|
|
180
|
+
if not session:
|
|
181
|
+
return "Error: No active capture session. Start one first."
|
|
182
|
+
try:
|
|
183
|
+
traffic = session.get_traffic(pattern)
|
|
184
|
+
return json.dumps(traffic, ensure_ascii=False, indent=2)
|
|
185
|
+
except Exception as e:
|
|
186
|
+
logger.error(f"Get traffic failed: {e}")
|
|
187
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
188
|
+
|
|
189
|
+
@mcp.tool()
|
|
190
|
+
async def investigator_analyze(
|
|
191
|
+
pattern: Annotated[str, "URLパターン(正規表現)"],
|
|
192
|
+
method: Annotated[str | None, "HTTPメソッドでフィルタ"] = None,
|
|
193
|
+
) -> str:
|
|
194
|
+
"""特定パターンのトラフィックを詳細分析します。
|
|
195
|
+
|
|
196
|
+
指定したURLパターンに一致するリクエストを集計・分析し、
|
|
197
|
+
レポート形式で返します。
|
|
198
|
+
"""
|
|
199
|
+
session = await CaptureSessionManager.get_active_session()
|
|
200
|
+
if not session:
|
|
201
|
+
return "Error: No active capture session. Start one first."
|
|
202
|
+
try:
|
|
203
|
+
return session.analyze_traffic(pattern, method)
|
|
204
|
+
except Exception as e:
|
|
205
|
+
logger.error(f"Analyze traffic failed: {e}")
|
|
206
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
207
|
+
|
|
208
|
+
@mcp.tool()
|
|
209
|
+
async def investigator_export(
|
|
210
|
+
output_path: Annotated[str, "出力ファイルパス"],
|
|
211
|
+
) -> str:
|
|
212
|
+
"""キャプチャデータをJSONファイルにエクスポートします。
|
|
213
|
+
|
|
214
|
+
これまでにキャプチャした全トラフィックをJSONファイルに保存します。
|
|
215
|
+
"""
|
|
216
|
+
session = await CaptureSessionManager.get_active_session()
|
|
217
|
+
if not session:
|
|
218
|
+
return "Error: No active capture session. Start one first."
|
|
219
|
+
try:
|
|
220
|
+
return session.export_traffic(output_path)
|
|
221
|
+
except OSError as e:
|
|
222
|
+
return f"Error: Failed to write file: {e}"
|
|
223
|
+
except Exception as e:
|
|
224
|
+
logger.error(f"Export failed: {e}")
|
|
225
|
+
return f"Error: {type(e).__name__}: {e}"
|